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 FirstPersonView ModelReplacementCompat v1.1.0
FirstPersonViewModelReplacementCompat.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using FirstPersonView; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using ModelReplacement; using ModelReplacement.Monobehaviors; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("FirstPersonView")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("v0id")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Compatibility patch between FirstPersonView and ModelReplacementAPI")] [assembly: AssemblyFileVersion("1.1.0.0")] [assembly: AssemblyInformationalVersion("1.1.0")] [assembly: AssemblyProduct("FirstPersonViewModelReplacementCompat")] [assembly: AssemblyTitle("FirstPersonViewModelReplacementCompat")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.0.0")] [module: UnverifiableCode] [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 FirstPersonViewModelReplacementCompat { public enum HeadPositionMode { Disabled, Auto, IndividualSuits } public static class ModConfig { private static readonly Dictionary<string, float> ParsedSuitOffsets = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase); public static ConfigEntry<HeadPositionMode> HeadPositionAdjustmentMode { get; private set; } = null; public static ConfigEntry<float> ManualHeadOffset { get; private set; } = null; public static ConfigEntry<string> SuitHeadOffsets { get; private set; } = null; public static void Init(ConfigFile config) { HeadPositionAdjustmentMode = config.Bind<HeadPositionMode>("HeadPosition", "AdjustmentMode", HeadPositionMode.Auto, "Determines how the first-person camera head position is adjusted for custom models. Options: Disabled, Auto, IndividualSuits."); ManualHeadOffset = config.Bind<float>("HeadPosition", "ManualHeadOffset", 0f, "Manual vertical offset in meters added to camera height. Applies in Auto mode or as a default fallback."); SuitHeadOffsets = config.Bind<string>("HeadPosition", "SuitHeadOffsets", "Ashley: 0.10, Default: 0.0", "Custom per-suit vertical head offsets in meters used when AdjustmentMode is set to IndividualSuits. Format: SuitName: Offset, SuitName2: Offset"); SuitHeadOffsets.SettingChanged += delegate { ParseOffsets(); }; ParseOffsets(); } private static void ParseOffsets() { ParsedSuitOffsets.Clear(); if (string.IsNullOrWhiteSpace(SuitHeadOffsets.Value)) { return; } string[] array = SuitHeadOffsets.Value.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text in array) { int num = text.IndexOf(':'); if (num > 0 && num < text.Length - 1) { string key = text.Substring(0, num).Trim(); if (float.TryParse(text.Substring(num + 1).Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { ParsedSuitOffsets[key] = result; } } } } public static float GetSuitOffset(string suitName) { if (string.IsNullOrEmpty(suitName)) { return ManualHeadOffset.Value; } if (ParsedSuitOffsets.TryGetValue(suitName, out var value)) { return value; } foreach (KeyValuePair<string, float> parsedSuitOffset in ParsedSuitOffsets) { if (suitName.IndexOf(parsedSuitOffset.Key, StringComparison.OrdinalIgnoreCase) >= 0 || parsedSuitOffset.Key.IndexOf(suitName, StringComparison.OrdinalIgnoreCase) >= 0) { return parsedSuitOffset.Value; } } return ManualHeadOffset.Value; } } public static class ModelReplacementCompat { private sealed class TrackedMesh { public SkinnedMeshRenderer Renderer; public Mesh OriginalMesh; public Mesh? HeadlessMesh; public Mesh? HeadlessArmlessMesh; public bool OriginalUpdateWhenOffscreen; } private sealed class TrackedHeadRenderer { public Renderer Renderer; public bool OriginalEnabled; } private static bool _initialized; private static bool _renderCallbacksHooked; private static readonly List<TrackedMesh> TrackedMeshes = new List<TrackedMesh>(); private static readonly List<TrackedHeadRenderer> TrackedHeadRenderers = new List<TrackedHeadRenderer>(); private static int _trackedModelInstanceId; private static Camera? _firstPersonCamera; private static bool _useVanillaArms; private static bool _isFirstPersonActive; private static float _smoothedHeadOffset; private static bool _hasCalculatedInitialHeadOffset; public static bool IsModelReplacementActive { get; private set; } public static void Initialize() { if (!_initialized) { _initialized = true; EnsureRenderCallbacks(); } } public static void Dispose() { Reset(); if (_renderCallbacksHooked) { RenderPipelineManager.beginCameraRendering -= OnBeginCameraRendering; RenderPipelineManager.endCameraRendering -= OnEndCameraRendering; _renderCallbacksHooked = false; } _initialized = false; } public static void Reset() { RestoreAll(); TrackedMeshes.Clear(); TrackedHeadRenderers.Clear(); _trackedModelInstanceId = 0; _firstPersonCamera = null; _useVanillaArms = false; _isFirstPersonActive = false; _smoothedHeadOffset = 0f; _hasCalculatedInitialHeadOffset = false; IsModelReplacementActive = false; } private static void EnsureRenderCallbacks() { if (!_renderCallbacksHooked) { _renderCallbacksHooked = true; RenderPipelineManager.beginCameraRendering += OnBeginCameraRendering; RenderPipelineManager.endCameraRendering += OnEndCameraRendering; } } public static bool CheckLocalPlayerReplacement(PlayerControllerB player, out BodyReplacementBase? replacement) { replacement = null; if ((Object)(object)player == (Object)null || !Players.IsLocal(player)) { return false; } replacement = ((Component)player).GetComponent<BodyReplacementBase>(); if ((Object)(object)replacement != (Object)null && replacement.IsActive) { return (Object)(object)replacement.replacementModel != (Object)null; } return false; } public static float GetHeadPositionOffset(PlayerControllerB player, BodyReplacementBase replacement) { //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) switch (ModConfig.HeadPositionAdjustmentMode.Value) { case HeadPositionMode.Disabled: return 0f; case HeadPositionMode.IndividualSuits: { string text = replacement.suitName; if (string.IsNullOrEmpty(text) && StartOfRound.Instance?.unlockablesList?.unlockables != null) { int currentSuitID = player.currentSuitID; if (currentSuitID >= 0 && currentSuitID < StartOfRound.Instance.unlockablesList.unlockables.Count) { text = StartOfRound.Instance.unlockablesList.unlockables[currentSuitID].unlockableName; } } if (string.IsNullOrEmpty(text) && (Object)(object)replacement.replacementModel != (Object)null) { text = ((Object)replacement.replacementModel).name; } return ModConfig.GetSuitOffset(text); } default: { GameObject replacementModel = replacement.replacementModel; if ((Object)(object)replacementModel == (Object)null) { return ModConfig.ManualHeadOffset.Value; } Transform val = ResolveHeadBone(replacementModel.GetComponentInChildren<Animator>(), replacement, replacementModel); if ((Object)(object)val == (Object)null) { return ModConfig.ManualHeadOffset.Value; } Transform val2 = ResolveVanillaHeadBone(player); Vector3 up = ((Component)player).transform.up; float num = Vector3.Dot(val.position - ((Component)player).transform.position, up); float num2 = (((Object)(object)val2 != (Object)null) ? Vector3.Dot(val2.position - ((Component)player).transform.position, up) : 1.45f); float num3 = Mathf.Clamp(num - num2, -1.2f, 1.2f) + ModConfig.ManualHeadOffset.Value; if (!_hasCalculatedInitialHeadOffset) { _smoothedHeadOffset = num3; _hasCalculatedInitialHeadOffset = true; } else { _smoothedHeadOffset = Mathf.Lerp(_smoothedHeadOffset, num3, Time.deltaTime * 12f); } return _smoothedHeadOffset; } } } public static void OnLateUpdate(PlayerControllerB player) { if (!CheckLocalPlayerReplacement(player, out BodyReplacementBase replacement) || (Object)(object)replacement == (Object)null) { if (IsModelReplacementActive) { Reset(); } return; } IsModelReplacementActive = true; _firstPersonCamera = player.gameplayCamera; if ((_isFirstPersonActive = LocalBodyViewController.LocalBodyShown) && (Object)(object)_firstPersonCamera != (Object)null) { int num = (1 << ViewStateManager.modelLayer) | (1 << ViewStateManager.NoPostModelLayer); if ((_firstPersonCamera.cullingMask & num) != num) { Camera? firstPersonCamera = _firstPersonCamera; firstPersonCamera.cullingMask |= num; } } if ((Object)(object)replacement.replacementViewModel == (Object)null) { _useVanillaArms = false; if ((Object)(object)player.thisPlayerModelArms != (Object)null && ((Renderer)player.thisPlayerModelArms).enabled) { ((Renderer)player.thisPlayerModelArms).enabled = false; } } else { _useVanillaArms = ResolveUseVanillaArms(player); SyncArmsVisibility(player, replacement, _useVanillaArms); } GameObject replacementModel = replacement.replacementModel; if (((Object)replacementModel).GetInstanceID() != _trackedModelInstanceId) { _hasCalculatedInitialHeadOffset = false; RebuildModelTracking(replacement, replacementModel); } } private static bool ResolveUseVanillaArms(PlayerControllerB player) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Invalid comparison between Unknown and I4 if (!LocalBodyViewController.LocalBodyShown) { return true; } if ((int)ConfigManager.Hands.Value == 1) { return false; } bool flag = Players.IsActivelyHolding(player); return !player.inSpecialInteractAnimation && flag; } private static void SyncArmsVisibility(PlayerControllerB player, BodyReplacementBase replacement, bool useVanillaArms) { GameObject replacementViewModel = replacement.replacementViewModel; if ((Object)(object)replacementViewModel != (Object)null) { if ((Object)(object)player.thisPlayerModelArms != (Object)null && ((Renderer)player.thisPlayerModelArms).enabled) { ((Renderer)player.thisPlayerModelArms).enabled = false; } Renderer[] componentsInChildren = replacementViewModel.GetComponentsInChildren<Renderer>(true); for (int i = 0; i < componentsInChildren.Length; i++) { if ((Object)(object)componentsInChildren[i] != (Object)null && componentsInChildren[i].enabled != useVanillaArms) { componentsInChildren[i].enabled = useVanillaArms; } } } else if ((Object)(object)player.thisPlayerModelArms != (Object)null && ((Renderer)player.thisPlayerModelArms).enabled) { ((Renderer)player.thisPlayerModelArms).enabled = false; } } private static void RebuildModelTracking(BodyReplacementBase replacement, GameObject model) { RestoreAll(); TrackedMeshes.Clear(); TrackedHeadRenderers.Clear(); _trackedModelInstanceId = ((Object)model).GetInstanceID(); Animator componentInChildren = model.GetComponentInChildren<Animator>(); Transform val = ResolveHeadBone(componentInChildren, replacement, model); Transform val2 = ResolveBone(componentInChildren, replacement, (HumanBodyBones)13, "arm.L_upper"); Transform val3 = ResolveBone(componentInChildren, replacement, (HumanBodyBones)14, "arm.R_upper"); if ((Object)(object)val == (Object)null) { Plugin.Log.LogWarning((object)"Could not find head bone on replacement model; head mesh surgery cannot be performed."); return; } SkinnedMeshRenderer[] componentsInChildren = model.GetComponentsInChildren<SkinnedMeshRenderer>(true); foreach (SkinnedMeshRenderer val4 in componentsInChildren) { if ((Object)(object)val4 == (Object)null || (Object)(object)val4.sharedMesh == (Object)null) { continue; } Mesh sharedMesh = val4.sharedMesh; if (MeshSurgery.IsGenerated(((Object)sharedMesh).GetInstanceID())) { continue; } Mesh orCreateHeadlessMesh = MeshSurgery.GetOrCreateHeadlessMesh(sharedMesh, val4, val); if ((Object)(object)orCreateHeadlessMesh != (Object)null && RemovesGeometry(sharedMesh, orCreateHeadlessMesh)) { Mesh val5 = MeshSurgery.GetOrCreateHeadlessArmlessMesh(sharedMesh, val4, val, val2, val3); if ((Object)(object)val5 == (Object)null) { val5 = BuildFallbackHeadlessArmlessMesh(sharedMesh, val4, val, val2, val3); } TrackedMeshes.Add(new TrackedMesh { Renderer = val4, OriginalMesh = sharedMesh, HeadlessMesh = orCreateHeadlessMesh, HeadlessArmlessMesh = val5, OriginalUpdateWhenOffscreen = val4.updateWhenOffscreen }); val4.updateWhenOffscreen = true; } } Renderer[] componentsInChildren2 = model.GetComponentsInChildren<Renderer>(true); foreach (Renderer val6 in componentsInChildren2) { if (!((Object)(object)val6 == (Object)null) && !(val6 is SkinnedMeshRenderer) && ((Object)(object)((Component)val6).transform == (Object)(object)val || ((Component)val6).transform.IsChildOf(val))) { TrackedHeadRenderers.Add(new TrackedHeadRenderer { Renderer = val6, OriginalEnabled = val6.enabled }); } } Plugin.Log.LogInfo((object)$"[FPV-MRCompat] Tracked {TrackedMeshes.Count} skinned mesh(es) and {TrackedHeadRenderers.Count} head accessory renderer(s) for '{((Object)model).name}'."); } private static Mesh? BuildFallbackHeadlessArmlessMesh(Mesh sourceMesh, SkinnedMeshRenderer smr, Transform headBone, Transform? leftArm, Transform? rightArm) { //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) try { if (smr.bones == null || sourceMesh.boneWeights == null || sourceMesh.boneWeights.Length == 0) { return null; } HashSet<int> boneAndChildrenIndices = GetBoneAndChildrenIndices(smr.bones, headBone); HashSet<int> hashSet = new HashSet<int>(); if ((Object)(object)leftArm != (Object)null) { hashSet.UnionWith(GetBoneAndChildrenIndices(smr.bones, leftArm)); } if ((Object)(object)rightArm != (Object)null) { hashSet.UnionWith(GetBoneAndChildrenIndices(smr.bones, rightArm)); } if (hashSet.Count == 0) { return null; } BoneWeight[] boneWeights = sourceMesh.boneWeights; Vector3[] array = (Vector3[])sourceMesh.vertices.Clone(); bool[] array2 = new bool[array.Length]; for (int i = 0; i < array.Length; i++) { BoneWeight val = boneWeights[i]; if (hashSet.Contains(((BoneWeight)(ref val)).boneIndex0) || hashSet.Contains(((BoneWeight)(ref val)).boneIndex1) || boneAndChildrenIndices.Contains(((BoneWeight)(ref val)).boneIndex0) || boneAndChildrenIndices.Contains(((BoneWeight)(ref val)).boneIndex1)) { array2[i] = true; array[i] = Vector3.zero; } } Mesh val2 = Object.Instantiate<Mesh>(sourceMesh); ((Object)val2).name = ((Object)sourceMesh).name + "_FPVHeadlessArmlessFallback"; val2.vertices = array; for (int j = 0; j < val2.subMeshCount; j++) { int[] triangles = sourceMesh.GetTriangles(j); List<int> list = new List<int>(triangles.Length); for (int k = 0; k < triangles.Length; k += 3) { int num = triangles[k]; int num2 = triangles[k + 1]; int num3 = triangles[k + 2]; if (!array2[num] && !array2[num2] && !array2[num3]) { list.Add(num); list.Add(num2); list.Add(num3); } } val2.SetTriangles(list, j); } val2.RecalculateBounds(); return val2; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not build fallback headless armless mesh: " + ex.Message)); return null; } } private static HashSet<int> GetBoneAndChildrenIndices(Transform[] bones, Transform root) { HashSet<int> hashSet = new HashSet<int>(); for (int i = 0; i < bones.Length; i++) { Transform val = bones[i]; if ((Object)(object)val != (Object)null && ((Object)(object)val == (Object)(object)root || val.IsChildOf(root))) { hashSet.Add(i); } } return hashSet; } private static Transform? ResolveVanillaHeadBone(PlayerControllerB player) { if ((Object)(object)player.thisPlayerModel != (Object)null && player.thisPlayerModel.bones != null) { Transform[] bones = player.thisPlayerModel.bones; foreach (Transform val in bones) { if ((Object)(object)val != (Object)null && ((Object)val).name.IndexOf("spine.004", StringComparison.OrdinalIgnoreCase) >= 0) { return val; } } } return null; } private static Transform? ResolveHeadBone(Animator? animator, BodyReplacementBase replacement, GameObject model) { Transform val = null; if ((Object)(object)animator != (Object)null && animator.isHuman) { val = animator.GetBoneTransform((HumanBodyBones)10); } if ((Object)(object)val == (Object)null && replacement.avatar != null) { val = replacement.avatar.GetAvatarTransformFromBoneName("spine.004"); } if ((Object)(object)val == (Object)null) { val = FindFirstByNameContains(model.transform, "head"); } return val; } private static Transform? ResolveBone(Animator? animator, BodyReplacementBase replacement, HumanBodyBones humanBone, string mrapiName) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) Transform val = null; if ((Object)(object)animator != (Object)null && animator.isHuman) { val = animator.GetBoneTransform(humanBone); } if ((Object)(object)val == (Object)null && replacement.avatar != null) { val = replacement.avatar.GetAvatarTransformFromBoneName(mrapiName); } return val; } private static Transform? FindFirstByNameContains(Transform root, string token) { Queue<Transform> queue = new Queue<Transform>(); queue.Enqueue(root); while (queue.Count > 0) { Transform val = queue.Dequeue(); if (((Object)val).name.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0) { return val; } for (int i = 0; i < val.childCount; i++) { queue.Enqueue(val.GetChild(i)); } } return null; } private static bool RemovesGeometry(Mesh source, Mesh headless) { if (headless.subMeshCount != source.subMeshCount) { return true; } for (int i = 0; i < source.subMeshCount; i++) { if (headless.GetIndexCount(i) != source.GetIndexCount(i)) { return true; } } return false; } private static void OnBeginCameraRendering(ScriptableRenderContext context, Camera camera) { if (!IsModelReplacementActive || (TrackedMeshes.Count == 0 && TrackedHeadRenderers.Count == 0)) { return; } bool flag = (Object)(object)camera == (Object)(object)_firstPersonCamera && _isFirstPersonActive; for (int i = 0; i < TrackedMeshes.Count; i++) { TrackedMesh trackedMesh = TrackedMeshes[i]; if ((Object)(object)trackedMesh.Renderer == (Object)null) { continue; } if (flag) { Mesh val = ((_useVanillaArms && (Object)(object)trackedMesh.HeadlessArmlessMesh != (Object)null) ? trackedMesh.HeadlessArmlessMesh : trackedMesh.HeadlessMesh); if ((Object)(object)val != (Object)null && (Object)(object)trackedMesh.Renderer.sharedMesh != (Object)(object)val) { trackedMesh.Renderer.sharedMesh = val; } } else if ((Object)(object)trackedMesh.OriginalMesh != (Object)null && (Object)(object)trackedMesh.Renderer.sharedMesh != (Object)(object)trackedMesh.OriginalMesh) { trackedMesh.Renderer.sharedMesh = trackedMesh.OriginalMesh; } } for (int j = 0; j < TrackedHeadRenderers.Count; j++) { TrackedHeadRenderer trackedHeadRenderer = TrackedHeadRenderers[j]; if (!((Object)(object)trackedHeadRenderer.Renderer == (Object)null)) { trackedHeadRenderer.Renderer.enabled = !flag && trackedHeadRenderer.OriginalEnabled; } } } private static void OnEndCameraRendering(ScriptableRenderContext context, Camera camera) { if (!IsModelReplacementActive || (Object)(object)camera != (Object)(object)_firstPersonCamera) { return; } for (int i = 0; i < TrackedMeshes.Count; i++) { TrackedMesh trackedMesh = TrackedMeshes[i]; if ((Object)(object)trackedMesh.Renderer != (Object)null && (Object)(object)trackedMesh.OriginalMesh != (Object)null && (Object)(object)trackedMesh.Renderer.sharedMesh != (Object)(object)trackedMesh.OriginalMesh) { trackedMesh.Renderer.sharedMesh = trackedMesh.OriginalMesh; } } for (int j = 0; j < TrackedHeadRenderers.Count; j++) { TrackedHeadRenderer trackedHeadRenderer = TrackedHeadRenderers[j]; if ((Object)(object)trackedHeadRenderer.Renderer != (Object)null) { trackedHeadRenderer.Renderer.enabled = trackedHeadRenderer.OriginalEnabled; } } } private static void RestoreAll() { for (int i = 0; i < TrackedMeshes.Count; i++) { TrackedMesh trackedMesh = TrackedMeshes[i]; if ((Object)(object)trackedMesh.Renderer != (Object)null) { if ((Object)(object)trackedMesh.OriginalMesh != (Object)null && (Object)(object)trackedMesh.Renderer.sharedMesh != (Object)(object)trackedMesh.OriginalMesh) { trackedMesh.Renderer.sharedMesh = trackedMesh.OriginalMesh; } trackedMesh.Renderer.updateWhenOffscreen = trackedMesh.OriginalUpdateWhenOffscreen; } } for (int j = 0; j < TrackedHeadRenderers.Count; j++) { TrackedHeadRenderer trackedHeadRenderer = TrackedHeadRenderers[j]; if ((Object)(object)trackedHeadRenderer.Renderer != (Object)null) { trackedHeadRenderer.Renderer.enabled = trackedHeadRenderer.OriginalEnabled; } } } } public static class PluginInfo { public const string GUID = "com.v0id.firstpersonview.modelreplacementcompat"; public const string NAME = "LC FirstPersonView ModelReplacement Compat"; public const string VERSION = "1.1.0"; } [BepInPlugin("com.v0id.firstpersonview.modelreplacementcompat", "LC FirstPersonView ModelReplacement Compat", "1.1.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { private readonly Harmony _harmony = new Harmony("com.v0id.firstpersonview.modelreplacementcompat"); public static Plugin Instance { get; private set; } public static ManualLogSource Log { get; private set; } private void Awake() { Instance = this; Log = ((BaseUnityPlugin)this).Logger; Log.LogInfo((object)"Initializing LC FirstPersonView ModelReplacement Compat v1.1.0"); ModConfig.Init(((BaseUnityPlugin)this).Config); ModelReplacementCompat.Initialize(); _harmony.PatchAll(); Log.LogInfo((object)"LC FirstPersonView ModelReplacement Compat loaded successfully."); } private void OnDestroy() { ModelReplacementCompat.Dispose(); _harmony.UnpatchSelf(); } } } namespace FirstPersonViewModelReplacementCompat.Patches { [HarmonyPatch(typeof(CameraRig))] internal static class CameraRigPatches { [HarmonyPatch("ApplyOffset")] [HarmonyPostfix] private static void ApplyOffset_Postfix(LocalBodyState state, PlayerControllerB player) { //IL_0065: 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_006a: 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_0073: 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_007d: 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_0095: 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_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) if (state != null && !((Object)(object)state.GameplayCamera == (Object)null) && state.CameraOffsetApplied && ModelReplacementCompat.CheckLocalPlayerReplacement(player, out BodyReplacementBase replacement) && (Object)(object)replacement != (Object)null) { float headPositionOffset = ModelReplacementCompat.GetHeadPositionOffset(player, replacement); if (Mathf.Abs(headPositionOffset) > 0.0001f) { Transform transform = ((Component)state.GameplayCamera).transform; Transform parent = transform.parent; Vector3 val = (((Object)(object)parent != (Object)null) ? parent.up : Vector3.up); Vector3 val2 = (transform.position += val * headPositionOffset); state.LastCameraTargetLocal = (((Object)(object)parent != (Object)null) ? parent.InverseTransformPoint(val2) : val2); } } } } [HarmonyPatch] internal static class FirstPersonBodyPatches { [HarmonyPatch(typeof(FirstPersonBody), "WarnIfBodyRendererDisabled")] [HarmonyPrefix] private static bool WarnIfBodyRendererDisabled_Prefix(SkinnedMeshRenderer body) { PlayerControllerB val = StartOfRound.Instance?.localPlayerController; if ((Object)(object)val != (Object)null && ModelReplacementCompat.CheckLocalPlayerReplacement(val, out BodyReplacementBase _)) { return false; } return true; } [HarmonyPatch(typeof(FirstPersonBody), "SetFpArmsEnabled")] [HarmonyPrefix] private static void SetFpArmsEnabled_Prefix(PlayerControllerB player, ref bool enabled) { if ((Object)(object)player != (Object)null && ModelReplacementCompat.CheckLocalPlayerReplacement(player, out BodyReplacementBase replacement) && ((Object)(object)replacement == (Object)null || (Object)(object)replacement.replacementViewModel == (Object)null)) { enabled = false; } } [HarmonyPatch(typeof(HeldItemView), "ApplyHolder")] [HarmonyPrefix] private static void HeldItemView_ApplyHolder_Prefix(LocalBodyState state, PlayerControllerB player, bool showBody, ref bool useVanillaArms) { if ((Object)(object)player != (Object)null && ModelReplacementCompat.CheckLocalPlayerReplacement(player, out BodyReplacementBase replacement) && ((Object)(object)replacement == (Object)null || (Object)(object)replacement.replacementViewModel == (Object)null)) { useVanillaArms = false; } } [HarmonyPatch(typeof(CameraRig), "ApplyArmAnchor")] [HarmonyPrefix] private static bool CameraRig_ApplyArmAnchor_Prefix(PlayerControllerB player, ref bool useVanillaArms) { if ((Object)(object)player != (Object)null && ModelReplacementCompat.CheckLocalPlayerReplacement(player, out BodyReplacementBase replacement) && ((Object)(object)replacement == (Object)null || (Object)(object)replacement.replacementViewModel == (Object)null)) { useVanillaArms = false; return false; } return true; } [HarmonyPatch(typeof(PlayerControllerB), "LateUpdate")] [HarmonyPostfix] [HarmonyPriority(0)] private static void PlayerControllerB_LateUpdate_Postfix(PlayerControllerB __instance) { if (Players.IsLocal(__instance)) { ModelReplacementCompat.OnLateUpdate(__instance); } } } [HarmonyPatch(typeof(ViewStateManager))] internal static class ViewStateManagerPatches { [HarmonyPatch("UpdateModelReplacement")] [HarmonyPostfix] private static void UpdateModelReplacement_Postfix(ViewStateManager __instance) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Invalid comparison between Unknown and I4 object? obj = AccessTools.Field(typeof(ManagerBase), "controller")?.GetValue(__instance); PlayerControllerB val = (PlayerControllerB)((obj is PlayerControllerB) ? obj : null); if (!((Object)(object)val == (Object)null) && Players.IsLocal(val) && (int)__instance.GetViewState() == 2 && LocalBodyViewController.LocalBodyShown) { int num = (1 << ViewStateManager.modelLayer) | (1 << ViewStateManager.NoPostModelLayer); if ((Object)(object)val.gameplayCamera != (Object)null && (val.gameplayCamera.cullingMask & num) != num) { Camera gameplayCamera = val.gameplayCamera; gameplayCamera.cullingMask |= num; } } } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }