Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of LCVR Fixes v2.0.1
BepInEx/plugins/BonemansLCVRFixes/BonemansLCVRFixes.dll
Decompiled 2 days agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using DunGen.Graph; using GameNetcodeStuff; using HarmonyLib; using LCVR; using LCVR.Input; using LCVR.Managers; using LCVR.Networking; using LCVR.Physics.Interactions; using LCVR.Physics.Interactions.Car; using LCVR.Player; using LCVR.UI.Spectating; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.HighDefinition; using UnityEngine.UI; using UnityEngine.XR; using UnityEngine.XR.OpenXR; using VRShaderFix; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("BonemansLCVRFixes")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+f00e3e0edbf530a36e7eb201259842f2ebe46042")] [assembly: AssemblyProduct("BonemansLCVRFixes")] [assembly: AssemblyTitle("BonemansLCVRFixes")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace VRShaderFix { public class ShaderFixer : MonoBehaviour { internal static ManualLogSource Log; private readonly Dictionary<Material, Material> converted = new Dictionary<Material, Material>(); private readonly Dictionary<Material, Material> convertedWorld = new Dictionary<Material, Material>(); private readonly Dictionary<string, Shader> gameShaders = new Dictionary<string, Shader>(); private readonly HashSet<string> reportedUnfixable = new HashSet<string>(); private int worldFixed; private ConfigEntry<bool> pluginEnabled; private ConfigEntry<bool> fixCosmetics; private ConfigEntry<bool> fixItems; private ConfigEntry<bool> fixInteriors; private Type configMenuType; private Type cosmeticType; private Shader vrTextShader; private bool loggedFirstFix; internal static void Bind(ConfigFile config, out ConfigEntry<bool> enabled, out ConfigEntry<bool> cosmetics, out ConfigEntry<bool> items, out ConfigEntry<bool> interiors) { enabled = config.Bind<bool>("Shaders", "Enabled", true, "Swap mod shaders that only draw in one eye for VR-safe ones (LethalConfig text plus the options below). Only does anything in VR."); cosmetics = config.Bind<bool>("Shaders", "FixCosmetics", true, "Put MoreCompany cosmetics on the game's own VR-capable shaders so they stop floating off players."); items = config.Bind<bool>("Shaders", "FixItems", true, "Put modded scrap and items on the game's own VR-capable shaders."); interiors = config.Bind<bool>("Shaders", "FixInteriors", true, "Put custom interiors (modded dungeons) on the game's own VR-capable shaders so walls stop wobbling."); } internal void Init(ManualLogSource log, ConfigEntry<bool> enabled, ConfigEntry<bool> cosmetics, ConfigEntry<bool> items, ConfigEntry<bool> interiors) { Log = log; pluginEnabled = enabled; fixCosmetics = cosmetics; fixItems = items; fixInteriors = interiors; } private void Start() { if (!pluginEnabled.Value) { Log.LogInfo((object)"Disabled by config"); } else { ((MonoBehaviour)this).StartCoroutine(Run()); } } private IEnumerator Run() { yield return null; if (Type.GetType("LCVR.Managers.VRSession, LCVR")?.GetProperty("InVR", BindingFlags.Static | BindingFlags.Public)?.GetValue(null) as bool? != true) { Log.LogInfo((object)"Not running in VR, doing nothing"); yield break; } configMenuType = Type.GetType("LethalConfig.MonoBehaviours.ConfigMenu, LethalConfig"); cosmeticType = Type.GetType("MoreCompany.Cosmetics.CosmeticInstance, MoreCompany"); if (fixInteriors.Value) { ((MonoBehaviour)this).StartCoroutine(FixInteriorLoop()); } while (true) { yield return (object)new WaitForSeconds(1f); try { if (configMenuType != null) { FixConfigMenus(); } } catch (Exception arg) { Log.LogError((object)$"Failed to fix LethalConfig text: {arg}"); } try { FixWorld(); } catch (Exception arg2) { Log.LogError((object)$"Failed to fix cosmetics/items: {arg2}"); } } } private bool LoadGameShaders() { if (gameShaders.Count > 0) { return true; } StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.playerPrefab == (Object)null) { return false; } Renderer[] componentsInChildren = instance.playerPrefab.GetComponentsInChildren<Renderer>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Material[] sharedMaterials = componentsInChildren[i].sharedMaterials; foreach (Material val in sharedMaterials) { if ((Object)(object)val != (Object)null && (Object)(object)val.shader != (Object)null && !gameShaders.ContainsKey(((Object)val.shader).name)) { gameShaders[((Object)val.shader).name] = val.shader; } } } if (gameShaders.Count > 0) { Log.LogInfo((object)("Game shaders from player prefab: " + string.Join(", ", gameShaders.Keys))); } return gameShaders.Count > 0; } private void FixWorld() { //IL_006b: Unknown result type (might be due to invalid IL or missing references) if (((!fixCosmetics.Value || cosmeticType == null) && !fixItems.Value) || !LoadGameShaders()) { return; } int num = worldFixed; if (fixCosmetics.Value && cosmeticType != null) { Object[] array = Object.FindObjectsOfType(cosmeticType, true); foreach (Object val in array) { FixRenderers(((Component)val).gameObject, "cosmetic"); } } if (fixItems.Value) { GrabbableObject[] array2 = Object.FindObjectsOfType<GrabbableObject>(); foreach (GrabbableObject val2 in array2) { FixRenderers(((Component)val2).gameObject, "item"); } } if (worldFixed > num) { Log.LogInfo((object)$"Switched {worldFixed - num} cosmetic/item material(s) to the game's shaders ({worldFixed} total)"); } } private void FixRenderers(GameObject root, string kind) { Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true); foreach (Renderer renderer in componentsInChildren) { FixRenderer(renderer, kind, ((Object)root).name); } } private void FixRenderer(Renderer renderer, string kind, string ownerName) { //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Expected O, but got Unknown Material[] sharedMaterials = renderer.sharedMaterials; bool flag = false; for (int i = 0; i < sharedMaterials.Length; i++) { Material val = sharedMaterials[i]; if ((Object)(object)val == (Object)null || (Object)(object)val.shader == (Object)null) { continue; } if (!gameShaders.TryGetValue(((Object)val.shader).name, out var value)) { if (reportedUnfixable.Add(((Object)val.shader).name)) { Log.LogInfo((object)("Can't fix " + kind + " '" + ownerName + "': shader '" + ((Object)val.shader).name + "' has no game version")); } } else if (!((Object)(object)val.shader == (Object)(object)value)) { if (!convertedWorld.TryGetValue(val, out var value2) || (Object)(object)value2 == (Object)null) { value2 = new Material(val) { shader = value, renderQueue = val.renderQueue, name = ((Object)val).name + " (VR)" }; convertedWorld[val] = value2; } sharedMaterials[i] = value2; flag = true; worldFixed++; } } if (flag) { renderer.sharedMaterials = sharedMaterials; } } private IEnumerator FixInteriorLoop() { int lastDungeon = 0; while (true) { yield return (object)new WaitForSeconds(2f); RoundManager round = RoundManager.Instance; GameObject root = ((!((Object)(object)round != (Object)null) || !round.dungeonCompletedGenerating) ? null : round.dungeonGenerator?.Generator?.Root); if ((Object)(object)root == (Object)null || ((Object)root).GetInstanceID() == lastDungeon || !LoadGameShaders()) { continue; } lastDungeon = ((Object)root).GetInstanceID(); Renderer[] renderers = root.GetComponentsInChildren<Renderer>(true); int before = worldFixed; for (int i = 0; i < renderers.Length; i++) { try { if ((Object)(object)renderers[i] != (Object)null) { ShaderFixer shaderFixer = this; Renderer renderer = renderers[i]; DungeonFlow dungeonFlow = round.dungeonGenerator.Generator.DungeonFlow; shaderFixer.FixRenderer(renderer, "interior", ((dungeonFlow != null) ? ((Object)dungeonFlow).name : null) ?? ((Object)root).name); } } catch (Exception ex) { Log.LogError((object)("Failed to fix interior renderer: " + ex.Message)); } if (i % 250 == 249) { yield return null; } } Log.LogInfo((object)$"Interior: switched {worldFixed - before} material(s) on {renderers.Length} renderers to the game's shaders"); } } private void FixConfigMenus() { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Expected O, but got Unknown Object[] array = Object.FindObjectsOfType(configMenuType, true); if (array.Length == 0) { return; } if ((Object)(object)vrTextShader == (Object)null) { ref Shader reference = ref vrTextShader; object? obj = Type.GetType("LCVR.Assets.AssetManager, LCVR")?.GetField("TMPAlwaysOnTop", BindingFlags.Static | BindingFlags.Public)?.GetValue(null); reference = (Shader)((obj is Shader) ? obj : null); if ((Object)(object)vrTextShader == (Object)null) { return; } } Object[] array2 = array; for (int i = 0; i < array2.Length; i++) { Transform transform = ((Component)array2[i]).transform; FixTree(transform); if ((Object)(object)transform.parent == (Object)null) { continue; } foreach (Transform item in transform.parent) { Transform val = item; if ((Object)(object)val != (Object)(object)transform && ((Object)val).name.StartsWith("ConfigMenu")) { FixTree(val); } } } } private void FixTree(Transform root) { int num = 0; TMP_Text[] componentsInChildren = ((Component)root).GetComponentsInChildren<TMP_Text>(true); foreach (TMP_Text val in componentsInChildren) { Material val2 = Convert(val.fontSharedMaterial); if ((Object)(object)val2 != (Object)null) { val.fontSharedMaterial = val2; num++; } } TMP_SubMeshUI[] componentsInChildren2 = ((Component)root).GetComponentsInChildren<TMP_SubMeshUI>(true); foreach (TMP_SubMeshUI val3 in componentsInChildren2) { Material val4 = Convert(val3.sharedMaterial); if ((Object)(object)val4 != (Object)null) { val3.sharedMaterial = val4; num++; } } if (num > 0 && !loggedFirstFix) { loggedFirstFix = true; Log.LogInfo((object)$"Switched LethalConfig text to LCVR's VR text shader ({num} elements under {((Object)root).name})"); } } private Material Convert(Material source) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Expected O, but got Unknown if ((Object)(object)source == (Object)null || (Object)(object)source.shader == (Object)(object)vrTextShader) { return null; } if (!converted.TryGetValue(source, out var value) || (Object)(object)value == (Object)null) { value = new Material(source) { shader = vrTextShader, name = ((Object)source).name + " (VR)" }; converted[source] = value; } return value; } } } namespace LCVRFixes { internal static class ConfigMigration { public static void FromOldPlugins(ConfigFile config) { int num = 0; num += Copy(config, "kylew.lcvrfixes.cfg", (string section, string key) => (section, key)); num += Copy(config, "kylew.vrshaderfix.cfg", (string section, string key) => ("Shaders", key)); if (num > 0) { config.Save(); Plugin.Log.LogInfo((object)$"Copied {num} setting(s) from the old LCVRFixes / VRShaderFix configs"); } } private static int Copy(ConfigFile config, string oldFile, Func<string, string, (string, string)> map) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown string path = Path.Combine(Paths.ConfigPath, oldFile); if (!File.Exists(path)) { return 0; } int num = 0; try { foreach (var item6 in Read(path)) { string item = item6.section; string item2 = item6.key; string item3 = item6.value; (string, string) tuple = map(item, item2); string item4 = tuple.Item1; string item5 = tuple.Item2; ConfigDefinition val = new ConfigDefinition(item4, item5); if (config.ContainsKey(val)) { config[val].SetSerializedValue(item3); num++; } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Couldn't read old settings from " + oldFile + ": " + ex.Message)); } return num; } private static IEnumerable<(string section, string key, string value)> Read(string path) { string section = ""; string[] array = File.ReadAllLines(path); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length == 0 || text.StartsWith("#")) { continue; } if (text.StartsWith("[") && text.EndsWith("]")) { section = text.Substring(1, text.Length - 2).Trim(); continue; } int num = text.IndexOf('='); if (num > 0) { yield return (section: section, key: text.Substring(0, num).Trim(), value: text.Substring(num + 1).Trim()); } } } } internal static class EveryoneFixes { private static Dictionary<string, Type> vrItemTypes; private static Type vrShovelType; internal static readonly Dictionary<GearStick, ushort> gearStickHolders = new Dictionary<GearStick, ushort>(); private static FieldInfo gearIsHeld; private static FieldInfo gearIsHeldByLocal; internal static FieldInfo leverActor; internal static FieldInfo leverRotateTo; internal static FieldInfo leverAnimator; internal static FieldInfo leverShouldTrigger; private static FieldInfo muffledPlayers; private static FieldInfo networkPlayers; private static FieldInfo clientsField; private static FieldInfo subscribersField; private static FieldInfo instanceField; private static MethodInfo initializedGetter; private static MethodInfo sendPacket; private static object handshakeResponse; private static Type clientInfoType; public static void ApplyItemErrors() { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown vrItemTypes = (Dictionary<string, Type>)AccessTools.Field(AccessTools.TypeByName("LCVR.Player.Items"), "items").GetValue(null); vrShovelType = AccessTools.TypeByName("LCVR.Items.VRShovelItem"); Type type = AccessTools.TypeByName("LCVR.Patches.UniversalItemPatches"); Plugin.Harmony.Patch((MethodBase)AccessTools.Method(type, "HandleUpdateItemOffset", (Type[])null, (Type[])null), new HarmonyMethod(typeof(EveryoneFixes), "ItemOffsetPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); HarmonyMethod val = new HarmonyMethod(typeof(EveryoneFixes), "SwallowSlotSwitch", (Type[])null); Plugin.Harmony.Patch((MethodBase)AccessTools.Method(AccessTools.TypeByName("LCVR.Patches.PlayerControllerPatches"), "SwitchedToItemSlot", (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, val, (HarmonyMethod)null); Plugin.Harmony.Patch((MethodBase)AccessTools.Method(AccessTools.TypeByName("LCVR.Patches.UniversalPlayerControllerPatches"), "SwitchedToItemSlot", (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, val, (HarmonyMethod)null); } private static bool ItemOffsetPrefix(GrabbableObject item, ref bool __result) { if (item.itemProperties == null) { __result = false; return false; } if (!Object.op_Implicit((Object)(object)item.itemProperties)) { __result = true; return false; } if (((object)item).GetType() == typeof(Shovel) && vrItemTypes.ContainsKey(((Object)item.itemProperties).name) && (Object)(object)((Component)item).GetComponent(vrShovelType) == (Object)null) { __result = true; return false; } return true; } private static Exception SwallowSlotSwitch(Exception __exception) { if (__exception != null) { Plugin.ReportOnce("LCVR slot switch", __exception); } return null; } public static void ApplyPlayerIdMixup() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Expected O, but got Unknown HarmonyMethod val = new HarmonyMethod(typeof(EveryoneFixes), "SlotLookupTranspiler", (Type[])null); MethodInfo[] array = new MethodInfo[5] { AccessTools.Method(AccessTools.TypeByName("LCVR.Patches.UniversalItemPatches"), "HandleUpdateItemOffset", (Type[])null, (Type[])null), AccessTools.Method(AccessTools.TypeByName("LCVR.Patches.Items.FlashlightItemPatches"), "SwitchFlashlightPatch", (Type[])null, (Type[])null), AccessTools.Method(AccessTools.TypeByName("LCVR.Patches.Items.FlashlightItemPatches"), "PocketFlashlightPatch", (Type[])null, (Type[])null), AccessTools.Method(typeof(SpectatingPlayer), "UpdateState", (Type[])null, (Type[])null), AccessTools.Method(typeof(SpectatingManager), "TeleportToPlayer", (Type[])null, (Type[])null) }; foreach (MethodInfo methodInfo in array) { if (methodInfo == null) { Plugin.Log.LogWarning((object)"A player-ID lookup target wasn't found; skipping it"); } else { Plugin.Harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null); } } Plugin.Harmony.Patch((MethodBase)AccessTools.Method(AccessTools.TypeByName("LCVR.Patches.Items.FlashlightItemPatches"), "PocketFlashlightPatch", (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(EveryoneFixes), "SwallowFlashlight", (Type[])null), (HarmonyMethod)null); } private static IEnumerable<CodeInstruction> SlotLookupTranspiler(IEnumerable<CodeInstruction> instructions) { MethodInfo isInVR = AccessTools.Method(typeof(NetworkSystem), "IsInVR", (Type[])null, (Type[])null); MethodInfo tryGetPlayer = AccessTools.Method(typeof(NetworkSystem), "TryGetPlayer", (Type[])null, (Type[])null); MethodInfo isInVRBySlot = AccessTools.Method(typeof(EveryoneFixes), "IsInVRBySlot", (Type[])null, (Type[])null); MethodInfo tryGetBySlot = AccessTools.Method(typeof(EveryoneFixes), "TryGetPlayerBySlot", (Type[])null, (Type[])null); foreach (CodeInstruction instruction in instructions) { if ((instruction.opcode == OpCodes.Call || instruction.opcode == OpCodes.Callvirt) && instruction.operand is MethodInfo methodInfo) { if (methodInfo == isInVR) { instruction.opcode = OpCodes.Call; instruction.operand = isInVRBySlot; } else if (methodInfo == tryGetPlayer) { instruction.opcode = OpCodes.Call; instruction.operand = tryGetBySlot; } } yield return instruction; } } public static bool IsInVRBySlot(NetworkSystem _, ushort slot) { VRNetPlayer player; return TryGetPlayerBySlot(_, slot, out player); } public static bool TryGetPlayerBySlot(NetworkSystem _, ushort slot, out VRNetPlayer player) { player = null; StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null) { return false; } PlayerControllerB[] allPlayerScripts = instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if ((Object)(object)val != (Object)null && (ushort)val.playerClientId == slot) { player = ((Component)val).GetComponent<VRNetPlayer>(); return (Object)(object)player != (Object)null; } } return false; } private static Exception SwallowFlashlight(Exception __exception) { if (__exception != null) { Plugin.ReportOnce("LCVR pocketed flashlight sync", __exception); } return null; } public static void ApplyStuckLeverAndGearStick() { //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Expected O, but got Unknown //IL_00e3: Expected O, but got Unknown gearIsHeld = AccessTools.Field(typeof(GearStick), "isHeld"); gearIsHeldByLocal = AccessTools.Field(typeof(GearStick), "isHeldByLocal"); leverActor = AccessTools.Field(typeof(ShipLever), "currentActor"); leverRotateTo = AccessTools.Field(typeof(ShipLever), "rotateTo"); leverAnimator = AccessTools.Field(typeof(ShipLever), "animator"); leverShouldTrigger = AccessTools.Field(typeof(ShipLever), "shouldTrigger"); Plugin.Harmony.Patch((MethodBase)AccessTools.Method(typeof(GearStick), "OnPacketReceived", (Type[])null, (Type[])null), new HarmonyMethod(typeof(EveryoneFixes), "GearPacketPrefix", (Type[])null), new HarmonyMethod(typeof(EveryoneFixes), "GearPacketPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Watchdog.CheckLeversAndGearSticks = true; } private static void GearPacketPrefix(GearStick __instance, out bool __state) { __state = (bool)gearIsHeld.GetValue(__instance); } private static void GearPacketPostfix(GearStick __instance, ushort sender, bool __state) { bool flag = (bool)gearIsHeld.GetValue(__instance); if (!__state && flag && !(bool)gearIsHeldByLocal.GetValue(__instance)) { gearStickHolders[__instance] = sender; } else if (__state && !flag) { gearStickHolders.Remove(__instance); } } internal static void ReleaseAbandonedLeversAndGearSticks() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown NetworkSystem instance = NetworkSystem.Instance; if ((Object)(object)instance == (Object)null) { return; } VRNetPlayer[] players = instance.Players; ShipLever[] array = Object.FindObjectsOfType<ShipLever>(); foreach (ShipLever obj in array) { if ((int)leverActor.GetValue(obj) != 2) { continue; } Transform hand = (Transform)leverRotateTo.GetValue(obj); if (!((Object)(object)hand != (Object)null) || !players.Any((VRNetPlayer p) => (Object)(object)p != (Object)null && (Object)(object)p.Bones.RightHand == (Object)(object)hand)) { leverRotateTo.SetValue(obj, null); leverShouldTrigger.SetValue(obj, Enum.ToObject(leverShouldTrigger.FieldType, 0)); leverActor.SetValue(obj, (object)(Actor)0); object? value = leverAnimator.GetValue(obj); Behaviour val = (Behaviour)((value is Behaviour) ? value : null); if (val != null && (Object)(object)val != (Object)null) { val.enabled = true; } Plugin.Log.LogInfo((object)"Released ship lever held by a VR player who left"); } } GearStick[] array2 = Object.FindObjectsOfType<GearStick>(); VRNetPlayer val3 = default(VRNetPlayer); foreach (GearStick val2 in array2) { if ((bool)gearIsHeld.GetValue(val2) && !(bool)gearIsHeldByLocal.GetValue(val2) && (gearStickHolders.TryGetValue(val2, out var value2) ? (instance.TryGetPlayer(value2, ref val3) ? 1 : 0) : players.Length) == 0) { gearIsHeld.SetValue(val2, false); gearStickHolders.Remove(val2); Plugin.Log.LogInfo((object)"Released gear stick held by a VR player who left"); } } foreach (GearStick item in gearStickHolders.Keys.Where((GearStick k) => (Object)(object)k == (Object)null).ToList()) { gearStickHolders.Remove(item); } } public static void ApplyMuffleFixes() { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Expected O, but got Unknown //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Expected O, but got Unknown //IL_00f3: Expected O, but got Unknown muffledPlayers = AccessTools.Field(typeof(MuffleManager), "muffledPlayers"); networkPlayers = AccessTools.Field(typeof(NetworkSystem), "players"); Plugin.Harmony.Patch((MethodBase)AccessTools.Method(AccessTools.TypeByName("LCVR.Physics.Interactions.UniversalMufflePatches"), "OnUpdatePlayerVoiceEffects", (Type[])null, (Type[])null), new HarmonyMethod(typeof(EveryoneFixes), "VoiceEffectsPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Harmony.Patch((MethodBase)AccessTools.Method(typeof(VRNetPlayer), "OnDestroy", (Type[])null, (Type[])null), new HarmonyMethod(typeof(EveryoneFixes), "VRNetPlayerDestroyedPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Harmony.Patch((MethodBase)AccessTools.Method(typeof(Muffler), "Update", (Type[])null, (Type[])null), new HarmonyMethod(typeof(EveryoneFixes), "MufflerPrefix", (Type[])null), new HarmonyMethod(typeof(EveryoneFixes), "MufflerPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static bool VoiceEffectsPrefix(StartOfRound __instance) { try { MuffleManager val = (((Object)(object)VRSession.Instance != (Object)null) ? VRSession.Instance.MuffleManager : null); NetworkSystem instance = NetworkSystem.Instance; if (val == null || (Object)(object)instance == (Object)null) { return false; } ushort[] array = ((HashSet<ushort>)muffledPlayers.GetValue(val)).ToArray(); VRNetPlayer val2 = default(VRNetPlayer); foreach (ushort num in array) { if (!instance.TryGetPlayer(num, ref val2) || (Object)(object)val2 == (Object)null) { continue; } PlayerControllerB playerController = val2.PlayerController; if (!((Object)(object)playerController == (Object)null) && !((Object)(object)playerController == (Object)(object)__instance.localPlayerController) && !playerController.isPlayerDead && !((Object)(object)playerController.currentVoiceChatAudioSource == (Object)null)) { OccludeAudio component = ((Component)playerController.currentVoiceChatAudioSource).GetComponent<OccludeAudio>(); if (!((Object)(object)component == (Object)null)) { component.overridingLowPass = true; component.lowPassOverride = 1000f; } } } } catch (Exception ex) { Plugin.ReportOnce("muffle voice effects", ex); } return false; } private static void VRNetPlayerDestroyedPrefix(VRNetPlayer __instance) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown try { NetworkSystem instance = NetworkSystem.Instance; MuffleManager val = (((Object)(object)VRSession.Instance != (Object)null) ? VRSession.Instance.MuffleManager : null); if ((Object)(object)instance == (Object)null || val == null) { return; } IDictionary obj = (IDictionary)networkPlayers.GetValue(instance); HashSet<ushort> hashSet = (HashSet<ushort>)muffledPlayers.GetValue(val); foreach (DictionaryEntry item in obj) { if ((Object)item.Value == (Object)(object)__instance) { hashSet.Remove((ushort)item.Key); } } } catch (Exception ex) { Plugin.ReportOnce("muffle cleanup", ex); } } private static void MufflerPrefix(Muffler __instance, out bool __state) { __state = __instance.Muffled; } private static void MufflerPostfix(Muffler __instance, bool __state) { if (__state && !__instance.Muffled && (Object)(object)VRSession.Instance != (Object)null) { VRSession.Instance.MuffleManager.SetLocalMuffled(false); } } public static void ApplyLateJoinHands() { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown clientsField = AccessTools.Field(typeof(NetworkSystem), "clients"); subscribersField = AccessTools.Field(typeof(NetworkSystem), "subscribers"); Plugin.Harmony.Patch((MethodBase)AccessTools.Method(typeof(NetworkSystem), "HandleHandshakeRequest", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(EveryoneFixes), "HandshakePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static void HandshakePostfix(NetworkSystem __instance, ushort sender, ushort protocol) { if (protocol == 9 && ((IDictionary)clientsField.GetValue(__instance)).Contains(sender)) { ((HashSet<ushort>)subscribersField.GetValue(__instance)).Add(sender); } } public static void ApplyAnnounceVR() { clientsField = AccessTools.Field(typeof(NetworkSystem), "clients"); instanceField = AccessTools.Field(typeof(NetworkSystem), "_instance"); initializedGetter = AccessTools.PropertyGetter(typeof(NetworkSystem), "Initialized"); sendPacket = AccessTools.Method(typeof(NetworkSystem), "SendPacket", (Type[])null, (Type[])null); if (clientsField == null || instanceField == null || initializedGetter == null || sendPacket == null) { throw new MissingMemberException("LCVR NetworkSystem internals changed"); } ParameterInfo[] parameters = sendPacket.GetParameters(); handshakeResponse = Enum.Parse(parameters[0].ParameterType, "HandshakeResponse"); clientInfoType = parameters[2].ParameterType.GetElementType(); Watchdog.AnnounceVR = true; } internal static void AnnounceInVR() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown if (!VRSession.InVR) { return; } NetworkSystem val = (NetworkSystem)instanceField.GetValue(null); if (!((Object)(object)val == (Object)null) && (bool)initializedGetter.Invoke(val, null)) { IDictionary dictionary = (IDictionary)clientsField.GetValue(val); if (dictionary.Count != 0) { Array array = Array.CreateInstance(clientInfoType, dictionary.Count); dictionary.Values.CopyTo(array, 0); sendPacket.Invoke(val, new object[3] { handshakeResponse, new byte[1] { 1 }, array }); } } } } internal class Watchdog : MonoBehaviour { internal static bool CheckLeversAndGearSticks; internal static bool AnnounceVR; private float nextCheck; private float nextAnnounce; private void Update() { if (AnnounceVR && Time.unscaledTime >= nextAnnounce) { nextAnnounce = Time.unscaledTime + 5f; try { EveryoneFixes.AnnounceInVR(); } catch (Exception ex) { Plugin.ReportOnce("announcing VR to other players", ex); } } if (!CheckLeversAndGearSticks || Time.unscaledTime < nextCheck) { return; } nextCheck = Time.unscaledTime + 0.5f; try { EveryoneFixes.ReleaseAbandonedLeversAndGearSticks(); } catch (Exception ex2) { Plugin.ReportOnce("lever/gear stick watchdog", ex2); } } } [BepInPlugin("boneman.lcvrfixes", "Boneman's LCVR Fixes", "2.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string Guid = "boneman.lcvrfixes"; public const string Name = "Boneman's LCVR Fixes"; public const string Version = "2.0.1"; internal static ManualLogSource Log; internal static Harmony Harmony; internal static ConfigEntry<bool> RenderEyesSeparatelyToggle; internal static ConfigEntry<bool> WristInventoryEnabled; internal static ConfigEntry<int> WristInventorySlots; internal static ConfigEntry<WristPlacement> WristPlacement; internal static ConfigEntry<string> WristSavedPosition; internal static ConfigEntry<string> WristSavedRotation; internal static ConfigEntry<float> WristGrabHoldSeconds; internal static ConfigEntry<bool> FingerHysteresis; internal static ConfigEntry<bool> RightHandFingersWhileHolding; internal static ConfigEntry<bool> PauseMenuStranding; internal static ConfigEntry<bool> PauseRenderScale; internal static ConfigEntry<bool> CruiserPausedInput; internal static ConfigEntry<bool> AnnounceVR; internal static ConfigEntry<bool> ItemErrors; internal static ConfigEntry<bool> PlayerIdMixup; internal static ConfigEntry<bool> StuckLeverAndGearStick; internal static ConfigEntry<bool> MuffleFixes; internal static ConfigEntry<bool> LateJoinHands; internal static ConfigEntry<bool> SmoothRemoteHands; internal static ConfigEntry<float> RemoteHandSmoothing; internal static ConfigEntry<float> RemoteFingerSmoothing; private static readonly HashSet<string> reported = new HashSet<string>(); private void Awake() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown //IL_0520: Unknown result type (might be due to invalid IL or missing references) //IL_0527: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Harmony = new Harmony("boneman.lcvrfixes"); bool num = !File.Exists(((BaseUnityPlugin)this).Config.ConfigFilePath); RenderEyesSeparatelyToggle = ((BaseUnityPlugin)this).Config.Bind<bool>("Rendering", "RenderEyesSeparately", true, "Render each eye as its own pass. Fixes every mod object/shader that floats, wobbles or shows in one eye (cosmetics, scrap, interiors, ship parts) at the cost of extra CPU. Restart the game after changing it: OpenXR has to be set up for it before the game starts."); WristInventoryEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Wrist inventory", "Enabled", true, "Show your inventory as a strip along your left forearm when you look at it; poke a slot with your right index finger to switch to it."); WristInventorySlots = ((BaseUnityPlugin)this).Config.Bind<int>("Wrist inventory", "Slots", 4, "How many inventory slots to show on the strip (4 = the normal slots; ReservedItemSlots' key/lockpicker slots come after these)."); WristPlacement = ((BaseUnityPlugin)this).Config.Bind<WristPlacement>("Wrist inventory", "Placement", LCVRFixes.WristPlacement.FollowEyes, "FollowEyes: the strip turns around your forearm to face you. Fixed: it stays where you put it. Grab the handle with your right hand to place it (switches to Fixed); poke the red button to go back to FollowEyes."); WristSavedPosition = ((BaseUnityPlugin)this).Config.Bind<string>("Wrist inventory", "SavedPosition", "", "Set automatically when you drop the strip after grabbing it. Clear to forget."); WristSavedRotation = ((BaseUnityPlugin)this).Config.Bind<string>("Wrist inventory", "SavedRotation", "", "Set automatically when you drop the strip after grabbing it. Clear to forget."); WristGrabHoldSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Wrist inventory", "GrabHoldSeconds", 3f, "How long you have to keep your hand closed on the handle (a ring fills up) before the strip comes loose. 0 = grab instantly."); FingerHysteresis = ((BaseUnityPlugin)this).Config.Bind<bool>("VR player", "FingerHysteresis", true, "Stop touch buttons (light switches, breakers, car horn, charger) from re-triggering when a tracked finger hovers around LCVR's 75% curl threshold."); RightHandFingersWhileHolding = ((BaseUnityPlugin)this).Config.Bind<bool>("VR player", "RightHandFingersWhileHolding", true, "Keep reading right-hand finger curls while holding an item, so finger gestures and what other players see don't freeze."); PauseMenuStranding = ((BaseUnityPlugin)this).Config.Bind<bool>("VR player", "PauseMenuStranding", true, "Don't enter LCVR's pause scene when another mod (TooManyEmotes, GeneralImprovements build mode) cancelled the pause menu."); PauseRenderScale = ((BaseUnityPlugin)this).Config.Bind<bool>("VR player", "PauseRenderScale", true, "Keep your configured render scale while paused instead of LCVR's forced 1.2 (avoids a stutter every time you pause)."); CruiserPausedInput = ((BaseUnityPlugin)this).Config.Bind<bool>("VR player", "CruiserPausedInput", true, "Stop the Cruiser from accelerating while the VR driver has the pause menu open or is typing in chat."); AnnounceVR = ((BaseUnityPlugin)this).Config.Bind<bool>("VR player", "AnnounceVR", true, "Keep telling other players you're in VR, so they always see your hands and fingers. LCVR sometimes misses you when you join a lobby that's already running. Others only need LCVR for this."); ItemErrors = ((BaseUnityPlugin)this).Config.Bind<bool>("Everyone", "ItemErrors", true, "Stop LCVR's per-frame errors and frozen items when held items have missing or unloaded item data (modded scrap, mid-round joins)."); PlayerIdMixup = ((BaseUnityPlugin)this).Config.Bind<bool>("Everyone", "PlayerIdMixup", true, "Fix LCVR mixing up voice-chat IDs with player slots, which applied VR item offsets / flashlight sync / muffling to the wrong player."); StuckLeverAndGearStick = ((BaseUnityPlugin)this).Config.Bind<bool>("Everyone", "StuckLeverAndGearStick", true, "Release the ship lever and Cruiser gear stick if the VR player holding them leaves or disconnects."); MuffleFixes = ((BaseUnityPlugin)this).Config.Bind<bool>("Everyone", "MuffleFixes", true, "Muffle (hand over mouth) the right player, clear it when they leave, and unmuffle when grabbing a two-handed item."); LateJoinHands = ((BaseUnityPlugin)this).Config.Bind<bool>("Everyone", "LateJoinHands", true, "Start sending VR hand data to players who join mid-round right away instead of after up to 10 seconds."); SmoothRemoteHands = ((BaseUnityPlugin)this).Config.Bind<bool>("Remote hands", "SmoothRemoteHands", true, "Smooth other VR players' hands, head and fingers on your screen and remove the backwards body snap when they walk in roomscale."); RemoteHandSmoothing = ((BaseUnityPlugin)this).Config.Bind<float>("Remote hands", "HandSmoothing", 18f, "How quickly remote hands follow new data. Higher = snappier, lower = smoother."); RemoteFingerSmoothing = ((BaseUnityPlugin)this).Config.Bind<float>("Remote hands", "FingerSmoothing", 15f, "How quickly remote fingers follow new data. Higher = snappier, lower = smoother."); ShaderFixer.Bind(((BaseUnityPlugin)this).Config, out var enabled, out var cosmetics, out var items, out var interiors); if (num) { ConfigMigration.FromOldPlugins(((BaseUnityPlugin)this).Config); } try { RenderEyesSeparately.Apply(); } catch (Exception arg) { Log.LogError((object)$"Couldn't set up per-eye rendering, skipping it: {arg}"); } Apply("finger hysteresis", FingerHysteresis, VRPlayerFixes.ApplyFingerHysteresis); Apply("right-hand fingers while holding", RightHandFingersWhileHolding, VRPlayerFixes.ApplyRightHandWhileHolding); Apply("pause menu stranding", PauseMenuStranding, VRPlayerFixes.ApplyPauseMenuStranding); Apply("pause render scale", PauseRenderScale, VRPlayerFixes.ApplyPauseRenderScale); Apply("Cruiser input while paused", CruiserPausedInput, VRPlayerFixes.ApplyCruiserPausedInput); Apply("VR announce", AnnounceVR, EveryoneFixes.ApplyAnnounceVR); Apply("item errors", ItemErrors, EveryoneFixes.ApplyItemErrors); Apply("player ID mix-up", PlayerIdMixup, EveryoneFixes.ApplyPlayerIdMixup); Apply("stuck lever and gear stick", StuckLeverAndGearStick, EveryoneFixes.ApplyStuckLeverAndGearStick); Apply("muffle fixes", MuffleFixes, EveryoneFixes.ApplyMuffleFixes); Apply("late-join hands", LateJoinHands, EveryoneFixes.ApplyLateJoinHands); Apply("smooth remote hands", SmoothRemoteHands, RemoteHands.Apply); GameObject val = new GameObject("BonemansLCVRFixes"); Object.DontDestroyOnLoad((Object)(object)val); ((Object)val).hideFlags = (HideFlags)61; val.AddComponent<Watchdog>(); if (WristInventoryEnabled.Value) { val.AddComponent<WristInventory>(); } val.AddComponent<ShaderFixer>().Init(Log, enabled, cosmetics, items, interiors); } private static void Apply(string name, ConfigEntry<bool> toggle, Action apply) { if (!toggle.Value) { return; } try { apply(); Log.LogInfo((object)("Applied " + name)); } catch (Exception arg) { Log.LogError((object)$"Couldn't apply {name}, skipping it: {arg}"); } } internal static void ReportOnce(string where, Exception ex) { if (reported.Add(where)) { Log.LogWarning((object)("Suppressed error in " + where + ": " + ex.GetType().Name + ": " + ex.Message)); } } } internal static class RemoteHands { private class State { public bool initialized; public Vector3 leftPos; public Vector3 rightPos; public Vector3 leftPosTarget; public Vector3 rightPosTarget; public Quaternion leftRot; public Quaternion rightRot; public Quaternion leftRotTarget; public Quaternion rightRotTarget; public Quaternion head; public Quaternion headTarget; public readonly float[] fingers = new float[10]; public readonly float[] fingersTarget = new float[10]; public Vector3 rawOffset; public Vector3 pending; public Vector3 pendingRoot; public float pendingTime; } private static readonly ConditionalWeakTable<VRNetPlayer, State> states = new ConditionalWeakTable<VRNetPlayer, State>(); private static FieldInfo leftController; private static FieldInfo rightController; private static FieldInfo cameraEulers; private static FieldInfo modelOffset; public static void Apply() { //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Expected O, but got Unknown leftController = AccessTools.Field(typeof(VRNetPlayer), "leftController"); rightController = AccessTools.Field(typeof(VRNetPlayer), "rightController"); cameraEulers = AccessTools.Field(typeof(VRNetPlayer), "cameraEulers"); modelOffset = AccessTools.Field(typeof(VRNetPlayer), "modelOffset"); Plugin.Harmony.Patch((MethodBase)AccessTools.Method(typeof(VRNetPlayer), "OnRigDataReceived", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(RemoteHands), "RigReceivedPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Harmony.Patch((MethodBase)AccessTools.Method(typeof(VRNetPlayer), "Update", (Type[])null, (Type[])null), new HarmonyMethod(typeof(RemoteHands), "UpdatePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static void RigReceivedPostfix(VRNetPlayer __instance) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) try { State orCreateValue = states.GetOrCreateValue(__instance); Transform val = (Transform)leftController.GetValue(__instance); Transform val2 = (Transform)rightController.GetValue(__instance); orCreateValue.leftPosTarget = val.localPosition; orCreateValue.leftRotTarget = val.localRotation; orCreateValue.rightPosTarget = val2.localPosition; orCreateValue.rightRotTarget = val2.localRotation; orCreateValue.headTarget = Quaternion.Euler((Vector3)cameraEulers.GetValue(__instance)); ReadFingers(__instance, orCreateValue.fingersTarget); Vector3 val3 = (Vector3)modelOffset.GetValue(__instance); if (((Vector3)(ref orCreateValue.rawOffset)).magnitude > 0.25f && ((Vector3)(ref val3)).magnitude < ((Vector3)(ref orCreateValue.rawOffset)).magnitude * 0.4f) { orCreateValue.pending += orCreateValue.rawOffset - val3; orCreateValue.pendingRoot = ((Component)__instance).transform.position; orCreateValue.pendingTime = Time.time; } orCreateValue.rawOffset = val3; if (!orCreateValue.initialized) { orCreateValue.initialized = true; orCreateValue.leftPos = orCreateValue.leftPosTarget; orCreateValue.leftRot = orCreateValue.leftRotTarget; orCreateValue.rightPos = orCreateValue.rightPosTarget; orCreateValue.rightRot = orCreateValue.rightRotTarget; orCreateValue.head = orCreateValue.headTarget; orCreateValue.fingersTarget.CopyTo(orCreateValue.fingers, 0); } else { val.localPosition = orCreateValue.leftPos; val.localRotation = orCreateValue.leftRot; val2.localPosition = orCreateValue.rightPos; val2.localRotation = orCreateValue.rightRot; cameraEulers.SetValue(__instance, ((Quaternion)(ref orCreateValue.head)).eulerAngles); WriteFingers(__instance, orCreateValue.fingers); } } catch (Exception ex) { Plugin.ReportOnce("remote hand smoothing (receive)", ex); } } private static void UpdatePrefix(VRNetPlayer __instance) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Expected O, but got Unknown //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) try { if (states.TryGetValue(__instance, out var value) && value.initialized) { float deltaTime = Time.deltaTime; float num = 1f - Mathf.Exp((0f - Mathf.Max(1f, Plugin.RemoteHandSmoothing.Value)) * deltaTime); float num2 = 1f - Mathf.Exp((0f - Mathf.Max(1f, Plugin.RemoteFingerSmoothing.Value)) * deltaTime); value.leftPos = Follow(value.leftPos, value.leftPosTarget, num); value.rightPos = Follow(value.rightPos, value.rightPosTarget, num); value.leftRot = Quaternion.Slerp(value.leftRot, value.leftRotTarget, num); value.rightRot = Quaternion.Slerp(value.rightRot, value.rightRotTarget, num); value.head = Quaternion.Slerp(value.head, value.headTarget, num); for (int i = 0; i < value.fingers.Length; i++) { value.fingers[i] = Mathf.Lerp(value.fingers[i], value.fingersTarget[i], num2); } Transform val = (Transform)leftController.GetValue(__instance); Transform val2 = (Transform)rightController.GetValue(__instance); val.localPosition = value.leftPos; val.localRotation = value.leftRot; val2.localPosition = value.rightPos; val2.localRotation = value.rightRot; cameraEulers.SetValue(__instance, ((Quaternion)(ref value.head)).eulerAngles); WriteFingers(__instance, value.fingers); modelOffset.SetValue(__instance, value.rawOffset + PendingOffset(__instance, value)); } } catch (Exception ex) { Plugin.ReportOnce("remote hand smoothing (update)", ex); } } private static Vector3 Follow(Vector3 current, Vector3 target, float t) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) Vector3 val = target - current; if (!(((Vector3)(ref val)).sqrMagnitude > 2.25f)) { return Vector3.Lerp(current, target, t); } return target; } private static Vector3 PendingOffset(VRNetPlayer player, State state) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) if (state.pending == Vector3.zero) { return Vector3.zero; } float num = Time.time - state.pendingTime; if (num > 1f) { state.pending = Vector3.zero; return Vector3.zero; } float magnitude = ((Vector3)(ref state.pending)).magnitude; Vector3 val = state.pending / magnitude; float num2 = Vector3.Dot(((Component)player).transform.position - state.pendingRoot, val); Vector3 val2 = state.pending - val * Mathf.Clamp(num2, 0f, magnitude); if (num > 0.6f) { val2 *= Mathf.Clamp01(1f - (num - 0.6f) / 0.4f); } return val2; } private static void ReadFingers(VRNetPlayer player, float[] into) { Read(player.LeftFingerCurler, into, 0); Read(player.RightFingerCurler, into, 5); } private static void WriteFingers(VRNetPlayer player, float[] from) { Write(player.LeftFingerCurler, from, 0); Write(player.RightFingerCurler, from, 5); } private static void Read(FingerCurler curler, float[] into, int offset) { if (curler != null) { into[offset] = curler.thumbFinger.curl; into[offset + 1] = curler.indexFinger.curl; into[offset + 2] = curler.middleFinger.curl; into[offset + 3] = curler.ringFinger.curl; into[offset + 4] = curler.pinkyFinger.curl; } } private static void Write(FingerCurler curler, float[] from, int offset) { if (curler != null) { curler.thumbFinger.curl = from[offset]; curler.indexFinger.curl = from[offset + 1]; curler.middleFinger.curl = from[offset + 2]; curler.ringFinger.curl = from[offset + 3]; curler.pinkyFinger.curl = from[offset + 4]; } } } internal static class RenderEyesSeparately { private static FieldInfo pipelineSettings; public static void Apply() { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown pipelineSettings = AccessTools.Field(typeof(HDRenderPipelineAsset), "m_RenderPipelineSettings"); Plugin.Harmony.Patch((MethodBase)AccessTools.Method(typeof(Config), "ApplySettings", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(RenderEyesSeparately), "Refresh", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.RenderEyesSeparatelyToggle.SettingChanged += delegate { Refresh(); }; Refresh(); } internal static void Refresh() { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) if (!VRSession.InVR) { return; } RenderPipelineAsset renderPipeline = QualitySettings.renderPipeline; HDRenderPipelineAsset val = (HDRenderPipelineAsset)(((object)((renderPipeline is HDRenderPipelineAsset) ? renderPipeline : null)) ?? ((object)/*isinst with value type is only supported in some contexts*/)); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)"No HDRP asset found; can't change eye rendering"); return; } RenderPipelineSettings val2 = (RenderPipelineSettings)pipelineSettings.GetValue(val); bool flag = !Plugin.RenderEyesSeparatelyToggle.Value; if (!flag && (int)OpenXRSettings.Instance.renderMode != 0) { Plugin.Log.LogWarning((object)"Render eyes separately is on, but OpenXR wasn't set up for it (is BepInEx/patchers/BonemansLCVRFixes installed? restart the game after changing the setting). Keeping LCVR's default so both eyes still render."); flag = true; } if (val2.xrSettings.singlePass != flag) { val2.xrSettings.singlePass = flag; pipelineSettings.SetValue(val, val2); RebuildPipeline(); Plugin.Log.LogInfo((object)(flag ? "Rendering both eyes in one pass (LCVR default)" : "Rendering each eye separately: mod shaders show correctly in both eyes")); } } private static void RebuildPipeline() { MethodInfo methodInfo = AccessTools.Method(typeof(RenderPipelineManager), "CleanupRenderPipeline", (Type[])null, (Type[])null); if (methodInfo == null) { Plugin.Log.LogWarning((object)"Couldn't restart the render pipeline; the eye mode applies after a game restart"); return; } methodInfo.Invoke(null, null); Plugin.Log.LogInfo((object)"Restarted the render pipeline so the new eye mode applies everywhere"); } } internal static class VRPlayerFixes { private class Latch { public bool index; public bool middle; } private static readonly ConditionalWeakTable<VRFingerCurler, Latch> latches = new ConditionalWeakTable<VRFingerCurler, Latch>(); private static MethodInfo updateCurls; public static void ApplyFingerHysteresis() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown Plugin.Harmony.Patch((MethodBase)AccessTools.Method(typeof(VRFingerCurler), "UpdateCurls", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(VRPlayerFixes), "HysteresisPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static void HysteresisPostfix(VRFingerCurler __instance) { Latch orCreateValue = latches.GetOrCreateValue(__instance); orCreateValue.index = Stabilize(((FingerCurler)__instance).indexFinger, orCreateValue.index); orCreateValue.middle = Stabilize(((FingerCurler)__instance).middleFinger, orCreateValue.middle); } private static bool Stabilize(Finger finger, bool latched) { if (finger.curl > 0.85f) { latched = true; } else if (finger.curl < 0.65f) { latched = false; } if (latched && finger.curl <= 0.75f) { finger.curl = 0.76f; } else if (!latched && finger.curl > 0.75f) { finger.curl = 0.74f; } return latched; } public static void ApplyRightHandWhileHolding() { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown updateCurls = AccessTools.Method(typeof(VRFingerCurler), "UpdateCurls", (Type[])null, (Type[])null); Plugin.Harmony.Patch((MethodBase)AccessTools.Method(typeof(VRPlayer), "LateUpdate", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(VRPlayerFixes), "RightHandPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static void RightHandPostfix(VRPlayer __instance) { try { VRFingerCurler rightFingerCurler = __instance.RightFingerCurler; if (rightFingerCurler != null && rightFingerCurler.Enabled && __instance.PlayerController.isHoldingObject) { updateCurls.Invoke(rightFingerCurler, null); } } catch (Exception ex) { Plugin.ReportOnce("right-hand finger update", ex); } } public static void ApplyPauseMenuStranding() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown Type type = AccessTools.TypeByName("LCVR.Patches.QuickMenuManagerPatches"); Plugin.Harmony.Patch((MethodBase)AccessTools.Method(type, "AfterOpenPauseMenu", (Type[])null, (Type[])null), new HarmonyMethod(typeof(VRPlayerFixes), "PausePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static bool PausePrefix() { PlayerControllerB val = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.localPlayerController : null); if ((Object)(object)val == (Object)null || (Object)(object)val.quickMenuManager == (Object)null) { return true; } return val.quickMenuManager.isMenuOpen; } public static void ApplyPauseRenderScale() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown Plugin.Harmony.Patch((MethodBase)AccessTools.Method(typeof(VRSession), "SwitchToMenuCamera", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(VRPlayerFixes), "RenderScalePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static void RenderScalePostfix() { XRSettings.eyeTextureResolutionScale = Plugin.Config.CameraResolution.Value; } public static void ApplyCruiserPausedInput() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown Plugin.Harmony.Patch((MethodBase)AccessTools.Method(typeof(VehicleController), "GetVehicleInput", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(VRPlayerFixes), "CruiserPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static void CruiserPostfix(VehicleController __instance) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) if (VRSession.InVR && __instance.localPlayerInControl) { PlayerControllerB val = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.localPlayerController : null); if (!((Object)(object)val == (Object)null) && (((Object)(object)val.quickMenuManager != (Object)null && val.quickMenuManager.isMenuOpen) || val.isTypingChat)) { __instance.moveInputVector = Vector2.zero; __instance.drivePedalPressed = false; __instance.brakePedalPressed = false; } } } } public enum WristPlacement { FollowEyes, Fixed } internal class WristInventory : MonoBehaviour { private const float SlotSize = 34f; private const float SlotSpacing = 40f; private const float SurfaceOffset = 0.045f; private const float LookAngle = 32f; private const float PressDepth = 8f; private const float GrabDistance = 0.09f; private const float ResetSize = 16f; private static readonly FieldInfo throwingObject = AccessTools.Field(typeof(PlayerControllerB), "throwingObject"); private static readonly FieldInfo timeSinceSwitchingSlots = AccessTools.Field(typeof(PlayerControllerB), "timeSinceSwitchingSlots"); private static readonly MethodInfo switchToItemSlot = AccessTools.Method(typeof(PlayerControllerB), "SwitchToItemSlot", (Type[])null, (Type[])null); private static readonly MethodInfo switchToSlotServerRpc = AccessTools.Method(typeof(PlayerControllerB), "SwitchToSlotServerRpc", (Type[])null, (Type[])null); private VRPlayer owner; private Canvas canvas; private CanvasGroup group; private Image[] frames; private Image[] icons; private Transform fingertip; private float visible; private bool wasTouching; private float cooldownUntil; private Image handle; private Image reset; private bool wasResetTouching; private Image ring; private float holdTime; private bool dragging; private bool gripWasClosed; private Vector3 dragPosition; private Quaternion dragRotation; private static Sprite ringSprite; private void LateUpdate() { try { Tick(); } catch (Exception ex) { Plugin.ReportOnce("wrist inventory", ex); SetShown(shown: false); } } private void Tick() { //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02ec: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) VRSession instance = VRSession.Instance; VRPlayer val = (((Object)(object)instance != (Object)null) ? instance.LocalPlayer : null); if (!VRSession.InVR || (Object)(object)val == (Object)null || (Object)(object)HUDManager.Instance == (Object)null || val.PlayerController.isPlayerDead) { SetShown(shown: false); return; } if ((Object)(object)owner != (Object)(object)val || (Object)(object)canvas == (Object)null) { Build(val); } Bones bones = val.Bones; Transform localLeftLowerArm = bones.LocalLeftLowerArm; Transform transform = ((Component)instance.MainCamera).transform; PlayerControllerB playerController = val.PlayerController; bool flag = UpdateDrag(val); if (!dragging) { if (Plugin.WristPlacement.Value == WristPlacement.Fixed && TryGetSavedPose(out var position, out var rotation)) { ((Component)canvas).transform.SetPositionAndRotation(localLeftLowerArm.TransformPoint(position), localLeftLowerArm.rotation * rotation); } else { PlaceFacingEyes(bones.LocalLeftHand.position, localLeftLowerArm.position, transform.position); } } Vector3 position2 = ((Component)canvas).transform.position; int num; if (!dragging) { if (Vector3.Angle(transform.forward, position2 - transform.position) < 32f) { Vector3 val2 = transform.position - position2; num = ((((Vector3)(ref val2)).magnitude < 0.9f) ? 1 : 0); } else { num = 0; } } else { num = 1; } bool flag2 = (byte)num != 0; visible = Mathf.MoveTowards(visible, flag2 ? 1f : 0f, Time.deltaTime * 8f); SetShown(visible > 0.01f); if (!((Component)canvas).gameObject.activeSelf) { wasTouching = false; wasResetTouching = false; return; } group.alpha = visible; ((Graphic)handle).color = (dragging ? new Color(0.4f, 1f, 0.5f, 1f) : (flag ? new Color(1f, 0.85f, 0.3f, 1f) : new Color(0.7f, 0.7f, 0.7f, 0.8f))); ((Component)reset).gameObject.SetActive(Plugin.WristPlacement.Value == WristPlacement.Fixed && !dragging); if (dragging) { wasTouching = false; wasResetTouching = false; UpdateSlots(playerController, -1); return; } bool flag3 = ((Component)reset).gameObject.activeSelf && FingerTouches(val, ((Graphic)reset).rectTransform.anchoredPosition, 16f); ((Graphic)reset).color = (flag3 ? new Color(1f, 0.5f, 0.4f, 1f) : new Color(0.85f, 0.3f, 0.25f, 0.85f)); if (flag3 && !wasResetTouching) { Plugin.WristPlacement.Value = WristPlacement.FollowEyes; Plugin.Log.LogInfo((object)"Wrist inventory placement reset to follow your eyes"); } wasResetTouching = flag3; bool touching; int num2 = FingerOverSlot(val, out touching); UpdateSlots(playerController, num2); if (touching && !wasTouching && num2 >= 0 && visible > 0.6f && Time.time >= cooldownUntil && TrySwitch(playerController, num2)) { cooldownUntil = Time.time + 0.4f; } wasTouching = touching; } private void PlaceFacingEyes(Vector3 wrist, Vector3 elbow, Vector3 eyes) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) Vector3 val = elbow - wrist; Vector3 normalized = ((Vector3)(ref val)).normalized; Vector3 val2 = Vector3.Lerp(wrist, elbow, 0.45f); val = Vector3.ProjectOnPlane(eyes - val2, normalized); Vector3 normalized2 = ((Vector3)(ref val)).normalized; ((Component)canvas).transform.SetPositionAndRotation(val2 + normalized2 * 0.045f, Quaternion.LookRotation(-normalized2, normalized)); } private bool UpdateDrag(VRPlayer player) { //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) Transform localRightHand = player.Bones.LocalRightHand; float num = ((player.RightFingerCurler != null) ? ((FingerCurler)player.RightFingerCurler).middleFinger.curl : 0f); if (dragging) { if (num <= 0.75f) { dragging = false; gripWasClosed = false; SavePose(player.Bones.LocalLeftLowerArm); } else { ((Component)canvas).transform.SetPositionAndRotation(localRightHand.TransformPoint(dragPosition), localRightHand.rotation * dragRotation); } ((Component)ring).gameObject.SetActive(false); return true; } bool num2 = visible > 0.5f && Vector3.Distance(localRightHand.position, ((Component)handle).transform.position) < 0.09f; bool flag = num > 0.75f; if (num2 && flag && (holdTime > 0f || !gripWasClosed)) { holdTime += Time.deltaTime; } else { holdTime = 0f; } float num3 = Mathf.Max(0f, Plugin.WristGrabHoldSeconds.Value); if (holdTime > 0f && holdTime >= num3) { holdTime = 0f; dragging = true; dragPosition = localRightHand.InverseTransformPoint(((Component)canvas).transform.position); dragRotation = Quaternion.Inverse(localRightHand.rotation) * ((Component)canvas).transform.rotation; } ((Component)ring).gameObject.SetActive(holdTime > 0f); ring.fillAmount = ((num3 > 0f) ? (holdTime / num3) : 1f); gripWasClosed = flag; return num2; } private void SavePose(Transform forearm) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) Vector3 val = forearm.InverseTransformPoint(((Component)canvas).transform.position); Quaternion val2 = Quaternion.Inverse(forearm.rotation) * ((Component)canvas).transform.rotation; Plugin.WristSavedPosition.Value = string.Join(",", F(val.x), F(val.y), F(val.z)); Plugin.WristSavedRotation.Value = string.Join(",", F(val2.x), F(val2.y), F(val2.z), F(val2.w)); Plugin.WristPlacement.Value = WristPlacement.Fixed; Plugin.Log.LogInfo((object)"Wrist inventory placement saved"); static string F(float value) { return value.ToString("R", CultureInfo.InvariantCulture); } } private static bool TryGetSavedPose(out Vector3 position, out Quaternion rotation) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) position = default(Vector3); rotation = Quaternion.identity; float[] array = Parse(Plugin.WristSavedPosition.Value, 3); float[] array2 = Parse(Plugin.WristSavedRotation.Value, 4); if (array == null || array2 == null) { return false; } position = new Vector3(array[0], array[1], array[2]); Quaternion val = new Quaternion(array2[0], array2[1], array2[2], array2[3]); rotation = ((Quaternion)(ref val)).normalized; return true; } private static float[] Parse(string text, int count) { string[] array = (text ?? "").Split(','); if (array.Length != count) { return null; } float[] array2 = new float[count]; for (int i = 0; i < count; i++) { if (!float.TryParse(array[i], NumberStyles.Float, CultureInfo.InvariantCulture, out array2[i])) { return null; } } return array2; } private bool FingerTouches(VRPlayer player, Vector2 position, float size) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)fingertip == (Object)null || player.RightFingerCurler == null || ((FingerCurler)player.RightFingerCurler).indexFinger.curl > 0.5f) { return false; } Vector3 val = ((Component)canvas).transform.InverseTransformPoint(fingertip.position); if (Mathf.Abs(val.x - position.x) < size * 0.7f && Mathf.Abs(val.y - position.y) < size * 0.7f && val.z > -8f) { return val.z < 30f; } return false; } private void UpdateSlots(PlayerControllerB controller, int hovered) { //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < frames.Length; i++) { Image val = ((i < HUDManager.Instance.itemSlotIcons.Length) ? HUDManager.Instance.itemSlotIcons[i] : null); icons[i].sprite = (((Object)(object)val != (Object)null) ? val.sprite : null); ((Behaviour)icons[i]).enabled = (Object)(object)val != (Object)null && ((Behaviour)val).enabled && (Object)(object)val.sprite != (Object)null; ((Graphic)frames[i]).color = ((i == hovered) ? new Color(1f, 0.85f, 0.3f, 1f) : ((i == controller.currentItemSlot) ? new Color(1f, 1f, 1f, 0.95f) : new Color(0.55f, 0.55f, 0.55f, 0.6f))); } } private int FingerOverSlot(VRPlayer player, out bool touching) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) touching = false; if ((Object)(object)fingertip == (Object)null || player.RightFingerCurler == null) { return -1; } if (((FingerCurler)player.RightFingerCurler).indexFinger.curl > 0.5f) { return -1; } Vector3 val = ((Component)canvas).transform.InverseTransformPoint(fingertip.position); if (Mathf.Abs(val.x) > 20.400002f || val.z < -60f || val.z > 30f) { return -1; } float num = (float)(-(frames.Length - 1)) * 40f / 2f; int num2 = Mathf.RoundToInt((val.y - num) / 40f); if (num2 < 0 || num2 >= frames.Length || Mathf.Abs(val.y - (num + (float)num2 * 40f)) > 20.400002f) { return -1; } touching = val.z > -8f; return num2; } private static bool TrySwitch(PlayerControllerB player, int slot) { if (slot == player.currentItemSlot || slot >= player.ItemSlots.Length) { return false; } if ((float)timeSinceSwitchingSlots.GetValue(player) < 0.3f || player.isGrabbingObjectAnimation || player.quickMenuManager.isMenuOpen || player.inSpecialInteractAnimation || (bool)throwingObject.GetValue(player) || player.isTypingChat || player.twoHanded || player.activatingItem || player.inTerminalMenu) { return false; } if ((player.jetpackControls || player.disablingJetpackControls) && (Object)(object)player.currentlyHeldObjectServer != (Object)null && player.currentlyHeldObjectServer.itemProperties.itemId == 13) { return false; } if ((Object)(object)ShipBuildModeManager.Instance != (Object)null) { ShipBuildModeManager.Instance.CancelBuildMode(true); } player.playerBodyAnimator.SetBool("GrabValidated", false); switchToItemSlot.Invoke(player, new object[2] { slot, null }); switchToSlotServerRpc.Invoke(player, new object[1] { slot }); GrabbableObject currentlyHeldObjectServer = player.currentlyHeldObjectServer; if ((Object)(object)currentlyHeldObjectServer != (Object)null && (Object)(object)currentlyHeldObjectServer.itemProperties != (Object)null) { AudioSource component = ((Component)currentlyHeldObjectServer).GetComponent<AudioSource>(); if (component != null) { component.PlayOneShot(currentlyHeldObjectServer.itemProperties.grabSFX, 0.6f); } } timeSinceSwitchingSlots.SetValue(player, 0f); return true; } private void Build(VRPlayer player) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected O, but got Unknown //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0301: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)canvas != (Object)null) { Object.Destroy((Object)(object)((Component)canvas).gameObject); } owner = player; int num = Mathf.Min(new int[3] { Mathf.Max(1, Plugin.WristInventorySlots.Value), player.PlayerController.ItemSlots.Length, HUDManager.Instance.itemSlotIcons.Length }); GameObject val = new GameObject("LCVRFixes Wrist Inventory"); val.layer = LayerMask.NameToLayer("UI"); canvas = val.AddComponent<Canvas>(); canvas.renderMode = (RenderMode)2; canvas.worldCamera = VRSession.Instance.MainCamera; val.transform.localScale = Vector3.one * 0.001f; val.GetComponent<RectTransform>().sizeDelta = new Vector2(44f, (float)num * 40f + 10f); group = val.AddComponent<CanvasGroup>(); group.interactable = false; group.blocksRaycasts = false; frames = (Image[])(object)new Image[num]; icons = (Image[])(object)new Image[num]; float num2 = (float)(-(num - 1)) * 40f / 2f; for (int i = 0; i < num; i++) { Sprite sprite = ((i < HUDManager.Instance.itemSlotIconFrames.Length) ? HUDManager.Instance.itemSlotIconFrames[i].sprite : null); frames[i] = CreateImage(val.transform, "Slot " + i, new Vector2(0f, num2 + (float)i * 40f), 34f, sprite); icons[i] = CreateImage(((Component)frames[i]).transform, "Icon", Vector2.zero, 27.2f, null); icons[i].preserveAspect = true; } handle = CreateImage(val.transform, "Handle", new Vector2(0f, 0f - num2 + 28f), 34f, null); ((Graphic)handle).rectTransform.sizeDelta = new Vector2(34f, 10f); reset = CreateImage(val.transform, "Reset", new Vector2(0f, num2 - 28f), 16f, null); val.GetComponent<RectTransform>().sizeDelta = new Vector2(44f, (float)(num + 2) * 40f); ring = CreateImage(((Component)handle).transform, "Hold Ring", Vector2.zero, 44f, RingSprite()); ring.type = (Type)3; ring.fillMethod = (FillMethod)4; ring.fillOrigin = 2; ring.fillClockwise = true; ring.fillAmount = 0f; ((Graphic)ring).color = new Color(0.4f, 1f, 0.5f, 1f); ((Component)ring).gameObject.SetActive(false); dragging = false; holdTime = 0f; fingertip = FindFingertip(player.Bones.LocalRightHand); if ((Object)(object)fingertip == (Object)null) { Plugin.Log.LogWarning((object)"Couldn't find the right index fingertip; wrist inventory will display but not respond to pokes"); } } private static Sprite RingSprite() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ringSprite != (Object)null) { return ringSprite; } Texture2D val = new Texture2D(128, 128, (TextureFormat)4, false) { wrapMode = (TextureWrapMode)1 }; float num = 63.5f; for (int i = 0; i < 128; i++) { for (int j = 0; j < 128; j++) { float num2 = Vector2.Distance(new Vector2((float)j, (float)i), new Vector2(num, num)); float num3 = Mathf.Clamp01(62f - num2) * Mathf.Clamp01(num2 - 50f); val.SetPixel(j, i, new Color(1f, 1f, 1f, num3)); } } val.Apply(); ringSprite = Sprite.Create(val, new Rect(0f, 0f, 128f, 128f), new Vector2(0.5f, 0.5f)); return ringSprite; } private static Image CreateImage(Transform parent, string name, Vector2 position, float size, Sprite sprite) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name) { layer = ((Component)parent).gameObject.layer }; val.transform.SetParent(parent, false); RectTransform obj = val.AddComponent<RectTransform>(); obj.anchoredPosition = position; obj.sizeDelta = new Vector2(size, size); Image obj2 = val.AddComponent<Image>(); obj2.sprite = sprite; ((Graphic)obj2).raycastTarget = false; return obj2; } private static Transform FindFingertip(Transform hand) { Transform val = (((Object)(object)hand != (Object)null) ? hand.Find("finger2.R") : null); while ((Object)(object)val != (Object)null && val.childCount > 0) { val = val.GetChild(0); } return val; } private void SetShown(bool shown) { if ((Object)(object)canvas != (Object)null && ((Component)canvas).gameObject.activeSelf != shown) { ((Component)canvas).gameObject.SetActive(shown); } } private void OnDestroy() { if ((Object)(object)canvas != (Object)null) { Object.Destroy((Object)(object)((Component)canvas).gameObject); } } } }
BepInEx/patchers/BonemansLCVRFixes/BonemansLCVRFixes.Patcher.dll
Decompiled 2 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Mono.Cecil; using UnityEngine; using UnityEngine.XR.OpenXR; using UnityEngine.XR.OpenXR.Features; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("BonemansLCVRFixes.Patcher")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+f00e3e0edbf530a36e7eb201259842f2ebe46042")] [assembly: AssemblyProduct("BonemansLCVRFixes.Patcher")] [assembly: AssemblyTitle("BonemansLCVRFixes.Patcher")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace IndexFingerTracking { public class HandTrackingFeature : OpenXRFeature { private struct XrHandTrackerCreateInfoEXT { public int type; public IntPtr next; public int hand; public int handJointSet; } private struct XrHandJointsLocateInfoEXT { public int type; public IntPtr next; public ulong baseSpace; public long time; } private struct XrHandJointLocationsEXT { public int type; public IntPtr next; public uint isActive; public uint jointCount; public IntPtr jointLocations; } [UnmanagedFunctionPointer(CallingConvention.StdCall)] private delegate int GetInstanceProcAddrFn(ulong instance, [MarshalAs(UnmanagedType.LPStr)] string name, out IntPtr function); [UnmanagedFunctionPointer(CallingConvention.StdCall)] private delegate int CreateHandTrackerFn(ulong session, ref XrHandTrackerCreateInfoEXT info, out ulong tracker); [UnmanagedFunctionPointer(CallingConvention.StdCall)] private delegate int DestroyHandTrackerFn(ulong tracker); [UnmanagedFunctionPointer(CallingConvention.StdCall)] private delegate int LocateHandJointsFn(ulong tracker, ref XrHandJointsLocateInfoEXT info, ref XrHandJointLocationsEXT locations); [UnmanagedFunctionPointer(CallingConvention.StdCall)] private delegate int ConvertPerformanceCounterFn(ulong instance, ref long counter, out long time); private const string HandTrackingExtension = "XR_EXT_hand_tracking"; private const string TimeExtension = "XR_KHR_win32_convert_performance_counter_time"; private const int XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT = 1000051001; private const int XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT = 1000051002; private const int XR_TYPE_HAND_JOINT_LOCATIONS_EXT = 1000051003; private const int JointCount = 26; private const int JointStride = 40; private const ulong OrientationValid = 1uL; private CreateHandTrackerFn createHandTracker; private DestroyHandTrackerFn destroyHandTracker; private LocateHandJointsFn locateHandJoints; private ConvertPerformanceCounterFn convertTime; private ulong xrInstance; private readonly ulong[] trackers = new ulong[2]; private readonly IntPtr[] jointBuffers = new IntPtr[2]; private readonly byte[] jointBytes = new byte[1040]; private readonly float[][] curls = new float[2][] { new float[5], new float[5] }; private readonly int[] lastFrame = new int[2] { -1, -1 }; private readonly bool[] lastResult = new bool[2]; private bool loggedLocateError; [DllImport("kernel32.dll")] private static extern bool QueryPerformanceCounter(out long count); internal static HandTrackingFeature Create() { HandTrackingFeature handTrackingFeature = ScriptableObject.CreateInstance<HandTrackingFeature>(); ((Object)handTrackingFeature).hideFlags = (HideFlags)61; Traverse.Create((object)handTrackingFeature).Field("nameUi").SetValue((object)"Index Finger Tracking"); Traverse.Create((object)handTrackingFeature).Field("version").SetValue((object)"1.0.0"); Traverse.Create((object)handTrackingFeature).Field("company").SetValue((object)"kylew"); Traverse.Create((object)handTrackingFeature).Field("featureIdInternal").SetValue((object)"kylew.indexfingertracking"); Traverse.Create((object)handTrackingFeature).Field("openxrExtensionStrings").SetValue((object)"XR_EXT_hand_tracking XR_KHR_win32_convert_performance_counter_time"); ((OpenXRFeature)handTrackingFeature).enabled = true; return handTrackingFeature; } protected override bool OnInstanceCreate(ulong instance) { xrInstance = instance; if (!OpenXRRuntime.IsExtensionEnabled("XR_EXT_hand_tracking")) { Patcher.Log.LogWarning((object)"The OpenXR runtime doesn't offer hand tracking (XR_EXT_hand_tracking); fingers stay button-driven"); return true; } if (!OpenXRRuntime.IsExtensionEnabled("XR_KHR_win32_convert_performance_counter_time")) { Patcher.Log.LogWarning((object)"The OpenXR runtime doesn't offer XR_KHR_win32_convert_performance_counter_time; fingers stay button-driven"); return true; } try { GetInstanceProcAddrFn delegateForFunctionPointer = Marshal.GetDelegateForFunctionPointer<GetInstanceProcAddrFn>(OpenXRFeature.xrGetInstanceProcAddr); createHandTracker = Load<CreateHandTrackerFn>(delegateForFunctionPointer, "xrCreateHandTrackerEXT"); destroyHandTracker = Load<DestroyHandTrackerFn>(delegateForFunctionPointer, "xrDestroyHandTrackerEXT"); locateHandJoints = Load<LocateHandJointsFn>(delegateForFunctionPointer, "xrLocateHandJointsEXT"); convertTime = Load<ConvertPerformanceCounterFn>(delegateForFunctionPointer, "xrConvertWin32PerformanceCounterToTimeKHR"); Patcher.Log.LogInfo((object)"Hand tracking extension enabled"); } catch (Exception ex) { Patcher.Log.LogError((object)("Failed to load hand tracking functions: " + ex.Message)); createHandTracker = null; } return true; } private T Load<T>(GetInstanceProcAddrFn getProcAddr, string name) where T : Delegate { IntPtr function; int num = getProcAddr(xrInstance, name, out function); if (num < 0 || function == IntPtr.Zero) { throw new Exception($"{name} unavailable (XrResult {num})"); } return Marshal.GetDelegateForFunctionPointer<T>(function); } protected override void OnSessionCreate(ulong session) { if (createHandTracker == null) { return; } for (int i = 0; i < 2; i++) { XrHandTrackerCreateInfoEXT info = new XrHandTrackerCreateInfoEXT { type = 1000051001, hand = i + 1, handJointSet = 0 }; int num = createHandTracker(session, ref info, out trackers[i]); if (num < 0) { Patcher.Log.LogError((object)string.Format("xrCreateHandTrackerEXT failed for {0} hand (XrResult {1})", (i == 0) ? "left" : "right", num)); trackers[i] = 0uL; } else if (jointBuffers[i] == IntPtr.Zero) { jointBuffers[i] = Marshal.AllocHGlobal(1040); } } } protected override void OnSessionDestroy(ulong session) { for (int i = 0; i < 2; i++) { if (trackers[i] != 0L) { destroyHandTracker?.Invoke(trackers[i]); } trackers[i] = 0uL; } } protected override void OnInstanceDestroy(ulong instance) { createHandTracker = null; locateHandJoints = null; } internal bool TryGetCurls(int hand, out float[] result) { result = curls[hand]; if (lastFrame[hand] == Time.frameCount) { return lastResult[hand]; } lastFrame[hand] = Time.frameCount; lastResult[hand] = Locate(hand); return lastResult[hand]; } private bool Locate(int hand) { if (locateHandJoints == null || trackers[hand] == 0L) { return false; } QueryPerformanceCounter(out var count); if (convertTime(xrInstance, ref count, out var time) < 0) { return false; } XrHandJointsLocateInfoEXT info = new XrHandJointsLocateInfoEXT { type = 1000051002, baseSpace = OpenXRFeature.GetCurrentAppSpace(), time = time }; XrHandJointLocationsEXT locations = new XrHandJointLocationsEXT { type = 1000051003, jointCount = 26u, jointLocations = jointBuffers[hand] }; int num = locateHandJoints(trackers[hand], ref info, ref locations); if (num < 0) { if (!loggedLocateError) { loggedLocateError = true; Patcher.Log.LogWarning((object)$"xrLocateHandJointsEXT failed (XrResult {num})"); } return false; } if (locations.isActive == 0) { return false; } Marshal.Copy(jointBuffers[hand], jointBytes, 0, jointBytes.Length); if (!Bend(2, 2, out var degrees)) { return false; } float[] array = curls[hand]; array[0] = Mathf.Clamp01(degrees / Mathf.Max(1f, Patcher.ThumbCurlAngle.Value)); int[] array2 = new int[4] { 6, 11, 16, 21 }; for (int i = 0; i < array2.Length; i++) { if (!Bend(array2[i], 3, out var degrees2)) { return false; } array[i + 1] = Mathf.Clamp01(degrees2 / Mathf.Max(1f, Patcher.FingerCurlAngle.Value)); } return true; } private bool Bend(int firstJoint, int segments, out float degrees) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) degrees = 0f; for (int i = firstJoint; i < firstJoint + segments; i++) { if (!TryOrientation(i, out var rotation) || !TryOrientation(i + 1, out var rotation2)) { return false; } degrees += Quaternion.Angle(rotation, rotation2); } return true; } private bool TryOrientation(int joint, out Quaternion rotation) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) int num = joint * 40; ulong num2 = BitConverter.ToUInt64(jointBytes, num); rotation = new Quaternion(BitConverter.ToSingle(jointBytes, num + 8), BitConverter.ToSingle(jointBytes, num + 12), BitConverter.ToSingle(jointBytes, num + 16), BitConverter.ToSingle(jointBytes, num + 20)); return (num2 & 1) != 0; } } internal static class LcvrHooks { private static FieldInfo loaderFeatures; private static FieldInfo settingsFeatures; private static FieldInfo handField; private static FieldInfo forceFistField; private static FieldInfo[] fingerFields; private static FieldInfo curlField; private static FieldInfo thumbCurlField; private static HandTrackingFeature feature; private static bool loggedActive; public static void Apply(Assembly lcvr) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Expected O, but got Unknown //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Expected O, but got Unknown Type type = lcvr.GetType("LCVR.OpenXR+Loader", throwOnError: true); Harmony val = new Harmony("kylew.indexfingertracking"); val.Patch((MethodBase)AccessTools.Method(type, "InitializeScripts", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(LcvrHooks), "SetRenderMode", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); if (!Patcher.Enabled.Value) { Patcher.Log.LogInfo((object)"Hooked LCVR (render mode only)"); return; } Type type2 = lcvr.GetType("LCVR.Input.VRFingerCurler", throwOnError: true); Type baseCurler = type2.BaseType; loaderFeatures = AccessTools.Field(type, "s_Features") ?? throw new MissingFieldException("LCVR.OpenXR.Loader.s_Features"); settingsFeatures = AccessTools.Field(typeof(OpenXRSettings), "features") ?? throw new MissingFieldException("OpenXRSettings.features"); handField = AccessTools.Field(type2, "hand") ?? throw new MissingFieldException("VRFingerCurler.hand"); forceFistField = AccessTools.Field(baseCurler, "forceFist") ?? throw new MissingFieldException("FingerCurler.forceFist"); fingerFields = new string[5] { "thumbFinger", "indexFinger", "middleFinger", "ringFinger", "pinkyFinger" }.Select((string name) => AccessTools.Field(baseCurler, name) ?? throw new MissingFieldException("FingerCurler." + name)).ToArray(); thumbCurlField = AccessTools.Field(fingerFields[0].FieldType, "curl"); curlField = AccessTools.Field(fingerFields[1].FieldType, "curl"); val.Patch((MethodBase)AccessTools.Method(type, "InitializeScripts", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(LcvrHooks), "AddFeature", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.Method(type2, "UpdateCurls", (Type[])null, (Type[])null), new HarmonyMethod(typeof(LcvrHooks), "UpdateCurlsPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Patcher.Log.LogInfo((object)"Hooked LCVR"); } private static void SetRenderMode() { if (Patcher.EyesSeparately) { OpenXRSettings.Instance.renderMode = (RenderMode)0; Patcher.Log.LogInfo((object)"OpenXR set to one image per eye (per-eye rendering is on)"); } } private static void AddFeature() { try { OpenXRFeature[] source = (OpenXRFeature[])loaderFeatures.GetValue(null); if (!source.Any((OpenXRFeature f) => f is HandTrackingFeature)) { if ((Object)(object)feature == (Object)null) { feature = HandTrackingFeature.Create(); } OpenXRFeature[] value = source.Append((OpenXRFeature)(object)feature).ToArray(); loaderFeatures.SetValue(null, value); settingsFeatures.SetValue(OpenXRSettings.Instance, value); Patcher.Log.LogInfo((object)"Registered hand tracking OpenXR feature"); } } catch (Exception arg) { Patcher.Log.LogError((object)$"Failed to register hand tracking feature: {arg}"); } } private static bool UpdateCurlsPrefix(object __instance) { try { if ((Object)(object)feature == (Object)null || (bool)forceFistField.GetValue(__instance)) { return true; } int hand = ((!((string)handField.GetValue(__instance) == "L")) ? 1 : 0); if (!feature.TryGetCurls(hand, out var result)) { return true; } if (!loggedActive) { loggedActive = true; Patcher.Log.LogInfo((object)"Receiving finger tracking data, fingers now follow your hands"); } float num = Mathf.Clamp(Patcher.Smoothing.Value, 0f, 0.95f); for (int i = 0; i < fingerFields.Length; i++) { object value = fingerFields[i].GetValue(__instance); FieldInfo obj = ((i == 0) ? thumbCurlField : curlField); float num2 = (float)obj.GetValue(value); obj.SetValue(value, Mathf.Lerp(result[i], num2, num)); } return false; } catch (Exception ex) { Patcher.Log.LogError((object)("Finger tracking update failed, falling back to buttons: " + ex.Message)); feature = null; return true; } } } public static class Patcher { internal static ManualLogSource Log; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<float> FingerCurlAngle; internal static ConfigEntry<float> ThumbCurlAngle; internal static ConfigEntry<float> Smoothing; internal static bool EyesSeparately; public static IEnumerable<string> TargetDLLs { get; } = Array.Empty<string>(); public static void Initialize() { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) Log = Logger.CreateLogSource("Boneman's LCVR Fixes (patcher)"); string text = Path.Combine(Paths.ConfigPath, "boneman.lcvrfixes.fingertracking.cfg"); string text2 = Path.Combine(Paths.ConfigPath, "kylew.indexfingertracking.cfg"); if (!File.Exists(text) && File.Exists(text2)) { try { File.Copy(text2, text); } catch (Exception ex) { Log.LogWarning((object)("Couldn't copy old finger tracking settings: " + ex.Message)); } } ConfigFile val = new ConfigFile(text, true); Enabled = val.Bind<bool>("General", "Enabled", true, "Drive LCVR's fingers from real finger tracking (Valve Index controllers via SteamVR) instead of buttons."); FingerCurlAngle = val.Bind<float>("Tuning", "FingerCurlAngle", 220f, "Total joint bend (degrees) that counts as a fully curled finger. Lower = fingers curl sooner."); ThumbCurlAngle = val.Bind<float>("Tuning", "ThumbCurlAngle", 110f, "Total joint bend (degrees) that counts as a fully curled thumb."); Smoothing = val.Bind<float>("Tuning", "Smoothing", 0.5f, "0 = raw tracking, closer to 1 = smoother but laggier fingers."); EyesSeparately = ReadPluginBool("Rendering", "RenderEyesSeparately", fallback: true); if (!Enabled.Value) { Log.LogInfo((object)"Finger tracking disabled by config"); } if (Enabled.Value || EyesSeparately) { AppDomain.CurrentDomain.AssemblyLoad += OnAssemblyLoad; } } private static bool ReadPluginBool(string section, string key, bool fallback) { try { string path = Path.Combine(Paths.ConfigPath, "boneman.lcvrfixes.cfg"); if (!File.Exists(path)) { return fallback; } string text = ""; string[] array = File.ReadAllLines(path); for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); bool result; if (text2.StartsWith("[") && text2.EndsWith("]")) { text = text2.Substring(1, text2.Length - 2).Trim(); } else if (text == section && text2.StartsWith(key) && text2.Contains("=")) { return bool.TryParse(text2.Substring(text2.IndexOf('=') + 1).Trim(), out result) ? result : fallback; } } } catch (Exception ex) { Log.LogWarning((object)("Couldn't read " + key + " from boneman.lcvrfixes.cfg: " + ex.Message)); } return fallback; } public static void Patch(AssemblyDefinition assembly) { } private static void OnAssemblyLoad(object sender, AssemblyLoadEventArgs args) { try { if (!(args.LoadedAssembly.GetName().Name != "LCVR")) { AppDomain.CurrentDomain.AssemblyLoad -= OnAssemblyLoad; typeof(Patcher).Assembly.GetType("IndexFingerTracking.LcvrHooks", throwOnError: true).GetMethod("Apply", BindingFlags.Static | BindingFlags.Public).Invoke(null, new object[1] { args.LoadedAssembly }); } } catch (Exception arg) { Log.LogError((object)$"Failed to hook LCVR, finger tracking disabled: {arg}"); } } } }