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 ImmersiveFirstPerson v1.4.1
BepInEx/plugins/ImmersiveFirstPerson/ImmersiveFirstPerson.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using BlacksmithTools; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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 ImmersiveFirstPerson { internal static class BlacksmithHeadHider { private sealed class BodypartEntrySnapshot { internal bool HadParts { get; set; } internal bool HadBones { get; set; } internal List<bodyPart>? Parts { get; set; } internal List<int>? Bones { get; set; } } private const string BodyPartControllerTypeName = "BlacksmithTools.BodyPartController"; private static readonly List<int> EquippedHashes = new List<int>(); private static readonly int[] HeadBoneIndexes = Util.BodyPartToBoneIndexes((bodyPart)0); private static readonly Dictionary<string, BodypartEntrySnapshot> EntrySnapshots = new Dictionary<string, BodypartEntrySnapshot>(); private static Type? _bodyPartControllerType; private static MethodInfo? _setupMethod; private static MethodInfo? _fullUpdateMethod; private static VisEquipment? _activeVisEquipment; private static string? _activeKey; private static bool _active; private static bool _dirty = true; internal static void RequestRefresh() { _dirty = true; } internal static bool TryApply(Player player, out string failureReason) { failureReason = string.Empty; if (!PlayerEquipmentAccess.TryGetVisEquipment(player, out VisEquipment visEquipment)) { return Fail("local VisEquipment was not found", out failureReason); } if ((Object)(object)_activeVisEquipment != (Object)null && (Object)(object)_activeVisEquipment != (Object)(object)visEquipment) { Restore(); } if (!CanUseBlacksmith(visEquipment, out failureReason)) { return false; } if (!TrySelectBodypartRuleKey(visEquipment, out string ruleKey, out failureReason)) { return false; } if (_active && !_dirty && (Object)(object)_activeVisEquipment == (Object)(object)visEquipment && string.Equals(_activeKey, ruleKey, StringComparison.Ordinal)) { return true; } if (_activeKey != null && !string.Equals(_activeKey, ruleKey, StringComparison.Ordinal)) { RestoreBodypartEntries(); _active = false; _activeKey = null; } RegisterHeadRule(ruleKey); if (!EnsureController(visEquipment, out Component controller, out failureReason)) { RestoreAfterFailedApply(visEquipment); return false; } if ((Object)(object)controller == (Object)null || !TriggerBodyControllerUpdate(visEquipment, controller, out failureReason)) { RestoreAfterFailedApply(visEquipment); return false; } if (!ValidateHeadHidden(visEquipment, out failureReason)) { RestoreAfterFailedApply(visEquipment); return false; } _activeVisEquipment = visEquipment; _activeKey = ruleKey; _active = true; _dirty = false; Plugin.HeadHidingDebugLog("Blacksmith head hide active using rule key '" + ruleKey + "'."); return true; } internal static void Restore() { VisEquipment activeVisEquipment = _activeVisEquipment; RestoreBodypartEntries(); if ((Object)(object)activeVisEquipment != (Object)null && TryGetController(activeVisEquipment, out Component controller) && (Object)(object)controller != (Object)null) { if (TriggerBodyControllerUpdate(activeVisEquipment, controller, out string failureReason)) { Plugin.HeadHidingDebugLog("Restored Blacksmith body mesh after first-person exit."); } else { Plugin.HeadHidingDebugLog("Blacksmith restore update failed: " + failureReason + "."); } } _activeVisEquipment = null; _activeKey = null; _active = false; _dirty = true; } private static bool CanUseBlacksmith(VisEquipment visEquipment, out string failureReason) { failureReason = string.Empty; if (Main.bodyHidingEnabled == null || !Main.bodyHidingEnabled.Value) { return Fail("Blacksmith bodypart hiding is disabled", out failureReason); } if ((Object)(object)visEquipment.m_bodyModel == (Object)null) { return Fail("VisEquipment has no body model renderer", out failureReason); } Mesh sharedMesh = visEquipment.m_bodyModel.sharedMesh; if ((Object)(object)sharedMesh == (Object)null) { return Fail("body model has no shared mesh", out failureReason); } if (!sharedMesh.isReadable) { return Fail("body model mesh is unreadable", out failureReason); } return true; } private static bool TrySelectBodypartRuleKey(VisEquipment visEquipment, out string ruleKey, out string failureReason) { ruleKey = string.Empty; failureReason = string.Empty; int helmetHash = PlayerEquipmentAccess.GetHelmetHash(visEquipment); if (helmetHash != 0 && PlayerEquipmentAccess.TryGetPrefabName(helmetHash, out ruleKey)) { return true; } PlayerEquipmentAccess.GetEquippedHashes(visEquipment, EquippedHashes); foreach (int equippedHash in EquippedHashes) { if (equippedHash == 0 || !PlayerEquipmentAccess.TryGetPrefabName(equippedHash, out ruleKey)) { continue; } return true; } return Fail("no stable equipped item prefab name was available for Blacksmith body hiding", out failureReason); } private static void RegisterHeadRule(string ruleKey) { CaptureEntrySnapshot(ruleKey); List<bodyPart> value; List<bodyPart> list = (BodypartSystem.bodypartSettings.TryGetValue(ruleKey, out value) ? new List<bodyPart>(value) : new List<bodyPart>()); if (!list.Contains((bodyPart)0)) { list.Add((bodyPart)0); } BodypartSystem.bodypartSettings[ruleKey] = list; List<int> value2; List<int> list2 = (BodypartSystem.bodypartSettingsAsBones.TryGetValue(ruleKey, out value2) ? new List<int>(value2) : new List<int>()); int[] headBoneIndexes = HeadBoneIndexes; foreach (int item in headBoneIndexes) { if (!list2.Contains(item)) { list2.Add(item); } } BodypartSystem.bodypartSettingsAsBones[ruleKey] = list2; Plugin.HeadHidingDebugLog("Registered temporary Blacksmith Head rule for '" + ruleKey + "'."); } private static void CaptureEntrySnapshot(string ruleKey) { if (!EntrySnapshots.ContainsKey(ruleKey)) { List<bodyPart> value; bool flag = BodypartSystem.bodypartSettings.TryGetValue(ruleKey, out value); List<int> value2; bool flag2 = BodypartSystem.bodypartSettingsAsBones.TryGetValue(ruleKey, out value2); EntrySnapshots[ruleKey] = new BodypartEntrySnapshot { HadParts = flag, HadBones = flag2, Parts = (flag ? new List<bodyPart>(value) : null), Bones = (flag2 ? new List<int>(value2) : null) }; } } private static bool EnsureController(VisEquipment visEquipment, out Component? controller, out string failureReason) { controller = null; failureReason = string.Empty; if (!TryResolveBodyPartControllerType(out Type controllerType, out failureReason)) { return false; } controller = ((Component)visEquipment).GetComponent(controllerType); if ((Object)(object)controller != (Object)null) { return true; } if (!CanUseBlacksmith(visEquipment, out failureReason)) { return false; } try { controller = ((Component)visEquipment).gameObject.AddComponent(controllerType); MethodInfo setupMethod = GetSetupMethod(controllerType); if (setupMethod == null) { return Fail("Blacksmith BodyPartController.Setup method was not found", out failureReason); } setupMethod.Invoke(controller, new object[1] { visEquipment }); Plugin.HeadHidingDebugLog("Attached missing Blacksmith BodyPartController to local VisEquipment."); return true; } catch (Exception ex) { return Fail("Blacksmith BodyPartController setup failed: " + ex.GetType().Name, out failureReason); } } private static bool TryGetController(VisEquipment visEquipment, out Component? controller) { controller = null; if (!TryResolveBodyPartControllerType(out Type controllerType, out string _)) { return false; } controller = (((Object)(object)visEquipment != (Object)null) ? ((Component)visEquipment).GetComponent(controllerType) : null); return (Object)(object)controller != (Object)null; } private static bool TriggerBodyControllerUpdate(VisEquipment visEquipment, Component controller, out string failureReason) { failureReason = string.Empty; try { MethodInfo fullUpdateMethod = GetFullUpdateMethod(((object)controller).GetType()); if (fullUpdateMethod == null) { return Fail("Blacksmith BodyPartController.FullUpdate method was not found", out failureReason); } fullUpdateMethod.Invoke(controller, Array.Empty<object>()); ApplyCurrentModelMesh(visEquipment); return true; } catch (Exception ex) { return Fail("Blacksmith BodyPartController update failed: " + ex.GetType().Name, out failureReason); } } private static void ApplyCurrentModelMesh(VisEquipment visEquipment) { if ((Object)(object)visEquipment == (Object)null || (Object)(object)visEquipment.m_bodyModel == (Object)null || visEquipment.m_models == null) { return; } int modelIndex = visEquipment.GetModelIndex(); if (modelIndex >= 0 && modelIndex < visEquipment.m_models.Length) { Mesh mesh = visEquipment.m_models[modelIndex].m_mesh; if ((Object)(object)mesh != (Object)null && (Object)(object)visEquipment.m_bodyModel.sharedMesh != (Object)(object)mesh) { visEquipment.m_bodyModel.sharedMesh = mesh; } } } private static bool ValidateHeadHidden(VisEquipment visEquipment, out string failureReason) { failureReason = string.Empty; if ((Object)(object)visEquipment.m_bodyModel == (Object)null) { return Fail("body model renderer disappeared during Blacksmith validation", out failureReason); } Mesh sharedMesh = visEquipment.m_bodyModel.sharedMesh; if ((Object)(object)sharedMesh == (Object)null) { return Fail("body model mesh disappeared during Blacksmith validation", out failureReason); } if (!sharedMesh.isReadable) { return Fail("body model mesh became unreadable during Blacksmith validation", out failureReason); } if (sharedMesh.boneWeights == null || sharedMesh.boneWeights.Length == 0) { return Fail("body model mesh has no bone weights for Blacksmith validation", out failureReason); } if (MeshContainsDominantHeadTriangles(sharedMesh)) { return Fail("Blacksmith update left dominant head-weighted body triangles visible", out failureReason); } return true; } private static bool MeshContainsDominantHeadTriangles(Mesh mesh) { BoneWeight[] boneWeights = mesh.boneWeights; for (int i = 0; i < mesh.subMeshCount; i++) { int[] triangles = mesh.GetTriangles(i); for (int j = 0; j + 2 < triangles.Length; j += 3) { if (TriangleWouldBeRemovedByBlacksmith(boneWeights, triangles, j)) { return true; } } } return false; } private static bool TriangleWouldBeRemovedByBlacksmith(BoneWeight[] boneWeights, int[] triangles, int triangleIndex) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) int num = 0; for (int i = 0; i < 2; i++) { int num2 = triangles[triangleIndex + i]; if (num2 >= 0 && num2 < boneWeights.Length && HasDominantHeadBone(boneWeights[num2]) && ++num == 1) { return true; } } return false; } private static bool HasDominantHeadBone(BoneWeight boneWeight) { //IL_004d: 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) float num = Mathf.Max(new float[4] { ((BoneWeight)(ref boneWeight)).weight0, ((BoneWeight)(ref boneWeight)).weight1, ((BoneWeight)(ref boneWeight)).weight2, ((BoneWeight)(ref boneWeight)).weight3 }); if (num <= 0f) { return false; } for (int i = 0; i < 4; i++) { int boneIndex = GetBoneIndex(boneWeight, i); if (HeadBoneIndexes.Contains(boneIndex)) { float boneWeight2 = GetBoneWeight(boneWeight, i); if (boneWeight2 / num > 0.9f) { return true; } } } return false; } private static int GetBoneIndex(BoneWeight boneWeight, int boneSlot) { if (1 == 0) { } int result = boneSlot switch { 0 => ((BoneWeight)(ref boneWeight)).boneIndex0, 1 => ((BoneWeight)(ref boneWeight)).boneIndex1, 2 => ((BoneWeight)(ref boneWeight)).boneIndex2, 3 => ((BoneWeight)(ref boneWeight)).boneIndex3, _ => -1, }; if (1 == 0) { } return result; } private static float GetBoneWeight(BoneWeight boneWeight, int boneSlot) { if (1 == 0) { } float result = boneSlot switch { 0 => ((BoneWeight)(ref boneWeight)).weight0, 1 => ((BoneWeight)(ref boneWeight)).weight1, 2 => ((BoneWeight)(ref boneWeight)).weight2, 3 => ((BoneWeight)(ref boneWeight)).weight3, _ => 0f, }; if (1 == 0) { } return result; } private static void RestoreAfterFailedApply(VisEquipment visEquipment) { RestoreBodypartEntries(); if (TryGetController(visEquipment, out Component controller) && (Object)(object)controller != (Object)null) { TriggerBodyControllerUpdate(visEquipment, controller, out string _); } _activeVisEquipment = null; _activeKey = null; _active = false; _dirty = true; } private static void RestoreBodypartEntries() { foreach (KeyValuePair<string, BodypartEntrySnapshot> entrySnapshot in EntrySnapshots) { string key = entrySnapshot.Key; BodypartEntrySnapshot value = entrySnapshot.Value; if (value.HadParts && value.Parts != null) { BodypartSystem.bodypartSettings[key] = new List<bodyPart>(value.Parts); } else { BodypartSystem.bodypartSettings.Remove(key); } if (value.HadBones && value.Bones != null) { BodypartSystem.bodypartSettingsAsBones[key] = new List<int>(value.Bones); } else { BodypartSystem.bodypartSettingsAsBones.Remove(key); } } EntrySnapshots.Clear(); } private static bool TryResolveBodyPartControllerType(out Type controllerType, out string failureReason) { failureReason = string.Empty; if ((object)_bodyPartControllerType == null) { _bodyPartControllerType = typeof(BodypartSystem).Assembly.GetType("BlacksmithTools.BodyPartController", throwOnError: false); } controllerType = _bodyPartControllerType; if (controllerType == null) { return Fail("Blacksmith BodyPartController type was not found", out failureReason); } return true; } private static MethodInfo? GetSetupMethod(Type controllerType) { if ((object)_setupMethod == null) { _setupMethod = controllerType.GetMethod("Setup", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } return _setupMethod; } private static MethodInfo? GetFullUpdateMethod(Type controllerType) { if ((object)_fullUpdateMethod == null) { _fullUpdateMethod = controllerType.GetMethod("FullUpdate", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } return _fullUpdateMethod; } private static bool Fail(string reason, out string failureReason) { failureReason = reason; Plugin.HeadHidingDebugLog("Blacksmith head hiding unavailable: " + reason + "."); return false; } } internal static class BodyVisibilityController { private static readonly Dictionary<Renderer, RendererStateSnapshot> OriginalRendererStates = new Dictionary<Renderer, RendererStateSnapshot>(); private static readonly List<Renderer?> DeadRenderers = new List<Renderer>(); private static Player? _cachedPlayer; private static bool _captured; private static readonly string[] HeldItemKeywords = new string[28] { "hand", "right", "left", "weapon", "sword", "axe", "mace", "hammer", "club", "knife", "bow", "arrow", "shield", "torch", "tool", "pickaxe", "hatchet", "battleaxe", "sledge", "spear", "atgeir", "crossbow", "buckler", "staff", "wand", "cultivator", "fishing", "itemstand" }; private static readonly string[] HeadKeywords = new string[7] { "head", "hair", "face", "jaw", "eye", "helmet", "helm" }; internal static void Update(Player player) { if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer) { return; } if (!Plugin.EnableMod.Value || !FirstPersonState.Active || !Plugin.ForceBodyVisible.Value) { Reset(); return; } if ((Object)(object)_cachedPlayer != (Object)null && (Object)(object)_cachedPlayer != (Object)(object)player) { Reset(); } _cachedPlayer = player; if (!_captured) { CaptureVisibleBodyRenderers(player); } ForceCapturedBodyRenderersVisible(); } internal static void Reset() { RestoreRendererStates(); OriginalRendererStates.Clear(); DeadRenderers.Clear(); _cachedPlayer = null; _captured = false; } internal static void RequestRefresh() { RestoreRendererStates(); OriginalRendererStates.Clear(); DeadRenderers.Clear(); _captured = false; } private static void CaptureVisibleBodyRenderers(Player player) { OriginalRendererStates.Clear(); Renderer[] componentsInChildren = ((Component)player).GetComponentsInChildren<Renderer>(true); Renderer[] array = componentsInChildren; foreach (Renderer val in array) { if (!((Object)(object)val == (Object)null) && LocalPlayerRendererOwnership.IsLocalPlayerRenderer(player, val) && val.enabled && !LooksLikeHeadRenderer(val)) { OriginalRendererStates[val] = new RendererStateSnapshot(val); } } _captured = true; Plugin.DebugLog($"Captured {OriginalRendererStates.Count} visible body renderers for first-person body restore."); } private static void ForceCapturedBodyRenderersVisible() { RemoveDestroyedRenderers(); foreach (Renderer key in OriginalRendererStates.Keys) { if (!((Object)(object)key == (Object)null) && !((Object)(object)_cachedPlayer == (Object)null) && LocalPlayerRendererOwnership.IsLocalPlayerRenderer(_cachedPlayer, key) && !key.enabled) { key.enabled = true; } } } private static bool LooksLikeHeadRenderer(Renderer renderer) { string text = (((Object)(object)((Component)renderer).transform != (Object)null) ? RendererScanner.GetPath(((Component)renderer).transform) : string.Empty); string value = (((Object)renderer).name + " " + text).ToLowerInvariant(); if (ContainsAny(value, HeldItemKeywords)) { return false; } return ContainsAnyHeadKeyword(value); } private static bool ContainsAny(string value, string[] keywords) { foreach (string value2 in keywords) { if (value.IndexOf(value2, StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } return false; } private static void RestoreRendererStates() { if (OriginalRendererStates.Count == 0) { return; } foreach (KeyValuePair<Renderer, RendererStateSnapshot> originalRendererState in OriginalRendererStates) { Renderer key = originalRendererState.Key; if (!((Object)(object)key == (Object)null)) { originalRendererState.Value.Restore(key); } } } private static bool ContainsAnyHeadKeyword(string value) { string[] headKeywords = HeadKeywords; foreach (string keyword in headKeywords) { if (ContainsKeywordTokenOrSafePrefix(value, keyword)) { return true; } } return false; } private static bool ContainsKeywordTokenOrSafePrefix(string value, string keyword) { int num = value.IndexOf(keyword, StringComparison.OrdinalIgnoreCase); while (num >= 0) { bool flag = num == 0 || !char.IsLetterOrDigit(value[num - 1]); int num2 = num + keyword.Length; bool flag2 = num2 >= value.Length || !char.IsLetterOrDigit(value[num2]); if (flag && flag2) { return true; } if (flag && keyword.Length >= 5) { return true; } num = value.IndexOf(keyword, num2, StringComparison.OrdinalIgnoreCase); } return false; } private static void RemoveDestroyedRenderers() { DeadRenderers.Clear(); foreach (Renderer key in OriginalRendererStates.Keys) { if ((Object)(object)key == (Object)null) { DeadRenderers.Add(key); } } foreach (Renderer deadRenderer in DeadRenderers) { if (deadRenderer != null) { OriginalRendererStates.Remove(deadRenderer); } } DeadRenderers.Clear(); } } internal static class DodgeDirectionController { private const float DodgeQueueBodyLockSuppressSeconds = 0.75f; private static Player? _suppressedPlayer; private static float _suppressBodyLockUntil; internal static void PrepareDodge(Player player, ref Vector3 dodgeDir) { //IL_002c: 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) if (!ShouldHandleFirstPersonDodge(player)) { return; } if (Plugin.DodgeWhereYouLook.Value) { if (TryGetFlatLookDirection(player, out var lookDirection)) { dodgeDir = lookDirection; } } else { _suppressedPlayer = player; _suppressBodyLockUntil = Time.unscaledTime + 0.75f; } } internal static bool ShouldSkipBodyYawLock(Player player) { if (!ShouldHandleFirstPersonDodge(player) || Plugin.DodgeWhereYouLook.Value) { return false; } if (((Character)player).InDodge()) { return true; } if ((Object)(object)_suppressedPlayer == (Object)(object)player && Time.unscaledTime <= _suppressBodyLockUntil) { return true; } if ((Object)(object)_suppressedPlayer == (Object)(object)player) { ClearSuppression(); } return false; } private static bool ShouldHandleFirstPersonDodge(Player player) { return (Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)Player.m_localPlayer && Plugin.EnableMod.Value && FirstPersonState.ShouldApplyCamera(player); } private static bool TryGetFlatLookDirection(Player player, out Vector3 lookDirection) { //IL_0003: 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_0043: 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) lookDirection = ((Character)player).GetLookDir(); lookDirection.y = 0f; if (((Vector3)(ref lookDirection)).sqrMagnitude <= 0.0001f && (Object)(object)GameCamera.instance != (Object)null) { lookDirection = ((Component)GameCamera.instance).transform.forward; lookDirection.y = 0f; } if (((Vector3)(ref lookDirection)).sqrMagnitude <= 0.0001f) { return false; } ((Vector3)(ref lookDirection)).Normalize(); return true; } private static void ClearSuppression() { _suppressedPlayer = null; _suppressBodyLockUntil = 0f; } } [HarmonyPatch(typeof(Player), "Dodge")] internal static class PlayerDodgeDirectionPatch { private static void Prefix(Player __instance, ref Vector3 dodgeDir) { DodgeDirectionController.PrepareDodge(__instance, ref dodgeDir); } } [HarmonyPatch(typeof(VisEquipment), "SetHelmetEquipped")] internal static class VisEquipmentSetHelmetEquippedPatch { private static void Prefix(VisEquipment __instance) { HelmetShadowController.CaptureHelmetChangeStart(__instance); } private static void Postfix(VisEquipment __instance, bool __result) { HelmetShadowController.CaptureHelmetChangeEnd(__instance, __result); if (__result && PlayerEquipmentAccess.IsLocalPlayerVisEquipment(__instance)) { BodyVisibilityController.RequestRefresh(); HeadVisibilityController.RequestRefresh(); } } } [HarmonyPatch(typeof(VisEquipment), "SetChestEquipped")] internal static class VisEquipmentSetChestEquippedPatch { private static void Postfix(VisEquipment __instance, bool __result) { if (__result && PlayerEquipmentAccess.IsLocalPlayerVisEquipment(__instance)) { BodyVisibilityController.RequestRefresh(); HeadVisibilityController.RequestRefresh(); } } } [HarmonyPatch(typeof(VisEquipment), "SetShoulderEquipped")] internal static class VisEquipmentSetShoulderEquippedPatch { private static void Postfix(VisEquipment __instance, bool __result) { if (__result && PlayerEquipmentAccess.IsLocalPlayerVisEquipment(__instance)) { BodyVisibilityController.RequestRefresh(); HeadVisibilityController.RequestRefresh(); } } } [HarmonyPatch(typeof(VisEquipment), "SetLegEquipped")] internal static class VisEquipmentSetLegEquippedPatch { private static void Postfix(VisEquipment __instance, bool __result) { if (__result && PlayerEquipmentAccess.IsLocalPlayerVisEquipment(__instance)) { BodyVisibilityController.RequestRefresh(); HeadVisibilityController.RequestRefresh(); } } } [HarmonyPatch(typeof(VisEquipment), "SetModel")] internal static class VisEquipmentSetModelPatch { private static void Postfix(VisEquipment __instance) { if (PlayerEquipmentAccess.IsLocalPlayerVisEquipment(__instance)) { BodyVisibilityController.RequestRefresh(); HeadVisibilityController.RequestRefresh(); } } } [HarmonyPatch(typeof(Player), "OnDestroy")] internal static class PlayerOnDestroyVisibilityPatch { private static void Prefix(Player __instance) { if ((Object)(object)__instance != (Object)null && (Object)(object)__instance == (Object)(object)Player.m_localPlayer) { FirstPersonState.ForceInactive(); } } } [HarmonyPatch(typeof(GameCamera))] [HarmonyPatch("UpdateCamera")] internal static class GameCameraUpdatePatch { private static void Postfix(GameCamera __instance) { FirstPersonCamera.Update(__instance); } } internal static class FirstPersonCamera { private const float HeadBobFilterSpeed = 3f; private static readonly string[] CameraEffectTypeNameFragments = new string[8] { "PostProcessLayer", "PostProcessVolume", "Bloom", "DepthOfField", "MotionBlur", "ScreenSpaceAmbientOcclusion", "SunShafts", "Vignette" }; private static readonly FieldInfo? CameraField = AccessTools.Field(typeof(GameCamera), "m_camera"); private static readonly MethodInfo? IsCrouchingMethod = FindInstanceMethod(typeof(Player), "IsCrouching") ?? FindInstanceMethod(typeof(Character), "IsCrouching"); private static readonly MethodInfo? InSneakMethod = FindInstanceMethod(typeof(Player), "InSneak") ?? FindInstanceMethod(typeof(Character), "InSneak"); private static readonly FieldInfo? CrouchField = AccessTools.Field(typeof(Player), "m_crouchToggled") ?? AccessTools.Field(typeof(Player), "m_crouch") ?? AccessTools.Field(typeof(Character), "m_crouch"); private static Camera? _lastCamera; private static Camera? _savedCamera; private static Player? _cachedAnchorPlayer; private static Transform? _cachedHeadAnchor; private static float _originalFov; private static float _originalNearClip; private static bool _originalUseOcclusionCulling; private static bool _savedOriginals; private static bool _loggedRenderingState; private static float _originalShadowDistance; private static int _originalShadowCascades; private static readonly Dictionary<Behaviour, bool> CameraEffectStates = new Dictionary<Behaviour, bool>(); private static Player? _filteredHeadPlayer; private static Vector3 _filteredLocalHeadPosition; private static bool _hasFilteredHeadPosition; private static Player? _attachedCameraPlayer; private static Vector3 _attachedLocalCameraPosition; private static bool _hasAttachedCameraPosition; private static float _currentShoulderPeekOffset; private static int _toggledShoulderPeekDirection; internal static void Update(GameCamera gameCamera) { //IL_0092: 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_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)gameCamera == (Object)null) { ResetShoulderPeek(); return; } Camera val = GetCamera(gameCamera) ?? Camera.main; if ((Object)(object)val == (Object)null) { ResetShoulderPeek(); return; } _lastCamera = val; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || !FirstPersonState.ShouldApplyCamera(localPlayer)) { RestoreCamera(val); ResetHeadBobFilter(); ResetAttachedCameraLock(); ResetShoulderPeek(); RestoreLocalVisibilityForSuppressedCamera(); return; } Quaternion rotation = ((Component)gameCamera).transform.rotation; bool flag = ShouldLockAttachedCamera(localPlayer); if (!flag) { ResetAttachedCameraLock(); } if (Plugin.LockBodyToCamera.Value && !flag && !DodgeDirectionController.ShouldSkipBodyYawLock(localPlayer)) { LockBodyYawToCamera(localPlayer, rotation); } SaveOriginalCameraValues(val); ApplyFirstPersonCamera(gameCamera, val, localPlayer, rotation, flag); LocalPlayerVisibilityOverride.ForceVisible(localPlayer); BodyVisibilityController.Update(localPlayer); HeadVisibilityController.Update(localPlayer); } internal static void RestoreLastCamera() { if ((Object)(object)_lastCamera != (Object)null) { RestoreCamera(_lastCamera); } ResetHeadBobFilter(); ResetAttachedCameraLock(); ResetShoulderPeek(); ResetAnchorCache(); } private static Camera? GetCamera(GameCamera gameCamera) { if (CameraField == null) { return null; } object? value = CameraField.GetValue(gameCamera); return (Camera?)((value is Camera) ? value : null); } private static MethodInfo? FindInstanceMethod(Type type, string name) { return type.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } private static void SaveOriginalCameraValues(Camera camera) { if (!_savedOriginals || !((Object)(object)_savedCamera == (Object)(object)camera)) { if (_savedOriginals && (Object)(object)_savedCamera != (Object)null) { RestoreCamera(_savedCamera); } _savedCamera = camera; _originalFov = camera.fieldOfView; _originalNearClip = camera.nearClipPlane; _originalUseOcclusionCulling = camera.useOcclusionCulling; _originalShadowDistance = QualitySettings.shadowDistance; _originalShadowCascades = QualitySettings.shadowCascades; _savedOriginals = true; LogRenderingState(); } } private static void LogRenderingState() { if (!_loggedRenderingState) { _loggedRenderingState = true; Plugin.Log.LogInfo((object)$"First-person rendering state: view distance unchanged; LOD unchanged; originalNearClip={_originalNearClip:0.###}; requestedNearClip={Plugin.NearClip.Value:0.###}; originalShadowDistance={_originalShadowDistance:0.###}; shadowDistanceCap={Plugin.FirstPersonShadowDistance.Value:0.###}; originalShadowCascades={_originalShadowCascades}; shadowCascadesCap={Plugin.FirstPersonShadowCascades.Value}; originalOcclusionCulling={_originalUseOcclusionCulling}; firstPersonOcclusionCulling=false; cameraEffectsDisabled={Plugin.DisableCameraEffects.Value}."); } } private static void RestoreLocalVisibilityForSuppressedCamera() { if (FirstPersonState.Active) { BodyVisibilityController.Reset(); HeadVisibilityController.ForceVisible(); } } private static bool ShouldLockAttachedCamera(Player player) { return Plugin.LockCameraWhileAttached.Value && ((Character)player).IsAttached(); } private static void LockBodyYawToCamera(Player player, Quaternion cameraRotation) { //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_000c: 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_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_008b: Unknown result type (might be due to invalid IL or missing references) //IL_006b: 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_0084: Unknown result type (might be due to invalid IL or missing references) Vector3 val = cameraRotation * Vector3.forward; val.y = 0f; if (!(((Vector3)(ref val)).sqrMagnitude <= 0.0001f)) { Quaternion val2 = Quaternion.LookRotation(((Vector3)(ref val)).normalized, Vector3.up); float num = Mathf.Max(0f, Plugin.BodyRotationFollowSpeed.Value); ((Component)player).transform.rotation = ((num <= 0f) ? val2 : Quaternion.Slerp(((Component)player).transform.rotation, val2, 1f - Mathf.Exp((0f - num) * Time.unscaledDeltaTime))); } } private static void ApplyFirstPersonCamera(GameCamera gameCamera, Camera camera, Player player, Quaternion vanillaCameraRotation, bool lockAttachedCamera) { //IL_000d: 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_0054: 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) //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) //IL_006f: 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_0071: 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_00ba: 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_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_009d: 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_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_016a: 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_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_011e: 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_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: 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_010c: 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_011d: Unknown result type (might be due to invalid IL or missing references) if (lockAttachedCamera) { ApplyAttachedCamera(gameCamera, camera, player, vanillaCameraRotation); return; } Transform cameraAnchor = GetCameraAnchor(player); bool flag = (Object)(object)cameraAnchor != (Object)null && Plugin.UseHeadTrackedAnchor.Value && (Object)(object)cameraAnchor != (Object)(object)((Character)player).m_eye; bool flag2 = IsCrouchingOrSneaking(player); Vector3 headBobScaledAnchorPosition = GetHeadBobScaledAnchorPosition(player, cameraAnchor, flag); headBobScaledAnchorPosition += Vector3.up * Plugin.CameraVerticalOffset.Value; Vector3 val = vanillaCameraRotation * Vector3.forward; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude > 0.0001f) { headBobScaledAnchorPosition += ((Vector3)(ref val)).normalized * Plugin.CameraForwardOffset.Value; } float num = Mathf.Clamp01(Vector3.Dot(vanillaCameraRotation * Vector3.forward, Vector3.down)); if (num > 0f) { if (((Vector3)(ref val)).sqrMagnitude > 0.0001f) { headBobScaledAnchorPosition += ((Vector3)(ref val)).normalized * Plugin.DownLookExtraForwardOffset.Value * num; } headBobScaledAnchorPosition += Vector3.up * Plugin.DownLookExtraVerticalOffset.Value * num; } if (!flag && flag2) { headBobScaledAnchorPosition += Vector3.up * Plugin.CrouchVerticalOffset.Value; } headBobScaledAnchorPosition = ApplyShoulderPeek(headBobScaledAnchorPosition, vanillaCameraRotation); ApplyCameraState(gameCamera, camera, headBobScaledAnchorPosition, vanillaCameraRotation); } private static void ApplyAttachedCamera(GameCamera gameCamera, Camera camera, Player player, Quaternion vanillaCameraRotation) { //IL_000d: 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_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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_002e: Unknown result type (might be due to invalid IL or missing references) ResetHeadBobFilter(); Quaternion rotation = ((Component)player).transform.rotation; Quaternion limitedAttachedCameraRotation = GetLimitedAttachedCameraRotation(rotation, vanillaCameraRotation); Vector3 attachedCameraPosition = GetAttachedCameraPosition(player, rotation); attachedCameraPosition = ApplyShoulderPeek(attachedCameraPosition, limitedAttachedCameraRotation); ApplyCameraState(gameCamera, camera, attachedCameraPosition, limitedAttachedCameraRotation); } private static Vector3 ApplyShoulderPeek(Vector3 eyePosition, Quaternion cameraRotation) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0064: 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_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: 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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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_0082: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.EnableShoulderPeek.Value) { ResetShoulderPeek(); return eyePosition; } int shoulderPeekDirection = GetShoulderPeekDirection(); float targetOffset = (float)shoulderPeekDirection * Mathf.Max(0f, Plugin.ShoulderPeekOffset.Value); _currentShoulderPeekOffset = SmoothShoulderPeekOffset(targetOffset); if (Mathf.Abs(_currentShoulderPeekOffset) <= 0.0001f) { return eyePosition; } return eyePosition + cameraRotation * Vector3.right * _currentShoulderPeekOffset; } private static int GetShoulderPeekDirection() { //IL_0006: 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_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) bool keyDown = Input.GetKeyDown(Plugin.PeekLeftKey.Value); bool keyDown2 = Input.GetKeyDown(Plugin.PeekRightKey.Value); bool key = Input.GetKey(Plugin.PeekLeftKey.Value); bool key2 = Input.GetKey(Plugin.PeekRightKey.Value); if (Plugin.ShoulderPeekMode.Value == ShoulderPeekMode.Toggle) { if (keyDown) { _toggledShoulderPeekDirection = ((_toggledShoulderPeekDirection != -1) ? (-1) : 0); } if (keyDown2) { _toggledShoulderPeekDirection = ((_toggledShoulderPeekDirection != 1) ? 1 : 0); } return _toggledShoulderPeekDirection; } if (key && !key2) { return -1; } if (key2 && !key) { return 1; } return 0; } private static float SmoothShoulderPeekOffset(float targetOffset) { float num = Mathf.Max(0f, Plugin.ShoulderPeekSpeed.Value); if (num <= 0f) { return targetOffset; } float num2 = Mathf.Min(Time.unscaledDeltaTime, 0.05f); float num3 = 1f - Mathf.Exp((0f - num) * num2); return Mathf.Lerp(_currentShoulderPeekOffset, targetOffset, num3); } private static void ResetShoulderPeek() { _toggledShoulderPeekDirection = 0; _currentShoulderPeekOffset = 0f; } private static Vector3 GetAttachedCameraPosition(Player player, Quaternion bodyRotation) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: 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_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0078: 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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: 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_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_attachedCameraPlayer != (Object)(object)player) { ResetAttachedCameraLock(); } if (!_hasAttachedCameraPosition) { _attachedCameraPlayer = player; _attachedLocalCameraPosition = CaptureAttachedLocalCameraPosition(player, bodyRotation); _hasAttachedCameraPosition = true; Plugin.DebugLog($"Captured attached camera local position: {_attachedLocalCameraPosition}"); } Vector3 attachedLocalCameraPosition = _attachedLocalCameraPosition; attachedLocalCameraPosition += Vector3.up * Plugin.AttachedCameraExtraVerticalOffset.Value; attachedLocalCameraPosition += Vector3.forward * Plugin.AttachedCameraExtraForwardOffset.Value; return ((Component)player).transform.TransformPoint(attachedLocalCameraPosition); } private static Vector3 CaptureAttachedLocalCameraPosition(Player player, Quaternion bodyRotation) { //IL_001a: 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_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: 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_0067: 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_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: 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_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0089: 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_004a: 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_005c: 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_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) Transform cameraAnchor = GetCameraAnchor(player); Vector3 val = (((Object)(object)cameraAnchor != (Object)null) ? cameraAnchor.position : GetFallbackEyePosition(player)); Vector3 val2 = bodyRotation * Vector3.forward; val2.y = 0f; if (((Vector3)(ref val2)).sqrMagnitude > 0.0001f) { val += ((Vector3)(ref val2)).normalized * Plugin.CameraForwardOffset.Value; } val += Vector3.up * Plugin.CameraVerticalOffset.Value; return ((Component)player).transform.InverseTransformPoint(val); } private static Vector3 GetFallbackEyePosition(Player player) { //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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: 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_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_0041: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)((Character)player).m_eye != (Object)null) { return ((Character)player).m_eye.position; } return ((Component)player).transform.position + Vector3.up * 1.6f; } private static Quaternion GetLimitedAttachedCameraRotation(Quaternion bodyRotation, Quaternion vanillaCameraRotation) { //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_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_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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_005f: 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_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: 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) Quaternion val = Quaternion.Inverse(bodyRotation) * vanillaCameraRotation; Vector3 val2 = NormalizeEuler(((Quaternion)(ref val)).eulerAngles); float num = Mathf.Clamp(Plugin.AttachedCameraMaxYaw.Value, 0f, 180f); float num2 = Mathf.Clamp(Plugin.AttachedCameraMaxPitch.Value, 1f, 89f); float num3 = Mathf.Clamp(val2.y, 0f - num, num); float num4 = Mathf.Clamp(val2.x, 0f - num2, num2); return bodyRotation * Quaternion.Euler(num4, num3, 0f); } private static Vector3 NormalizeEuler(Vector3 euler) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000c: 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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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) return new Vector3(NormalizeAngle(euler.x), NormalizeAngle(euler.y), NormalizeAngle(euler.z)); } private static float NormalizeAngle(float angle) { angle %= 360f; if (angle > 180f) { angle -= 360f; } else if (angle < -180f) { angle += 360f; } return angle; } private static Vector3 GetHeadBobScaledAnchorPosition(Player player, Transform? anchor, bool hasHeadAnchor) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_010e: 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_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: 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_008e: Unknown result type (might be due to invalid IL or missing references) //IL_008f: 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_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: 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_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: 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_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: 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) if ((Object)(object)anchor == (Object)null) { ResetHeadBobFilter(); return GetFallbackEyePosition(player); } if (!hasHeadAnchor) { ResetHeadBobFilter(); return anchor.position; } float num = Mathf.Clamp01(Plugin.HeadBobAmount.Value); Vector3 val = ((Component)player).transform.InverseTransformPoint(anchor.position); if ((Object)(object)_filteredHeadPlayer != (Object)(object)player) { ResetHeadBobFilter(); } if (!_hasFilteredHeadPosition) { _filteredHeadPlayer = player; _filteredLocalHeadPosition = val; _hasFilteredHeadPosition = true; } float num2 = 1f - Mathf.Exp(-3f * Time.unscaledDeltaTime); _filteredLocalHeadPosition = Vector3.Lerp(_filteredLocalHeadPosition, val, num2); if (num >= 0.999f) { return anchor.position; } Vector3 val2 = val - _filteredLocalHeadPosition; Vector3 val3 = _filteredLocalHeadPosition + val2 * num; return ((Component)player).transform.TransformPoint(val3); } private static Transform GetCameraAnchor(Player player) { if (!Plugin.UseHeadTrackedAnchor.Value) { return ((Object)(object)((Character)player).m_eye != (Object)null) ? ((Character)player).m_eye : ((Component)player).transform; } if ((Object)(object)_cachedAnchorPlayer == (Object)(object)player && (Object)(object)_cachedHeadAnchor != (Object)null) { return _cachedHeadAnchor; } _cachedAnchorPlayer = player; _cachedHeadAnchor = FindBestHeadAnchor(player); if ((Object)(object)_cachedHeadAnchor != (Object)null) { Plugin.DebugLog("Using head-tracked camera anchor: " + RendererScanner.GetPath(_cachedHeadAnchor)); return _cachedHeadAnchor; } return ((Object)(object)((Character)player).m_eye != (Object)null) ? ((Character)player).m_eye : ((Component)player).transform; } private static Transform? FindBestHeadAnchor(Player player) { Transform[] componentsInChildren = ((Component)player).GetComponentsInChildren<Transform>(true); Transform val = null; int num = int.MinValue; Transform[] array = componentsInChildren; foreach (Transform val2 in array) { if (!((Object)(object)val2 == (Object)null)) { int num2 = ScoreHeadAnchor(val2); if (num2 > num) { num = num2; val = val2; } } } return (num > 0) ? val : null; } private static int ScoreHeadAnchor(Transform transform) { string text = ((Object)transform).name.ToLowerInvariant(); string text2 = RendererScanner.GetPath(transform).ToLowerInvariant(); string text3 = text + " " + text2; if (!text3.Contains("head")) { return int.MinValue; } if (text3.Contains("helmet") || text3.Contains("helm") || text3.Contains("hair") || text3.Contains("beard")) { return int.MinValue; } int num = 10; if (text == "head") { num += 100; } if (text.Contains("head")) { num += 40; } if (text2.Contains("neck")) { num += 10; } if ((Object)(object)((Component)transform).GetComponent<Renderer>() != (Object)null) { num -= 50; } return num; } private static bool IsCrouchingOrSneaking(Player player) { if (TryInvokeBool(player, IsCrouchingMethod, out var value) && value) { return true; } if (TryInvokeBool(player, InSneakMethod, out var value2) && value2) { return true; } if (CrouchField != null && CrouchField.GetValue(player) is bool result) { return result; } return false; } private static bool TryInvokeBool(Player player, MethodInfo? method, out bool value) { value = false; if (method == null) { return false; } if (!(method.Invoke(player, null) is bool flag) || 1 == 0) { return false; } value = flag; return true; } private static void ApplyCameraState(GameCamera gameCamera, Camera camera, Vector3 desiredPosition, Quaternion desiredRotation) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0014: 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_0044: Unknown result type (might be due to invalid IL or missing references) ((Component)gameCamera).transform.position = desiredPosition; ((Component)gameCamera).transform.rotation = desiredRotation; if ((Object)(object)((Component)camera).transform != (Object)(object)((Component)gameCamera).transform) { ((Component)camera).transform.position = desiredPosition; ((Component)camera).transform.rotation = desiredRotation; } if (Plugin.UseCustomFov.Value) { camera.fieldOfView = Mathf.Clamp(Plugin.Fov.Value, 40f, 120f); } else { camera.fieldOfView = _originalFov; } ApplyFirstPersonRendering(camera); } private static void ApplyFirstPersonRendering(Camera camera) { camera.nearClipPlane = Mathf.Clamp(Plugin.NearClip.Value, 0.005f, 0.5f); camera.useOcclusionCulling = false; ApplyShadowOverrides(); ApplyCameraEffectOverrides(camera); } private static void ApplyShadowOverrides() { if (Plugin.FirstPersonShadowDistance.Value >= 0f) { float num = Mathf.Max(0f, Plugin.FirstPersonShadowDistance.Value); QualitySettings.shadowDistance = Mathf.Min(_originalShadowDistance, num); } if (Plugin.FirstPersonShadowCascades.Value >= 0) { int num2 = NormalizeShadowCascades(Plugin.FirstPersonShadowCascades.Value); QualitySettings.shadowCascades = Mathf.Min(_originalShadowCascades, num2); } } private static int NormalizeShadowCascades(int value) { if (value <= 0) { return 0; } if (value <= 2) { return 2; } return 4; } private static void ApplyCameraEffectOverrides(Camera camera) { if (!Plugin.DisableCameraEffects.Value) { RestoreCameraEffectStates(); return; } Behaviour[] components = ((Component)camera).GetComponents<Behaviour>(); foreach (Behaviour val in components) { if (!((Object)(object)val == (Object)null) && IsCameraEffectComponent(val)) { if (!CameraEffectStates.ContainsKey(val)) { CameraEffectStates.Add(val, val.enabled); } val.enabled = false; } } } private static bool IsCameraEffectComponent(Behaviour component) { Type type = ((object)component).GetType(); string text = type.FullName ?? type.Name; if (string.Equals(text, "UnityEngine.Rendering.Volume", StringComparison.Ordinal)) { return true; } string[] cameraEffectTypeNameFragments = CameraEffectTypeNameFragments; foreach (string value in cameraEffectTypeNameFragments) { if (text.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } return false; } private static void RestoreCamera(Camera camera) { if (_savedOriginals) { Camera val = (Camera)(((Object)(object)_savedCamera != (Object)null) ? ((object)_savedCamera) : ((object)camera)); if ((Object)(object)val != (Object)null) { val.fieldOfView = _originalFov; val.nearClipPlane = _originalNearClip; val.useOcclusionCulling = _originalUseOcclusionCulling; } QualitySettings.shadowDistance = _originalShadowDistance; QualitySettings.shadowCascades = _originalShadowCascades; RestoreCameraEffectStates(); _savedCamera = null; _savedOriginals = false; } } private static void RestoreCameraEffectStates() { foreach (KeyValuePair<Behaviour, bool> cameraEffectState in CameraEffectStates) { if ((Object)(object)cameraEffectState.Key != (Object)null) { cameraEffectState.Key.enabled = cameraEffectState.Value; } } CameraEffectStates.Clear(); } private static void ResetHeadBobFilter() { //IL_000d: 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) _filteredHeadPlayer = null; _hasFilteredHeadPosition = false; _filteredLocalHeadPosition = Vector3.zero; } private static void ResetAttachedCameraLock() { //IL_000d: 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) _attachedCameraPlayer = null; _hasAttachedCameraPosition = false; _attachedLocalCameraPosition = Vector3.zero; } private static void ResetAnchorCache() { _cachedAnchorPlayer = null; _cachedHeadAnchor = null; } } internal static class FirstPersonState { private static Player? _cachedPlayer; private static bool _defaultApplied; internal static bool Active { get; private set; } internal static void Update(Player player) { //IL_00c2: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer) { return; } if ((Object)(object)_cachedPlayer != (Object)null && (Object)(object)_cachedPlayer != (Object)(object)player) { ForceInactive(); _defaultApplied = false; } _cachedPlayer = player; if (!Plugin.EnableMod.Value) { SetActive(active: false); return; } if (!IsSafePlayerState(player)) { SetActive(active: false); return; } if (!_defaultApplied) { _defaultApplied = true; if (Plugin.DefaultToFirstPerson.Value) { SetActive(active: true); } } if (CanReadToggleInput() && Input.GetKeyDown(Plugin.ToggleFirstPersonKey.Value)) { SetActive(!Active); } if (Active && Plugin.LogRendererNames.Value) { RendererScanner.LogRenderersOnce(player); } } internal static bool ShouldApplyCamera(Player player) { return Plugin.EnableMod.Value && Active && (Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)Player.m_localPlayer && IsSafePlayerState(player) && CanOverrideCurrentCameraContext(); } internal static void ForceInactive() { SetActive(active: false); _cachedPlayer = null; _defaultApplied = false; } private static void SetActive(bool active) { if (Active != active) { Active = active; if (!active) { HeadVisibilityController.ForceVisible(); FirstPersonCamera.RestoreLastCamera(); RendererScanner.ResetLogState(); } Plugin.Log.LogInfo((object)(active ? "Immersive first person active." : "Immersive first person inactive.")); } } private static bool CanReadToggleInput() { return !IsAnyBlockingUiVisible(); } private static bool CanOverrideCurrentCameraContext() { if (!Plugin.OverrideForcedThirdPerson.Value) { return !IsAnyBlockingUiVisible() && !IsPlayerAttached(); } if (IsHardCameraBlockVisible()) { return false; } return true; } private static bool IsAnyBlockingUiVisible() { return IsInputBlockingUiVisible() || IsHardCameraBlockVisible(); } private static bool IsInputBlockingUiVisible() { if (InventoryGui.IsVisible()) { return true; } return false; } private static bool IsHardCameraBlockVisible() { if (Menu.IsVisible()) { return true; } if (Minimap.IsOpen()) { return true; } return false; } private static bool IsSafePlayerState(Player player) { if (((Character)player).IsDead()) { return false; } return true; } private static bool IsPlayerAttached() { Player localPlayer = Player.m_localPlayer; return (Object)(object)localPlayer != (Object)null && ((Character)localPlayer).IsAttached(); } } internal static class HeadVisibilityController { private readonly struct TransformState { internal readonly Vector3 LocalPosition; internal readonly Vector3 LocalScale; internal TransformState(Transform transform) { //IL_0003: 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_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) LocalPosition = transform.localPosition; LocalScale = transform.localScale; } } private const float HeadSlotClipRadius = 0.55f; private const float MaxHeadSlotExtent = 1.15f; private const float MinHeadSlotHeight = 0.9f; private const float MaxHeadSlotHeight = 2.4f; private const float MaxHeadSlotHorizontalDistance = 0.75f; private const float HeadShrinkScale = 0.001f; private const float HeadSlotCompensationScale = 999.99994f; private static readonly Vector3 HeadShrinkVector = Vector3.one * 0.001f; private static readonly Dictionary<Renderer, RendererStateSnapshot> OriginalRendererStates = new Dictionary<Renderer, RendererStateSnapshot>(); private static readonly Dictionary<Transform, Vector3> OriginalBoneScales = new Dictionary<Transform, Vector3>(); private static readonly Dictionary<Transform, TransformState> OriginalHeadSlotStates = new Dictionary<Transform, TransformState>(); private static readonly HashSet<Renderer> DesiredRenderers = new HashSet<Renderer>(); private static readonly List<Transform> CachedHeadBones = new List<Transform>(); private static readonly List<Renderer> ManagedHelmetRenderers = new List<Renderer>(); private static readonly List<Renderer?> RenderersToRemove = new List<Renderer>(); private static readonly List<Transform?> BonesToRemove = new List<Transform>(); private static readonly List<Transform?> HeadSlotTransformsToRemove = new List<Transform>(); private static Player? _cachedPlayer; private static bool _active; private static bool _headBoneCacheInitialized; private static float _nextRefreshTime; private static string? _lastFallbackReason; private static readonly string[] HeadSlotKeywords = new string[18] { "head", "hair", "beard", "face", "jaw", "eye", "brow", "mouth", "nose", "teeth", "helmet", "helm", "hat", "hood", "circlet", "crown", "headgear", "padded" }; private static readonly string[] HeadSlotHierarchyKeywords = new string[8] { "attach_helmet", "attach_helm", "attach_head", "helmet", "helm", "hair", "beard", "headgear" }; private static readonly string[] HeadBoneRejectKeywords = new string[10] { "helmet", "helm", "hat", "hood", "hair", "beard", "circlet", "crown", "headgear", "padded" }; private static readonly string[] EquipmentSkeletonKeywords = new string[6] { "attach_skin", "attach_armor", "attach_helmet", "attach_helm", "attach_shoulder", "attach_back" }; private static readonly string[] HeldItemKeywords = new string[28] { "hand", "right", "left", "weapon", "sword", "axe", "mace", "hammer", "club", "knife", "bow", "arrow", "shield", "torch", "tool", "pickaxe", "hatchet", "battleaxe", "sledge", "spear", "atgeir", "crossbow", "buckler", "staff", "wand", "cultivator", "fishing", "itemstand" }; private static readonly string[] BodyKeywords = new string[14] { "body", "torso", "chest", "arm", "leg", "foot", "feet", "hand", "player", "character", "human", "male", "female", "skin" }; internal static void Update(Player player) { if (!IsLocalPlayer(player)) { ForceVisible(); return; } bool shouldHide = Plugin.EnableMod.Value && FirstPersonState.Active && Plugin.HideHead.Value; Apply(player, shouldHide); } internal static void ForceVisible() { BlacksmithHeadHider.Restore(); HelmetShadowController.Restore(); RestoreHeadSlotStates(); RestoreBoneScales(); RestoreRendererStates(); ResetCache(); } internal static void RequestRefresh() { _nextRefreshTime = 0f; _headBoneCacheInitialized = false; BlacksmithHeadHider.RequestRefresh(); HelmetShadowController.RequestRefresh(); } private static void Apply(Player player, bool shouldHide) { if (!IsLocalPlayer(player)) { ForceVisible(); return; } if ((Object)(object)_cachedPlayer != (Object)null && (Object)(object)_cachedPlayer != (Object)(object)player) { ForceVisible(); } _cachedPlayer = player; if (!shouldHide) { ForceVisible(); return; } if (!_active) { OriginalRendererStates.Clear(); OriginalBoneScales.Clear(); OriginalHeadSlotStates.Clear(); DesiredRenderers.Clear(); CachedHeadBones.Clear(); _active = true; _nextRefreshTime = 0f; } HelmetShadowController.Update(player, shouldHide: true); bool flag = Time.unscaledTime >= _nextRefreshTime; if (flag) { RefreshRendererCache(player); _nextRefreshTime = Time.unscaledTime + Mathf.Clamp(Plugin.VisibilityRefreshInterval.Value, 0.1f, 10f); } HideCachedRenderersShadowsOnly(); HelmetShadowController.Update(player, shouldHide: true); if (ShouldUseBlacksmith(player, out string fallbackReason)) { RestoreHeadSlotStates(); RestoreBoneScales(); _lastFallbackReason = null; return; } if (!ShouldUseShrinkFallback(fallbackReason)) { RestoreHeadSlotStates(); RestoreBoneScales(); return; } BlacksmithHeadHider.Restore(); LogFallbackUse(fallbackReason); if (flag || !_headBoneCacheInitialized) { RefreshHeadBoneCache(player); } ApplyCachedHeadBoneScale(); CompensateHeadSlotTransforms(); } private static bool ShouldUseBlacksmith(Player player, out string fallbackReason) { fallbackReason = string.Empty; if (Plugin.HeadHidingMode.Value == HeadHidingMode.ShrinkFallback) { fallbackReason = "ShrinkFallback mode is selected"; return false; } if (BlacksmithHeadHider.TryApply(player, out fallbackReason)) { return true; } if (Plugin.HeadHidingMode.Value == HeadHidingMode.BlacksmithTools) { Plugin.HeadHidingDebugLog("BlacksmithTools mode did not hide the head: " + fallbackReason + "."); return false; } return false; } private static bool ShouldUseShrinkFallback(string fallbackReason) { return Plugin.HeadHidingMode.Value == HeadHidingMode.ShrinkFallback || (Plugin.HeadHidingMode.Value == HeadHidingMode.Auto && !string.IsNullOrEmpty(fallbackReason)); } private static void LogFallbackUse(string fallbackReason) { string text = (string.IsNullOrEmpty(fallbackReason) ? "Blacksmith head hiding was unavailable" : fallbackReason); if (!string.Equals(_lastFallbackReason, text, StringComparison.Ordinal)) { _lastFallbackReason = text; Plugin.Log.LogWarning((object)("Using first-person head shrink fallback because " + text + ".")); } } private static void RefreshRendererCache(Player player) { //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) RestoreHeadSlotStates(); RemoveDestroyedRenderers(); RemoveDestroyedHeadSlotTransforms(); DesiredRenderers.Clear(); Renderer[] componentsInChildren = ((Component)player).GetComponentsInChildren<Renderer>(true); Renderer[] array = componentsInChildren; foreach (Renderer val in array) { if (!((Object)(object)val == (Object)null) && IsRendererOwnedByPlayer(player, val) && !HelmetShadowController.IsManagedRenderer(val) && ShouldHideHeadSlotRenderer(player, val)) { DesiredRenderers.Add(val); } } RenderersToRemove.Clear(); foreach (KeyValuePair<Renderer, RendererStateSnapshot> originalRendererState in OriginalRendererStates) { Renderer key = originalRendererState.Key; if ((Object)(object)key == (Object)null || !DesiredRenderers.Contains(key)) { RenderersToRemove.Add(key); } } foreach (Renderer item in RenderersToRemove) { if (item != null) { RestoreRenderer(item); OriginalRendererStates.Remove(item); } } RenderersToRemove.Clear(); foreach (Renderer desiredRenderer in DesiredRenderers) { if (!OriginalRendererStates.ContainsKey(desiredRenderer)) { OriginalRendererStates.Add(desiredRenderer, new RendererStateSnapshot(desiredRenderer)); string arg = BuildRendererDescriptor(desiredRenderer); Bounds bounds = desiredRenderer.bounds; Plugin.DebugLog($"First-person head-slot visibility matched renderer: {arg} | bounds={((Bounds)(ref bounds)).size}"); } } } private static bool ShouldHideHeadSlotRenderer(Player player, Renderer renderer) { if (!IsRendererOwnedByPlayer(player, renderer)) { return false; } string text = BuildRendererDescriptor(renderer); if (LooksLikeHeldItem(text)) { return false; } if (LooksLikeFullBodyRenderer(renderer, text)) { return false; } bool flag = ContainsAnyHeadSlotKeyword(text); bool flag2 = LooksLikeHeadSlotHierarchy(renderer, text); bool flag3 = IsSmallRendererNearHeadOrCamera(player, renderer); if (flag2 && (flag || flag3)) { return true; } return flag && flag3; } private static bool IsSmallRendererNearHeadOrCamera(Player player, Renderer renderer) { //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_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_008a: 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_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) Bounds bounds = renderer.bounds; Vector3 size = ((Bounds)(ref bounds)).size; float num = Mathf.Max(new float[3] { size.x, size.y, size.z }); if (num > 1.15f) { return false; } Vector3 val = ((Component)player).transform.InverseTransformPoint(((Bounds)(ref bounds)).center); float y = val.y; if (y < 0.9f || y > 2.4f) { return false; } Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(val.x, val.z); if (((Vector2)(ref val2)).magnitude > 0.75f) { return false; } Camera main = Camera.main; if ((Object)(object)main == (Object)null) { return false; } Vector3 val3 = ((Bounds)(ref bounds)).ClosestPoint(((Component)main).transform.position); return Vector3.Distance(val3, ((Component)main).transform.position) <= 0.55f; } private static string BuildRendererDescriptor(Renderer renderer) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(((Object)renderer).name).Append(' '); if ((Object)(object)((Component)renderer).transform != (Object)null) { stringBuilder.Append(RendererScanner.GetPath(((Component)renderer).transform)).Append(' '); } SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null); if (val != null) { if ((Object)(object)val.sharedMesh != (Object)null) { stringBuilder.Append(((Object)val.sharedMesh).name).Append(' '); } if ((Object)(object)val.rootBone != (Object)null) { stringBuilder.Append(RendererScanner.GetPath(val.rootBone)).Append(' '); } } Material[] sharedMaterials = renderer.sharedMaterials; if (sharedMaterials != null) { Material[] array = sharedMaterials; foreach (Material val2 in array) { if ((Object)(object)val2 != (Object)null) { stringBuilder.Append(((Object)val2).name).Append(' '); } } } return stringBuilder.ToString().ToLowerInvariant(); } private static bool LooksLikeHeadSlotHierarchy(Renderer renderer, string descriptor) { if ((Object)(object)renderer == (Object)null) { return false; } if (ContainsAny(descriptor, HeadSlotHierarchyKeywords)) { return true; } if (IsTransformUnderLikelyHeadBone(((Component)renderer).transform, includeSelf: false)) { return true; } SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((renderer is SkinnedMeshRenderer) ? renderer : null); if (val != null) { if (IsTransformUnderLikelyHeadBone(val.rootBone, includeSelf: true)) { return true; } Transform[] bones = val.bones; if (bones != null) { Transform[] array = bones; foreach (Transform transform in array) { if (IsTransformUnderLikelyHeadBone(transform, includeSelf: true)) { return true; } } } } return false; } private static bool IsTransformUnderLikelyHeadBone(Transform? transform, bool includeSelf) { Transform val = (Transform)(includeSelf ? ((object)transform) : ((object)((transform != null) ? transform.parent : null))); while ((Object)(object)val != (Object)null) { if (IsLikelyCharacterHeadBoneName(((Object)val).name)) { return true; } val = val.parent; } return false; } private static bool IsLikelyCharacterHeadBoneName(string name) { if (name.Equals("head", StringComparison.OrdinalIgnoreCase) || name.Equals("bip_head", StringComparison.OrdinalIgnoreCase) || name.Equals("bip01 head", StringComparison.OrdinalIgnoreCase) || name.Equals("bip01head", StringComparison.OrdinalIgnoreCase) || name.Equals("bip001 head", StringComparison.OrdinalIgnoreCase) || name.Equals("bip001head", StringComparison.OrdinalIgnoreCase)) { return true; } return name.Length > 4 && name.StartsWith("head", StringComparison.OrdinalIgnoreCase) && char.IsDigit(name[4]); } private static bool LooksLikeHeldItem(string descriptor) { return ContainsAny(descriptor, HeldItemKeywords); } private static bool LooksLikeFullBodyRenderer(Renderer renderer, string descriptor) { //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_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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_0051: Unknown result type (might be due to invalid IL or missing references) Bounds bounds = renderer.bounds; Vector3 size = ((Bounds)(ref bounds)).size; float num = Mathf.Max(new float[3] { size.x, size.y, size.z }); bool flag = ContainsAny(descriptor, BodyKeywords) && !ContainsAnyHeadSlotKeyword(descriptor); bool flag2 = size.y > 1.2f && num > 1.4f; return flag || flag2; } private static bool ContainsAny(string value, string[] keywords) { foreach (string value2 in keywords) { if (value.IndexOf(value2, StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } return false; } private static bool ContainsAnyHeadSlotKeyword(string value) { string[] headSlotKeywords = HeadSlotKeywords; foreach (string keyword in headSlotKeywords) { if (ContainsKeywordTokenOrSafePrefix(value, keyword)) { return true; } } return false; } private static bool ContainsAnyHeadBoneRejectKeyword(string value) { string[] headBoneRejectKeywords = HeadBoneRejectKeywords; foreach (string keyword in headBoneRejectKeywords) { if (ContainsKeywordTokenOrSafePrefix(value, keyword)) { return true; } } return false; } private static bool ContainsKeywordTokenOrSafePrefix(string value, string keyword) { int num = value.IndexOf(keyword, StringComparison.OrdinalIgnoreCase); while (num >= 0) { bool flag = num == 0 || !char.IsLetterOrDigit(value[num - 1]); int num2 = num + keyword.Length; bool flag2 = num2 >= value.Length || !char.IsLetterOrDigit(value[num2]); if (flag && flag2) { return true; } if (flag && keyword.Length >= 5) { return true; } num = value.IndexOf(keyword, num2, StringComparison.OrdinalIgnoreCase); } return false; } private static void HideCachedRenderersShadowsOnly() { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Invalid comparison between Unknown and I4 foreach (Renderer key in OriginalRendererStates.Keys) { if (!((Object)(object)key == (Object)null) && IsCachedLocalRenderer(key)) { if (!key.enabled) { key.enabled = true; } if ((int)key.shadowCastingMode != 3) { key.shadowCastingMode = (ShadowCastingMode)3; } } } } private static void RefreshHeadBoneCache(Player player) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) RemoveDestroyedBones(); _headBoneCacheInitialized = true; Transform[] componentsInChildren = ((Component)player).GetComponentsInChildren<Transform>(true); Transform[] array = componentsInChildren; foreach (Transform val in array) { if (!((Object)(object)val == (Object)null) && IsHeadBone(val) && IsTransformOwnedByPlayer(player, val) && !OriginalBoneScales.ContainsKey(val)) { OriginalBoneScales.Add(val, val.localScale); CachedHeadBones.Add(val); Plugin.DebugLog("Shrinking local head bone for first-person view: " + RendererScanner.GetPath(val)); } } } private static void ApplyCachedHeadBoneScale() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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) RemoveDestroyedBones(); foreach (Transform cachedHeadBone in CachedHeadBones) { if (!((Object)(object)cachedHeadBone == (Object)null) && IsCachedLocalTransform(cachedHeadBone) && cachedHeadBone.localScale != HeadShrinkVector) { cachedHeadBone.localScale = HeadShrinkVector; } } } private static bool IsHeadBone(Transform transform) { string value = (((Object)transform).name + " " + RendererScanner.GetPath(transform)).ToLowerInvariant(); if (ContainsAny(value, EquipmentSkeletonKeywords)) { return false; } if (ContainsAny(value, HeldItemKeywords)) { return false; } if (ContainsAnyHeadBoneRejectKeyword(value)) { return false; } string name = ((Object)transform).name; return IsLikelyCharacterHeadBoneName(name) || ContainsKeywordTokenOrSafePrefix(name, "head"); } private static void CompensateHeadSlotTransforms() { foreach (Renderer key in OriginalRendererStates.Keys) { if (!((Object)(object)key == (Object)null) && IsCachedLocalRenderer(key)) { CompensateTransformIfUnderShrunkHead(((Component)key).transform); SkinnedMeshRenderer val = (SkinnedMeshRenderer)(object)((key is SkinnedMeshRenderer) ? key : null); if (val != null && (Object)(object)val.rootBone != (Object)null) { CompensateTransformIfUnderShrunkHead(val.rootBone); } } } HelmetShadowController.CopyManagedRenderers(ManagedHelmetRenderers); foreach (Renderer managedHelmetRenderer in ManagedHelmetRenderers) { if (!((Object)(object)managedHelmetRenderer == (Object)null)) { CompensateTransformIfUnderShrunkHead(((Component)managedHelmetRenderer).transform); SkinnedMeshRenderer val2 = (SkinnedMeshRenderer)(object)((managedHelmetRenderer is SkinnedMeshRenderer) ? managedHelmetRenderer : null); if (val2 != null && (Object)(object)val2.rootBone != (Object)null) { CompensateTransformIfUnderShrunkHead(val2.rootBone); } } } RemoveDestroyedHeadSlotTransforms(); } private static void CompensateTransformIfUnderShrunkHead(Transform transform) { if (IsCachedLocalTransform(transform)) { Transform val = FindCompensationRootUnderShrunkHead(transform); if (!((Object)(object)val == (Object)null)) { CompensateHeadSlotTransform(val, compensatePosition: true, "position and scale"); } } } private static void CompensateHeadSlotTransform(Transform transform, bool compensatePosition, string mode) { //IL_006f: 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_0067: Unknown result type (might be due to invalid IL or missing references) //IL_007e: 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_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: 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_0096: 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_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) if (IsCachedLocalTransform(transform)) { if (!OriginalHeadSlotStates.ContainsKey(transform)) { OriginalHeadSlotStates.Add(transform, new TransformState(transform)); Plugin.DebugLog("Compensating head-slot transform " + mode + ": " + RendererScanner.GetPath(transform)); } TransformState transformState = OriginalHeadSlotStates[transform]; Vector3 val = (compensatePosition ? (transformState.LocalPosition * 999.99994f) : transformState.LocalPosition); Vector3 val2 = transformState.LocalScale * 999.99994f; if (transform.localPosition != val) { transform.localPosition = val; } if (transform.localScale != val2) { transform.localScale = val2; } } } private static Transform? FindCompensationRootUnderShrunkHead(Transform transform) { if ((Object)(object)transform == (Object)null || !IsCachedLocalTransform(transform) || OriginalBoneScales.ContainsKey(transform)) { return null; } Transform val = transform; while ((Object)(object)val.parent != (Object)null) { if (OriginalBoneScales.ContainsKey(val.parent)) { return val; } val = val.parent; } return null; } private static void RestoreRendererStates() { if (OriginalRendererStates.Count == 0) { return; } foreach (KeyValuePair<Renderer, RendererStateSnapshot> originalRendererState in OriginalRendererStates) { Renderer key = originalRendererState.Key; if (!((Object)(object)key == (Object)null)) { originalRendererState.Value.Restore(key); } } OriginalRendererStates.Clear(); RenderersToRemove.Clear(); _nextRefreshTime = 0f; } private static void RestoreRenderer(Renderer renderer) { if (!((Object)(object)renderer == (Object)null) && OriginalRendererStates.TryGetValue(renderer, out var value)) { value.Restore(renderer); } } private static void RestoreBoneScales() { //IL_0045: Unknown result type (might be due to invalid IL or missing references) if (OriginalBoneScales.Count == 0) { return; } foreach (KeyValuePair<Transform, Vector3> originalBoneScale in OriginalBoneScales) { Transform key = originalBoneScale.Key; if (!((Object)(object)key == (Object)null)) { key.localScale = originalBoneScale.Value; } } OriginalBoneScales.Clear(); CachedHeadBones.Clear(); BonesToRemove.Clear(); } private static void RestoreHeadSlotStates() { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) if (OriginalHeadSlotStates.Count == 0) { return; } foreach (KeyValuePair<Transform, TransformState> originalHeadSlotState in OriginalHeadSlotStates) { Transform key = originalHeadSlotState.Key; if (!((Object)(object)key == (Object)null)) { key.localPosition = originalHeadSlotState.Value.LocalPosition; key.localScale = originalHeadSlotState.Value.LocalScale; } } OriginalHeadSlotStates.Clear(); HeadSlotTransformsToRemove.Clear(); } private static void RemoveDestroyedRenderers() { RenderersToRemove.Clear(); foreach (Renderer key in OriginalRendererStates.Keys) { if ((Object)(object)key == (Object)null) { RenderersToRemove.Add(key); } } foreach (Renderer item in RenderersToRemove) { if (item != null) { OriginalRendererStates.Remove(item); } } RenderersToRemove.Clear(); } private static void RemoveDestroyedBones() { BonesToRemove.Clear(); for (int num = CachedHeadBones.Count - 1; num >= 0; num--) { Transform val = CachedHeadBones[num]; if (!((Object)(object)val != (Object)null)) { CachedHeadBones.RemoveAt(num); if (val != null) { OriginalBoneScales.Remove(val); } } } foreach (Transform key in OriginalBoneScales.Keys) { if ((Object)(object)key == (Object)null) { BonesToRemove.Add(key); } } foreach (Transform item in BonesToRemove) { if (item != null) { OriginalBoneScales.Remove(item); CachedHeadBones.Remove(item); } } BonesToRemove.Clear(); } private static void RemoveDestroyedHeadSlotTransforms() { HeadSlotTransformsToRemove.Clear(); foreach (Transform key in OriginalHeadSlotStates.Keys) { if ((Object)(object)key == (Object)null) { HeadSlotTransformsToRemove.Add(key); } } foreach (Transform item in HeadSlotTransformsToRemove) { if (item != null) { OriginalHeadSlotStates.Remove(item); } } HeadSlotTransformsToRemove.Clear(); } private static bool IsLocalPlayer(Player player) { return (Object)(object)player != (Object)null && (Object)(object)player == (Object)(object)Player.m_localPlayer; } private static bool IsRendererOwnedByPlayer(Player player, Renderer renderer) { return LocalPlayerRendererOwnership.IsLocalPlayerRenderer(player, renderer); } private static bool IsTransformOwnedByPlayer(Player player, Transform transform) { return LocalPlayerRendererOwnership.IsLocalPlayerTransform(player, transform); } private static bool IsCachedLocalRenderer(Renderer renderer) { return (Object)(object)_cachedPlayer != (Object)null && IsRendererOwnedByPlayer(_cachedPlayer, renderer); } private static bool IsCachedLocalTransform(Transform transform) { return (Object)(object)_cachedPlayer != (Object)null && IsTransformOwnedByPlayer(_cachedPlayer, transform); } private static void ResetCache() { _cachedPlayer = null; _active = false; _headBoneCacheInitialized = false; _nextRefreshTime = 0f; OriginalRendererStates.Clear(); OriginalBoneScales.Clear(); OriginalHeadSlotStates.Clear(); DesiredRenderers.Clear(); CachedHeadBones.Clear(); ManagedHelmetRenderers.Clear(); RenderersToRemove.Clear(); BonesToRemove.Clear(); HeadSlotTransformsToRemove.Clear(); _lastFallbackReason = null; } } internal static class HelmetShadowController { private const float MaxHelmetRendererExtent = 1.35f; private const float MinHelmetRendererHeight = 0.85f; private const float MaxHelmetRendererHeight = 2.45f; private const float MaxHelmetHorizontalDistance = 0.9f; private static readonly FieldInfo? HelmetItemInstanceField = AccessTools.Field(typeof(VisEquipment), "m_helmetItemInstance"); private static readonly Dictionary<Renderer, RendererStateSnapshot> OriginalRendererStates = new Dictionary<Renderer, RendererStateSnapshot>(); private static readonly Dictionary<VisEquipment, HashSet<Renderer>> HelmetChangeSnapshots = new Dictionary<VisEquipment, HashSet<Renderer>>(); private static readonly HashSet<Renderer> DesiredRenderers = new HashSet<Renderer>(); private static readonly HashSet<Renderer> ObservedHelmetRenderers = new HashSet<Renderer>(); private static readonly HashSet<Renderer> WarnedUnsafeRenderers = new HashSet<Renderer>(); private static readonly HashSet<string> HelmetPrefabFingerprints = new HashSet<string>(); private static readonly List<Renderer?> RenderersToRemove = new List<Renderer>(); private static readonly List<VisEquipment?> SnapshotsToRemove = new List<VisEquipment>(); private static Player? _cachedPlayer; private static bool _active; private static bool _dirty = true; private static float _nextRefreshTime; private static readonly string[] FullBodyKeywords = new string[14] { "body", "torso", "chest", "arm", "leg", "foot", "feet", "hand", "player", "character", "human", "male", "female", "skin" }; private static readonly string[] HeadSlotKeywords = new string[10] { "head", "helmet", "helm", "hat", "hood", "hair", "beard", "circlet", "crown", "headgear" }; internal static void RequestRefresh() { _dirty = true; _nextRefreshTime = 0f; } internal static void Update(Player player, bool shouldHide) { if (!shouldHide || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer) { Restore(); return; } if ((Object)(object)_cachedPlayer != (Object)null && (Object)(object)_cachedPlayer != (Object)(object)player) { Restore(); } _cachedPlayer = player; if (!_active) { OriginalRendererStates.Clear(); DesiredRenderers.Clear(); _active = true; _dirty = true; _nextRefreshTime = 0f; } if (_dirty || Time.unscaledTime >= _nextRefreshTime) { RefreshRendererCache(player); _dirty = false; _nextRefreshTime = Time.unscaledTime + Mathf.Clamp(Plugin.VisibilityRefreshInterval.Value, 0.1f, 10f); } ApplyShadowsOnly(); } internal static void Restore() { RestoreRendererStates(); DesiredRenderers.Clear(); ObservedHelmetRenderers.Clear(); HelmetChangeSnapshots.Clear(); WarnedUnsafeRenderers.Clear(); HelmetPrefabFingerprints.Clear(); RenderersToRemove.Clear(); SnapshotsToRemove.Clear(); _cachedPlayer = null; _active = false; _dirty = true; _nextRefreshTime = 0f; } internal static bool IsManagedRenderer(Renderer renderer) { return (Object)(object)renderer != (Object)null && (DesiredRenderers.Contains(renderer) || OriginalRendererStates.ContainsKey(renderer)); } internal static void CopyManagedRenderers(List<Renderer> target) { target.Clear(); RemoveDestroyedRenderers(); foreach (Renderer desiredRenderer in DesiredRenderers) { if ((Object)(object)desiredRenderer != (Object)null) { target.Add(desiredRenderer); } } } internal static void CaptureHelmetChangeStart(VisEquipment visEquipment) { if (ShouldObserveHelmetChange(visEquipment)) { HashSet<Renderer> value = new HashSet<Renderer>(((Component)visEquipment).GetComponentsInChildren<Renderer>(true)); HelmetChangeSnapshots[visEquipment] = value; } } internal static void CaptureHelmetChangeEnd(VisEquipment visEquipment, bool changed) { if ((Object)(object)visEquipment == (Object)null || !HelmetChangeSnapshots.TryGetValue(visEquipment, out HashSet<Renderer> value)) { return; } HelmetChangeSnapshots.Remove(visEquipment); if (!changed || !PlayerEquipmentAccess.IsLocalPlayerVisEquipment(visEquipment)) { RequestRefresh(); return; } Renderer[] componentsInChildren = ((Component)visEquipment).GetComponentsInChildren<Renderer>(true); Renderer[] array = componentsInChildren; foreach (Renderer val in array) { if (!((Object)(object)val == (Object)null) && !v