using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Peak; using Peak.Afflictions; using Peak.Network; using PeakSafeOptimizer.Config; using PeakSafeOptimizer.Diagnostics; using PeakSafeOptimizer.Graphics; using PeakSafeOptimizer.Infrastructure; using PeakSafeOptimizer.Patches.Scale; using Photon.Pun; using UnityEngine; using UnityEngine.Animations.Rigging; using UnityEngine.Playables; using UnityEngine.SceneManagement; using Zorro.Core; using Zorro.Core.Serizalization; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("PeakSafeOptimizer")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+2651244b36adcdccf970b931a35bed725d4c6566")] [assembly: AssemblyProduct("PeakSafeOptimizer")] [assembly: AssemblyTitle("PeakSafeOptimizer")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace PeakSafeOptimizer { internal sealed class CollisionCallbackReuse { private readonly ManualLogSource _log; private bool _applied; private bool _originalValue; private bool _hasOriginalValue; private bool _loggedBlocked; internal CollisionCallbackReuse(ManualLogSource log) { _log = log; } internal void Evaluate(PatchInstaller installer) { ConfigEntry collisionCallbackReuse = OptimizerConfig.CollisionCallbackReuse; bool flag = collisionCallbackReuse != null && collisionCallbackReuse.Value && installer != null && installer.IsInstalled(PatchId.SnowballContactSnapshot) && installer.IsInstalled(PatchId.SnowballContactConsume); if (flag == _applied) { if (!flag && !_loggedBlocked) { ConfigEntry collisionCallbackReuse2 = OptimizerConfig.CollisionCallbackReuse; if (collisionCallbackReuse2 != null && collisionCallbackReuse2.Value) { LogBlocked(installer); } } return; } _loggedBlocked = false; try { if (flag) { if (!_hasOriginalValue) { _originalValue = Physics.reuseCollisionCallbacks; _hasOriginalValue = true; } Physics.reuseCollisionCallbacks = true; _applied = true; ManualLogSource log = _log; if (log != null) { log.LogInfo((object)("PeakSafeOptimizer | Physics.reuseCollisionCallbacks = true " + $"(was {_originalValue}); the Snowball cross-frame collision reference is guarded.")); } } else { Restore("guard unavailable"); } } catch (Exception ex) { ManualLogSource log2 = _log; if (log2 != null) { log2.LogError((object)("Collision callback reuse toggle failed safely: " + ex.GetType().Name + ": " + ex.Message)); } } } internal void Shutdown() { if (_applied) { Restore("shutdown"); } } private void Restore(string reason) { _applied = false; if (!_hasOriginalValue) { return; } try { Physics.reuseCollisionCallbacks = _originalValue; ManualLogSource log = _log; if (log != null) { log.LogInfo((object)$"PeakSafeOptimizer | Physics.reuseCollisionCallbacks restored to {_originalValue} ({reason})."); } } catch (Exception ex) { ManualLogSource log2 = _log; if (log2 != null) { log2.LogError((object)("Collision callback reuse restore failed safely: " + ex.GetType().Name + ": " + ex.Message)); } } } private void LogBlocked(PatchInstaller installer) { _loggedBlocked = true; bool flag = installer?.IsInstalled(PatchId.SnowballContactSnapshot) ?? false; bool flag2 = installer?.IsInstalled(PatchId.SnowballContactConsume) ?? false; ManualLogSource log = _log; if (log != null) { log.LogWarning((object)("PeakSafeOptimizer | CollisionCallbackReuse stays off: it needs both Snowball guards " + $"(SnowballContactSnapshot installed={flag}, SnowballContactConsume installed={flag2}).")); } } } [BepInPlugin("com.peak.safeoptimizer", "PeakSafeOptimizer", "1.0.0")] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "com.peak.safeoptimizer"; public const string PluginName = "PeakSafeOptimizer"; public const string PluginVersion = "1.0.0"; private Harmony _harmony; private LifecycleRegistry _lifecycle; private OptimizerConfig _settings; private PatchInstaller _installer; private BoneWeightCap _boneWeightCap; private CollisionCallbackReuse _collisionReuse; private int _mainThreadId; private readonly ConcurrentQueue _pendingSettingChanges = new ConcurrentQueue(); private void Awake() { //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown try { _mainThreadId = Thread.CurrentThread.ManagedThreadId; _settings = OptimizerConfig.Bind(((BaseUnityPlugin)this).Config); RateLimitedDiagnostics.Initialize(((BaseUnityPlugin)this).Logger, _settings.DetailedDiagnostics); _lifecycle = new LifecycleRegistry(((BaseUnityPlugin)this).Logger); _lifecycle.Register(RateLimitedDiagnostics.Reset); BuildFingerprint buildFingerprint = BuildFingerprint.Capture(); ((BaseUnityPlugin)this).Logger.LogInfo((object)buildFingerprint.ToDiagnosticString()); _harmony = new Harmony("com.peak.safeoptimizer"); _installer = new PatchInstaller(_harmony, buildFingerprint, ((BaseUnityPlugin)this).Logger); PatchCatalogSnapshot catalog = PatchCatalog.Discover(typeof(Plugin).Assembly, _settings, _lifecycle, ((BaseUnityPlugin)this).Logger); foreach (string item in _installer.Install(catalog).FormatReport()) { ((BaseUnityPlugin)this).Logger.LogInfo((object)item); } _boneWeightCap = new BoneWeightCap(((BaseUnityPlugin)this).Logger); _collisionReuse = new CollisionCallbackReuse(((BaseUnityPlugin)this).Logger); _collisionReuse.Evaluate(_installer); ((BaseUnityPlugin)this).Config.SettingChanged += OnSettingChanged; } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Plugin startup failed safely; no failure will escape Awake. {arg}"); RollbackAfterFailedStartup(); } } private void RollbackAfterFailedStartup() { try { ((BaseUnityPlugin)this).Config.SettingChanged -= OnSettingChanged; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Startup rollback: unsubscribe SettingChanged failed safely: " + ex.GetType().Name + ": " + ex.Message)); } if (UninstallAll("Startup rollback")) { ShutdownGlobalLanes(); DisposeLifecycle("Startup rollback"); _lifecycle = null; _harmony = null; _installer = null; _settings = null; ((BaseUnityPlugin)this).Logger.LogWarning((object)"PeakSafeOptimizer | startup rolled back: all known patches were removed."); } else { ((BaseUnityPlugin)this).Logger.LogError((object)"PeakSafeOptimizer | startup rollback left one or more patches attached; their state was retained rather than reset underneath live Harmony methods."); } } private void OnSettingChanged(object sender, SettingChangedEventArgs args) { try { if (((args != null) ? args.ChangedSetting : null) == null || _settings == null || !_settings.TryGetPatchIds(args.ChangedSetting, out var ids)) { return; } bool flag = Thread.CurrentThread.ManagedThreadId != _mainThreadId; for (int i = 0; i < ids.Count; i++) { if (flag) { _pendingSettingChanges.Enqueue(ids[i]); } else { ApplySettingChange(ids[i]); } } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("HotReload failed safely: " + ex.GetType().Name + ": " + ex.Message)); } } private void Update() { PatchId result; while (_pendingSettingChanges.TryDequeue(out result)) { ApplySettingChange(result); } _boneWeightCap?.Update(Time.unscaledDeltaTime); _collisionReuse?.Evaluate(_installer); } private void ApplySettingChange(PatchId id) { if (_settings == null || _installer == null) { return; } bool flag = _settings.IsEnabled(id); PatchStatus patchStatus = _installer.Toggle(id, flag); PatchStatusEntry patchStatusEntry = ((patchStatus.Entries.Count > 0) ? patchStatus.Entries[0] : null); if (patchStatusEntry != null) { switch (patchStatusEntry.Outcome) { case PatchOutcome.Applied: ((BaseUnityPlugin)this).Logger.LogInfo((object)(flag ? $"HotReload: {id} enabled→installed" : $"HotReload: {id} disabled→uninstalled")); break; case PatchOutcome.Skipped: ((BaseUnityPlugin)this).Logger.LogInfo((object)(flag ? $"HotReload: {id} enabled→{patchStatusEntry.Result}: {patchStatusEntry.Reason}" : $"HotReload: {id} disabled→{patchStatusEntry.Result}: {patchStatusEntry.Reason}")); break; case PatchOutcome.Failed: ((BaseUnityPlugin)this).Logger.LogError((object)$"HotReload: {id} {patchStatusEntry.Result}: {patchStatusEntry.Reason}"); break; } } } private void OnDestroy() { try { ((BaseUnityPlugin)this).Config.SettingChanged -= OnSettingChanged; } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Unsubscribe SettingChanged failed: {arg}"); } ShutdownGlobalLanes(); if (UninstallAll("Shutdown")) { DisposeLifecycle("Shutdown"); _lifecycle = null; _harmony = null; _installer = null; _settings = null; } else { ((BaseUnityPlugin)this).Logger.LogError((object)"PeakSafeOptimizer shutdown left one or more patches attached; state was retained to keep those methods safe until process exit."); } } private bool UninstallAll(string phase) { if (_installer == null) { return true; } try { foreach (PatchStatusEntry entry in _installer.UninstallAll().Entries) { if (entry.Outcome == PatchOutcome.Failed) { ((BaseUnityPlugin)this).Logger.LogError((object)$"{phase}: {entry.Name} {entry.Result}: {entry.Reason}"); } } return !_installer.HasInstalledPatches; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)(phase + ": verified uninstall failed safely: " + ex.GetType().Name + ": " + ex.Message)); return false; } } private void ShutdownGlobalLanes() { try { _collisionReuse?.Shutdown(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Collision reuse shutdown failed safely: " + ex.GetType().Name + ": " + ex.Message)); } _collisionReuse = null; try { _boneWeightCap?.Shutdown(); } catch (Exception ex2) { ((BaseUnityPlugin)this).Logger.LogError((object)("Bone weight cap shutdown failed safely: " + ex2.GetType().Name + ": " + ex2.Message)); } _boneWeightCap = null; } private void DisposeLifecycle(string phase) { try { _lifecycle?.Dispose(); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)(phase + ": lifecycle dispose failed safely: " + ex.GetType().Name + ": " + ex.Message)); } } } } namespace PeakSafeOptimizer.Patches.Stability { internal sealed class EmoteWheelGuardModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.EmoteWheelGuard, () => new PatchDefinition(PatchId.EmoteWheelGuard, EmoteWheelGuardPatch.Initialize, EmoteWheelGuardPatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(EmoteWheelGuardPatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, EmoteWheelGuardPatch.Reset)); } } internal static class EmoteWheelGuardPatch { internal static void Initialize() { ResolveAndValidateTarget(); FieldInfo field = typeof(Character).GetField("localCharacter", BindingFlags.Static | BindingFlags.Public); if (field == null || !field.IsStatic || field.FieldType != typeof(Character)) { throw new InvalidOperationException("Character.localCharacter failed structural self-check"); } StabilityPatchValidation.RequireInstanceField(typeof(Character), "data", typeof(CharacterData)); StabilityPatchValidation.RequireInstanceField(typeof(Character), "refs", typeof(CharacterRefs)); StabilityPatchValidation.RequireInstanceField(typeof(CharacterRefs), "stats", typeof(CharacterStats)); } internal static MethodInfo ResolveAndValidateTarget() { return StabilityPatchValidation.RequireInstanceMethod(typeof(GUIManager), "UpdateEmoteWheel", typeof(void), Type.EmptyTypes, requirePublic: false); } internal static void Reset() { } internal static bool Prefix() { if (Object.op_Implicit((Object)(object)Character.localCharacter)) { Character localCharacter = Character.localCharacter; if ((Object)(object)localCharacter.data != (Object)null && localCharacter.refs != null && (Object)(object)localCharacter.refs.stats != (Object)null) { return true; } RateLimitedDiagnostics.Hit("EmoteWheelGuard.localCharacter-members-unavailable"); return false; } RateLimitedDiagnostics.Hit("EmoteWheelGuard.localCharacter-unavailable"); return false; } } internal sealed class IKItemGuardModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.IKItemGuard, () => new PatchDefinition(PatchId.IKItemGuard, IKItemGuardPatch.Initialize, IKItemGuardPatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(IKItemGuardPatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, IKItemGuardPatch.Reset)); } } internal static class IKItemGuardPatch { private static FieldRef _character; internal static void Initialize() { ResolveAndValidateTarget(); FieldInfo fieldInfo = StabilityPatchValidation.RequireInstanceField(typeof(CharacterAnimations), "character", typeof(Character)); if (fieldInfo.IsPublic) { throw new InvalidOperationException("CharacterAnimations.character is no longer a private instance field"); } StabilityPatchValidation.RequireInstanceField(typeof(Character), "refs", typeof(CharacterRefs)); StabilityPatchValidation.RequireInstanceField(typeof(CharacterRefs), "IKHandTargetLeft", typeof(Transform)); StabilityPatchValidation.RequireInstanceField(typeof(Character), "data", typeof(CharacterData)); StabilityPatchValidation.RequireInstanceProperty(typeof(CharacterData), "currentItem", typeof(Item)); StabilityPatchValidation.RequireInstanceField(typeof(CharacterRefs), "IKHandTargetRight", typeof(Transform)); _character = AccessTools.FieldRefAccess(fieldInfo) ?? throw new InvalidOperationException("IKItemGuard accessor creation failed"); } internal static MethodInfo ResolveAndValidateTarget() { return StabilityPatchValidation.RequireInstanceMethod(typeof(CharacterAnimations), "ConfigureIK", typeof(void), Type.EmptyTypes); } internal static void Reset() { _character = null; } internal static bool Prefix(CharacterAnimations __instance) { FieldRef character = _character; if (character == null) { RateLimitedDiagnostics.Hit("IKItemGuard.accessors-unavailable"); return true; } Character val = character.Invoke(__instance); if ((Object)(object)val == (Object)null || val.refs == null || (Object)(object)val.data == (Object)null) { return true; } if ((Object)(object)val.refs.IKHandTargetLeft == (Object)null) { return true; } Item currentItem = val.data.currentItem; if ((Object)(object)currentItem == (Object)null) { return true; } Transform val2 = ((Component)currentItem).transform.Find("Hand_R"); Transform val3 = ((Component)currentItem).transform.Find("Hand_L"); if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null) { RateLimitedDiagnostics.Hit("IKItemGuard.hand-node-missing"); return false; } return true; } } internal static class ParachutePatch { private static FieldRef _character; private static FieldRef _handlerCharacter; internal static void Initialize() { FieldInfo fieldInfo = StabilityPatchValidation.RequireInstanceField(typeof(CharacterData), "character", typeof(Character)); FieldInfo fieldInfo2 = StabilityPatchValidation.RequireInstanceField(typeof(CharacterBackpackHandler), "character", typeof(Character)); ValidateCharacterStructure(); ValidateCharacterDataStructure(); ValidateInventoryStructure(); ValidateBackpackStructure(); FieldRef obj = AccessTools.FieldRefAccess(fieldInfo); FieldRef val = AccessTools.FieldRefAccess(fieldInfo2); if (obj == null || val == null) { throw new InvalidOperationException("Parachute FieldRef accessor creation failed"); } _character = obj; _handlerCharacter = val; } internal static MethodInfo ResolveAndValidateTarget() { return StabilityPatchValidation.RequireInstanceMethod(typeof(CharacterData), "UpdateHasParachute", typeof(void), Type.EmptyTypes); } internal static void Reset() { _character = null; _handlerCharacter = null; } internal static bool Prefix(CharacterData __instance) { Character val = _character.Invoke(__instance); if ((Object)(object)val != (Object)null && val.isScoutmaster) { return false; } __instance.hasParachute = false; __instance.currentParachuteSlot = null; __instance.currentParachuteItem = null; if ((Object)(object)val == (Object)null) { RateLimitedDiagnostics.Hit("Parachute.character-null-or-destroyed"); return false; } CharacterData data = val.data; if ((Object)(object)data == (Object)null) { RateLimitedDiagnostics.Hit("Parachute.characterData-null-or-destroyed"); return false; } Item currentItem = data.currentItem; if ((Object)(object)currentItem != (Object)null) { GameObject gameObject = ((Component)currentItem).gameObject; if ((Object)(object)gameObject == (Object)null) { RateLimitedDiagnostics.Hit("Parachute.held-gameObject-null-or-destroyed"); } else if (gameObject.CompareTag("Parachute")) { __instance.currentParachuteItem = currentItem; __instance.hasParachute = true; return false; } } Player player = val.player; if ((Object)(object)player == (Object)null) { RateLimitedDiagnostics.Hit("Parachute.player-null-or-destroyed"); return false; } ItemSlot[] itemSlots = player.itemSlots; if (itemSlots == null) { RateLimitedDiagnostics.Hit("Parachute.itemSlots-null"); return false; } ItemSlot[] array = itemSlots; foreach (ItemSlot val2 in array) { if (val2 == null) { RateLimitedDiagnostics.Hit("Parachute.slot-null"); } else if (!val2.IsEmpty()) { Item prefab = val2.prefab; if ((Object)(object)prefab == (Object)null) { RateLimitedDiagnostics.Hit("Parachute.nonempty-prefab-null-or-destroyed"); } else if ((Object)(object)((Component)prefab).gameObject == (Object)null) { RateLimitedDiagnostics.Hit("Parachute.prefab-gameObject-null-or-destroyed"); } else if (((Component)prefab).CompareTag("Parachute")) { __instance.currentParachuteSlot = val2; __instance.hasParachute = true; return false; } } } CharacterRefs refs = val.refs; if (refs == null) { RateLimitedDiagnostics.Hit("Parachute.characterRefs-null"); return false; } CharacterBackpackHandler backpackHandler = refs.backpackHandler; if ((Object)(object)backpackHandler == (Object)null) { RateLimitedDiagnostics.Hit("Parachute.backpackHandler-null-or-destroyed"); return false; } Character val3 = _handlerCharacter.Invoke(backpackHandler); if ((Object)(object)val3 == (Object)null || (Object)(object)val3 != (Object)(object)val) { RateLimitedDiagnostics.Hit("Parachute.backpackHandler-owner-invalid"); return false; } if (player.backpackSlot == null) { RateLimitedDiagnostics.Hit("Parachute.backpackSlot-null"); return false; } BackpackOnBackVisuals activeBackpackVisuals = backpackHandler.activeBackpackVisuals; Item currentParachuteItem = default(Item); if ((Object)(object)activeBackpackVisuals != (Object)null && ((BackpackVisuals)activeBackpackVisuals).ContainsParachute(ref currentParachuteItem)) { __instance.currentParachuteItem = currentParachuteItem; __instance.hasParachute = true; } return false; } private static void ValidateCharacterStructure() { StabilityPatchValidation.RequireInstanceField(typeof(Character), "isScoutmaster", typeof(bool)); StabilityPatchValidation.RequireInstanceField(typeof(Character), "data", typeof(CharacterData)); StabilityPatchValidation.RequireInstanceProperty(typeof(Character), "player", typeof(Player)); StabilityPatchValidation.RequireInstanceField(typeof(Character), "refs", typeof(CharacterRefs)); } private static void ValidateCharacterDataStructure() { StabilityPatchValidation.RequireInstanceField(typeof(CharacterData), "hasParachute", typeof(bool)); StabilityPatchValidation.RequireInstanceField(typeof(CharacterData), "currentParachuteSlot", typeof(ItemSlot)); StabilityPatchValidation.RequireInstanceField(typeof(CharacterData), "currentParachuteItem", typeof(Item)); StabilityPatchValidation.RequireInstanceProperty(typeof(CharacterData), "currentItem", typeof(Item)); } private static void ValidateInventoryStructure() { StabilityPatchValidation.RequireInstanceField(typeof(Player), "itemSlots", typeof(ItemSlot[])); StabilityPatchValidation.RequireInstanceField(typeof(Player), "backpackSlot", typeof(BackpackSlot)); StabilityPatchValidation.RequireInstanceMethod(typeof(ItemSlot), "IsEmpty", typeof(bool), Type.EmptyTypes); StabilityPatchValidation.RequireInstanceProperty(typeof(ItemSlot), "prefab", typeof(Item)); } private static void ValidateBackpackStructure() { StabilityPatchValidation.RequireInstanceField(typeof(CharacterRefs), "backpackHandler", typeof(CharacterBackpackHandler)); StabilityPatchValidation.RequireInstanceProperty(typeof(CharacterBackpackHandler), "activeBackpackVisuals", typeof(BackpackOnBackVisuals)); Type type = typeof(Item).MakeByRefType(); ParameterInfo parameterInfo = StabilityPatchValidation.RequireInstanceMethod(typeof(BackpackVisuals), "ContainsParachute", typeof(bool), new Type[1] { type }).GetParameters()[0]; if (!parameterInfo.IsOut || parameterInfo.IsIn) { throw new InvalidOperationException("BackpackVisuals.ContainsParachute parameter is no longer an out Item"); } } } internal sealed class RopeSegmentGuardModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.RopeSegmentGuard, () => new PatchDefinition(PatchId.RopeSegmentGuard, RopeSegmentGuardPatch.Initialize, RopeSegmentGuardPatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(RopeSegmentGuardPatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, RopeSegmentGuardPatch.Reset)); } } internal static class RopeSegmentGuardPatch { private static FieldRef _character; internal static void Initialize() { ResolveAndValidateTarget(); FieldInfo fieldInfo = StabilityPatchValidation.RequireInstanceField(typeof(CharacterRopeHandling), "character", typeof(Character)); if (fieldInfo.IsPublic) { throw new InvalidOperationException("CharacterRopeHandling.character is no longer a private instance field"); } StabilityPatchValidation.RequireInstanceField(typeof(Character), "data", typeof(CharacterData)); StabilityPatchValidation.RequireInstanceField(typeof(CharacterData), "heldRope", typeof(Rope)); StabilityPatchValidation.RequireInstanceField(typeof(CharacterData), "isRopeClimbing", typeof(bool)); StabilityPatchValidation.RequireInstanceField(typeof(CharacterData), "ropePercent", typeof(float)); StabilityPatchValidation.RequireInstanceField(typeof(CharacterData), "ropeClimbWorldNormal", typeof(Vector3)); StabilityPatchValidation.RequireInstanceField(typeof(CharacterData), "ropeClimbWorldUp", typeof(Vector3)); StabilityPatchValidation.RequireInstanceField(typeof(CharacterData), "ropeClimbNormal", typeof(Vector3)); StabilityPatchValidation.RequireInstanceField(typeof(Rope), "climbingAPI", typeof(RopeClimbingAPI)); StabilityPatchValidation.RequireInstanceMethod(typeof(Rope), "GetRopeSegments", typeof(List), Type.EmptyTypes); StabilityPatchValidation.RequireInstanceMethod(typeof(RopeClimbingAPI), "GetUp", typeof(Vector3), new Type[1] { typeof(float) }); StabilityPatchValidation.RequireInstanceMethod(typeof(RopeClimbingAPI), "GetSegmentFromPercent", typeof(Transform), new Type[1] { typeof(float) }); _character = AccessTools.FieldRefAccess(fieldInfo) ?? throw new InvalidOperationException("RopeSegmentGuard accessor creation failed"); } internal static MethodInfo ResolveAndValidateTarget() { return StabilityPatchValidation.RequireInstanceMethod(typeof(CharacterRopeHandling), "Climbing", typeof(void), Type.EmptyTypes, requirePublic: false); } internal static void Reset() { _character = null; } internal static bool Prefix(CharacterRopeHandling __instance) { FieldRef character = _character; if (character == null) { RateLimitedDiagnostics.Hit("RopeSegmentGuard.accessors-unavailable"); return true; } Character val = character.Invoke(__instance); CharacterData val2 = (((Object)(object)val != (Object)null) ? val.data : null); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { RateLimitedDiagnostics.Hit("RopeSegmentGuard.character-unavailable"); return true; } Rope heldRope = val2.heldRope; if ((Object)(object)heldRope == (Object)null || (Object)(object)((MonoBehaviourPun)heldRope).photonView == (Object)null) { return true; } if ((Object)(object)heldRope.climbingAPI == (Object)null) { RateLimitedDiagnostics.Hit("RopeSegmentGuard.climbingAPI-null"); return false; } List ropeSegments = heldRope.GetRopeSegments(); if (ropeSegments == null) { RateLimitedDiagnostics.Hit("RopeSegmentGuard.segments-null"); return false; } if (ropeSegments.Count == 0) { RateLimitedDiagnostics.Hit("RopeSegmentGuard.segments-empty"); return false; } return true; } } internal static class RunBasedValuesPatch { private static StructFieldRef> _ints; private static StructFieldRef> _floats; internal static void Initialize() { Type typeFromHandle = typeof(SerializableRunBasedValues); if (!typeFromHandle.IsValueType || typeFromHandle.IsEnum) { throw new InvalidOperationException("SerializableRunBasedValues is no longer a non-enum value type"); } FieldInfo fieldInfo = StabilityPatchValidation.RequireInstanceField(typeFromHandle, "runBasedInts", typeof(Dictionary)); FieldInfo fieldInfo2 = StabilityPatchValidation.RequireInstanceField(typeFromHandle, "runBasedFloats", typeof(Dictionary)); if (fieldInfo.IsInitOnly || fieldInfo2.IsInitOnly) { throw new InvalidOperationException("RunBasedValues dictionary fields are unexpectedly readonly"); } StructFieldRef> obj = AccessTools.StructFieldRefAccess>(fieldInfo); StructFieldRef> val = AccessTools.StructFieldRefAccess>(fieldInfo2); if (obj == null || val == null) { throw new InvalidOperationException("RunBasedValues StructFieldRef accessor creation failed"); } _ints = obj; _floats = val; } internal static MethodInfo ResolveAndValidateTarget() { return StabilityPatchValidation.RequireInstanceMethod(typeof(SerializableRunBasedValues), "SerializeRunBasedValues", typeof(void), new Type[1] { typeof(BinarySerializer) }); } internal static void Reset() { _ints = null; _floats = null; } internal static void Prefix(ref SerializableRunBasedValues __instance) { if (_ints.Invoke(ref __instance) == null) { _ints.Invoke(ref __instance) = new Dictionary(); RateLimitedDiagnostics.Hit("RunBasedValues.runBasedInts-null"); } if (_floats.Invoke(ref __instance) == null) { _floats.Invoke(ref __instance) = new Dictionary(); RateLimitedDiagnostics.Hit("RunBasedValues.runBasedFloats-null"); } } } internal sealed class StabilityPatchModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.RunBasedValues, () => new PatchDefinition(PatchId.RunBasedValues, RunBasedValuesPatch.Initialize, RunBasedValuesPatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(RunBasedValuesPatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: false, RunBasedValuesPatch.Reset)); context.Register(PatchId.Parachute, () => new PatchDefinition(PatchId.Parachute, ParachutePatch.Initialize, ParachutePatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(ParachutePatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, ParachutePatch.Reset)); } } internal static class StabilityPatchValidation { private const BindingFlags DeclaredInstance = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; internal static FieldInfo RequireInstanceField(Type declaringType, string name, Type fieldType) { FieldInfo field = declaringType.GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { throw new MissingFieldException(declaringType.FullName, name); } if (field.DeclaringType != declaringType || field.IsStatic || field.FieldType != fieldType) { throw new InvalidOperationException("Unexpected field structure for " + declaringType.FullName + "." + name); } return field; } internal static PropertyInfo RequireInstanceProperty(Type declaringType, string name, Type propertyType, bool requirePublicGetter = true) { PropertyInfo property = declaringType.GetProperty(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); MethodInfo methodInfo = property?.GetGetMethod(nonPublic: true); if (property == null || property.DeclaringType != declaringType || property.PropertyType != propertyType || property.GetIndexParameters().Length != 0 || methodInfo == null || methodInfo.IsStatic || methodInfo.ContainsGenericParameters || (requirePublicGetter && !methodInfo.IsPublic)) { throw new InvalidOperationException("Unexpected property structure for " + declaringType.FullName + "." + name); } return property; } internal static MethodInfo RequireInstanceMethod(Type declaringType, string name, Type returnType, Type[] parameterTypes, bool requirePublic = true) { MethodInfo method = declaringType.GetMethod(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, parameterTypes, null); if (method == null) { throw new MissingMethodException(declaringType.FullName, name); } if (method.DeclaringType != declaringType || method.IsStatic || method.ReturnType != returnType || method.ContainsGenericParameters || (requirePublic && !method.IsPublic)) { throw new InvalidOperationException("Unexpected method structure for " + declaringType.FullName + "." + name); } ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length != parameterTypes.Length) { throw new InvalidOperationException("Unexpected parameter count for " + declaringType.FullName + "." + name); } for (int i = 0; i < parameters.Length; i++) { if (parameters[i].ParameterType != parameterTypes[i]) { throw new InvalidOperationException($"Unexpected parameter {i} for {declaringType.FullName}.{name}"); } } return method; } } } namespace PeakSafeOptimizer.Patches.Scale { internal sealed class AnimatedMouthMaterialModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.AnimatedMouthMaterial, () => new PatchDefinition(PatchId.AnimatedMouthMaterial, AnimatedMouthMaterialPatch.Initialize, AnimatedMouthMaterialPatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(AnimatedMouthMaterialPatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, AnimatedMouthMaterialPatch.Reset)); } } internal static class AnimatedMouthMaterialPatch { private sealed class State { internal int LastUseTalkSprites = -1; internal int LastAmplitudeIndex = -1; } private static Func _getAudioSource; private static FieldRef _lastBuffer; private static FieldRef _pushToTalkSetting; private static FieldRef _volumePeak; private static Func _micLevel; private static Func _getPushToTalkValue; private static ConditionalWeakTable _state; internal static void Initialize() { ResolveAndValidateTarget(); Type? typeFromHandle = typeof(AnimatedMouth); FieldInfo field = ScaleValidation.RequireInstanceFieldByTypeName(typeFromHandle, "audioSource", "UnityEngine.AudioSource"); ScaleValidation.RequireInstanceField(typeFromHandle, "isGhost", typeof(bool)); ScaleValidation.RequireInstanceField(typeFromHandle, "character", typeof(Character)); ScaleValidation.RequireInstanceField(typeFromHandle, "mouthRenderer", typeof(Renderer)); ScaleValidation.RequireInstanceField(typeFromHandle, "mouthTextures", typeof(Texture2D[])); ScaleValidation.RequireInstanceField(typeFromHandle, "amplitudeIndex", typeof(int)); ScaleValidation.RequireInstanceField(typeFromHandle, "isSpeaking", typeof(bool)); ScaleValidation.RequireInstanceField(typeFromHandle, "volume", typeof(float)); ScaleValidation.RequireInstanceField(typeFromHandle, "amplitudePeakLimiter", typeof(float)); ScaleValidation.RequireInstanceField(typeFromHandle, "minAmplitudeThreshold", typeof(float)); ScaleValidation.RequireInstanceField(typeFromHandle, "amplitudeHighestDecay", typeof(float)); ScaleValidation.RequireInstanceField(typeFromHandle, "amplitudeSmoothing", typeof(float)); ScaleValidation.RequireInstanceField(typeFromHandle, "talkThreshold", typeof(float)); ScaleValidation.RequireInstanceField(typeFromHandle, "amplitudeMult", typeof(float)); ScaleValidation.RequireInstanceField(typeFromHandle, "decibelToAmountCurve", typeof(AnimationCurve)); FieldInfo fieldInfo = ScaleValidation.RequireInstanceField(typeFromHandle, "m_lastSentLocalBuffer", typeof(float[])); FieldInfo fieldInfo2 = ScaleValidation.RequireInstanceField(typeFromHandle, "pushToTalkSetting", typeof(PushToTalkSetting)); FieldInfo fieldInfo3 = ScaleValidation.RequireInstanceField(typeFromHandle, "volumePeak", typeof(float)); ScaleValidation.RequireInstanceProperty(typeFromHandle, "NormalizedAmplitude", typeof(float)); ScaleValidation.RequireInstanceProperty(typeFromHandle, "VoiceHandler", typeof(CharacterVoiceHandler)); MethodInfo methodInfo = ScaleValidation.RequireInstanceMethod(typeFromHandle, "MicrophoneLevelMax", typeof(float), new Type[1] { typeof(float[]) }, requirePublic: false); ScaleValidation.RequireInstanceField(typeof(Character), "data", typeof(CharacterData)); ScaleValidation.RequireInstanceField(typeof(Character), "input", typeof(CharacterInput)); ScaleValidation.RequireInstanceProperty(typeof(Character), "IsLocal", typeof(bool)); ScaleValidation.RequireInstanceProperty(typeof(CharacterData), "dead", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "passedOut", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(CharacterInput), "pushToTalkPressed", typeof(bool)); ScaleValidation.RequireInstanceProperty(typeof(CharacterVoiceHandler), "LastReadSquaredMax", typeof(float)); ScaleValidation.RequireInstanceProperty(typeof(CharacterVoiceHandler), "LastAudioBuffer", typeof(float[])); PropertyInfo propertyInfo = ScaleValidation.RequireInheritedInstanceProperty(typeof(PushToTalkSetting), "Value", typeof(PushToTalkType)); if (!Enum.IsDefined(typeof(PushToTalkType), (object)(PushToTalkType)1) || !Enum.IsDefined(typeof(PushToTalkType), (object)(PushToTalkType)2)) { throw new InvalidOperationException("PushToTalkType values are no longer defined"); } Func func = ScaleEmit.CreateUnityObjectFieldGetter(field); FieldRef val = AccessTools.FieldRefAccess(fieldInfo); FieldRef val2 = AccessTools.FieldRefAccess(fieldInfo2); FieldRef val3 = AccessTools.FieldRefAccess(fieldInfo3); Func func2 = (Func)methodInfo.CreateDelegate(typeof(Func)); Func func3 = EmitPushToTalkValueGetter(propertyInfo.GetGetMethod(nonPublic: true)); if (func == null || val == null || val2 == null || val3 == null || func2 == null || func3 == null) { throw new InvalidOperationException("AnimatedMouthMaterial accessor creation failed"); } _getAudioSource = func; _lastBuffer = val; _pushToTalkSetting = val2; _volumePeak = val3; _micLevel = func2; _getPushToTalkValue = func3; _state = new ConditionalWeakTable(); } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(AnimatedMouth), "ProcessMicData", typeof(void), new Type[1] { typeof(float[]) }, requirePublic: false); } internal static void Reset() { _getAudioSource = null; _lastBuffer = null; _pushToTalkSetting = null; _volumePeak = null; _micLevel = null; _getPushToTalkValue = null; _state = null; } private static Func EmitPushToTalkValueGetter(MethodInfo getter) { DynamicMethod dynamicMethod = new DynamicMethod("PSO_GetPushToTalkValue", typeof(PushToTalkType), new Type[1] { typeof(PushToTalkSetting) }, typeof(AnimatedMouthMaterialPatch).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Castclass, getter.DeclaringType); iLGenerator.Emit(OpCodes.Callvirt, getter); iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } internal static bool Prefix(AnimatedMouth __instance, float[] buffer) { //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Invalid comparison between Unknown and I4 //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Invalid comparison between Unknown and I4 Func getAudioSource = _getAudioSource; FieldRef lastBuffer = _lastBuffer; FieldRef pushToTalkSetting = _pushToTalkSetting; FieldRef volumePeak = _volumePeak; Func micLevel = _micLevel; Func getPushToTalkValue = _getPushToTalkValue; ConditionalWeakTable state = _state; if (getAudioSource == null || lastBuffer == null || pushToTalkSetting == null || volumePeak == null || micLevel == null || getPushToTalkValue == null || state == null) { RateLimitedDiagnostics.Hit("AnimatedMouthMaterial.accessors-unavailable"); return true; } Renderer mouthRenderer = __instance.mouthRenderer; if ((Object)(object)mouthRenderer == (Object)null) { RateLimitedDiagnostics.Hit("AnimatedMouthMaterial.mouthRenderer-null"); return true; } Texture2D[] mouthTextures = __instance.mouthTextures; if (mouthTextures == null || mouthTextures.Length == 0) { RateLimitedDiagnostics.Hit("AnimatedMouthMaterial.mouthTextures-empty"); return true; } Character character = __instance.character; if ((Object)(object)character == (Object)null) { RateLimitedDiagnostics.Hit("AnimatedMouthMaterial.character-null"); return true; } if (getAudioSource(__instance) == (Object)null) { return false; } if (!__instance.isGhost && (character.data.dead || character.data.passedOut)) { return false; } bool isLocal = character.IsLocal; float num = ((!isLocal) ? __instance.VoiceHandler.LastReadSquaredMax : micLevel(__instance, buffer)); if (!isLocal) { lastBuffer.Invoke(__instance) = __instance.VoiceHandler.LastAudioBuffer; } float num2 = AnimatedMouth.MicrophoneLevelMaxDecibels(num); PushToTalkSetting arg = pushToTalkSetting.Invoke(__instance); PushToTalkType val = getPushToTalkValue(arg); if (isLocal && (((int)val == 1 && !character.input.pushToTalkPressed) || ((int)val == 2 && character.input.pushToTalkPressed))) { num2 = -80f; } float num3 = __instance.decibelToAmountCurve.Evaluate(num2); if (num3 > __instance.amplitudePeakLimiter) { __instance.amplitudePeakLimiter = num3; } if (__instance.amplitudePeakLimiter > __instance.minAmplitudeThreshold) { __instance.amplitudePeakLimiter -= __instance.amplitudeHighestDecay * Time.deltaTime; __instance.amplitudePeakLimiter = Mathf.Max(__instance.amplitudePeakLimiter, __instance.minAmplitudeThreshold); } __instance.volume = num3 / __instance.amplitudePeakLimiter; float num4 = volumePeak.Invoke(__instance); num4 = ((!(__instance.volume > num4)) ? Mathf.Lerp(num4, 0f, Time.deltaTime * __instance.amplitudeSmoothing) : Mathf.Lerp(num4, __instance.volume, Time.deltaTime * __instance.amplitudeSmoothing)); volumePeak.Invoke(__instance) = num4; int num5; bool isSpeaking; if (num4 > __instance.talkThreshold) { num5 = 1; isSpeaking = true; } else { isSpeaking = false; num5 = 0; } __instance.isSpeaking = isSpeaking; State value = state.GetValue(__instance, (AnimatedMouth _) => new State()); Material material = mouthRenderer.material; if (value.LastUseTalkSprites != num5 || material.GetInt("_UseTalkSprites") != num5) { material.SetInt("_UseTalkSprites", num5); value.LastUseTalkSprites = num5; } int num6 = (__instance.amplitudeIndex = (int)(__instance.NormalizedAmplitude * (float)(mouthTextures.Length - 1))); Texture2D val2 = mouthTextures[num6]; if (value.LastAmplitudeIndex != num6 || (Object)(object)material.GetTexture("_TalkSprite") != (Object)(object)val2) { material.SetTexture("_TalkSprite", (Texture)(object)val2); value.LastAmplitudeIndex = num6; } return false; } } internal sealed class AnimatorValuesHashModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.AnimatorValuesHash, () => new PatchDefinition(PatchId.AnimatorValuesHash, AnimatorValuesHashPatch.Initialize, AnimatorValuesHashPatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(AnimatorValuesHashPatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, AnimatorValuesHashPatch.Reset)); } } internal static class AnimatorValuesHashPatch { private static Func _getAnimator; private static FieldRef _character; private static Func _stringToHash; private static Func _getFloat; private static Action _setFloat; private static Action _setFloatDamped; private static Func _getBool; private static Action _setBool; private static int _inputXHash; private static int _inputYHash; private static int _isGroundedHash; private static int _sprintHash; private static int _velocityYHash; internal static void Initialize() { ResolveAndValidateTarget(); Type? typeFromHandle = typeof(AnimatorValues); FieldInfo fieldInfo = ScaleValidation.RequireInstanceFieldByTypeName(typeFromHandle, "anim", "UnityEngine.Animator"); FieldInfo fieldInfo2 = ScaleValidation.RequireInstanceField(typeFromHandle, "character", typeof(Character)); ScaleValidation.RequireInstanceField(typeof(Character), "input", typeof(CharacterInput)); ScaleValidation.RequireInstanceField(typeof(Character), "data", typeof(CharacterData)); ScaleValidation.RequireInstanceField(typeof(Character), "refs", typeof(CharacterRefs)); ScaleValidation.RequireInstanceField(typeof(CharacterInput), "movementInput", typeof(Vector2)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "isGrounded", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "isSprinting", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "avarageVelocity", typeof(Vector3)); ScaleValidation.RequireInstanceField(typeof(CharacterRefs), "movement", typeof(CharacterMovement)); ScaleValidation.RequireInstanceField(typeof(CharacterMovement), "sprintAnimationDisabled", typeof(bool)); Type fieldType = fieldInfo.FieldType; MethodInfo methodInfo = RequireMethod(fieldType, "StringToHash", typeof(int), true, typeof(string)); MethodInfo methodInfo2 = RequireMethod(fieldType, "GetFloat", typeof(float), false, typeof(int)); MethodInfo methodInfo3 = RequireMethod(fieldType, "SetFloat", typeof(void), false, typeof(int), typeof(float)); MethodInfo methodInfo4 = RequireMethod(fieldType, "SetFloat", typeof(void), false, typeof(int), typeof(float), typeof(float), typeof(float)); MethodInfo methodInfo5 = RequireMethod(fieldType, "GetBool", typeof(bool), false, typeof(int)); MethodInfo methodInfo6 = RequireMethod(fieldType, "SetBool", typeof(void), false, typeof(int), typeof(bool)); Func func = ScaleEmit.CreateUnityObjectFieldGetter(fieldInfo); FieldRef val = AccessTools.FieldRefAccess(fieldInfo2); Func func2 = (Func)methodInfo.CreateDelegate(typeof(Func)); Func func3 = EmitGetFloat(fieldType, methodInfo2); Action action = EmitSetFloat(fieldType, methodInfo3); Action action2 = EmitSetFloatDamped(fieldType, methodInfo4); Func func4 = EmitGetBool(fieldType, methodInfo5); Action action3 = EmitSetBool(fieldType, methodInfo6); if (func == null || val == null || func2 == null || func3 == null || action == null || action2 == null || func4 == null || action3 == null) { throw new InvalidOperationException("AnimatorValuesHash accessor creation failed"); } _getAnimator = func; _character = val; _stringToHash = func2; _getFloat = func3; _setFloat = action; _setFloatDamped = action2; _getBool = func4; _setBool = action3; _inputXHash = func2("Input X"); _inputYHash = func2("Input Y"); _isGroundedHash = func2("Is Grounded"); _sprintHash = func2("Sprint"); _velocityYHash = func2("Velocity Y"); } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(AnimatorValues), "Update", typeof(void), Type.EmptyTypes, requirePublic: false); } internal static void Reset() { _getAnimator = null; _character = null; _stringToHash = null; _getFloat = null; _setFloat = null; _setFloatDamped = null; _getBool = null; _setBool = null; _inputXHash = 0; _inputYHash = 0; _isGroundedHash = 0; _sprintHash = 0; _velocityYHash = 0; } internal static bool Prefix(AnimatorValues __instance) { //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) Func getAnimator = _getAnimator; FieldRef character = _character; Func getFloat = _getFloat; Action setFloat = _setFloat; Action setFloatDamped = _setFloatDamped; Func getBool = _getBool; Action setBool = _setBool; if (getAnimator == null || character == null || _stringToHash == null || getFloat == null || setFloat == null || setFloatDamped == null || getBool == null || setBool == null) { return true; } Object val = getAnimator(__instance); Character val2 = character.Invoke(__instance); if (val == (Object)null || (Object)(object)val2 == (Object)null || (Object)(object)val2.input == (Object)null || (Object)(object)val2.data == (Object)null || val2.refs == null || (Object)(object)val2.refs.movement == (Object)null) { return true; } CharacterData data = val2.data; Vector2 movementInput = val2.input.movementInput; SetFloatIfChanged(val, _inputXHash, movementInput.x, getFloat, setFloat); SetFloatIfChanged(val, _inputYHash, movementInput.y, getFloat, setFloat); SetBoolIfChanged(val, _isGroundedHash, data.isGrounded, getBool, setBool); if (val2.refs.movement.sprintAnimationDisabled) { SetFloatIfChanged(val, _sprintHash, 0f, getFloat, setFloat); } else { float num = (data.isSprinting ? 1f : 0f); if (getFloat(val, _sprintHash) != num) { setFloatDamped(val, _sprintHash, num, 0.125f, Time.deltaTime); } } SetFloatIfChanged(val, _velocityYHash, data.avarageVelocity.y, getFloat, setFloat); if (data.isGrounded) { val2.refs.movement.sprintAnimationDisabled = false; } return false; } private static void SetFloatIfChanged(Object animator, int hash, float target, Func getFloat, Action setFloat) { if (getFloat(animator, hash) != target) { setFloat(animator, hash, target); } } private static void SetBoolIfChanged(Object animator, int hash, bool target, Func getBool, Action setBool) { if (getBool(animator, hash) != target) { setBool(animator, hash, target); } } private static MethodInfo RequireMethod(Type owner, string name, Type returnType, bool isStatic, params Type[] parameterTypes) { BindingFlags bindingAttr = (BindingFlags)(0x10 | (isStatic ? 8 : 4)); MethodInfo method = owner.GetMethod(name, bindingAttr, null, parameterTypes, null); if (method == null || method.DeclaringType != owner || method.IsStatic != isStatic || method.ReturnType != returnType || method.ContainsGenericParameters) { throw new MissingMethodException(owner.FullName, name); } return method; } private static Func EmitGetFloat(Type animatorType, MethodInfo methodInfo) { DynamicMethod dynamicMethod = NewAnimatorMethod("PSO_AnimatorGetFloat", typeof(float), typeof(int)); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); EmitAnimatorCallPrefix(iLGenerator, animatorType, 1); iLGenerator.Emit(OpCodes.Callvirt, methodInfo); iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } private static Action EmitSetFloat(Type animatorType, MethodInfo methodInfo) { DynamicMethod dynamicMethod = NewAnimatorMethod("PSO_AnimatorSetFloat", typeof(void), typeof(int), typeof(float)); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); EmitAnimatorCallPrefix(iLGenerator, animatorType, 2); iLGenerator.Emit(OpCodes.Callvirt, methodInfo); iLGenerator.Emit(OpCodes.Ret); return (Action)dynamicMethod.CreateDelegate(typeof(Action)); } private static Action EmitSetFloatDamped(Type animatorType, MethodInfo methodInfo) { DynamicMethod dynamicMethod = NewAnimatorMethod("PSO_AnimatorSetFloatDamped", typeof(void), typeof(int), typeof(float), typeof(float), typeof(float)); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); EmitAnimatorCallPrefix(iLGenerator, animatorType, 4); iLGenerator.Emit(OpCodes.Callvirt, methodInfo); iLGenerator.Emit(OpCodes.Ret); return (Action)dynamicMethod.CreateDelegate(typeof(Action)); } private static Func EmitGetBool(Type animatorType, MethodInfo methodInfo) { DynamicMethod dynamicMethod = NewAnimatorMethod("PSO_AnimatorGetBool", typeof(bool), typeof(int)); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); EmitAnimatorCallPrefix(iLGenerator, animatorType, 1); iLGenerator.Emit(OpCodes.Callvirt, methodInfo); iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } private static Action EmitSetBool(Type animatorType, MethodInfo methodInfo) { DynamicMethod dynamicMethod = NewAnimatorMethod("PSO_AnimatorSetBool", typeof(void), typeof(int), typeof(bool)); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); EmitAnimatorCallPrefix(iLGenerator, animatorType, 2); iLGenerator.Emit(OpCodes.Callvirt, methodInfo); iLGenerator.Emit(OpCodes.Ret); return (Action)dynamicMethod.CreateDelegate(typeof(Action)); } private static DynamicMethod NewAnimatorMethod(string name, Type returnType, params Type[] parametersAfterAnimator) { Type[] array = new Type[parametersAfterAnimator.Length + 1]; array[0] = typeof(Object); Array.Copy(parametersAfterAnimator, 0, array, 1, parametersAfterAnimator.Length); return new DynamicMethod(name, returnType, array, typeof(AnimatorValuesHashPatch).Module, skipVisibility: true); } private static void EmitAnimatorCallPrefix(ILGenerator il, Type animatorType, int argumentCount) { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Castclass, animatorType); for (int i = 1; i <= argumentCount; i++) { il.Emit(OpCodes.Ldarg, i); } } } internal sealed class BarAfflictionLayoutModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.BarAfflictionLayout, () => new PatchDefinition(PatchId.BarAfflictionLayout, BarAfflictionLayoutPatch.Initialize, BarAfflictionLayoutPatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(BarAfflictionLayoutPatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, BarAfflictionLayoutPatch.Reset)); } } internal static class BarAfflictionLayoutPatch { private static Func _getRtf; internal static void Initialize() { ResolveAndValidateTarget(); FieldInfo field = ScaleValidation.RequireInstanceFieldByTypeName(typeof(BarAffliction), "rtf", "UnityEngine.RectTransform"); ScaleValidation.RequireInstanceProperty(typeof(BarAffliction), "width", typeof(float)); ScaleValidation.RequireInstanceField(typeof(BarAffliction), "size", typeof(float)); _getRtf = ScaleEmit.CreateUnityObjectFieldGetter(field) ?? throw new InvalidOperationException("BarAfflictionLayout accessor creation failed"); } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(BarAffliction), "UpdateAffliction", typeof(void), new Type[1] { typeof(StaminaBar) }, requirePublic: true); } internal static void Reset() { _getRtf = null; } internal static bool Prefix(BarAffliction __instance) { Func getRtf = _getRtf; if (getRtf == null) { RateLimitedDiagnostics.Hit("BarAfflictionLayout.accessors-unavailable"); return true; } if (getRtf(__instance) == (Object)null) { RateLimitedDiagnostics.Hit("BarAfflictionLayout.rtf-null"); return true; } float width = __instance.width; if (Mathf.Lerp(width, __instance.size, Mathf.Min(Time.deltaTime * 10f, 0.1f)) == width) { return false; } return true; } } internal sealed class BodypartDragIdentityModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.BodypartDragIdentity, () => new PatchDefinition(PatchId.BodypartDragIdentity, BodypartDragIdentityPatch.Initialize, BodypartDragIdentityPatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(BodypartDragIdentityPatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, BodypartDragIdentityPatch.Reset)); } } internal static class BodypartDragIdentityPatch { private const string RigidbodyTypeName = "UnityEngine.Rigidbody"; private static FieldRef _character; internal static void Initialize() { ResolveAndValidateTarget(); FieldInfo fieldInfo = ScaleValidation.RequireInstanceField(typeof(Bodypart), "character", typeof(Character)); ScaleValidation.RequireInstanceField(typeof(Character), "data", typeof(CharacterData)); ScaleValidation.RequireInstanceProperty(typeof(CharacterData), "currentRagdollControll", typeof(float)); FieldInfo fieldInfo2 = ScaleValidation.RequireInstanceFieldByTypeName(typeof(Bodypart), "rig", "UnityEngine.Rigidbody"); ScaleValidation.RequireInstancePropertyByTypeName(fieldInfo2.FieldType, "isKinematic", typeof(bool).FullName, requireSetter: true); ScaleValidation.RequireInstancePropertyByTypeName(fieldInfo2.FieldType, "linearVelocity", "UnityEngine.Vector3", requireSetter: true); ScaleValidation.RequireInstancePropertyByTypeName(fieldInfo2.FieldType, "angularVelocity", "UnityEngine.Vector3", requireSetter: true); _character = AccessTools.FieldRefAccess(fieldInfo) ?? throw new InvalidOperationException("BodypartDragIdentity FieldRef creation failed"); } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(Bodypart), "Drag", typeof(void), new Type[2] { typeof(float), typeof(bool) }, requirePublic: false); } internal static void Reset() { _character = null; } internal static bool Prefix(Bodypart __instance, float drag, bool ignoreRagdoll) { FieldRef character = _character; if (character == null || (Object)(object)__instance == (Object)null) { return true; } float num = drag; if (!ignoreRagdoll) { Character val = character.Invoke(__instance); CharacterData val2 = (((Object)(object)val != (Object)null) ? val.data : null); if ((Object)(object)val2 == (Object)null) { return true; } num = Mathf.Lerp(1f, drag, val2.currentRagdollControll); } return num != 1f; } } internal sealed class BodypartMovementForceIdentityModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.BodypartMovementForceIdentity, () => new PatchDefinition(PatchId.BodypartMovementForceIdentity, BodypartMovementForceIdentityPatch.Initialize, BodypartMovementForceIdentityPatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(BodypartMovementForceIdentityPatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, BodypartMovementForceIdentityPatch.Reset)); } } internal static class BodypartMovementForceIdentityPatch { private static FieldRef _character; internal static void Initialize() { ResolveAndValidateTarget(); FieldInfo fieldInfo = ScaleValidation.RequireInstanceField(typeof(Bodypart), "character", typeof(Character)); ScaleValidation.RequireInstanceField(typeof(Character), "data", typeof(CharacterData)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "worldMovementInput_Lerp", typeof(Vector3)); ScaleValidation.RequireInstanceMethod(typeof(Bodypart), "AddForce", typeof(void), new Type[2] { typeof(Vector3), typeof(ForceMode) }, requirePublic: true); ScaleValidation.RequireInstanceMethod(typeof(Bodypart), "ApplyForces", typeof(void), Type.EmptyTypes, requirePublic: false); ScaleValidation.RequireInstanceField(typeof(Bodypart), "forcesToAdd", typeof(Vector3)); ScaleValidation.RequireInstanceFieldByTypeName(typeof(Bodypart), "rig", "UnityEngine.Rigidbody"); _character = AccessTools.FieldRefAccess(fieldInfo) ?? throw new InvalidOperationException("BodypartMovementForceIdentity FieldRef creation failed"); } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(Bodypart), "AddMovementForce", typeof(void), new Type[1] { typeof(float) }, requirePublic: false); } internal static void Reset() { _character = null; } internal static bool Prefix(Bodypart __instance, float movementForce, bool __runOriginal) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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_006b: Unknown result type (might be due to invalid IL or missing references) if (!__runOriginal) { return false; } FieldRef character = _character; if (character == null || (Object)(object)__instance == (Object)null) { return true; } Character val = character.Invoke(__instance); if ((Object)(object)val == (Object)null) { return true; } CharacterData data = val.data; if ((Object)(object)data == (Object)null) { return true; } Vector3 worldMovementInput_Lerp = data.worldMovementInput_Lerp; Vector3 val2 = movementForce * worldMovementInput_Lerp; if (val2.x == 0f && val2.y == 0f) { return val2.z != 0f; } return true; } } internal sealed class CampfireProtectionMergeModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.CampfireProtectionMerge, () => new PatchDefinition(PatchId.CampfireProtectionMerge, CampfireProtectionMergePatch.Initialize, CampfireProtectionMergePatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(CampfireProtectionMergePatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, CampfireProtectionMergePatch.Reset)); } } internal static class CampfireProtectionMergePatch { private static FieldRef> _charactersInRadius; private static FieldRef _timebuffLastApplied; private static FieldRef _campfireBuffGetter; internal static void Initialize() { ResolveAndValidateTarget(); FieldInfo fieldInfo = ScaleValidation.RequireInstanceField(typeof(Campfire), "_charactersInRadius", typeof(List)); FieldInfo fieldInfo2 = ScaleValidation.RequireInstanceField(typeof(Campfire), "_timebuffLastApplied", typeof(float)); ScaleValidation.RequireInstanceField(typeof(Campfire), "moraleBoostRadius", typeof(float)); FieldInfo field = typeof(Campfire).GetField("s_CampfireBuff", BindingFlags.Static | BindingFlags.NonPublic); if (field == null || !field.IsStatic || field.FieldType != typeof(Affliction_NoHunger)) { throw new InvalidOperationException("Campfire.s_CampfireBuff failed structural self-check"); } FieldRef val = AccessTools.StaticFieldRefAccess(field); if (val == null) { throw new InvalidOperationException("Campfire.s_CampfireBuff getter creation failed"); } ScaleValidation.RequireStaticField(typeof(Character), "localCharacter", typeof(Character)); ScaleValidation.RequireStaticProperty(typeof(PlayerHandler), "Exists", typeof(bool)); ScaleValidation.RequireStaticMethod(typeof(PlayerHandler), "GetAllPlayerCharacters", typeof(List), Type.EmptyTypes, requirePublic: true); ScaleValidation.RequireInstanceField(typeof(Character), "data", typeof(CharacterData)); ScaleValidation.RequireInstanceField(typeof(Character), "refs", typeof(CharacterRefs)); ScaleValidation.RequireInstanceField(typeof(CharacterRefs), "afflictions", typeof(CharacterAfflictions)); ScaleValidation.RequireInstanceProperty(typeof(CharacterData), "dead", typeof(bool)); ScaleValidation.RequireInstanceProperty(typeof(Character), "Center", typeof(Vector3)); ScaleValidation.RequireInstanceProperty(typeof(CharacterAfflictions), "canGetHungry", typeof(bool)); ScaleValidation.RequireInstanceMethod(typeof(CharacterAfflictions), "AddAffliction", typeof(void), new Type[2] { typeof(Affliction), typeof(bool) }, requirePublic: true); ScaleValidation.RequireStaticProperty(typeof(Singleton), "Instance", typeof(OrbFogHandler)); ScaleValidation.RequireInstanceProperty(typeof(OrbFogHandler), "PlayersAreResting", typeof(bool)); FieldRef> obj = AccessTools.FieldRefAccess>(fieldInfo); FieldRef val2 = AccessTools.FieldRefAccess(fieldInfo2); if (obj == null || val2 == null) { throw new InvalidOperationException("CampfireProtectionMerge accessor creation failed"); } _charactersInRadius = obj; _timebuffLastApplied = val2; _campfireBuffGetter = val; } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(Campfire), "ApplyCampfireProtection", typeof(void), Type.EmptyTypes, requirePublic: false); } internal static void Reset() { _charactersInRadius = null; _timebuffLastApplied = null; _campfireBuffGetter = null; } internal static bool Prefix(Campfire __instance) { //IL_007f: 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) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) FieldRef> charactersInRadius = _charactersInRadius; FieldRef timebuffLastApplied = _timebuffLastApplied; FieldRef campfireBuffGetter = _campfireBuffGetter; Affliction val = null; if (campfireBuffGetter != null) { val = (Affliction)(object)campfireBuffGetter.Invoke(); } if (charactersInRadius == null || timebuffLastApplied == null || val == null) { RateLimitedDiagnostics.Hit("CampfireProtectionMerge.accessors-unavailable"); return true; } List list = charactersInRadius.Invoke(__instance); if (list == null) { RateLimitedDiagnostics.Hit("CampfireProtectionMerge.charactersInRadius-null"); return true; } bool playersAreResting = true; list.Clear(); if (PlayerHandler.Exists) { List allPlayerCharacters = PlayerHandler.GetAllPlayerCharacters(); if (allPlayerCharacters == null) { RateLimitedDiagnostics.Hit("CampfireProtectionMerge.roster-null"); return true; } Vector3 position = ((Component)__instance).transform.position; float moraleBoostRadius = __instance.moraleBoostRadius; for (int i = 0; i < allPlayerCharacters.Count; i++) { Character val2 = allPlayerCharacters[i]; if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.data == (Object)null) && !val2.data.dead) { if (!(Vector3.Distance(position, val2.Center) > moraleBoostRadius)) { list.Add(val2); } else { playersAreResting = false; } } } } OrbFogHandler instance = Singleton.Instance; if (Object.op_Implicit((Object)(object)instance)) { instance.PlayersAreResting = playersAreResting; } Character localCharacter = Character.localCharacter; bool flag = (Object)(object)localCharacter != (Object)null && list.Contains(localCharacter); if (!PlayerHandler.Exists || flag) { if ((Object)(object)localCharacter == (Object)null || localCharacter.refs == null) { RateLimitedDiagnostics.Hit("CampfireProtectionMerge.localCharacter-null"); return false; } CharacterAfflictions afflictions = localCharacter.refs.afflictions; if ((Object)(object)afflictions == (Object)null) { RateLimitedDiagnostics.Hit("CampfireProtectionMerge.afflictions-null"); return false; } if (afflictions.canGetHungry || Time.time - timebuffLastApplied.Invoke(__instance) > 2f) { afflictions.AddAffliction(val, false); timebuffLastApplied.Invoke(__instance) = Time.time; } } return false; } } internal sealed class CollisionCharacterLookupModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.CollisionCharacterLookup, () => new PatchDefinition(PatchId.CollisionCharacterLookup, CollisionCharacterLookupPatch.Initialize, CollisionCharacterLookupPatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(CollisionCharacterLookupPatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, CollisionCharacterLookupPatch.Reset)); } } internal static class CollisionCharacterLookupPatch { private const string CollisionTypeName = "UnityEngine.Collision"; private const string ColliderTypeName = "UnityEngine.Collider"; private const string RigidbodyTypeName = "UnityEngine.Rigidbody"; private const string CapsuleColliderTypeName = "UnityEngine.CapsuleCollider"; private static FieldRef _character; private static Func _hasRigidbody; private static Func _tryGetCharacter; internal static void Initialize() { MethodInfo methodInfo = ResolveAndValidateTarget(); FieldInfo fieldInfo = ScaleValidation.RequireInstanceField(typeof(CharacterMovement), "character", typeof(Character)); ScaleValidation.RequireInstanceField(typeof(Character), "data", typeof(CharacterData)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "sincePalJump", typeof(float)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "isCrouching", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "sinceStandOnPlayer", typeof(float)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "lastStoodOnPlayer", typeof(Character)); Type parameterType = methodInfo.GetParameters()[0].ParameterType; if (!string.Equals(parameterType.FullName, "UnityEngine.Collision", StringComparison.Ordinal)) { throw new InvalidOperationException("CharacterMovement.StandOnPlayer collision type mismatch"); } PropertyInfo propertyInfo = ScaleValidation.RequireInstancePropertyByTypeName(parameterType, "collider", "UnityEngine.Collider", requireSetter: false); PropertyInfo propertyInfo2 = ScaleValidation.RequireInstancePropertyByTypeName(parameterType, "rigidbody", "UnityEngine.Rigidbody", requireSetter: false); Type propertyType = propertyInfo.PropertyType; Type fieldType = typeof(Dictionary<, >).MakeGenericType(propertyType, typeof(Character)); MethodInfo tryGetCharacter = ScaleValidation.RequireStaticMethod(typeof(CharacterRagdoll), "TryGetCharacterFromCollider", typeof(bool), new Type[2] { propertyType, typeof(Character).MakeByRefType() }, requirePublic: true); ScaleValidation.RequireStaticField(typeof(CharacterRagdoll), "COLLIDERS_TO_CHARACTERS", fieldType); ScaleValidation.RequireInstanceField(typeof(CharacterRagdoll), "partList", typeof(List)); ScaleValidation.RequireInstanceField(typeof(CharacterRagdoll), "character", typeof(Character)); ScaleValidation.RequireInstanceMethod(typeof(CharacterRagdoll), "Start", typeof(void), Type.EmptyTypes, requirePublic: false); ScaleValidation.RequireInstanceMethod(typeof(CharacterRagdoll), "RegisterBodypartColliders", typeof(void), Type.EmptyTypes, requirePublic: false); ScaleValidation.RequireInstanceField(typeof(Bodypart), "colliders", typeof(List)); MethodInfo methodInfo2 = ScaleValidation.RequireInstanceMethodByTypeNames(typeof(RigCreatorCollider), "Col", "UnityEngine.CapsuleCollider", Array.Empty()); if (!propertyType.IsAssignableFrom(methodInfo2.ReturnType)) { throw new InvalidOperationException("RigCreatorCollider.Col is not a Collider"); } FieldRef obj = AccessTools.FieldRefAccess(fieldInfo); Func func = EmitHasRigidbody(parameterType, propertyInfo2.GetGetMethod(nonPublic: true)); Func func2 = EmitCharacterLookup(parameterType, propertyInfo.GetGetMethod(nonPublic: true), tryGetCharacter); if (obj == null || func == null || func2 == null) { throw new InvalidOperationException("CollisionCharacterLookup accessor creation failed"); } _character = obj; _hasRigidbody = func; _tryGetCharacter = func2; } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethodByTypeNames(typeof(CharacterMovement), "StandOnPlayer", typeof(bool).FullName, new string[1] { "UnityEngine.Collision" }); } internal static void Reset() { _character = null; _hasRigidbody = null; _tryGetCharacter = null; } internal static bool Prefix(CharacterMovement __instance, object collision, ref bool __result) { FieldRef character = _character; Func hasRigidbody = _hasRigidbody; Func tryGetCharacter = _tryGetCharacter; if (character == null || hasRigidbody == null || tryGetCharacter == null) { return true; } Character val = character.Invoke(__instance); if ((Object)(object)val == (Object)null || (Object)(object)val.data == (Object)null || collision == null) { return true; } CharacterData data = val.data; if (data.sincePalJump < 0.5f || data.isCrouching) { __result = false; return false; } if (!hasRigidbody(collision)) { __result = false; return false; } Character val2 = tryGetCharacter(collision); if ((Object)(object)val2 == (Object)null || (Object)(object)val2.data == (Object)null) { return true; } if ((Object)(object)val2 == (Object)(object)val || !val2.data.isCrouching) { __result = false; return false; } data.sinceStandOnPlayer = 0f; data.lastStoodOnPlayer = val2; __result = true; return false; } private static Func EmitHasRigidbody(Type collisionType, MethodInfo rigidbodyGetter) { if (rigidbodyGetter == null || rigidbodyGetter.IsStatic) { throw new MissingMethodException("UnityEngine.Collision", "get_rigidbody"); } DynamicMethod dynamicMethod = new DynamicMethod("PSO_CollisionHasRigidbody", typeof(bool), new Type[1] { typeof(object) }, typeof(CollisionCharacterLookupPatch).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Castclass, collisionType); iLGenerator.Emit(OpCodes.Callvirt, rigidbodyGetter); iLGenerator.Emit(OpCodes.Ldnull); iLGenerator.Emit(OpCodes.Call, ResolveUnityObjectInequality()); iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } private static Func EmitCharacterLookup(Type collisionType, MethodInfo colliderGetter, MethodInfo tryGetCharacter) { if (colliderGetter == null || colliderGetter.IsStatic) { throw new MissingMethodException("UnityEngine.Collision", "get_collider"); } DynamicMethod dynamicMethod = new DynamicMethod("PSO_CollisionCharacterLookup", typeof(Character), new Type[1] { typeof(object) }, typeof(CollisionCharacterLookupPatch).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); LocalBuilder local = iLGenerator.DeclareLocal(typeof(Character)); Label label = iLGenerator.DefineLabel(); Label label2 = iLGenerator.DefineLabel(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Castclass, collisionType); iLGenerator.Emit(OpCodes.Callvirt, colliderGetter); iLGenerator.Emit(OpCodes.Dup); iLGenerator.Emit(OpCodes.Ldnull); iLGenerator.Emit(OpCodes.Call, ResolveUnityObjectInequality()); iLGenerator.Emit(OpCodes.Brfalse_S, label2); iLGenerator.Emit(OpCodes.Ldloca_S, local); iLGenerator.Emit(OpCodes.Call, tryGetCharacter); iLGenerator.Emit(OpCodes.Brtrue_S, label); iLGenerator.Emit(OpCodes.Ldnull); iLGenerator.Emit(OpCodes.Ret); iLGenerator.MarkLabel(label2); iLGenerator.Emit(OpCodes.Pop); iLGenerator.Emit(OpCodes.Ldnull); iLGenerator.Emit(OpCodes.Ret); iLGenerator.MarkLabel(label); iLGenerator.Emit(OpCodes.Ldloc, local); iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } private static MethodInfo ResolveUnityObjectInequality() { MethodInfo method = typeof(Object).GetMethod("op_Inequality", BindingFlags.Static | BindingFlags.Public, null, new Type[2] { typeof(Object), typeof(Object) }, null); if (method == null || method.ReturnType != typeof(bool)) { throw new MissingMethodException("UnityEngine.Object", "op_Inequality"); } return method; } } internal sealed class CollisionContactsNoAllocModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.CollisionContactsNoAlloc, () => new PatchDefinition(PatchId.CollisionContactsNoAlloc, CollisionContactsNoAllocPatch.Initialize, CollisionContactsNoAllocPatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(CollisionContactsNoAllocPatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, CollisionContactsNoAllocPatch.Reset)); } } internal static class CollisionContactsNoAllocPatch { private const string RocketRpcName = "RocketExplodeRPC"; private static FieldRef _character; private static FieldRef _rocketActive; private static FieldRef _currentRocketTime; private static Func _standOnPlayer; private static Func _standableRig; private static Func _doGroundChecks; private static Func _acceptableAngle; private static Func _canStand; internal static void Initialize() { ResolveAndValidateTarget(); FieldInfo fieldInfo = ScaleValidation.RequireInstanceField(typeof(CharacterMovement), "character", typeof(Character)); FieldInfo fieldInfo2 = ScaleValidation.RequireInstanceField(typeof(CharacterMovement), "rocketActive", typeof(bool)); FieldInfo fieldInfo3 = ScaleValidation.RequireInstanceField(typeof(CharacterMovement), "_currentRocketTime", typeof(float)); MethodInfo methodInfo = ScaleValidation.RequireInstanceMethod(typeof(CharacterMovement), "StandOnPlayer", typeof(bool), new Type[1] { typeof(Collision) }, requirePublic: false); MethodInfo methodInfo2 = ScaleValidation.RequireInstanceMethod(typeof(CharacterMovement), "StandableRig", typeof(bool), new Type[1] { typeof(Rigidbody) }, requirePublic: false); MethodInfo methodInfo3 = ScaleValidation.RequireInstanceMethod(typeof(CharacterMovement), "DoGroundChecks", typeof(bool), Type.EmptyTypes, requirePublic: false); MethodInfo methodInfo4 = ScaleValidation.RequireInstanceMethod(typeof(CharacterMovement), "AcceptableAngle", typeof(bool), new Type[1] { typeof(float) }, requirePublic: false); MethodInfo methodInfo5 = ScaleValidation.RequireInstanceMethod(typeof(CollisionModifier), "CanStand", typeof(bool), new Type[1] { typeof(Character) }, requirePublic: false); ScaleValidation.RequireInstanceMethod(typeof(CharacterMovement), "AddGroundSample", typeof(void), new Type[1] { typeof(PlayerGroundSample) }, requirePublic: true); ScaleValidation.RequireInstanceMethod(typeof(CharacterMovement), "AddGroundSample_All", typeof(void), new Type[1] { typeof(PlayerGroundSample) }, requirePublic: true); ScaleValidation.RequireInstanceMethod(typeof(CollisionModifier), "Collide", typeof(void), new Type[4] { typeof(Character), typeof(ContactPoint), typeof(Collision), typeof(Bodypart) }, requirePublic: true); ScaleValidation.RequireInstanceField(typeof(CollisionModifier), "standable", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(Character), "refs", typeof(CharacterRefs)); ScaleValidation.RequireInstanceField(typeof(CharacterRefs), "view", typeof(PhotonView)); ScaleValidation.RequireInstanceProperty(typeof(Character), "IsLocal", typeof(bool)); RequireRocketRpc(); RequireGroundSampleShape(); FieldRef obj = AccessTools.FieldRefAccess(fieldInfo); FieldRef val = AccessTools.FieldRefAccess(fieldInfo2); FieldRef val2 = AccessTools.FieldRefAccess(fieldInfo3); Func func = (Func)methodInfo.CreateDelegate(typeof(Func)); Func func2 = (Func)methodInfo2.CreateDelegate(typeof(Func)); Func func3 = (Func)methodInfo3.CreateDelegate(typeof(Func)); Func func4 = (Func)methodInfo4.CreateDelegate(typeof(Func)); Func func5 = (Func)methodInfo5.CreateDelegate(typeof(Func)); if (obj == null || val == null || val2 == null || func == null || func2 == null || func3 == null || func4 == null || func5 == null) { throw new InvalidOperationException("CollisionContactsNoAlloc accessor creation failed"); } _character = obj; _rocketActive = val; _currentRocketTime = val2; _standOnPlayer = func; _standableRig = func2; _doGroundChecks = func3; _acceptableAngle = func4; _canStand = func5; } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(CharacterMovement), "OnCollision", typeof(void), new Type[3] { typeof(Collision), typeof(bool), typeof(Bodypart) }, requirePublic: false); } internal static void Reset() { _character = null; _rocketActive = null; _currentRocketTime = null; _standOnPlayer = null; _standableRig = null; _doGroundChecks = null; _acceptableAngle = null; _canStand = null; } internal static bool Prefix(CharacterMovement __instance, Collision collision, bool collisionEnter, Bodypart bodypart) { //IL_007f: 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) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) FieldRef character = _character; Func standOnPlayer = _standOnPlayer; Func standableRig = _standableRig; Func doGroundChecks = _doGroundChecks; Func acceptableAngle = _acceptableAngle; Func canStand = _canStand; if (character == null || standOnPlayer == null || standableRig == null || doGroundChecks == null || acceptableAngle == null || canStand == null || (Object)(object)__instance == (Object)null || collision == null) { return true; } Character val = character.Invoke(__instance); if ((Object)(object)val == (Object)null) { return true; } Collider collider = collision.collider; if ((Object)(object)collider == (Object)null) { return true; } if (collision.contactCount <= 0) { return true; } ContactPoint contact = collision.GetContact(0); CollisionModifier component = ((Component)collider).GetComponent(); if ((Object)(object)component != (Object)null) { component.Collide(val, contact, collision, bodypart); if (!component.standable || !canStand(component, val)) { return false; } } bool flag = false; if (standOnPlayer(__instance, collision)) { flag = true; } else if (!standableRig(__instance, collision.rigidbody)) { return false; } if (_rocketActive.Invoke(__instance) && _currentRocketTime.Invoke(__instance) > 1f && val.IsLocal) { PhotonView val2 = val.refs?.view; if ((Object)(object)val2 == (Object)null) { RateLimitedDiagnostics.Hit("CollisionContactsNoAlloc.rocket-view-unavailable"); return true; } val2.RPC("RocketExplodeRPC", (RpcTarget)0, Array.Empty()); _rocketActive.Invoke(__instance) = false; } float arg = Vector3.Angle(Vector3.up, ((ContactPoint)(ref contact)).normal); if (doGroundChecks(__instance)) { if (acceptableAngle(__instance, arg) || flag) { __instance.AddGroundSample(new PlayerGroundSample(((ContactPoint)(ref contact)).point, ((ContactPoint)(ref contact)).normal)); } __instance.AddGroundSample_All(new PlayerGroundSample(((ContactPoint)(ref contact)).point, ((ContactPoint)(ref contact)).normal)); } return false; } private static void RequireRocketRpc() { MethodInfo method = typeof(CharacterMovement).GetMethod("RocketExplodeRPC", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (method == null || method.ReturnType != typeof(void) || method.GetParameters().Length != 0) { throw new MissingMethodException(typeof(CharacterMovement).FullName, "RocketExplodeRPC"); } if (((MemberInfo)method).GetCustomAttribute() == null) { throw new InvalidOperationException("CharacterMovement.RocketExplodeRPC is no longer a PunRPC"); } } private static void RequireGroundSampleShape() { Type typeFromHandle = typeof(PlayerGroundSample); if (!typeFromHandle.IsValueType) { throw new InvalidOperationException("PlayerGroundSample is no longer a struct"); } if (typeFromHandle.GetConstructor(BindingFlags.Instance | BindingFlags.Public, null, new Type[2] { typeof(Vector3), typeof(Vector3) }, null) == null) { throw new MissingMethodException(typeFromHandle.FullName, ".ctor(Vector3, Vector3)"); } ScaleValidation.RequireInstanceField(typeFromHandle, "point", typeof(Vector3)); ScaleValidation.RequireInstanceField(typeFromHandle, "normal", typeof(Vector3)); ScaleValidation.RequireInstanceField(typeFromHandle, "IsValid", typeof(bool)); } } internal sealed class GenericOptimizerRangeModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.GenericOptimizerRange, () => new PatchDefinition(PatchId.GenericOptimizerRange, GenericOptimizerRangePatch.Initialize, GenericOptimizerRangePatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(GenericOptimizerRangePatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, GenericOptimizerRangePatch.Reset)); } } internal static class GenericOptimizerRangePatch { internal static void Initialize() { ResolveAndValidateTarget(); ScaleValidation.RequireStaticField(typeof(Character), "AllCharacters", typeof(List)); ScaleValidation.RequireInstanceField(typeof(Character), "data", typeof(CharacterData)); ScaleValidation.RequireInstanceProperty(typeof(CharacterData), "dead", typeof(bool)); ScaleValidation.RequireInstanceProperty(typeof(Character), "Center", typeof(Vector3)); ScaleValidation.RequireInstanceField(typeof(GenericOptimizer), "rangeToDisableScripts", typeof(float)); ScaleValidation.RequireInstanceProperty(typeof(GenericOptimizer), "transform", typeof(Transform)); ScaleValidation.RequireStaticMethod(typeof(Vector3), "Distance", typeof(float), new Type[2] { typeof(Vector3), typeof(Vector3) }, requirePublic: true); } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(GenericOptimizer), "AnyCharacterWithinRange", typeof(bool), new Type[1] { typeof(float) }, requirePublic: true); } internal static void Reset() { } internal static bool Prefix(GenericOptimizer __instance, float range, ref bool __result) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: 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) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) if (!(range >= 0f)) { RateLimitedDiagnostics.Hit("GenericOptimizerRange.non-positive-range-fallback"); return true; } List allCharacters = Character.AllCharacters; if (allCharacters == null) { RateLimitedDiagnostics.Hit("GenericOptimizerRange.allCharacters-null"); return true; } Transform transform = ((Component)__instance).transform; if ((Object)(object)transform == (Object)null) { RateLimitedDiagnostics.Hit("GenericOptimizerRange.transform-null"); return true; } Vector3 position = transform.position; bool flag = float.IsPositiveInfinity(range); float num = range * range; if (!flag && range > 0f && (!(num > 0f) || float.IsInfinity(num))) { return true; } for (int i = 0; i < allCharacters.Count; i++) { Character val = allCharacters[i]; if ((Object)(object)val == (Object)null) { continue; } CharacterData data = val.data; if ((Object)(object)data == (Object)null || data.dead) { continue; } if (flag) { if (Vector3.Distance(val.Center, position) < range) { __result = true; return false; } continue; } Vector3 val2 = val.Center - position; if (((Vector3)(ref val2)).sqrMagnitude < num) { __result = true; return false; } } __result = false; return false; } } internal sealed class HeatEmissionScanModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.HeatEmissionScan, () => new PatchDefinition(PatchId.HeatEmissionScan, HeatEmissionScanPatch.Initialize, HeatEmissionScanPatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(HeatEmissionScanPatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, HeatEmissionScanPatch.Reset)); } } internal static class HeatEmissionScanPatch { private static FieldRef _character; private static FieldRef _counter; private static FieldRef _afflictionsCharacter; private static bool _ownerShortCircuitProven; internal static void Initialize() { ResolveAndValidateTarget(); FieldInfo fieldInfo = ScaleValidation.RequireInstanceField(typeof(CharacterHeatEmission), "character", typeof(Character)); FieldInfo fieldInfo2 = ScaleValidation.RequireInstanceField(typeof(CharacterHeatEmission), "counter", typeof(float)); ScaleValidation.RequireInstanceField(typeof(CharacterHeatEmission), "radius", typeof(float)); ScaleValidation.RequireInstanceField(typeof(CharacterHeatEmission), "heatAmount", typeof(float)); ScaleValidation.RequireInstanceField(typeof(CharacterHeatEmission), "rate", typeof(float)); ScaleValidation.RequireInstanceField(typeof(Character), "refs", typeof(CharacterRefs)); ScaleValidation.RequireInstanceField(typeof(Character), "data", typeof(CharacterData)); ScaleValidation.RequireInstanceField(typeof(CharacterRefs), "hip", typeof(Bodypart)); ScaleValidation.RequireInstanceField(typeof(CharacterRefs), "afflictions", typeof(CharacterAfflictions)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "sinceAddedCold", typeof(float)); ScaleValidation.RequireStaticField(typeof(Character), "AllCharacters", typeof(List)); ScaleValidation.RequireInstanceProperty(typeof(Character), "Center", typeof(Vector3)); ScaleValidation.RequireInheritedInstanceProperty(typeof(Bodypart), "transform", typeof(Transform)); ScaleValidation.RequireInstanceMethod(typeof(CharacterAfflictions), "SubtractStatus", typeof(void), new Type[4] { typeof(STATUSTYPE), typeof(float), typeof(bool), typeof(bool) }, requirePublic: true); FieldRef val = AccessTools.FieldRefAccess(fieldInfo); FieldRef val2 = AccessTools.FieldRefAccess(fieldInfo2); if (val == null || val2 == null) { throw new InvalidOperationException("HeatEmissionScan FieldRef creation failed"); } _ownerShortCircuitProven = false; _afflictionsCharacter = null; try { FieldRef val3 = AccessTools.FieldRefAccess(ScaleValidation.RequireInstanceField(typeof(CharacterAfflictions), "character", typeof(Character))); if (val3 != null) { _afflictionsCharacter = val3; _ownerShortCircuitProven = true; } } catch (Exception) { _ownerShortCircuitProven = false; _afflictionsCharacter = null; } _character = val; _counter = val2; } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(CharacterHeatEmission), "Update", typeof(void), Type.EmptyTypes, requirePublic: true); } internal static void Reset() { _character = null; _counter = null; _afflictionsCharacter = null; _ownerShortCircuitProven = false; } internal static bool Prefix(CharacterHeatEmission __instance) { //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0158: 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_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) FieldRef character = _character; FieldRef counter = _counter; if (character == null || counter == null) { RateLimitedDiagnostics.Hit("HeatEmissionScan.accessors-unavailable"); return true; } Character val = character.Invoke(__instance); if ((Object)(object)val == (Object)null) { RateLimitedDiagnostics.Hit("HeatEmissionScan.character-null"); return true; } CharacterRefs refs = val.refs; Bodypart val2 = refs?.hip; CharacterData data = val.data; if (refs == null || (Object)(object)val2 == (Object)null || (Object)(object)data == (Object)null) { RateLimitedDiagnostics.Hit("HeatEmissionScan.owner-refs-incomplete"); return true; } List allCharacters = Character.AllCharacters; if (allCharacters == null) { RateLimitedDiagnostics.Hit("HeatEmissionScan.allCharacters-null"); return true; } Transform transform = ((Component)__instance).transform; Transform transform2 = val2.transform; if ((Object)(object)transform == (Object)null || (Object)(object)transform2 == (Object)null) { RateLimitedDiagnostics.Hit("HeatEmissionScan.transform-null"); return true; } float radius = __instance.radius; float num = radius * radius; if (radius > 0f && (!(num > 0f) || float.IsInfinity(num))) { RateLimitedDiagnostics.Hit("HeatEmissionScan.radius-out-of-square-range"); return true; } transform.position = transform2.position; if (data.sinceAddedCold < 3f) { return false; } float num2 = counter.Invoke(__instance) + Time.deltaTime; if (num2 < __instance.rate) { counter.Invoke(__instance) = num2; return false; } counter.Invoke(__instance) = 0f; if (!(radius > 0f)) { return false; } Vector3 position = transform.position; float heatAmount = __instance.heatAmount; bool ownerShortCircuitProven = _ownerShortCircuitProven; FieldRef afflictionsCharacter = _afflictionsCharacter; for (int i = 0; i < allCharacters.Count; i++) { Character val3 = allCharacters[i]; if ((Object)(object)val3 == (Object)null) { continue; } Vector3 val4 = position - val3.Center; if (((Vector3)(ref val4)).sqrMagnitude < num) { CharacterAfflictions val5 = val3.refs?.afflictions; if (!((Object)(object)val5 == (Object)null) && (!ownerShortCircuitProven || afflictionsCharacter == null || !((Object)(object)afflictionsCharacter.Invoke(val5) == (Object)(object)val3) || ((MonoBehaviourPun)val3).photonView.IsMine)) { val5.SubtractStatus((STATUSTYPE)2, heatAmount, false, false); } } } return false; } } internal sealed class IsLookedAtScanModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.IsLookedAtScan, () => new PatchDefinition(PatchId.IsLookedAtScan, IsLookedAtScanPatch.Initialize, IsLookedAtScanPatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(IsLookedAtScanPatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, IsLookedAtScanPatch.Reset)); } } internal static class IsLookedAtScanPatch { private static FieldRef _index; internal static void Initialize() { ResolveAndValidateTarget(); Type? typeFromHandle = typeof(IsLookedAt); FieldInfo fieldInfo = ScaleValidation.RequireInstanceField(typeFromHandle, "index", typeof(int)); ScaleValidation.RequireInstanceField(typeFromHandle, "mouth", typeof(AnimatedMouth)); ScaleValidation.RequireInstanceField(typeFromHandle, "visibleDistance", typeof(float)); ScaleValidation.RequireInstanceField(typeFromHandle, "visibleAngle", typeof(float)); ScaleValidation.RequireInstanceField(typeFromHandle, "angleDistRatio", typeof(float)); ScaleValidation.RequireInstanceField(typeFromHandle, "playerNamePos", typeof(Transform)); ScaleValidation.RequireStaticField(typeof(MainCamera), "instance", typeof(MainCamera)); ScaleValidation.RequireInstanceField(typeof(AnimatedMouth), "character", typeof(Character)); ScaleValidation.RequireInstanceField(typeof(AnimatedMouth), "amplitudeIndex", typeof(int)); ScaleValidation.RequireInstanceField(typeof(Character), "data", typeof(CharacterData)); ScaleValidation.RequireInstanceField(typeof(Character), "refs", typeof(CharacterRefs)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "isBlind", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(CharacterRefs), "afflictions", typeof(CharacterAfflictions)); ScaleValidation.RequireInstanceProperty(typeof(CharacterAfflictions), "isStruggling", typeof(bool)); ScaleValidation.RequireStaticField(typeof(GUIManager), "instance", typeof(GUIManager)); ScaleValidation.RequireInstanceField(typeof(GUIManager), "playerNames", typeof(UIPlayerNames)); ScaleValidation.RequireInstanceMethod(typeof(UIPlayerNames), "UpdateName", typeof(void), new Type[4] { typeof(int), typeof(Vector3), typeof(bool), typeof(int) }, requirePublic: true); _index = AccessTools.FieldRefAccess(fieldInfo) ?? throw new InvalidOperationException("IsLookedAtScan accessor creation failed"); } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(IsLookedAt), "Update", typeof(void), Type.EmptyTypes, requirePublic: false); } internal static void Reset() { _index = null; } internal static bool Prefix(IsLookedAt __instance) { //IL_00e8: 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_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: 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_016c: Unknown result type (might be due to invalid IL or missing references) FieldRef index = _index; if (index == null) { RateLimitedDiagnostics.Hit("IsLookedAtScan.accessors-unavailable"); return true; } MainCamera instance = MainCamera.instance; if ((Object)(object)instance == (Object)null) { RateLimitedDiagnostics.Hit("IsLookedAtScan.camera-null"); return true; } AnimatedMouth mouth = __instance.mouth; if ((Object)(object)mouth == (Object)null) { RateLimitedDiagnostics.Hit("IsLookedAtScan.mouth-null"); return true; } Character character = mouth.character; if ((Object)(object)character == (Object)null) { RateLimitedDiagnostics.Hit("IsLookedAtScan.character-null"); return true; } CharacterRefs refs = character.refs; if (refs == null) { RateLimitedDiagnostics.Hit("IsLookedAtScan.refs-null"); return true; } Transform playerNamePos = __instance.playerNamePos; if ((Object)(object)playerNamePos == (Object)null) { RateLimitedDiagnostics.Hit("IsLookedAtScan.playerNamePos-null"); return true; } GUIManager instance2 = GUIManager.instance; if ((Object)(object)instance2 == (Object)null) { RateLimitedDiagnostics.Hit("IsLookedAtScan.gui-null"); return true; } UIPlayerNames playerNames = instance2.playerNames; if ((Object)(object)playerNames == (Object)null) { RateLimitedDiagnostics.Hit("IsLookedAtScan.playerNames-null"); return true; } Transform transform = ((Component)instance).transform; Vector3 val = ((Component)__instance).transform.position - transform.position; bool flag = false; float magnitude = ((Vector3)(ref val)).magnitude; if (magnitude < __instance.visibleDistance && Vector3.Angle(transform.forward, val) < __instance.visibleAngle + (__instance.visibleDistance - magnitude) / __instance.visibleDistance * __instance.angleDistRatio) { flag = true; } if (character.data.isBlind || refs.afflictions.isStruggling) { flag = false; } playerNames.UpdateName(index.Invoke(__instance), playerNamePos.position, flag, mouth.amplitudeIndex); return false; } } internal sealed class ItemAudioManagerHashModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.ItemAudioManagerHash, () => new PatchDefinition(PatchId.ItemAudioManagerHash, ItemAudioManagerHashPatch.Initialize, ItemAudioManagerHashPatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(ItemAudioManagerHashPatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, ItemAudioManagerHashPatch.Reset)); } } internal static class ItemAudioManagerHashPatch { private sealed class HashBox { internal int Hash; } private static FieldRef _character; private static FieldRef _prevUse; private static FieldRef _prevItem; private static Func _getAnimator; private static Func _getThrowCharge; private static Func _stringToHash; private static Action _setBool; private static Func _getBool; private static Func _getVolume; private static Action _setVolume; private static Func _getPitch; private static Action _setPitch; private static int _eatHash; private static int _healHash; private static int _drinkHash; private static int _antidoteHash; private static int _consumedItemHash; private static ConditionalWeakTable _hashCache; internal static void Initialize() { ResolveAndValidateTarget(); FieldInfo fieldInfo = ScaleValidation.RequireInstanceField(typeof(ItemAudioManager), "character", typeof(Character)); FieldInfo fieldInfo2 = ScaleValidation.RequireInstanceField(typeof(ItemAudioManager), "prevUse", typeof(string)); FieldInfo fieldInfo3 = ScaleValidation.RequireInstanceField(typeof(ItemAudioManager), "prevItem", typeof(Item)); ScaleValidation.RequireInstanceField(typeof(ItemAudioManager), "finishTimer", typeof(float)); ScaleValidation.RequireInstanceField(typeof(ItemAudioManager), "switchGeneric", typeof(SFX_Instance[])); FieldInfo fieldInfo4 = ScaleValidation.RequireInstanceFieldByTypeName(typeof(ItemAudioManager), "throwCharge", "UnityEngine.AudioSource"); ScaleValidation.RequireInstanceField(typeof(Character), "refs", typeof(CharacterRefs)); ScaleValidation.RequireInstanceField(typeof(Character), "data", typeof(CharacterData)); FieldInfo fieldInfo5 = ScaleValidation.RequireInstanceFieldByTypeName(typeof(CharacterRefs), "animator", "UnityEngine.Animator"); ScaleValidation.RequireInstanceField(typeof(CharacterRefs), "items", typeof(CharacterItems)); ScaleValidation.RequireInstanceField(typeof(CharacterItems), "throwChargeLevel", typeof(float)); ScaleValidation.RequireInstanceProperty(typeof(CharacterData), "currentItem", typeof(Item)); ScaleValidation.RequireInstanceProperty(typeof(Item), "isUsingPrimary", typeof(bool)); ScaleValidation.RequireInstanceProperty(typeof(Item), "castProgress", typeof(float)); ScaleValidation.RequireInstanceField(typeof(ItemUseFeedback), "useAnimation", typeof(string)); ScaleValidation.RequireInstanceField(typeof(ItemUseFeedback), "equip", typeof(SFX_Instance[])); ScaleValidation.RequireInstanceMethod(typeof(SFX_Instance), "Play", typeof(void), new Type[1] { typeof(Vector3) }, requirePublic: true); Type fieldType = fieldInfo5.FieldType; MethodInfo method = fieldType.GetMethod("StringToHash", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(string) }, null); if (method == null || method.ReturnType != typeof(int) || !method.IsStatic) { throw new MissingMethodException("UnityEngine.Animator", "StringToHash"); } MethodInfo method2 = fieldType.GetMethod("SetBool", BindingFlags.Instance | BindingFlags.Public, null, new Type[2] { typeof(int), typeof(bool) }, null); if (method2 == null || method2.ReturnType != typeof(void) || method2.IsStatic) { throw new MissingMethodException("UnityEngine.Animator", "SetBool(int, bool)"); } MethodInfo method3 = fieldType.GetMethod("GetBool", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(int) }, null); if (method3 == null || method3.ReturnType != typeof(bool) || method3.IsStatic) { throw new MissingMethodException("UnityEngine.Animator", "GetBool(int)"); } Type fieldType2 = fieldInfo4.FieldType; PropertyInfo property = fieldType2.GetProperty("volume", BindingFlags.Instance | BindingFlags.Public); PropertyInfo property2 = fieldType2.GetProperty("pitch", BindingFlags.Instance | BindingFlags.Public); if (property == null || property.PropertyType != typeof(float) || property.GetGetMethod(nonPublic: false) == null || property.GetSetMethod(nonPublic: false) == null) { throw new MissingMethodException("UnityEngine.AudioSource", "volume"); } if (property2 == null || property2.PropertyType != typeof(float) || property2.GetGetMethod(nonPublic: false) == null || property2.GetSetMethod(nonPublic: false) == null) { throw new MissingMethodException("UnityEngine.AudioSource", "pitch"); } FieldRef obj = AccessTools.FieldRefAccess(fieldInfo); FieldRef val = AccessTools.FieldRefAccess(fieldInfo2); FieldRef val2 = AccessTools.FieldRefAccess(fieldInfo3); Func func = ScaleEmit.CreateUnityObjectFieldGetter(fieldInfo5); Func func2 = ScaleEmit.CreateUnityObjectFieldGetter(fieldInfo4); Func func3 = (Func)method.CreateDelegate(typeof(Func)); Action action = EmitSetBool(fieldType, method2); Func func4 = EmitGetBool(fieldType, method3); Func func5 = EmitPropertyGetter(fieldType2, property.GetGetMethod(nonPublic: false), "volume"); Action action2 = EmitPropertySetter(fieldType2, property.GetSetMethod(nonPublic: false), "volume"); Func func6 = EmitPropertyGetter(fieldType2, property2.GetGetMethod(nonPublic: false), "pitch"); Action action3 = EmitPropertySetter(fieldType2, property2.GetSetMethod(nonPublic: false), "pitch"); if (obj == null || val == null || val2 == null || func == null || func2 == null || func3 == null || action == null || func4 == null || func5 == null || action2 == null || func6 == null || action3 == null) { throw new InvalidOperationException("ItemAudioManagerHash accessor creation failed"); } _character = obj; _prevUse = val; _prevItem = val2; _getAnimator = func; _getThrowCharge = func2; _stringToHash = func3; _setBool = action; _getBool = func4; _getVolume = func5; _setVolume = action2; _getPitch = func6; _setPitch = action3; _eatHash = func3("Eat"); _healHash = func3("Heal"); _drinkHash = func3("Drink"); _antidoteHash = func3("Antidote"); _consumedItemHash = func3("Consumed Item"); _hashCache = new ConditionalWeakTable(); } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(ItemAudioManager), "Update", typeof(void), Type.EmptyTypes, requirePublic: false); } internal static void Reset() { _character = null; _prevUse = null; _prevItem = null; _getAnimator = null; _getThrowCharge = null; _stringToHash = null; _setBool = null; _getBool = null; _getVolume = null; _setVolume = null; _getPitch = null; _setPitch = null; _hashCache = null; } internal static bool Prefix(ItemAudioManager __instance) { //IL_047f: Unknown result type (might be due to invalid IL or missing references) //IL_038c: Unknown result type (might be due to invalid IL or missing references) //IL_03d6: Unknown result type (might be due to invalid IL or missing references) FieldRef character = _character; FieldRef prevUse = _prevUse; FieldRef prevItem = _prevItem; Func getAnimator = _getAnimator; Func getThrowCharge = _getThrowCharge; Func stringToHash = _stringToHash; Action setBool = _setBool; Func getBool = _getBool; Func getVolume = _getVolume; Action setVolume = _setVolume; Func getPitch = _getPitch; Action setPitch = _setPitch; ConditionalWeakTable hashCache = _hashCache; if (character == null || prevUse == null || prevItem == null || getAnimator == null || getThrowCharge == null || stringToHash == null || setBool == null || getBool == null || getVolume == null || setVolume == null || getPitch == null || setPitch == null || hashCache == null) { RateLimitedDiagnostics.Hit("ItemAudioManagerHash.accessors-unavailable"); return true; } Character val = character.Invoke(__instance); if ((Object)(object)val == (Object)null) { RateLimitedDiagnostics.Hit("ItemAudioManagerHash.character-null"); return true; } CharacterRefs refs = val.refs; if (refs == null) { RateLimitedDiagnostics.Hit("ItemAudioManagerHash.refs-null"); return true; } Object val2 = getAnimator(refs); if (val2 == (Object)null) { RateLimitedDiagnostics.Hit("ItemAudioManagerHash.animator-null"); return true; } Object val3 = getThrowCharge(__instance); if (val3 == (Object)null) { RateLimitedDiagnostics.Hit("ItemAudioManagerHash.throwCharge-null"); return true; } int eatHash = _eatHash; int healHash = _healHash; int drinkHash = _drinkHash; int antidoteHash = _antidoteHash; int consumedItemHash = _consumedItemHash; if (getBool(val2, eatHash)) { setBool(val2, eatHash, arg3: false); } if (getBool(val2, healHash)) { setBool(val2, healHash, arg3: false); } if (getBool(val2, drinkHash)) { setBool(val2, drinkHash, arg3: false); } if (getBool(val2, antidoteHash)) { setBool(val2, antidoteHash, arg3: false); } float deltaTime = Time.deltaTime; float num = getVolume(val3); float num2 = Mathf.Lerp(num, 0f, deltaTime * 5f); if (num2 != num) { setVolume(val3, num2); } float num3 = getPitch(val3); float num4 = Mathf.Lerp(num3, 1f, deltaTime * 5f); if (num4 != num3) { setPitch(val3, num4); } string text = prevUse.Invoke(__instance); bool flag = !string.IsNullOrEmpty(text); int arg = 0; if (flag) { arg = GetStringHash(hashCache, stringToHash, text); } if (flag && getBool(val2, arg)) { setBool(val2, arg, arg3: false); } Item currentItem = val.data.currentItem; if (!Object.op_Implicit((Object)(object)currentItem) && flag && getBool(val2, arg)) { setBool(val2, arg, arg3: false); } if (getBool(val2, consumedItemHash)) { __instance.finishTimer -= deltaTime; } else { __instance.finishTimer = 0.25f; } if (__instance.finishTimer <= 0f && getBool(val2, consumedItemHash)) { setBool(val2, consumedItemHash, arg3: false); } if (Object.op_Implicit((Object)(object)currentItem)) { float throwChargeLevel = val.refs.items.throwChargeLevel; if (throwChargeLevel > 0f) { float num5 = getVolume(val3); float num6 = Mathf.Lerp(num5, 0.3f, deltaTime * 10f); if (num6 != num5) { setVolume(val3, num6); } float num7 = getPitch(val3); float num8 = Mathf.Lerp(num7, 2f + throwChargeLevel * 3f, deltaTime * 10f); if (num8 != num7) { setPitch(val3, num8); } } Item val4 = prevItem.Invoke(__instance); if ((Object)(object)val4 != (Object)(object)currentItem) { SFX_Instance[] switchGeneric = __instance.switchGeneric; for (int i = 0; i < switchGeneric.Length; i++) { switchGeneric[i].Play(((Component)__instance).transform.position); } } ItemUseFeedback val5 = default(ItemUseFeedback); if (((Component)currentItem).TryGetComponent(ref val5)) { if ((Object)(object)val4 != (Object)(object)currentItem) { SFX_Instance[] equip = val5.equip; for (int j = 0; j < equip.Length; j++) { equip[j].Play(((Component)__instance).transform.position); } } string useAnimation = val5.useAnimation; if (!string.IsNullOrEmpty(useAnimation)) { bool flag2 = currentItem.isUsingPrimary && currentItem.castProgress < 1f; int stringHash = GetStringHash(hashCache, stringToHash, useAnimation); if (getBool(val2, stringHash) != flag2) { setBool(val2, stringHash, flag2); } } prevUse.Invoke(__instance) = useAnimation; } } if (Object.op_Implicit((Object)(object)prevItem.Invoke(__instance)) && !Object.op_Implicit((Object)(object)currentItem)) { SFX_Instance[] switchGeneric2 = __instance.switchGeneric; for (int k = 0; k < switchGeneric2.Length; k++) { switchGeneric2[k].Play(((Component)__instance).transform.position); } } prevItem.Invoke(__instance) = currentItem; return false; } private static int GetStringHash(ConditionalWeakTable cache, Func stringToHash, string name) { HashBox value = cache.GetValue(name, (string _) => new HashBox()); int num = value.Hash; if (num == 0) { num = (value.Hash = stringToHash(name)); } return num; } private static Action EmitSetBool(Type animatorType, MethodInfo setBool) { DynamicMethod dynamicMethod = new DynamicMethod("PSO_SetBool", typeof(void), new Type[3] { typeof(Object), typeof(int), typeof(bool) }, typeof(ItemAudioManagerHashPatch).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Castclass, animatorType); iLGenerator.Emit(OpCodes.Ldarg_1); iLGenerator.Emit(OpCodes.Ldarg_2); iLGenerator.Emit(OpCodes.Callvirt, setBool); iLGenerator.Emit(OpCodes.Ret); return (Action)dynamicMethod.CreateDelegate(typeof(Action)); } private static Func EmitGetBool(Type animatorType, MethodInfo getBool) { DynamicMethod dynamicMethod = new DynamicMethod("PSO_GetBool", typeof(bool), new Type[2] { typeof(Object), typeof(int) }, typeof(ItemAudioManagerHashPatch).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Castclass, animatorType); iLGenerator.Emit(OpCodes.Ldarg_1); iLGenerator.Emit(OpCodes.Callvirt, getBool); iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } private static Func EmitPropertyGetter(Type ownerType, MethodInfo getter, string name) { DynamicMethod dynamicMethod = new DynamicMethod("PSO_Get_" + name, typeof(float), new Type[1] { typeof(Object) }, typeof(ItemAudioManagerHashPatch).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Castclass, ownerType); iLGenerator.Emit(OpCodes.Callvirt, getter); iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } private static Action EmitPropertySetter(Type ownerType, MethodInfo setter, string name) { DynamicMethod dynamicMethod = new DynamicMethod("PSO_Set_" + name, typeof(void), new Type[2] { typeof(Object), typeof(float) }, typeof(ItemAudioManagerHashPatch).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Castclass, ownerType); iLGenerator.Emit(OpCodes.Ldarg_1); iLGenerator.Emit(OpCodes.Callvirt, setter); iLGenerator.Emit(OpCodes.Ret); return (Action)dynamicMethod.CreateDelegate(typeof(Action)); } } internal sealed class ItemCollisionModeModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.ItemCollisionMode, () => new PatchDefinition(PatchId.ItemCollisionMode, ItemCollisionModePatch.Initialize, ItemCollisionModePatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(ItemCollisionModePatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, ItemCollisionModePatch.Reset)); } } internal static class ItemCollisionModePatch { private const string RigidbodyTypeName = "UnityEngine.Rigidbody"; private const string CollisionDetectionModeTypeName = "UnityEngine.CollisionDetectionMode"; private const string ContinuousDynamicName = "ContinuousDynamic"; private const string DiscreteName = "Discrete"; private static Func _getRig; private static Func _getMode; private static Action _setMode; private static int _continuousDynamic; private static int _discrete; internal static void Initialize() { ResolveAndValidateTarget(); FieldInfo fieldInfo = ScaleValidation.RequireInstanceFieldByTypeName(typeof(Item), "rig", "UnityEngine.Rigidbody"); ScaleValidation.RequireInstanceProperty(typeof(Item), "itemState", typeof(ItemState)); if (!Enum.IsDefined(typeof(ItemState), (object)(ItemState)0)) { throw new InvalidOperationException("ItemState.Ground is no longer defined"); } PropertyInfo propertyInfo = ScaleValidation.RequireInstancePropertyByTypeName(fieldInfo.FieldType, "collisionDetectionMode", "UnityEngine.CollisionDetectionMode", requireSetter: true); Type propertyType = propertyInfo.PropertyType; if (!propertyType.IsEnum || Enum.GetUnderlyingType(propertyType) != typeof(int)) { throw new InvalidOperationException("CollisionDetectionMode is not an int-backed enum"); } if (!Enum.IsDefined(propertyType, "ContinuousDynamic") || !Enum.IsDefined(propertyType, "Discrete")) { throw new InvalidOperationException("CollisionDetectionMode values are no longer defined"); } _continuousDynamic = Convert.ToInt32(Enum.Parse(propertyType, "ContinuousDynamic")); _discrete = Convert.ToInt32(Enum.Parse(propertyType, "Discrete")); if (_continuousDynamic == _discrete) { throw new InvalidOperationException("CollisionDetectionMode values are ambiguous"); } Func func = ScaleEmit.CreateUnityObjectFieldGetter(fieldInfo); Func func2 = ScaleEmit.CreateEnumPropertyGetterViaField(fieldInfo, propertyInfo); Action action = ScaleEmit.CreateEnumPropertySetterViaField(fieldInfo, propertyInfo); if (func == null || func2 == null || action == null) { throw new InvalidOperationException("ItemCollisionMode accessor creation failed"); } _getRig = func; _getMode = func2; _setMode = action; } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(Item), "UpdateCollisionDetectionMode", typeof(void), Type.EmptyTypes, requirePublic: false); } internal static void Reset() { _getRig = null; _getMode = null; _setMode = null; _continuousDynamic = 0; _discrete = 0; } internal static bool Prefix(Item __instance) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) Func getRig = _getRig; Func getMode = _getMode; Action setMode = _setMode; if (getRig == null || getMode == null || setMode == null) { RateLimitedDiagnostics.Hit("ItemCollisionMode.accessors-unavailable"); return true; } if (getRig(__instance) == (Object)null) { RateLimitedDiagnostics.Hit("ItemCollisionMode.rig-null"); return true; } int num = (((int)__instance.itemState == 0) ? _continuousDynamic : _discrete); if (getMode(__instance) == num) { return false; } setMode(__instance, num); return false; } } internal sealed class ItemDatabaseNameLookupModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.ItemDatabaseNameLookup, () => new PatchDefinition(PatchId.ItemDatabaseNameLookup, ItemDatabaseNameLookupPatch.Initialize, ItemDatabaseNameLookupPatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(ItemDatabaseNameLookupPatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, ItemDatabaseNameLookupPatch.Reset)); } } internal static class ItemDatabaseNameLookupPatch { private static Func _getInstance; private static Func> _getLookup; private static Func, int> _getLookupVersion; private static Dictionary _nameCache; private static Dictionary _cachedLookup; private static int _builtCount = -1; private static int _builtVersion = int.MinValue; internal static void Initialize() { ResolveAndValidateTarget(); Type type = ResolveItemDatabaseType(); FieldInfo field = type.GetField("itemLookup", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null || field.IsStatic || field.FieldType != typeof(Dictionary)) { throw new MissingFieldException("ItemDatabase", "itemLookup"); } Func func = ResolveSingletonInstance(type); Func> func2 = EmitLookupGetter(type, field); Func, int> func3 = CreateDictionaryVersionGetter(); if (func == null || func2 == null || func3 == null) { throw new InvalidOperationException("ItemDatabaseNameLookup accessor creation failed"); } _getInstance = func; _getLookup = func2; _getLookupVersion = func3; } internal static MethodInfo ResolveAndValidateTarget() { MethodInfo method = ResolveItemDatabaseType().GetMethod("TryGetItem", BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2] { typeof(string), typeof(Item).MakeByRefType() }, null); if (method == null || !method.IsStatic || !method.IsPublic || method.ReturnType != typeof(bool)) { throw new MissingMethodException("ItemDatabase", "TryGetItem(string, out Item)"); } return method; } internal static void Reset() { _getInstance = null; _getLookup = null; _getLookupVersion = null; _nameCache = null; _cachedLookup = null; _builtCount = -1; _builtVersion = int.MinValue; } private static Type ResolveItemDatabaseType() { Type? type = typeof(Item).Assembly.GetType("ItemDatabase", throwOnError: false); if (type == null) { throw new TypeLoadException("ItemDatabase type not found"); } return type; } private static Func ResolveSingletonInstance(Type itemDatabaseType) { Type baseType = itemDatabaseType.BaseType; while (baseType != null) { PropertyInfo property = baseType.GetProperty("Instance", BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (!(property == null)) { MethodInfo getMethod = property.GetGetMethod(nonPublic: true); if (!(getMethod == null) && getMethod.IsStatic && !(getMethod.ReturnType != itemDatabaseType)) { return EmitSingletonGetter(getMethod); } } baseType = baseType.BaseType; } throw new InvalidOperationException("ItemDatabase singleton Instance getter not found"); } private static Func EmitSingletonGetter(MethodInfo getter) { DynamicMethod dynamicMethod = new DynamicMethod("PSO_GetItemDatabaseInstance", typeof(Object), Type.EmptyTypes, typeof(ItemDatabaseNameLookupPatch).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Call, getter); iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } private static Func> EmitLookupGetter(Type itemDatabaseType, FieldInfo itemLookupField) { DynamicMethod dynamicMethod = new DynamicMethod("PSO_GetItemLookup", typeof(Dictionary), new Type[1] { typeof(object) }, typeof(ItemDatabaseNameLookupPatch).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Castclass, itemDatabaseType); iLGenerator.Emit(OpCodes.Ldfld, itemLookupField); iLGenerator.Emit(OpCodes.Ret); return (Func>)dynamicMethod.CreateDelegate(typeof(Func>)); } private static Func, int> CreateDictionaryVersionGetter() { Type typeFromHandle = typeof(Dictionary); FieldInfo fieldInfo = typeFromHandle.GetField("_version", BindingFlags.Instance | BindingFlags.NonPublic) ?? typeFromHandle.GetField("version", BindingFlags.Instance | BindingFlags.NonPublic); if (fieldInfo == null || fieldInfo.IsStatic || fieldInfo.FieldType != typeof(int)) { throw new MissingFieldException(typeFromHandle.FullName, "_version/version"); } DynamicMethod dynamicMethod = new DynamicMethod("PSO_GetItemLookupVersion", typeof(int), new Type[1] { typeFromHandle }, typeof(ItemDatabaseNameLookupPatch).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldfld, fieldInfo); iLGenerator.Emit(OpCodes.Ret); return (Func, int>)dynamicMethod.CreateDelegate(typeof(Func, int>)); } internal static bool Prefix(string itemNameOnFile, ref Item item, ref bool __result) { Func getInstance = _getInstance; Func> getLookup = _getLookup; Func, int> getLookupVersion = _getLookupVersion; Dictionary cache = _nameCache; Dictionary cachedLookup = _cachedLookup; int builtCount = _builtCount; int builtVersion = _builtVersion; if (getInstance == null || getLookup == null || getLookupVersion == null) { RateLimitedDiagnostics.Hit("ItemDatabaseNameLookup.accessors-unavailable"); return true; } Object val = getInstance(); if (val == (Object)null) { RateLimitedDiagnostics.Hit("ItemDatabaseNameLookup.instance-null"); return true; } Dictionary dictionary = getLookup(val); if (dictionary == null) { RateLimitedDiagnostics.Hit("ItemDatabaseNameLookup.lookup-null"); return true; } if (itemNameOnFile == null) { item = null; __result = false; return false; } int count = dictionary.Count; int num = getLookupVersion(dictionary); if (cache == null || dictionary != cachedLookup || count != builtCount || num != builtVersion) { if (!TryBuildCache(dictionary, count, out cache)) { return true; } _nameCache = cache; _cachedLookup = dictionary; _builtCount = count; _builtVersion = num; } if (cache.TryGetValue(itemNameOnFile, out var value)) { if ((Object)(object)value == (Object)null || (Object)(object)((Component)value).gameObject == (Object)null || ((Object)((Component)value).gameObject).name != itemNameOnFile) { return true; } item = value; __result = true; return false; } return true; } private static bool TryBuildCache(Dictionary lookup, int count, out Dictionary cache) { Dictionary dictionary = new Dictionary(count); foreach (KeyValuePair item in lookup) { Item value = item.Value; if ((Object)(object)value == (Object)null) { RateLimitedDiagnostics.Hit("ItemDatabaseNameLookup.null-entry"); cache = null; return false; } if ((Object)(object)((Component)value).gameObject == (Object)null) { RateLimitedDiagnostics.Hit("ItemDatabaseNameLookup.entry-object-null"); cache = null; return false; } dictionary[((Object)((Component)value).gameObject).name] = value; } cache = dictionary; return true; } } internal sealed class LightVolumeSampleCacheModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.LightVolumeSampleCache, () => new PatchDefinition(PatchId.LightVolumeSampleCache, LightVolumeSampleCachePatch.Initialize, LightVolumeSampleCachePatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(LightVolumeSampleCachePatch), "Prefix", (Type[])null), () => new HarmonyMethod(typeof(LightVolumeSampleCachePatch), "Postfix", (Type[])null), null, null, requireCurrentMvid: true, LightVolumeSampleCachePatch.Reset)); } } internal static class LightVolumeSampleCachePatch { internal sealed class PendingKey { internal long Key; } private const string LightVolumeTypeName = "LightVolume"; private const string CompressableLightMapTypeName = "Peak.CompressableLightMap"; private const string Texture3DTypeName = "UnityEngine.Texture3D"; private const int MaxEntries = 1024; private static Func _gridOffset; private static Func _raySpacing; private static Func _lightmap; private static Func _updateCount; private static Dictionary _cache; private static int _generationTextureId; private static uint _generationUpdateCount; private static bool _hasGeneration; internal static void Initialize() { Type declaringType = ResolveAndValidateTarget().DeclaringType; FieldInfo field = ScaleValidation.RequireInstanceField(declaringType, "gridOffset", typeof(Vector3)); FieldInfo field2 = ScaleValidation.RequireInstanceField(declaringType, "raySpacing", typeof(float)); FieldInfo fieldInfo = ScaleValidation.RequireInstanceFieldByTypeName(declaringType, "lightMapData", "Peak.CompressableLightMap"); if (!fieldInfo.FieldType.IsValueType) { throw new InvalidOperationException("LightVolume.lightMapData is no longer a struct"); } ScaleValidation.RequireInstanceMethodByTypeNames(declaringType, "WorldPosToLightmapCoords", "UnityEngine.Vector3", new string[1] { "UnityEngine.Vector3" }); ScaleValidation.RequireInstanceMethodByTypeNames(declaringType, "SamplePosition", "UnityEngine.Color", new string[2] { "UnityEngine.Vector3", typeof(bool).FullName }); PropertyInfo propertyInfo = ScaleValidation.RequireInstancePropertyByTypeName(fieldInfo.FieldType, "Uncompressed", "UnityEngine.Texture3D", requireSetter: false); Type propertyType = propertyInfo.PropertyType; MethodInfo method = propertyType.GetMethod("GetPixel", BindingFlags.Instance | BindingFlags.Public, null, new Type[3] { typeof(int), typeof(int), typeof(int) }, null); if (method == null || method.IsStatic || !string.Equals(method.ReturnType.FullName, "UnityEngine.Color", StringComparison.Ordinal)) { throw new MissingMethodException(propertyType.FullName, "GetPixel(int, int, int)"); } PropertyInfo property = ScaleValidation.RequireInstancePropertyByTypeName(propertyType, "updateCount", typeof(uint).FullName, requireSetter: false); Func func = EmitVector3Field(declaringType, field); Func func2 = EmitFloatField(declaringType, field2); Func func3 = EmitLightmapGetter(declaringType, fieldInfo, propertyInfo); Func func4 = EmitUpdateCount(propertyType, property); if (func == null || func2 == null || func3 == null || func4 == null) { throw new InvalidOperationException("LightVolumeSampleCache accessor creation failed"); } _gridOffset = func; _raySpacing = func2; _lightmap = func3; _updateCount = func4; _cache = new Dictionary(1024); _generationTextureId = 0; _generationUpdateCount = 0u; _hasGeneration = false; } internal static MethodInfo ResolveAndValidateTarget() { Type type = AccessTools.TypeByName("LightVolume"); if (type == null) { throw new TypeLoadException("LightVolume type not found"); } return ScaleValidation.RequireInstanceMethodByTypeNames(type, "SamplePositionAlpha", typeof(float).FullName, new string[2] { "UnityEngine.Vector3", typeof(bool).FullName }); } internal static void Reset() { _gridOffset = null; _raySpacing = null; _lightmap = null; _updateCount = null; _cache = null; _generationTextureId = 0; _generationUpdateCount = 0u; _hasGeneration = false; } internal static bool Prefix(object __instance, Vector3 worldPos, ref float __result, ref PendingKey __state) { //IL_0069: 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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_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_0093: 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_00b3: Unknown result type (might be due to invalid IL or missing references) __state = null; Func gridOffset = _gridOffset; Func raySpacing = _raySpacing; Func lightmap = _lightmap; Func updateCount = _updateCount; Dictionary cache = _cache; if (gridOffset == null || raySpacing == null || lightmap == null || updateCount == null || cache == null || __instance == null) { return true; } float num = raySpacing(__instance); if (!(num > 0f) || float.IsInfinity(num)) { return true; } Object val = lightmap(__instance); if (val == (Object)null) { return true; } Vector3 val2 = (worldPos - gridOffset(__instance)) / num + 0.5f * Vector3.one; if (!TryTruncate(val2.x, out var result) || !TryTruncate(val2.y, out var result2) || !TryTruncate(val2.z, out var result3)) { return true; } int instanceID = val.GetInstanceID(); uint num2 = updateCount(val); if (!_hasGeneration || _generationTextureId != instanceID || _generationUpdateCount != num2) { cache.Clear(); _generationTextureId = instanceID; _generationUpdateCount = num2; _hasGeneration = true; } long key = PackKey(result, result2, result3); if (cache.TryGetValue(key, out var value)) { __result = value; return false; } if (cache.Count >= 1024) { cache.Clear(); } __state = new PendingKey { Key = key }; return true; } internal static void Postfix(float __result, PendingKey __state, bool __runOriginal) { if (__runOriginal && __state != null) { Dictionary cache = _cache; if (cache != null) { cache[__state.Key] = __result; } } } private static bool TryTruncate(float value, out int result) { if (float.IsNaN(value) || value <= -2.147483E+09f || value >= 2.147483E+09f) { result = 0; return false; } result = (int)value; return true; } private static long PackKey(int x, int y, int z) { long num = (long)(x + 1048576) & 0x1FFFFFL; long num2 = (long)(y + 1048576) & 0x1FFFFFL; long num3 = (long)(z + 1048576) & 0x1FFFFFL; return (num << 42) | (num2 << 21) | num3; } private static Func EmitVector3Field(Type owner, FieldInfo field) { DynamicMethod dynamicMethod = new DynamicMethod("PSO_LightVolumeGridOffset", typeof(Vector3), new Type[1] { typeof(object) }, typeof(LightVolumeSampleCachePatch).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Castclass, owner); iLGenerator.Emit(OpCodes.Ldfld, field); iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } private static Func EmitFloatField(Type owner, FieldInfo field) { DynamicMethod dynamicMethod = new DynamicMethod("PSO_LightVolumeRaySpacing", typeof(float), new Type[1] { typeof(object) }, typeof(LightVolumeSampleCachePatch).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Castclass, owner); iLGenerator.Emit(OpCodes.Ldfld, field); iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } private static Func EmitLightmapGetter(Type owner, FieldInfo field, PropertyInfo property) { MethodInfo getMethod = property.GetGetMethod(nonPublic: true); if (getMethod == null || getMethod.IsStatic) { throw new MissingMethodException(property.DeclaringType?.FullName, property.Name); } DynamicMethod dynamicMethod = new DynamicMethod("PSO_LightVolumeLightmap", typeof(Object), new Type[1] { typeof(object) }, typeof(LightVolumeSampleCachePatch).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Castclass, owner); iLGenerator.Emit(OpCodes.Ldflda, field); iLGenerator.Emit(OpCodes.Call, getMethod); iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } private static Func EmitUpdateCount(Type textureType, PropertyInfo property) { MethodInfo getMethod = property.GetGetMethod(nonPublic: true); if (getMethod == null || getMethod.IsStatic) { throw new MissingMethodException(textureType.FullName, property.Name); } DynamicMethod dynamicMethod = new DynamicMethod("PSO_TextureUpdateCount", typeof(uint), new Type[1] { typeof(Object) }, typeof(LightVolumeSampleCachePatch).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Castclass, textureType); iLGenerator.Emit(OpCodes.Callvirt, getMethod); iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } } internal sealed class PlayerNameUiWritesModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.PlayerNameUiWrites, () => new PatchDefinition(PatchId.PlayerNameUiWrites, PlayerNameUiWritesPatch.Initialize, PlayerNameUiWritesPatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(PlayerNameUiWritesPatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, PlayerNameUiWritesPatch.Reset)); } } internal static class PlayerNameUiWritesPatch { private sealed class State { internal Object[] LastSprites; } private static Func _getCamera; private static Func _worldToScreenPoint; private static Func _getCannibalismSetting; private static Func _getPhotonOwner; private static Func _getIsMasterClient; private static Func _getGroup; private static Func _getImage; private static Func _getAlpha; private static Action _setAlpha; private static Func _getSprite; private static Action _setSprite; private static Func _canCannibalize; private static ConditionalWeakTable _states; internal static void Initialize() { ResolveAndValidateTarget(); Type? typeFromHandle = typeof(UIPlayerNames); ScaleValidation.RequireInstanceField(typeFromHandle, "playerNameText", typeof(PlayerName[])); ScaleValidation.RequireInstanceField(typeFromHandle, "audioSprites", typeof(Sprite[])); ScaleValidation.RequireInstanceField(typeFromHandle, "mutedAudioSprite", typeof(Sprite)); FieldInfo field = ScaleValidation.RequireInstanceField(typeFromHandle, "localCannibalismSetting", typeof(CannibalismSetting)); ScaleValidation.RequireInstanceField(typeFromHandle, "audioImageTimeoutMax", typeof(float)); if (!ScaleValidation.RequireStaticField(typeFromHandle, "CANNIBAL_HUNGER_THRESHOLD", typeof(float)).IsPublic) { throw new InvalidOperationException("UIPlayerNames.CANNIBAL_HUNGER_THRESHOLD is not public"); } MethodInfo methodInfo = ScaleValidation.RequireInstanceMethod(typeFromHandle, "CanCannibalize", typeof(bool), new Type[1] { typeof(Character) }, requirePublic: false); FieldInfo fieldInfo = ScaleValidation.RequireInstanceFieldByTypeName(typeof(PlayerName), "group", "UnityEngine.CanvasGroup"); FieldInfo fieldInfo2 = ScaleValidation.RequireInstanceFieldByTypeName(typeof(PlayerName), "audioImage", "UnityEngine.UI.Image"); ScaleValidation.RequireInstanceField(typeof(PlayerName), "hostStar", typeof(GameObject)); ScaleValidation.RequireInstanceField(typeof(PlayerName), "audioImageTimeout", typeof(float)); ScaleValidation.RequireInstanceField(typeof(PlayerName), "characterInteractable", typeof(CharacterInteractible)); ScaleValidation.RequireInheritedInstanceProperty(typeof(PlayerName), "transform", typeof(Transform)); ScaleValidation.RequireInheritedInstanceProperty(typeof(PlayerName), "gameObject", typeof(GameObject)); ScaleValidation.RequireInstanceField(typeof(CharacterInteractible), "character", typeof(Character)); ScaleValidation.RequireStaticField(typeof(Character), "localCharacter", typeof(Character)); ScaleValidation.RequireInstanceField(typeof(Character), "isBot", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(Character), "data", typeof(CharacterData)); ScaleValidation.RequireInstanceField(typeof(Character), "refs", typeof(CharacterRefs)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "fullyPassedOut", typeof(bool)); ScaleValidation.RequireInstanceProperty(typeof(CharacterData), "fullyConscious", typeof(bool)); ScaleValidation.RequireInstanceProperty(typeof(CharacterData), "cannibalismPermitted", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(CharacterRefs), "customization", typeof(CharacterCustomization)); ScaleValidation.RequireInstanceField(typeof(CharacterRefs), "afflictions", typeof(CharacterAfflictions)); ScaleValidation.RequireInstanceField(typeof(CharacterCustomization), "isCannibalizable", typeof(bool)); ScaleValidation.RequireInstanceMethod(typeof(CharacterCustomization), "BecomeChicken", typeof(void), Type.EmptyTypes, requirePublic: true); ScaleValidation.RequireInstanceMethod(typeof(CharacterCustomization), "BecomeHuman", typeof(void), Type.EmptyTypes, requirePublic: true); ScaleValidation.RequireInstanceMethod(typeof(CharacterAfflictions), "GetCurrentStatus", typeof(float), new Type[1] { typeof(STATUSTYPE) }, requirePublic: true); if (!Enum.IsDefined(typeof(STATUSTYPE), (object)(STATUSTYPE)1)) { throw new InvalidOperationException("Player name enum values are no longer defined"); } PropertyInfo propertyInfo = ScaleValidation.RequireInstancePropertyByTypeName(typeof(CannibalismSetting), "Value", "Zorro.Settings.OffOnMode", requireSetter: false); if (!propertyInfo.PropertyType.IsEnum || !Enum.IsDefined(propertyInfo.PropertyType, "ON")) { throw new InvalidOperationException("CannibalismSetting.Value structure mismatch"); } ScaleValidation.RequireInstanceProperty(typeof(Character), "player", typeof(Player)); ScaleValidation.RequireStaticMethod(typeof(NetworkingUtilities), "GetUserId", typeof(string), new Type[1] { typeof(Player) }, requirePublic: true); ScaleValidation.RequireStaticMethod(typeof(AudioLevels), "GetPlayerLevel", typeof(float), new Type[1] { typeof(string) }, requirePublic: true); ScaleValidation.RequireInheritedInstanceProperty(typeof(Character), "photonView", typeof(PhotonView)); PropertyInfo propertyInfo2 = ScaleValidation.RequireInstancePropertyByTypeName(typeof(PhotonView), "Owner", "Photon.Realtime.Player", requireSetter: false); PropertyInfo property = ScaleValidation.RequireInstancePropertyByTypeName(propertyInfo2.PropertyType, "IsMasterClient", typeof(bool).FullName, requireSetter: false); ScaleValidation.RequireStaticField(typeof(MainCamera), "instance", typeof(MainCamera)); FieldInfo fieldInfo3 = ScaleValidation.RequireInstanceFieldByTypeName(typeof(MainCamera), "cam", "UnityEngine.Camera"); Type fieldType = fieldInfo3.FieldType; MethodInfo method = fieldType.GetMethod("WorldToScreenPoint", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(Vector3) }, null); if (method == null || method.DeclaringType != fieldType || method.ReturnType != typeof(Vector3) || method.IsStatic) { throw new MissingMethodException(fieldType.FullName, "WorldToScreenPoint(Vector3)"); } Type fieldType2 = fieldInfo.FieldType; Type fieldType3 = fieldInfo2.FieldType; PropertyInfo property2 = ScaleValidation.RequireInstancePropertyByTypeName(fieldType2, "alpha", typeof(float).FullName, requireSetter: true); PropertyInfo property3 = ScaleValidation.RequireInstancePropertyByTypeName(fieldType3, "sprite", typeof(Sprite).FullName, requireSetter: true); ScaleValidation.RequireInstanceProperty(typeof(GameObject), "activeSelf", typeof(bool)); ScaleValidation.RequireInstanceMethod(typeof(GameObject), "SetActive", typeof(void), new Type[1] { typeof(bool) }, requirePublic: true); Func func = ScaleEmit.CreateUnityObjectFieldGetter(fieldInfo3); Func func2 = EmitWorldToScreen(fieldType, method); Func func3 = EmitReferenceFieldGetter(field, "PSO_GetCannibalismSetting"); Func func4 = EmitReferencePropertyGetter(propertyInfo2, "PSO_GetPhotonOwner"); Func func5 = EmitBoolPropertyGetter(property, "PSO_GetIsMasterClient"); Func func6 = ScaleEmit.CreateUnityObjectFieldGetter(fieldInfo); Func func7 = ScaleEmit.CreateUnityObjectFieldGetter(fieldInfo2); Func func8 = EmitFloatFieldPropertyGetter(fieldInfo, property2, "PSO_PlayerNameGetAlpha"); Action action = EmitFloatFieldPropertySetter(fieldInfo, property2, "PSO_PlayerNameSetAlpha"); Func func9 = EmitObjectFieldPropertyGetter(fieldInfo2, property3, "PSO_PlayerNameGetSprite"); Action action2 = EmitObjectFieldPropertySetter(fieldInfo2, property3, "PSO_PlayerNameSetSprite"); Func func10 = (Func)methodInfo.CreateDelegate(typeof(Func)); if (func == null || func2 == null || func3 == null || func4 == null || func5 == null || func6 == null || func7 == null || func8 == null || action == null || func9 == null || action2 == null || func10 == null) { throw new InvalidOperationException("PlayerNameUiWrites accessor creation failed"); } _getCamera = func; _worldToScreenPoint = func2; _getCannibalismSetting = func3; _getPhotonOwner = func4; _getIsMasterClient = func5; _getGroup = func6; _getImage = func7; _getAlpha = func8; _setAlpha = action; _getSprite = func9; _setSprite = action2; _canCannibalize = func10; _states = new ConditionalWeakTable(); } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(UIPlayerNames), "UpdateName", typeof(void), new Type[4] { typeof(int), typeof(Vector3), typeof(bool), typeof(int) }, requirePublic: true); } internal static void Reset() { _getCamera = null; _worldToScreenPoint = null; _getCannibalismSetting = null; _getPhotonOwner = null; _getIsMasterClient = null; _getGroup = null; _getImage = null; _getAlpha = null; _setAlpha = null; _getSprite = null; _setSprite = null; _canCannibalize = null; _states = null; } internal static bool Prefix(UIPlayerNames __instance, int index, Vector3 position, bool visible, int speakingAmplitude) { //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Unknown result type (might be due to invalid IL or missing references) Func getCamera = _getCamera; Func worldToScreenPoint = _worldToScreenPoint; Func getCannibalismSetting = _getCannibalismSetting; Func getPhotonOwner = _getPhotonOwner; Func getIsMasterClient = _getIsMasterClient; Func getGroup = _getGroup; Func getImage = _getImage; Func getAlpha = _getAlpha; Action setAlpha = _setAlpha; Func getSprite = _getSprite; Action setSprite = _setSprite; Func canCannibalize = _canCannibalize; ConditionalWeakTable states = _states; if (getCamera == null || worldToScreenPoint == null || getCannibalismSetting == null || getPhotonOwner == null || getIsMasterClient == null || getGroup == null || getImage == null || getAlpha == null || setAlpha == null || getSprite == null || setSprite == null || canCannibalize == null || states == null) { return true; } Character localCharacter = Character.localCharacter; PlayerName[] playerNameText = __instance.playerNameText; if ((Object)(object)localCharacter == (Object)null || playerNameText == null || index < 0 || index >= playerNameText.Length) { return true; } PlayerName val = playerNameText[index]; MainCamera instance = MainCamera.instance; if ((Object)(object)val == (Object)null || (Object)(object)instance == (Object)null || getCamera(instance) == (Object)null || getGroup(val) == (Object)null || getImage(val) == (Object)null || (Object)(object)val.hostStar == (Object)null || (Object)(object)val.characterInteractable == (Object)null || (Object)(object)val.characterInteractable.character == (Object)null || (Object)(object)localCharacter.data == (Object)null || localCharacter.refs == null || (Object)(object)localCharacter.refs.afflictions == (Object)null) { return true; } Character character = val.characterInteractable.character; if ((Object)(object)character.data == (Object)null || character.refs == null || (Object)(object)character.refs.customization == (Object)null) { return true; } Sprite[] audioSprites = __instance.audioSprites; Player val2 = null; PhotonView val3 = null; object obj = null; bool flag = false; if (visible) { try { val2 = character.player; if (getCannibalismSetting(__instance) == null || audioSprites == null || audioSprites.Length == 0 || (Object)(object)val2 == (Object)null) { return true; } string userId = NetworkingUtilities.GetUserId(val2); if (userId == null) { return true; } flag = AudioLevels.GetPlayerLevel(userId) == 0f; if (!flag) { val3 = ((MonoBehaviourPun)character).photonView; obj = (((Object)(object)val3 != (Object)null) ? getPhotonOwner(val3) : null); if ((Object)(object)val3 == (Object)null || obj == null) { return true; } } } catch (Exception) { RateLimitedDiagnostics.Hit("PlayerNameUiWrites.owner-lookup-failed"); return true; } } ((Component)val).transform.position = worldToScreenPoint(getCamera(instance), position); if (visible) { if (canCannibalize(__instance, character)) { character.refs.customization.BecomeChicken(); } SetActiveIfChanged(((Component)val).gameObject, target: true); MoveAlpha(val, 1f, getAlpha, setAlpha); if (Object.op_Implicit((Object)(object)val.characterInteractable) && flag) { SetSpriteIfChanged(__instance, val, index, __instance.mutedAudioSprite, states, getSprite, setSprite); return false; } if (speakingAmplitude <= 0) { val.audioImageTimeout -= Time.deltaTime; if (val.audioImageTimeout <= 0f) { SetSpriteIfChanged(__instance, val, index, audioSprites[0], states, getSprite, setSprite); } } else { int num = Mathf.Clamp(speakingAmplitude * 2, 0, audioSprites.Length - 1); SetSpriteIfChanged(__instance, val, index, audioSprites[num], states, getSprite, setSprite); val.audioImageTimeout = __instance.audioImageTimeoutMax; } bool target = getIsMasterClient(obj); SetActiveIfChanged(val.hostStar, target); } else { MoveAlpha(val, 0f, getAlpha, setAlpha); if (getAlpha(val) < 0.01f && ((Component)val).gameObject.activeSelf) { character.refs.customization.BecomeHuman(); SetActiveIfChanged(((Component)val).gameObject, target: false); } } if ((localCharacter.data.fullyPassedOut || localCharacter.refs.afflictions.GetCurrentStatus((STATUSTYPE)1) < UIPlayerNames.CANNIBAL_HUNGER_THRESHOLD) && ((Component)val).gameObject.activeSelf) { character.refs.customization.BecomeHuman(); } return false; } private static void MoveAlpha(PlayerName name, float target, Func getAlpha, Action setAlpha) { float num = getAlpha(name); if (!Mathf.Approximately(num, target)) { setAlpha(name, Mathf.MoveTowards(num, target, Time.deltaTime * 5f)); } } private static void SetActiveIfChanged(GameObject gameObject, bool target) { if (gameObject.activeSelf != target) { gameObject.SetActive(target); } } private static void SetSpriteIfChanged(UIPlayerNames owner, PlayerName name, int index, Sprite target, ConditionalWeakTable states, Func getSprite, Action setSprite) { State value = states.GetValue(owner, (UIPlayerNames _) => new State()); Object[] array = value.LastSprites; if (array == null || array.Length != owner.playerNameText.Length) { array = (value.LastSprites = (Object[])(object)new Object[owner.playerNameText.Length]); } Object val = getSprite(name); if (array[index] != val) { array[index] = val; } if ((object)array[index] != target) { setSprite(name, (Object)(object)target); array[index] = (Object)(object)target; } } private static Func EmitWorldToScreen(Type cameraType, MethodInfo methodInfo) { DynamicMethod dynamicMethod = new DynamicMethod("PSO_WorldToScreenPoint", typeof(Vector3), new Type[2] { typeof(Object), typeof(Vector3) }, typeof(PlayerNameUiWritesPatch).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Castclass, cameraType); iLGenerator.Emit(OpCodes.Ldarg_1); iLGenerator.Emit(OpCodes.Callvirt, methodInfo); iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } private static Func EmitReferenceFieldGetter(FieldInfo field, string name) { if (field == null || field.IsStatic || field.DeclaringType != typeof(TInstance) || field.FieldType.IsValueType) { throw new InvalidOperationException("Unexpected reference field: " + field?.Name); } DynamicMethod dynamicMethod = new DynamicMethod(name, typeof(object), new Type[1] { typeof(TInstance) }, typeof(PlayerNameUiWritesPatch).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldfld, field); iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } private static Func EmitReferencePropertyGetter(PropertyInfo property, string name) { MethodInfo methodInfo = property?.GetGetMethod(nonPublic: true); if (property == null || methodInfo == null || methodInfo.IsStatic || property.PropertyType.IsValueType || !property.DeclaringType.IsAssignableFrom(typeof(TInstance))) { throw new InvalidOperationException("Unexpected reference property: " + property?.Name); } DynamicMethod dynamicMethod = new DynamicMethod(name, typeof(object), new Type[1] { typeof(TInstance) }, typeof(PlayerNameUiWritesPatch).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Callvirt, methodInfo); iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } private static Func EmitBoolPropertyGetter(PropertyInfo property, string name) { MethodInfo methodInfo = property?.GetGetMethod(nonPublic: true); if (property == null || methodInfo == null || methodInfo.IsStatic || property.PropertyType != typeof(bool)) { throw new InvalidOperationException("Unexpected bool property: " + property?.Name); } DynamicMethod dynamicMethod = new DynamicMethod(name, typeof(bool), new Type[1] { typeof(object) }, typeof(PlayerNameUiWritesPatch).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Castclass, property.DeclaringType); iLGenerator.Emit(OpCodes.Callvirt, methodInfo); iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } private static Func EmitFloatFieldPropertyGetter(FieldInfo field, PropertyInfo property, string name) { DynamicMethod dynamicMethod = new DynamicMethod(name, typeof(float), new Type[1] { typeof(PlayerName) }, typeof(PlayerNameUiWritesPatch).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldfld, field); iLGenerator.Emit(OpCodes.Callvirt, property.GetGetMethod(nonPublic: true)); iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } private static Action EmitFloatFieldPropertySetter(FieldInfo field, PropertyInfo property, string name) { DynamicMethod dynamicMethod = new DynamicMethod(name, typeof(void), new Type[2] { typeof(PlayerName), typeof(float) }, typeof(PlayerNameUiWritesPatch).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldfld, field); iLGenerator.Emit(OpCodes.Ldarg_1); iLGenerator.Emit(OpCodes.Callvirt, property.GetSetMethod(nonPublic: true)); iLGenerator.Emit(OpCodes.Ret); return (Action)dynamicMethod.CreateDelegate(typeof(Action)); } private static Func EmitObjectFieldPropertyGetter(FieldInfo field, PropertyInfo property, string name) { DynamicMethod dynamicMethod = new DynamicMethod(name, typeof(Object), new Type[1] { typeof(PlayerName) }, typeof(PlayerNameUiWritesPatch).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldfld, field); iLGenerator.Emit(OpCodes.Callvirt, property.GetGetMethod(nonPublic: true)); iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } private static Action EmitObjectFieldPropertySetter(FieldInfo field, PropertyInfo property, string name) { DynamicMethod dynamicMethod = new DynamicMethod(name, typeof(void), new Type[2] { typeof(PlayerName), typeof(Object) }, typeof(PlayerNameUiWritesPatch).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldfld, field); iLGenerator.Emit(OpCodes.Ldarg_1); iLGenerator.Emit(OpCodes.Castclass, property.PropertyType); iLGenerator.Emit(OpCodes.Callvirt, property.GetSetMethod(nonPublic: true)); iLGenerator.Emit(OpCodes.Ret); return (Action)dynamicMethod.CreateDelegate(typeof(Action)); } } internal sealed class PocketBehaviorGuardModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.PocketBehaviorGuard, () => new PatchDefinition(PatchId.PocketBehaviorGuard, PocketBehaviorGuardPatch.Initialize, PocketBehaviorGuardPatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(PocketBehaviorGuardPatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, PocketBehaviorGuardPatch.Reset)); } } internal static class PocketBehaviorGuardPatch { private static FieldRef _character; internal static void Initialize() { ResolveAndValidateTarget(); FieldInfo fieldInfo = ScaleValidation.RequireInstanceField(typeof(CharacterItems), "character", typeof(Character)); ScaleValidation.RequireInstanceProperty(typeof(Character), "player", typeof(Player)); ScaleValidation.RequireInstanceField(typeof(Player), "itemSlots", typeof(ItemSlot[])); ScaleValidation.RequireInstanceMethod(typeof(ItemSlot), "IsEmpty", typeof(bool), Type.EmptyTypes, requirePublic: true); ScaleValidation.RequireInstanceMethod(typeof(ItemSlot), "UpdatePocketBehaviors", typeof(void), new Type[1] { typeof(bool) }, requirePublic: true); _character = AccessTools.FieldRefAccess(fieldInfo) ?? throw new InvalidOperationException("PocketBehaviorGuard FieldRef creation failed"); } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(CharacterItems), "UpdatePocketBehaviors", typeof(void), Type.EmptyTypes, requirePublic: false); } internal static void Reset() { _character = null; } internal static bool Prefix(CharacterItems __instance) { FieldRef character = _character; if (character == null) { RateLimitedDiagnostics.Hit("PocketBehaviorGuard.accessor-unavailable"); return true; } Character val = character.Invoke(__instance); if ((Object)(object)val == (Object)null) { RateLimitedDiagnostics.Hit("PocketBehaviorGuard.character-unavailable"); return false; } Player player = val.player; if ((Object)(object)player == (Object)null) { RateLimitedDiagnostics.Hit("PocketBehaviorGuard.player-unavailable"); return false; } if (player.itemSlots == null) { RateLimitedDiagnostics.Hit("PocketBehaviorGuard.itemSlots-unavailable"); return false; } return true; } } internal sealed class RagdollPhysicsMatsModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.RagdollPhysicsMats, () => new PatchDefinition(PatchId.RagdollPhysicsMats, RagdollPhysicsMatsPatch.Initialize, RagdollPhysicsMatsPatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(RagdollPhysicsMatsPatch), "Prefix", (Type[])null), () => new HarmonyMethod(typeof(RagdollPhysicsMatsPatch), "Postfix", (Type[])null), null, null, requireCurrentMvid: true, RagdollPhysicsMatsPatch.Reset)); } } internal static class RagdollPhysicsMatsPatch { private sealed class State { internal bool HasApplied; internal int FrictionType; internal int PartCount; internal int ColliderSignature; internal int MaterialAuditSignature; internal int SlipperyMatId; internal int NormalMatId; internal int LastForcedFrame; internal float LastForcedTime; internal bool HasPending; internal int PendingFrictionType; internal int PendingPartCount; internal int PendingColliderSignature; internal int PendingMaterialAuditSignature; internal int PendingSlipperyMatId; internal int PendingNormalMatId; } private const string PhysicsMaterialTypeName = "UnityEngine.PhysicsMaterial"; private const string RigCreatorColliderTypeName = "RigCreatorCollider"; private const string CapsuleColliderTypeName = "UnityEngine.CapsuleCollider"; private const int ForceRefreshFrameInterval = 300; private const float ForceRefreshSecondsInterval = 5f; private const int MissingColliderMaterialSentinel = int.MinValue; private static ConditionalWeakTable _states; private static FieldRef _character; private static Func _slipperyMat; private static Func _normalMat; private static Func _colliderCount; private static Func _allColliderMaterialIdHash; internal static void Initialize() { ResolveAndValidateTarget(); FieldInfo fieldInfo = ScaleValidation.RequireInstanceField(typeof(CharacterRagdoll), "character", typeof(Character)); ScaleValidation.RequireInstanceField(typeof(CharacterRagdoll), "partList", typeof(List)); FieldInfo field = ScaleValidation.RequireInstanceFieldByTypeName(typeof(CharacterRagdoll), "slipperyMat", "UnityEngine.PhysicsMaterial"); FieldInfo field2 = ScaleValidation.RequireInstanceFieldByTypeName(typeof(CharacterRagdoll), "normalMat", "UnityEngine.PhysicsMaterial"); ScaleValidation.RequireInstanceField(typeof(Bodypart), "frictionType", typeof(FrictionType)); FieldInfo field3 = typeof(Bodypart).GetField("colliders", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field3 == null || field3.IsStatic || !ScaleEmit.IsClosedGenericListOf(field3.FieldType, "RigCreatorCollider")) { throw new InvalidOperationException("Bodypart.colliders failed structural self-check"); } ScaleValidation.RequireInstanceField(typeof(Character), "data", typeof(CharacterData)); ScaleValidation.RequireInstanceProperty(typeof(CharacterData), "currentRagdollControll", typeof(float)); FieldInfo field4 = field3.FieldType.GetGenericArguments()[0].GetField("col", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field4 == null || field4.IsStatic || field4.FieldType.FullName != "UnityEngine.CapsuleCollider") { throw new InvalidOperationException("RigCreatorCollider.col failed structural self-check"); } PropertyInfo objectProperty = ScaleValidation.RequireInstancePropertyByTypeName(field4.FieldType, "sharedMaterial", "UnityEngine.PhysicsMaterial", requireSetter: true); ScaleValidation.RequireInstanceMethodByTypeNames(typeof(Bodypart), "SetPhysicsMaterial", typeof(void).FullName, new string[3] { typeof(FrictionType).FullName, "UnityEngine.PhysicsMaterial", "UnityEngine.PhysicsMaterial" }); ScaleValidation.RequireInstanceMethod(typeof(CharacterRagdoll), "GetFrictionType", typeof(FrictionType), Type.EmptyTypes, requirePublic: false); FieldRef obj = AccessTools.FieldRefAccess(fieldInfo); Func func = ScaleEmit.CreateUnityObjectFieldGetter(field); Func func2 = ScaleEmit.CreateUnityObjectFieldGetter(field2); Func func3 = ScaleEmit.CreateCollectionCountGetter(field3); Func func4 = ScaleEmit.CreateAllElementsNestedObjectIdHash(field3, field4, objectProperty); if (obj == null || func == null || func2 == null || func3 == null || func4 == null) { throw new InvalidOperationException("RagdollPhysicsMats accessor creation failed"); } _states = new ConditionalWeakTable(); _character = obj; _slipperyMat = func; _normalMat = func2; _colliderCount = func3; _allColliderMaterialIdHash = func4; } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(CharacterRagdoll), "SetPhysicsMats", typeof(void), Type.EmptyTypes, requirePublic: false); } internal static void Reset() { _states = null; _character = null; _slipperyMat = null; _normalMat = null; _colliderCount = null; _allColliderMaterialIdHash = null; } internal static bool Prefix(CharacterRagdoll __instance) { //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Expected I4, but got Unknown ConditionalWeakTable states = _states; FieldRef character = _character; Func slipperyMat = _slipperyMat; Func normalMat = _normalMat; Func colliderCount = _colliderCount; Func allColliderMaterialIdHash = _allColliderMaterialIdHash; if (states == null || character == null || slipperyMat == null || normalMat == null || colliderCount == null || allColliderMaterialIdHash == null) { RateLimitedDiagnostics.Hit("RagdollPhysicsMats.state-unavailable"); return true; } List partList = __instance.partList; Character val = character.Invoke(__instance); if (partList == null || (Object)(object)val == (Object)null || (Object)(object)val.data == (Object)null) { RateLimitedDiagnostics.Hit("RagdollPhysicsMats.inputs-incomplete"); return true; } int num = ((val.data.currentRagdollControll < 0.9f) ? 1 : 2); int count = partList.Count; int num2 = 17; State orCreateValue = states.GetOrCreateValue(__instance); int frameCount = Time.frameCount; float time = Time.time; bool flag = !orCreateValue.HasApplied || frameCount - orCreateValue.LastForcedFrame >= 300 || frameCount < orCreateValue.LastForcedFrame || time - orCreateValue.LastForcedTime >= 5f || time < orCreateValue.LastForcedTime; int num3 = (flag ? 17 : orCreateValue.MaterialAuditSignature); for (int i = 0; i < count; i++) { Bodypart val2 = partList[i]; if ((Object)(object)val2 == (Object)null) { RateLimitedDiagnostics.Hit("RagdollPhysicsMats.part-null"); return true; } int num4 = colliderCount(val2); if (num4 < 0) { RateLimitedDiagnostics.Hit("RagdollPhysicsMats.colliders-null"); return true; } num2 = num2 * 31 + num4; num2 = num2 * 31 + val2.frictionType; if (flag) { num3 = num3 * 31 + allColliderMaterialIdHash(val2, int.MinValue); } } Object val3 = slipperyMat(__instance); Object val4 = normalMat(__instance); int num5 = ((val3 != (Object)null) ? val3.GetInstanceID() : 0); int num6 = ((val4 != (Object)null) ? val4.GetInstanceID() : 0); if (!flag && orCreateValue.HasApplied && orCreateValue.FrictionType == num && orCreateValue.PartCount == count && orCreateValue.ColliderSignature == num2 && orCreateValue.MaterialAuditSignature == num3 && orCreateValue.SlipperyMatId == num5 && orCreateValue.NormalMatId == num6) { return false; } orCreateValue.PendingFrictionType = num; orCreateValue.PendingPartCount = count; orCreateValue.PendingColliderSignature = num2; orCreateValue.PendingMaterialAuditSignature = num3; orCreateValue.PendingSlipperyMatId = num5; orCreateValue.PendingNormalMatId = num6; orCreateValue.HasPending = true; orCreateValue.LastForcedFrame = frameCount; orCreateValue.LastForcedTime = time; return true; } internal static void Postfix(CharacterRagdoll __instance, bool __runOriginal) { ConditionalWeakTable states = _states; if (states != null && !((Object)(object)__instance == (Object)null) && states.TryGetValue(__instance, out var value) && value.HasPending) { if (!__runOriginal) { value.HasPending = false; return; } value.HasApplied = true; value.FrictionType = value.PendingFrictionType; value.PartCount = value.PendingPartCount; value.ColliderSignature = value.PendingColliderSignature; value.MaterialAuditSignature = value.PendingMaterialAuditSignature; value.SlipperyMatId = value.PendingSlipperyMatId; value.NormalMatId = value.PendingNormalMatId; value.HasPending = false; } } } internal static class ScaleEmit { private sealed class NestedAccessorMethods { internal MethodInfo CountGetter; internal MethodInfo ItemGetter; internal MethodInfo ObjectGetter; internal MethodInfo InstanceIdGetter; } internal static Func CreateUnityObjectFieldGetter(FieldInfo field) { if (field == null) { throw new ArgumentNullException("field"); } if (field.IsStatic || field.DeclaringType != typeof(TInstance)) { throw new InvalidOperationException("Unexpected field owner for " + field.Name); } if (!typeof(Object).IsAssignableFrom(field.FieldType)) { throw new InvalidOperationException(field.Name + " is not a UnityEngine.Object field"); } DynamicMethod dynamicMethod = new DynamicMethod("PSO_Get_" + field.Name, typeof(Object), new Type[1] { typeof(TInstance) }, typeof(ScaleEmit).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldfld, field); iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } internal static Func CreateEnumPropertyGetterViaField(FieldInfo field, PropertyInfo property) { MethodInfo meth = RequireAccessor(field, property, wantSetter: false); DynamicMethod dynamicMethod = new DynamicMethod("PSO_GetEnum_" + property.Name, typeof(int), new Type[1] { typeof(TInstance) }, typeof(ScaleEmit).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldfld, field); iLGenerator.Emit(OpCodes.Callvirt, meth); iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } internal static Action CreateEnumPropertySetterViaField(FieldInfo field, PropertyInfo property) { MethodInfo meth = RequireAccessor(field, property, wantSetter: true); DynamicMethod dynamicMethod = new DynamicMethod("PSO_SetEnum_" + property.Name, typeof(void), new Type[2] { typeof(TInstance), typeof(int) }, typeof(ScaleEmit).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldfld, field); iLGenerator.Emit(OpCodes.Ldarg_1); iLGenerator.Emit(OpCodes.Callvirt, meth); iLGenerator.Emit(OpCodes.Ret); return (Action)dynamicMethod.CreateDelegate(typeof(Action)); } internal static Func CreateCollectionCountGetter(FieldInfo field) { if (field == null) { throw new ArgumentNullException("field"); } if (field.IsStatic || field.DeclaringType != typeof(TInstance)) { throw new InvalidOperationException("Unexpected field owner for " + field.Name); } PropertyInfo property = field.FieldType.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public); MethodInfo methodInfo = property?.GetGetMethod(nonPublic: false); if (property == null || methodInfo == null || property.PropertyType != typeof(int)) { throw new InvalidOperationException(field.Name + " has no int Count property"); } DynamicMethod dynamicMethod = new DynamicMethod("PSO_Count_" + field.Name, typeof(int), new Type[1] { typeof(TInstance) }, typeof(ScaleEmit).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); Label label = iLGenerator.DefineLabel(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldfld, field); iLGenerator.Emit(OpCodes.Dup); iLGenerator.Emit(OpCodes.Brtrue_S, label); iLGenerator.Emit(OpCodes.Pop); iLGenerator.Emit(OpCodes.Ldc_I4_M1); iLGenerator.Emit(OpCodes.Ret); iLGenerator.MarkLabel(label); iLGenerator.Emit(OpCodes.Callvirt, methodInfo); iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } internal static Func CreateAllElementsNestedObjectIdHash(FieldInfo listField, FieldInfo elementField, PropertyInfo objectProperty) { NestedAccessorMethods nestedAccessorMethods = ResolveNestedObjectAccessors(listField, elementField, objectProperty); Type fieldType = listField.FieldType; Type localType = fieldType.GetGenericArguments()[0]; Type fieldType2 = elementField.FieldType; Type propertyType = objectProperty.PropertyType; DynamicMethod dynamicMethod = new DynamicMethod("PSO_AllNestedObjectIdHash_" + listField.Name, typeof(int), new Type[2] { typeof(TInstance), typeof(int) }, typeof(ScaleEmit).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); Label label = iLGenerator.DefineLabel(); Label label2 = iLGenerator.DefineLabel(); Label label3 = iLGenerator.DefineLabel(); Label label4 = iLGenerator.DefineLabel(); LocalBuilder local = iLGenerator.DeclareLocal(fieldType); LocalBuilder local2 = iLGenerator.DeclareLocal(typeof(int)); LocalBuilder local3 = iLGenerator.DeclareLocal(typeof(int)); LocalBuilder local4 = iLGenerator.DeclareLocal(typeof(int)); LocalBuilder local5 = iLGenerator.DeclareLocal(localType); LocalBuilder local6 = iLGenerator.DeclareLocal(fieldType2); LocalBuilder local7 = iLGenerator.DeclareLocal(propertyType); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldfld, listField); iLGenerator.Emit(OpCodes.Stloc, local); iLGenerator.Emit(OpCodes.Ldloc, local); iLGenerator.Emit(OpCodes.Brfalse, label); iLGenerator.Emit(OpCodes.Ldloc, local); iLGenerator.Emit(OpCodes.Callvirt, nestedAccessorMethods.CountGetter); iLGenerator.Emit(OpCodes.Stloc, local2); iLGenerator.Emit(OpCodes.Ldloc, local2); iLGenerator.Emit(OpCodes.Brfalse, label); iLGenerator.Emit(OpCodes.Ldc_I4, 17); iLGenerator.Emit(OpCodes.Stloc, local4); iLGenerator.Emit(OpCodes.Ldc_I4_0); iLGenerator.Emit(OpCodes.Stloc, local3); iLGenerator.MarkLabel(label2); iLGenerator.Emit(OpCodes.Ldloc, local3); iLGenerator.Emit(OpCodes.Ldloc, local2); iLGenerator.Emit(OpCodes.Bge, label3); iLGenerator.Emit(OpCodes.Ldloc, local); iLGenerator.Emit(OpCodes.Ldloc, local3); iLGenerator.Emit(OpCodes.Callvirt, nestedAccessorMethods.ItemGetter); iLGenerator.Emit(OpCodes.Stloc, local5); iLGenerator.Emit(OpCodes.Ldloc, local5); iLGenerator.Emit(OpCodes.Brfalse, label4); iLGenerator.Emit(OpCodes.Ldloc, local5); iLGenerator.Emit(OpCodes.Ldfld, elementField); iLGenerator.Emit(OpCodes.Stloc, local6); iLGenerator.Emit(OpCodes.Ldloc, local6); iLGenerator.Emit(OpCodes.Brfalse, label4); iLGenerator.Emit(OpCodes.Ldloc, local6); iLGenerator.Emit(OpCodes.Callvirt, nestedAccessorMethods.ObjectGetter); iLGenerator.Emit(OpCodes.Stloc, local7); iLGenerator.Emit(OpCodes.Ldloc, local7); iLGenerator.Emit(OpCodes.Brfalse, label4); iLGenerator.Emit(OpCodes.Ldc_I4, 31); iLGenerator.Emit(OpCodes.Ldloc, local4); iLGenerator.Emit(OpCodes.Mul); iLGenerator.Emit(OpCodes.Ldloc, local7); iLGenerator.Emit(OpCodes.Callvirt, nestedAccessorMethods.InstanceIdGetter); iLGenerator.Emit(OpCodes.Add); iLGenerator.Emit(OpCodes.Stloc, local4); iLGenerator.MarkLabel(label4); iLGenerator.Emit(OpCodes.Ldloc, local3); iLGenerator.Emit(OpCodes.Ldc_I4_1); iLGenerator.Emit(OpCodes.Add); iLGenerator.Emit(OpCodes.Stloc, local3); iLGenerator.Emit(OpCodes.Br, label2); iLGenerator.MarkLabel(label3); iLGenerator.Emit(OpCodes.Ldloc, local4); iLGenerator.Emit(OpCodes.Ret); iLGenerator.MarkLabel(label); iLGenerator.Emit(OpCodes.Ldarg_1); iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } private static NestedAccessorMethods ResolveNestedObjectAccessors(FieldInfo listField, FieldInfo elementField, PropertyInfo objectProperty) { if (listField == null) { throw new ArgumentNullException("listField"); } if (elementField == null) { throw new ArgumentNullException("elementField"); } if (objectProperty == null) { throw new ArgumentNullException("objectProperty"); } if (listField.IsStatic || listField.DeclaringType != typeof(TInstance)) { throw new InvalidOperationException("Unexpected field owner for " + listField.Name); } Type fieldType = listField.FieldType; if (!fieldType.IsGenericType || fieldType.GetGenericTypeDefinition() != typeof(List<>)) { throw new InvalidOperationException(listField.Name + " is not a List<>"); } Type type = fieldType.GetGenericArguments()[0]; if (type.IsValueType) { throw new InvalidOperationException(listField.Name + " element type must be a reference type"); } if (elementField.IsStatic || elementField.DeclaringType != type) { throw new InvalidOperationException(elementField.Name + " is not declared on the element type"); } if (!typeof(Object).IsAssignableFrom(elementField.FieldType)) { throw new InvalidOperationException(elementField.Name + " is not a UnityEngine.Object field"); } if (!objectProperty.DeclaringType.IsAssignableFrom(elementField.FieldType)) { throw new InvalidOperationException(objectProperty.Name + " is not reachable from " + elementField.Name); } if (!typeof(Object).IsAssignableFrom(objectProperty.PropertyType) || objectProperty.GetIndexParameters().Length != 0) { throw new InvalidOperationException(objectProperty.Name + " is not a parameterless UnityEngine.Object property"); } MethodInfo getMethod = objectProperty.GetGetMethod(nonPublic: true); if (getMethod == null || getMethod.IsStatic) { throw new InvalidOperationException(objectProperty.Name + " getter is unavailable"); } PropertyInfo property = fieldType.GetProperty("Count", BindingFlags.Instance | BindingFlags.Public); MethodInfo methodInfo = property?.GetGetMethod(nonPublic: false); MethodInfo methodInfo2 = fieldType.GetProperty("Item", BindingFlags.Instance | BindingFlags.Public)?.GetGetMethod(nonPublic: false); if (methodInfo == null || methodInfo2 == null || property.PropertyType != typeof(int)) { throw new InvalidOperationException(listField.Name + " has no usable Count/Item accessors"); } MethodInfo method = typeof(Object).GetMethod("GetInstanceID", BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null); if (method == null || method.ReturnType != typeof(int)) { throw new InvalidOperationException("UnityEngine.Object.GetInstanceID structure mismatch"); } return new NestedAccessorMethods { CountGetter = methodInfo, ItemGetter = methodInfo2, ObjectGetter = getMethod, InstanceIdGetter = method }; } internal static bool IsClosedGenericListOf(Type type, string elementTypeFullName) { if (type == null || !type.IsGenericType || type.IsGenericTypeDefinition) { return false; } if (type.GetGenericTypeDefinition() != typeof(List<>)) { return false; } Type[] genericArguments = type.GetGenericArguments(); if (genericArguments.Length == 1) { return string.Equals(genericArguments[0].FullName, elementTypeFullName, StringComparison.Ordinal); } return false; } private static MethodInfo RequireAccessor(FieldInfo field, PropertyInfo property, bool wantSetter) { if (field == null) { throw new ArgumentNullException("field"); } if (property == null) { throw new ArgumentNullException("property"); } if (field.IsStatic) { throw new InvalidOperationException(field.Name + " must be an instance field"); } if (!property.DeclaringType.IsAssignableFrom(field.FieldType)) { throw new InvalidOperationException(property.Name + " is not reachable through field " + field.Name); } if (!property.PropertyType.IsEnum || Enum.GetUnderlyingType(property.PropertyType) != typeof(int)) { throw new InvalidOperationException(property.Name + " is not an int-backed enum"); } MethodInfo methodInfo = (wantSetter ? property.GetSetMethod(nonPublic: true) : property.GetGetMethod(nonPublic: true)); if (methodInfo == null || methodInfo.IsStatic) { throw new InvalidOperationException(property.Name + " accessor is unavailable"); } return methodInfo; } } internal static class ScaleValidation { private const BindingFlags DeclaredInstance = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private const BindingFlags DeclaredStatic = BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; internal static FieldInfo RequireInstanceField(Type owner, string name, Type fieldType) { FieldInfo field = owner.GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { throw new MissingFieldException(owner.FullName, name); } if (field.DeclaringType != owner || field.IsStatic || field.FieldType != fieldType) { throw new InvalidOperationException("Unexpected field structure: " + owner.FullName + "." + name); } return field; } internal static FieldInfo RequireInstanceFieldByTypeName(Type owner, string name, string fieldTypeFullName) { FieldInfo field = owner.GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { throw new MissingFieldException(owner.FullName, name); } if (field.DeclaringType != owner || field.IsStatic || !string.Equals(field.FieldType.FullName, fieldTypeFullName, StringComparison.Ordinal)) { throw new InvalidOperationException("Unexpected field structure: " + owner.FullName + "." + name); } return field; } internal static PropertyInfo RequireInstancePropertyByTypeName(Type owner, string name, string propertyTypeFullName, bool requireSetter) { PropertyInfo property = owner.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); MethodInfo methodInfo = property?.GetGetMethod(nonPublic: true); MethodInfo methodInfo2 = property?.GetSetMethod(nonPublic: true); if (property == null || methodInfo == null || methodInfo.IsStatic || property.GetIndexParameters().Length != 0 || !string.Equals(property.PropertyType.FullName, propertyTypeFullName, StringComparison.Ordinal) || (requireSetter && (methodInfo2 == null || methodInfo2.IsStatic))) { throw new InvalidOperationException("Unexpected property structure: " + owner.FullName + "." + name); } return property; } internal static MethodInfo RequireInstanceMethodByTypeNames(Type owner, string name, string returnTypeFullName, string[] parameterTypeFullNames) { MethodInfo[] methods = owner.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); MethodInfo methodInfo = null; foreach (MethodInfo methodInfo2 in methods) { if (!string.Equals(methodInfo2.Name, name, StringComparison.Ordinal) || methodInfo2.IsStatic || methodInfo2.ContainsGenericParameters || !string.Equals(methodInfo2.ReturnType.FullName, returnTypeFullName, StringComparison.Ordinal)) { continue; } ParameterInfo[] parameters = methodInfo2.GetParameters(); if (parameters.Length != parameterTypeFullNames.Length) { continue; } bool flag = true; for (int j = 0; j < parameters.Length; j++) { if (!string.Equals(parameters[j].ParameterType.FullName, parameterTypeFullNames[j], StringComparison.Ordinal)) { flag = false; break; } } if (flag) { if (methodInfo != null) { throw new InvalidOperationException("Ambiguous method structure: " + owner.FullName + "." + name); } methodInfo = methodInfo2; } } if (methodInfo == null) { throw new MissingMethodException(owner.FullName, name); } return methodInfo; } internal static FieldInfo RequireStaticField(Type owner, string name, Type fieldType) { FieldInfo field = owner.GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { throw new MissingFieldException(owner.FullName, name); } if (field.DeclaringType != owner || !field.IsStatic || field.FieldType != fieldType) { throw new InvalidOperationException("Unexpected static field structure: " + owner.FullName + "." + name); } return field; } internal static PropertyInfo RequireInstanceProperty(Type owner, string name, Type propertyType) { PropertyInfo property = owner.GetProperty(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); MethodInfo methodInfo = property?.GetGetMethod(nonPublic: true); if (property == null || property.DeclaringType != owner || property.PropertyType != propertyType || property.GetIndexParameters().Length != 0 || methodInfo == null || methodInfo.IsStatic) { throw new InvalidOperationException("Unexpected property structure: " + owner.FullName + "." + name); } return property; } internal static PropertyInfo RequireStaticProperty(Type owner, string name, Type propertyType) { PropertyInfo property = owner.GetProperty(name, BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); MethodInfo methodInfo = property?.GetGetMethod(nonPublic: true); if (property == null || property.DeclaringType != owner || property.PropertyType != propertyType || property.GetIndexParameters().Length != 0 || methodInfo == null || !methodInfo.IsStatic) { throw new InvalidOperationException("Unexpected static property structure: " + owner.FullName + "." + name); } return property; } internal static PropertyInfo RequireInheritedInstanceProperty(Type owner, string name, Type propertyType) { PropertyInfo property = owner.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); MethodInfo methodInfo = property?.GetGetMethod(nonPublic: true); if (property == null || property.PropertyType != propertyType || property.GetIndexParameters().Length != 0 || methodInfo == null || methodInfo.IsStatic) { throw new InvalidOperationException("Unexpected inherited property structure: " + owner.FullName + "." + name); } return property; } internal static MethodInfo RequireInstanceMethod(Type owner, string name, Type returnType, Type[] parameterTypes, bool requirePublic) { MethodInfo? method = owner.GetMethod(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, parameterTypes, null); Validate(method, owner, name, returnType, parameterTypes, requireStatic: false, requirePublic); return method; } internal static MethodInfo RequireStaticMethod(Type owner, string name, Type returnType, Type[] parameterTypes, bool requirePublic) { MethodInfo? method = owner.GetMethod(name, BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, parameterTypes, null); Validate(method, owner, name, returnType, parameterTypes, requireStatic: true, requirePublic); return method; } private static void Validate(MethodInfo method, Type owner, string name, Type returnType, Type[] parameterTypes, bool requireStatic, bool requirePublic) { if (method == null) { throw new MissingMethodException(owner.FullName, name); } if (method.DeclaringType != owner || method.IsStatic != requireStatic || method.ReturnType != returnType || method.ContainsGenericParameters || (requirePublic && !method.IsPublic)) { throw new InvalidOperationException("Unexpected method structure: " + owner.FullName + "." + name); } ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length != parameterTypes.Length) { throw new InvalidOperationException("Unexpected parameter count: " + owner.FullName + "." + name); } for (int i = 0; i < parameters.Length; i++) { if (parameters[i].ParameterType != parameterTypes[i]) { throw new InvalidOperationException($"Unexpected parameter {i}: {owner.FullName}.{name}"); } } } } internal sealed class SnowballContactModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.SnowballContactSnapshot, () => new PatchDefinition(PatchId.SnowballContactSnapshot, SnowballContactPatch.Initialize, SnowballContactPatch.ResolveStayTarget, () => new HarmonyMethod(typeof(SnowballContactPatch), "StayPrefix", (Type[])null), null, null, null, requireCurrentMvid: true)); context.Register(PatchId.SnowballContactConsume, () => new PatchDefinition(PatchId.SnowballContactConsume, SnowballContactPatch.Initialize, SnowballContactPatch.ResolveProcessTarget, () => new HarmonyMethod(typeof(SnowballContactPatch), "ProcessPrefix", (Type[])null), null, null, null, requireCurrentMvid: true)); } } internal static class SnowballContactPatch { private enum ContactType { Unknown, RegularGround, SnowyGround, Snowball } private sealed class Snapshot { internal Collider Collider; internal GameObject GameObject; internal Vector3 Normal; internal bool HasNormal; } private const string SnowName = "snow"; private const string IceName = "ice"; private const string StoneTag = "Stone1"; private const string SnowballTag = "Snowball"; private static readonly ConditionalWeakTable Snapshots = new ConditionalWeakTable(); private static FieldRef _unprocessedContact; private static FieldRef _lastCollision; private static FieldRef _terrainLayer; private static FieldRef _characterLayer; private static FieldRef _lastContactType; private static FieldRef _timeLastCollided; private static FieldRef _timeLastTouchedScout; private static FieldRef _previousPosition; private static FieldRef _scaleRate; private static FieldRef _minimumSpeedToGrow; private static FieldRef _scaleSyncer; private static Action _updateMass; internal static void Initialize() { ResolveStayTarget(); ResolveProcessTarget(); FieldInfo fieldInfo = ScaleValidation.RequireInstanceField(typeof(Snowball), "_unprocessedContact", typeof(Collision)); FieldInfo fieldInfo2 = ScaleValidation.RequireInstanceField(typeof(Snowball), "_lastCollision", typeof(Collider)); FieldInfo fieldInfo3 = ScaleValidation.RequireInstanceField(typeof(Snowball), "terrainLayer", typeof(int)); FieldInfo fieldInfo4 = ScaleValidation.RequireInstanceField(typeof(Snowball), "characterLayer", typeof(int)); FieldInfo fieldInfo5 = RequireContactTypeField(); FieldInfo fieldInfo6 = ScaleValidation.RequireInstanceField(typeof(Snowball), "_timeLastCollided", typeof(float)); FieldInfo fieldInfo7 = ScaleValidation.RequireInstanceField(typeof(Snowball), "_timeLastTouchedScout", typeof(float)); FieldInfo fieldInfo8 = ScaleValidation.RequireInstanceField(typeof(Snowball), "_previousPosition", typeof(Vector3?)); FieldInfo fieldInfo9 = ScaleValidation.RequireInstanceField(typeof(Snowball), "scaleRate", typeof(float)); FieldInfo fieldInfo10 = ScaleValidation.RequireInstanceField(typeof(Snowball), "minimumSpeedToGrow", typeof(float)); FieldInfo fieldInfo11 = ScaleValidation.RequireInstanceField(typeof(Snowball), "scaleSyncer", typeof(ItemScaleSyncer)); MethodInfo methodInfo = ScaleValidation.RequireInstanceMethod(typeof(Snowball), "UpdateMass", typeof(void), Type.EmptyTypes, requirePublic: false); ScaleValidation.RequireInstanceProperty(typeof(Snowball), "CanGrow", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(ItemScaleSyncer), "currentScale", typeof(float)); ScaleValidation.RequireInstanceField(typeof(Item), "rig", typeof(Rigidbody)); ScaleValidation.RequireInstanceField(typeof(ItemComponent), "item", typeof(Item)); ScaleValidation.RequireInstanceMethod(typeof(Snowball), "Scale", typeof(void), new Type[1] { typeof(float) }, requirePublic: false); ScaleValidation.RequireInstanceMethod(typeof(Snowball), "ClassifyCurrentContact", RequireContactTypeField().FieldType, Type.EmptyTypes, requirePublic: false); ScaleValidation.RequireInstanceMethod(typeof(Item), "SetKinematic", typeof(void), new Type[1] { typeof(bool) }, requirePublic: true); FieldRef obj = AccessTools.FieldRefAccess(fieldInfo); FieldRef val = AccessTools.FieldRefAccess(fieldInfo2); FieldRef val2 = AccessTools.FieldRefAccess(fieldInfo3); FieldRef val3 = AccessTools.FieldRefAccess(fieldInfo4); FieldRef val4 = AccessTools.FieldRefAccess(fieldInfo5); FieldRef val5 = AccessTools.FieldRefAccess(fieldInfo6); FieldRef val6 = AccessTools.FieldRefAccess(fieldInfo7); FieldRef val7 = AccessTools.FieldRefAccess(fieldInfo8); FieldRef val8 = AccessTools.FieldRefAccess(fieldInfo9); FieldRef val9 = AccessTools.FieldRefAccess(fieldInfo10); FieldRef val10 = AccessTools.FieldRefAccess(fieldInfo11); Action action = (Action)methodInfo.CreateDelegate(typeof(Action)); if (obj == null || val == null || val2 == null || val3 == null || val4 == null || val5 == null || val6 == null || val7 == null || val8 == null || val9 == null || val10 == null || action == null) { throw new InvalidOperationException("SnowballContact accessor creation failed"); } _unprocessedContact = obj; _lastCollision = val; _terrainLayer = val2; _characterLayer = val3; _lastContactType = val4; _timeLastCollided = val5; _timeLastTouchedScout = val6; _previousPosition = val7; _scaleRate = val8; _minimumSpeedToGrow = val9; _scaleSyncer = val10; _updateMass = action; } internal static MethodInfo ResolveStayTarget() { return ScaleValidation.RequireInstanceMethod(typeof(Snowball), "OnCollisionStay", typeof(void), new Type[1] { typeof(Collision) }, requirePublic: false); } internal static MethodInfo ResolveProcessTarget() { return ScaleValidation.RequireInstanceMethod(typeof(Snowball), "ProcessLastCollision", typeof(void), Type.EmptyTypes, requirePublic: false); } internal static void Reset() { _unprocessedContact = null; _lastCollision = null; _terrainLayer = null; _characterLayer = null; _lastContactType = null; _timeLastCollided = null; _timeLastTouchedScout = null; _previousPosition = null; _scaleRate = null; _minimumSpeedToGrow = null; _scaleSyncer = null; _updateMass = null; } internal static bool StayPrefix(Snowball __instance, Collision other) { //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_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_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) FieldRef characterLayer = _characterLayer; FieldRef unprocessedContact = _unprocessedContact; FieldRef timeLastTouchedScout = _timeLastTouchedScout; if (characterLayer == null || unprocessedContact == null || timeLastTouchedScout == null || (Object)(object)__instance == (Object)null || other == null) { return true; } GameObject gameObject; try { gameObject = other.gameObject; } catch (Exception) { RateLimitedDiagnostics.Hit("SnowballContactSnapshot.gameObject-unavailable"); return true; } if ((Object)(object)gameObject == (Object)null) { return true; } if (gameObject.layer != characterLayer.Invoke(__instance)) { Snapshot orCreateValue = Snapshots.GetOrCreateValue(__instance); orCreateValue.GameObject = gameObject; orCreateValue.Collider = other.collider; if (other.contactCount > 0) { ContactPoint contact = other.GetContact(0); orCreateValue.Normal = ((ContactPoint)(ref contact)).normal; orCreateValue.HasNormal = true; } else { orCreateValue.Normal = Vector3.zero; orCreateValue.HasNormal = false; } unprocessedContact.Invoke(__instance) = other; return false; } Item item = ((ItemComponent)__instance).item; if ((Object)(object)item == (Object)null) { RateLimitedDiagnostics.Hit("SnowballContactSnapshot.item-unavailable"); return true; } timeLastTouchedScout.Invoke(__instance) = Time.time; item.SetKinematic(false); return false; } internal static bool ProcessPrefix(Snowball __instance) { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) FieldRef unprocessedContact = _unprocessedContact; FieldRef lastCollision = _lastCollision; FieldRef lastContactType = _lastContactType; FieldRef timeLastCollided = _timeLastCollided; FieldRef previousPosition = _previousPosition; if (unprocessedContact == null || lastCollision == null || lastContactType == null || timeLastCollided == null || previousPosition == null || (Object)(object)__instance == (Object)null) { return true; } if (unprocessedContact.Invoke(__instance) == null) { return false; } if (!Snapshots.TryGetValue(__instance, out var value) || value == null || (Object)(object)value.GameObject == (Object)null) { RateLimitedDiagnostics.Hit("SnowballContactConsume.snapshot-unavailable"); return true; } lastCollision.Invoke(__instance) = value.Collider; ContactType contactType = Classify(__instance, value); if (contactType == ContactType.SnowyGround) { if (CanGrow(__instance)) { Grow(__instance, value); } previousPosition.Invoke(__instance) = ((Component)__instance).transform.position; } timeLastCollided.Invoke(__instance) = Time.time; lastContactType.Invoke(__instance) = (int)contactType; unprocessedContact.Invoke(__instance) = null; value.Collider = null; value.GameObject = null; value.HasNormal = false; return false; } private static bool CanGrow(Snowball instance) { //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) Item item = ((ItemComponent)instance).item; Rigidbody val = (((Object)(object)item != (Object)null) ? item.rig : null); if ((Object)(object)val == (Object)null) { return false; } Vector3 linearVelocity = val.linearVelocity; return ((Vector3)(ref linearVelocity)).magnitude > _minimumSpeedToGrow.Invoke(instance); } private static void Grow(Snowball instance, Snapshot snapshot) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //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_005d: 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_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) Vector3? val = _previousPosition.Invoke(instance); if (!val.HasValue) { return; } if (!snapshot.HasNormal) { RateLimitedDiagnostics.Hit("SnowballContactConsume.no-contact-point"); return; } ItemScaleSyncer val2 = _scaleSyncer.Invoke(instance); if (!((Object)(object)val2 == (Object)null)) { Vector3 val3 = ((Component)instance).transform.position - val.Value; val3 = Vector3.ProjectOnPlane(val3, snapshot.Normal); float num = Mathf.Clamp(1f * _scaleRate.Invoke(instance) * ((Vector3)(ref val3)).magnitude, 0f, 0.1f); val2.currentScale += num / val2.currentScale; _updateMass(instance); } } private static ContactType Classify(Snowball instance, Snapshot snapshot) { GameObject gameObject = snapshot.GameObject; Renderer val = default(Renderer); if ((gameObject.layer == _terrainLayer.Invoke(instance) || gameObject.CompareTag("Stone1")) && gameObject.TryGetComponent(ref val)) { string text = ((Object)val.sharedMaterial).name.ToLowerInvariant(); if (!text.Contains("ice") && !text.Contains("snow")) { return ContactType.RegularGround; } return ContactType.SnowyGround; } if (!gameObject.CompareTag("Snowball")) { return ContactType.Unknown; } return ContactType.Snowball; } private static FieldInfo RequireContactTypeField() { FieldInfo field = typeof(Snowball).GetField("_lastContactType", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) { throw new MissingFieldException(typeof(Snowball).FullName, "_lastContactType"); } Type fieldType = field.FieldType; if (!fieldType.IsEnum || Enum.GetUnderlyingType(fieldType) != typeof(int)) { throw new InvalidOperationException("Snowball._lastContactType is not an int-backed enum"); } string[] array = new string[4] { "Unknown", "RegularGround", "SnowyGround", "Snowball" }; string[] names = Enum.GetNames(fieldType); if (names.Length != array.Length) { throw new InvalidOperationException("Snowball ContactType member count changed"); } for (int i = 0; i < array.Length; i++) { if (!string.Equals(names[i], array[i], StringComparison.Ordinal)) { throw new InvalidOperationException("Snowball ContactType." + array[i] + " moved"); } if ((int)Enum.Parse(fieldType, array[i]) != i) { throw new InvalidOperationException("Snowball ContactType." + array[i] + " changed value"); } } return field; } } internal sealed class ZombieDisableScanModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.ZombieScanRange, () => new PatchDefinition(PatchId.ZombieScanRange, ZombieDisableScanPatch.Initialize, ZombieDisableScanPatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(ZombieDisableScanPatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, ZombieDisableScanPatch.Reset)); } } internal static class ZombieDisableScanPatch { private static FieldRef _character; private static FieldRef _timeDiedAt; internal static void Initialize() { ResolveAndValidateTarget(); FieldInfo fieldInfo = ScaleValidation.RequireInstanceField(typeof(MushroomZombie), "character", typeof(Character)); ScaleValidation.RequireInstanceField(typeof(MushroomZombie), "distanceToEnable", typeof(float)); ScaleValidation.RequireInstanceField(typeof(MushroomZombie), "_currentState", typeof(State)); ScaleValidation.RequireInstanceProperty(typeof(MushroomZombie), "currentState", typeof(State)); FieldInfo fieldInfo2 = ScaleValidation.RequireInstanceField(typeof(MushroomZombie), "timeDiedAt", typeof(float)); if (fieldInfo2.IsPublic) { throw new InvalidOperationException("MushroomZombie.timeDiedAt is no longer a private instance field"); } ScaleValidation.RequireStaticField(typeof(Character), "AllCharacters", typeof(List)); ScaleValidation.RequireInstanceProperty(typeof(Character), "Center", typeof(Vector3)); ScaleValidation.RequireStaticMethod(typeof(Vector3), "Distance", typeof(float), new Type[2] { typeof(Vector3), typeof(Vector3) }, requirePublic: true); if (!Enum.IsDefined(typeof(State), (object)(State)6) || !Enum.IsDefined(typeof(State), (object)(State)0)) { throw new InvalidOperationException("MushroomZombie.State.Dead/Sleeping is no longer defined"); } FieldRef obj = AccessTools.FieldRefAccess(fieldInfo); FieldRef val = AccessTools.FieldRefAccess(fieldInfo2); if (obj == null || val == null) { throw new InvalidOperationException("ZombieDisableScan accessor creation failed"); } _character = obj; _timeDiedAt = val; } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(MushroomZombie), "ReadyToDisable", typeof(bool), Type.EmptyTypes, requirePublic: true); } internal static void Reset() { _character = null; _timeDiedAt = null; } internal static bool Prefix(MushroomZombie __instance, ref bool __result) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Invalid comparison between Unknown and I4 //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_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Invalid comparison between Unknown and I4 //IL_0124: Unknown result type (might be due to invalid IL or missing references) FieldRef character = _character; FieldRef timeDiedAt = _timeDiedAt; if (character == null || timeDiedAt == null) { RateLimitedDiagnostics.Hit("ZombieDisableScan.accessors-unavailable"); return true; } if ((int)__instance.currentState == 6 && timeDiedAt.Invoke(__instance) + 10f < Time.time) { __result = true; return false; } Character val = character.Invoke(__instance); List allCharacters = Character.AllCharacters; if ((Object)(object)val == (Object)null || allCharacters == null) { RateLimitedDiagnostics.Hit("ZombieDisableScan.inputs-unavailable"); return true; } float num = __instance.distanceToEnable + 5f; if (!(num > 0f)) { RateLimitedDiagnostics.Hit("ZombieDisableScan.non-positive-threshold-fallback"); return true; } Vector3 center = val.Center; float num2 = 10000f; float num3 = num * num; if (!(num3 > 0f) || float.IsInfinity(num3)) { return true; } bool flag = false; bool flag2 = false; for (int i = 0; i < allCharacters.Count; i++) { Character val2 = allCharacters[i]; if (!((Object)(object)val2 == (Object)null)) { Vector3 val3 = val2.Center - center; float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude; if (sqrMagnitude <= num2) { flag2 = true; } if (sqrMagnitude <= num3) { flag = true; } if (flag && flag2) { break; } } } if (!flag2) { __result = true; return false; } if ((int)__instance.currentState != 6 && (int)__instance.currentState != 0) { __result = false; return false; } __result = !flag; return false; } } internal sealed class ZombieSpawnScanModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.ZombieSpawnScanRange, () => new PatchDefinition(PatchId.ZombieSpawnScanRange, ZombieSpawnScanPatch.Initialize, ZombieSpawnScanPatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(ZombieSpawnScanPatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, ZombieSpawnScanPatch.Reset)); } } internal static class ZombieSpawnScanPatch { private static FieldRef _spawned; internal static void Initialize() { ResolveAndValidateTarget(); FieldInfo fieldInfo = ScaleValidation.RequireInstanceField(typeof(MushroomZombieSpawner), "spawned", typeof(bool)); if (fieldInfo.IsPublic) { throw new InvalidOperationException("MushroomZombieSpawner.spawned is no longer a private instance field"); } ScaleValidation.RequireInstanceField(typeof(MushroomZombieSpawner), "spawnedZombie", typeof(MushroomZombie)); ScaleValidation.RequireInstanceField(typeof(MushroomZombieSpawner), "mushroomZombiePrefab", typeof(MushroomZombie)); ScaleValidation.RequireInstanceField(typeof(MushroomZombie), "distanceToEnable", typeof(float)); ScaleValidation.RequireStaticField(typeof(Character), "AllCharacters", typeof(List)); ScaleValidation.RequireInstanceProperty(typeof(Character), "Center", typeof(Vector3)); ScaleValidation.RequireStaticMethod(typeof(Vector3), "Distance", typeof(float), new Type[2] { typeof(Vector3), typeof(Vector3) }, requirePublic: true); _spawned = AccessTools.FieldRefAccess(fieldInfo) ?? throw new InvalidOperationException("ZombieSpawnScan accessor creation failed"); } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(MushroomZombieSpawner), "ReadyToSpawn", typeof(bool), Type.EmptyTypes, requirePublic: true); } internal static void Reset() { _spawned = null; } internal static bool Prefix(MushroomZombieSpawner __instance, ref bool __result) { //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_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_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) FieldRef spawned = _spawned; if (spawned == null) { RateLimitedDiagnostics.Hit("ZombieSpawnScan.accessors-unavailable"); return true; } if ((Object)(object)__instance.spawnedZombie != (Object)null || spawned.Invoke(__instance)) { __result = false; return false; } MushroomZombie mushroomZombiePrefab = __instance.mushroomZombiePrefab; List allCharacters = Character.AllCharacters; if ((Object)(object)mushroomZombiePrefab == (Object)null || allCharacters == null) { RateLimitedDiagnostics.Hit("ZombieSpawnScan.inputs-unavailable"); return true; } float distanceToEnable = mushroomZombiePrefab.distanceToEnable; if (!(distanceToEnable >= 0f)) { RateLimitedDiagnostics.Hit("ZombieSpawnScan.negative-threshold-fallback"); return true; } Vector3 position = ((Component)__instance).transform.position; float num = distanceToEnable * distanceToEnable; if (distanceToEnable > 0f && (!(num > 0f) || float.IsInfinity(num))) { return true; } for (int i = 0; i < allCharacters.Count; i++) { Character val = allCharacters[i]; if (!((Object)(object)val == (Object)null)) { Vector3 val2 = val.Center - position; if (((Vector3)(ref val2)).sqrMagnitude <= num) { __result = true; return false; } } } __result = false; return false; } } } namespace PeakSafeOptimizer.Patches.ScaleExperimental { internal sealed class DetailBodypartThrottleModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.DetailBodypartThrottle, () => new PatchDefinition(PatchId.DetailBodypartThrottle, DetailBodypartThrottlePatch.Initialize, DetailBodypartThrottlePatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(DetailBodypartThrottlePatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, DetailBodypartThrottlePatch.Reset)); } } internal static class DetailBodypartThrottlePatch { private sealed class State { internal int LastPhysicsTick = int.MinValue; internal bool LastResult; } private const int Interval = 3; private const float FullRagdollControlThreshold = 0.9f; private const float ItemAttachRecencySeconds = 0.5f; private const string FixedJointTypeName = "UnityEngine.FixedJoint"; private static readonly string[] DetailPartNames = new string[59] { "Finger_1_1_R", "Finger_1_2_R", "Finger_1_3_R", "Finger_2_1_R", "Finger_2_2_R", "Finger_2_3_R", "Finger_3_1_R", "Finger_3_2_R", "Finger_3_3_R", "Finger_4_1_R", "Finger_4_2_R", "Finger_4_3_R", "Finger_5_1_R", "Finger_5_2_R", "Finger_5_3_R", "Finger_1_1_L", "Finger_1_2_L", "Finger_1_3_L", "Finger_2_1_L", "Finger_2_2_L", "Finger_2_3_L", "Finger_3_1_L", "Finger_3_2_L", "Finger_3_3_L", "Finger_4_1_L", "Finger_4_2_L", "Finger_4_3_L", "Finger_5_1_L", "Finger_5_2_L", "Finger_5_3_L", "Finger_L", "Finger_R", "Jiggle_1_L", "Jiggle_1_R", "Jiggle_2_L", "Jiggle_2_R", "Jiggle_3_L", "Jiggle_3_R", "Jiggle_4_L", "Jiggle_4_R", "Jiggle_5_L", "Jiggle_5_R", "Jiggle_6_L", "Jiggle_6_R", "Jiggle_7_L", "Jiggle_7_R", "Jiggle_8_L", "Jiggle_8_R", "Jiggle_9_L", "Jiggle_9_R", "Jiggle_10_L", "Jiggle_10_R", "Toe_L", "Toe_R", "Mouth", "Jaw_U", "Jaw_D", "Jaw_L", "Jaw_R" }; private static readonly string[] ProtectedPartNames = new string[29] { "Hip", "Mid", "Torso", "Neck", "Head", "Arm_L", "Elbow_L", "Hand_L", "Arm_R", "Elbow_R", "Hand_R", "Leg_L", "Knee_L", "Foot_L", "Leg_R", "Knee_R", "Foot_R", "Hip_L", "Hip_R", "Shoulder_L", "Shoulder_R", "Item", "Leg_1_L", "Knee_1_L", "Foot_1_L", "Spine_1", "Spine_10", "Tail_1", "Extra_1" }; private static bool[] _detailParts; private static FieldRef _partType; private static FieldRef _bodypartCharacter; private static FieldRef _grabbedPlayer; private static FieldRef _grabbingPlayer; private static Func _grabJoint; private static ConditionalWeakTable _states; internal static void Initialize() { ResolveAndValidateTarget(); ValidateStructure(); FieldInfo fieldInfo = ScaleValidation.RequireInstanceField(typeof(Bodypart), "partType", typeof(BodypartType)); FieldInfo fieldInfo2 = ScaleValidation.RequireInstanceField(typeof(Bodypart), "character", typeof(Character)); FieldInfo field = ScaleValidation.RequireInstanceFieldByTypeName(typeof(CharacterData), "grabJoint", "UnityEngine.FixedJoint"); FieldInfo fieldInfo3 = ScaleValidation.RequireInstanceField(typeof(CharacterData), "grabbedPlayer", typeof(Character)); FieldInfo fieldInfo4 = ScaleValidation.RequireInstanceField(typeof(CharacterData), "grabbingPlayer", typeof(Character)); bool[] detailParts = BuildDetailTable(); FieldRef obj = AccessTools.FieldRefAccess(fieldInfo); FieldRef val = AccessTools.FieldRefAccess(fieldInfo2); Func func = ScaleEmit.CreateUnityObjectFieldGetter(field); FieldRef val2 = AccessTools.FieldRefAccess(fieldInfo3); FieldRef val3 = AccessTools.FieldRefAccess(fieldInfo4); if (obj == null || val == null || val2 == null || val3 == null || func == null) { throw new InvalidOperationException("DetailBodypartThrottle accessor creation failed"); } _states = new ConditionalWeakTable(); _partType = obj; _bodypartCharacter = val; _grabbedPlayer = val2; _grabbingPlayer = val3; _grabJoint = func; _detailParts = detailParts; } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(Bodypart), "Animate", typeof(void), new Type[2] { typeof(float), typeof(float) }, requirePublic: false); } internal static void Reset() { _detailParts = null; _partType = null; _bodypartCharacter = null; _grabbedPlayer = null; _grabbingPlayer = null; _grabJoint = null; _states = null; } [HarmonyPriority(200)] internal static bool Prefix(Bodypart __instance) { bool[] detailParts = _detailParts; FieldRef partType = _partType; if (detailParts == null || partType == null || (Object)(object)__instance == (Object)null) { return true; } int num = (int)partType.Invoke(__instance); if ((uint)num >= (uint)detailParts.Length || !detailParts[num]) { return true; } int num2 = Math.Abs(((Object)__instance).GetInstanceID() % 3); if ((Mathf.FloorToInt(Time.fixedTime / Time.fixedDeltaTime) + num2) % 3 == 0) { return true; } FieldRef bodypartCharacter = _bodypartCharacter; if (bodypartCharacter == null) { return true; } Character val = bodypartCharacter.Invoke(__instance); if ((Object)(object)val == (Object)null) { return true; } return !ShouldThrottle(val); } private static bool ShouldThrottle(Character c) { ConditionalWeakTable states = _states; Func grabJoint = _grabJoint; FieldRef grabbedPlayer = _grabbedPlayer; FieldRef grabbingPlayer = _grabbingPlayer; if (states == null || grabJoint == null || grabbedPlayer == null || grabbingPlayer == null) { return false; } int num = Mathf.FloorToInt(Time.fixedTime / Time.fixedDeltaTime); State value; bool flag = states.TryGetValue(c, out value); if (flag && value.LastPhysicsTick == num) { return value.LastResult; } bool flag2 = Evaluate(c, grabJoint, grabbedPlayer, grabbingPlayer); if (!flag) { value = states.GetOrCreateValue(c); } value.LastPhysicsTick = num; value.LastResult = flag2; return flag2; } private static bool Evaluate(Character c, Func grabJoint, FieldRef grabbedPlayerRef, FieldRef grabbingPlayerRef) { CharacterData data = c.data; Character localCharacter = Character.localCharacter; if ((Object)(object)data == (Object)null || (Object)(object)localCharacter == (Object)null) { return false; } if ((Object)(object)c == (Object)(object)localCharacter) { return false; } PhotonView photonView = ((MonoBehaviourPun)c).photonView; if ((Object)(object)photonView == (Object)null || photonView.IsMine) { return false; } if (!c.IsPlayerControlled) { return false; } if (c.warping) { return false; } if ((Object)(object)data.carrier != (Object)null || (Object)(object)data.carriedPlayer != (Object)null) { return false; } if (data.isCarried || (Object)(object)grabbedPlayerRef.Invoke(data) != (Object)null || (Object)(object)grabbingPlayerRef.Invoke(data) != (Object)null) { return false; } if (data.dead || data.fullyPassedOut) { return false; } if (grabJoint(data) != (Object)null) { return false; } if (data.isClimbing || data.isRopeClimbing || data.isVineClimbing) { return false; } if ((Object)(object)data.currentClimbHandle != (Object)null || data.isReaching || data.isKicking) { return false; } if (data.isKinecmatic) { return false; } if (data.sinceItemAttach < 0.5f) { return false; } if (!(data.currentRagdollControll >= 0.9f)) { return false; } if ((Object)(object)Character.observedCharacter == (Object)(object)c) { return false; } return true; } private static bool[] BuildDetailTable() { Type typeFromHandle = typeof(BodypartType); if (!typeFromHandle.IsEnum || Enum.GetUnderlyingType(typeFromHandle) != typeof(int)) { throw new InvalidOperationException("BodypartType is not an int-backed enum"); } Array values = Enum.GetValues(typeFromHandle); int num = -1; for (int i = 0; i < values.Length; i++) { int num2 = (int)values.GetValue(i); if (num2 > num) { num = num2; } } if (num < 0) { throw new InvalidOperationException("BodypartType has no usable values"); } bool[] array = new bool[num + 1]; for (int j = 0; j < DetailPartNames.Length; j++) { int num3 = RequireDefined(typeFromHandle, DetailPartNames[j]); if ((uint)num3 >= (uint)array.Length) { throw new InvalidOperationException("BodypartType." + DetailPartNames[j] + " is out of table range"); } if (array[num3]) { throw new InvalidOperationException("BodypartType." + DetailPartNames[j] + " is listed twice"); } array[num3] = true; } for (int k = 0; k < ProtectedPartNames.Length; k++) { int num4 = RequireDefined(typeFromHandle, ProtectedPartNames[k]); if ((uint)num4 < (uint)array.Length && array[num4]) { throw new InvalidOperationException("BodypartType." + ProtectedPartNames[k] + " must never be throttled"); } } return array; } private static int RequireDefined(Type enumType, string name) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected I4, but got Unknown if (!Enum.IsDefined(enumType, name)) { throw new InvalidOperationException("BodypartType." + name + " is no longer defined"); } return (int)(BodypartType)Enum.Parse(enumType, name); } private static void ValidateStructure() { ScaleValidation.RequireStaticField(typeof(Character), "localCharacter", typeof(Character)); ScaleValidation.RequireStaticProperty(typeof(Character), "observedCharacter", typeof(Character)); ScaleValidation.RequireInstanceField(typeof(Character), "data", typeof(CharacterData)); ScaleValidation.RequireInstanceField(typeof(Character), "isBot", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(Character), "isZombie", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(Character), "isScoutmaster", typeof(bool)); ScaleValidation.RequireInstanceProperty(typeof(Character), "IsPlayerControlled", typeof(bool)); ScaleValidation.RequireInstanceProperty(typeof(Character), "warping", typeof(bool)); ScaleValidation.RequireInheritedInstanceProperty(typeof(Character), "photonView", typeof(PhotonView)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "carrier", typeof(Character)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "carriedPlayer", typeof(Character)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "grabbedPlayer", typeof(Character)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "grabbingPlayer", typeof(Character)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "isCarried", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "currentClimbHandle", typeof(ClimbHandle)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "isReaching", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "isKicking", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "fullyPassedOut", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "isClimbing", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "isRopeClimbing", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "isVineClimbing", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "isKinecmatic", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "sinceItemAttach", typeof(float)); ScaleValidation.RequireInstanceProperty(typeof(CharacterData), "dead", typeof(bool)); ScaleValidation.RequireInstanceProperty(typeof(CharacterData), "currentRagdollControll", typeof(float)); ScaleValidation.RequireInstanceMethod(typeof(CharacterMovement), "FixedUpdate", typeof(void), Type.EmptyTypes, requirePublic: false); ScaleValidation.RequireInstanceMethod(typeof(Bodypart), "Gravity", typeof(void), new Type[1] { typeof(Vector3) }, requirePublic: false); ScaleValidation.RequireInstanceMethod(typeof(Bodypart), "ToggleUseGravity", typeof(void), new Type[1] { typeof(bool) }, requirePublic: false); ScaleValidation.RequireInstanceMethod(typeof(Bodypart), "Drag", typeof(void), new Type[2] { typeof(float), typeof(bool) }, requirePublic: false); ScaleValidation.RequireInstanceMethod(typeof(Bodypart), "ApplyForces", typeof(void), Type.EmptyTypes, requirePublic: false); ScaleValidation.RequireInstanceMethod(typeof(CharacterRagdoll), "FixedUpdate", typeof(void), Type.EmptyTypes, requirePublic: true); ScaleValidation.RequireInstanceMethod(typeof(Bodypart), "SaveAnimationData", typeof(void), Type.EmptyTypes, requirePublic: true); ScaleValidation.RequireInstanceMethod(typeof(Bodypart), "SnapToAnim", typeof(void), Type.EmptyTypes, requirePublic: true); } } internal sealed class ExplosionScaleModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.ExplosionScale, () => new PatchDefinition(PatchId.ExplosionScale, ExplosionScalePatch.Initialize, ExplosionScalePatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(ExplosionScalePatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, ExplosionScalePatch.Reset)); } } internal static class ExplosionScalePatch { private const string ExplosionOrbArrayTypeName = "ExplosionOrb[]"; private const int RingCapacity = 16; private const int ClusterLightNeighbours = 2; private const int ClusterHeavyNeighbours = 5; private const int PointCap = 3; private const int SubPointCap = 1; private const float ClusterWindowSeconds = 1.2f; private const float ClusterRadius = 3.5f; private const float NearDistance = 50f; private const float FarDistance = 120f; private static readonly Vector3[] _clusterPositions = (Vector3[])(object)new Vector3[16]; private static readonly float[] _clusterTimes = CreateEmptyTimes(); private static int _clusterWriteIndex; private static int _clusterSceneHandle = int.MinValue; internal static void Initialize() { ResolveAndValidateTarget(); FieldInfo fieldInfo = ScaleValidation.RequireInstanceField(typeof(ExplosionEffect), "explosionPointCount", typeof(int)); FieldInfo fieldInfo2 = ScaleValidation.RequireInstanceField(typeof(ExplosionEffect), "subExplosionPointCount", typeof(int)); if (!fieldInfo.IsPublic || !fieldInfo2.IsPublic) { throw new InvalidOperationException("ExplosionEffect explosionPointCount/subExplosionPointCount are no longer public instance fields"); } ScaleValidation.RequireInstanceFieldByTypeName(typeof(ExplosionEffect), "explosionPoints", "ExplosionOrb[]"); ScaleValidation.RequireInstanceMethod(typeof(ExplosionEffect), "Start", typeof(void), Type.EmptyTypes, requirePublic: false); ScaleValidation.RequireInheritedInstanceProperty(typeof(ExplosionEffect), "transform", typeof(Transform)); ScaleValidation.RequireStaticField(typeof(MainCamera), "instance", typeof(MainCamera)); ScaleValidation.RequireInheritedInstanceProperty(typeof(MainCamera), "transform", typeof(Transform)); ScaleValidation.RequireStaticField(typeof(Character), "localCharacter", typeof(Character)); ScaleValidation.RequireInstanceField(typeof(Character), "refs", typeof(CharacterRefs)); ScaleValidation.RequireInstanceProperty(typeof(Character), "Center", typeof(Vector3)); ScaleValidation.RequireInstanceField(typeof(CharacterRefs), "ragdoll", typeof(CharacterRagdoll)); ScaleValidation.RequireInstanceField(typeof(CharacterRagdoll), "partDict", typeof(Dictionary)); ScaleValidation.RequireInheritedInstanceProperty(typeof(Bodypart), "transform", typeof(Transform)); if (!Enum.IsDefined(typeof(BodypartType), (object)(BodypartType)2)) { throw new InvalidOperationException("BodypartType.Torso is no longer defined"); } } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(ExplosionEffect), "GetPoints", typeof(void), Type.EmptyTypes, requirePublic: false); } internal static void Reset() { //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) for (int i = 0; i < 16; i++) { _clusterPositions[i] = Vector3.zero; _clusterTimes[i] = float.NegativeInfinity; } _clusterWriteIndex = 0; _clusterSceneHandle = int.MinValue; } internal static bool Prefix(ExplosionEffect __instance) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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_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_0068: 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_00b5: 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) Scene scene = ((Component)__instance).gameObject.scene; int num = SceneHandle.op_Implicit(((Scene)(ref scene)).handle); if (_clusterSceneHandle != num) { Reset(); _clusterSceneHandle = num; } int explosionPointCount = __instance.explosionPointCount; int subExplosionPointCount = __instance.subExplosionPointCount; if (explosionPointCount < 0 || subExplosionPointCount < 0) { RateLimitedDiagnostics.Hit("ExplosionScale.negative-prefab-count"); return true; } int num2 = 3; int num3 = 1; Vector3 position = ((Component)__instance).transform.position; float time = Time.time; int num4 = CountClusterNeighbours(position, time); Record(position, time); if (num4 >= 5) { num2 = Math.Min(num2, 1); num3 = Math.Min(num3, 0); } else if (num4 >= 2) { num2 = Math.Min(num2, 2); num3 = Math.Min(num3, 1); } if (TryGetViewpoint(out var viewpoint)) { Vector3 val = position - viewpoint; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude >= 14400f) { num2 = Math.Min(num2, 0); num3 = Math.Min(num3, 0); } else if (sqrMagnitude >= 2500f) { num2 = Math.Min(num2, 1); num3 = Math.Min(num3, 0); } } num2 = Mathf.Clamp(num2, 0, explosionPointCount); num3 = Mathf.Clamp(num3, 0, subExplosionPointCount); if (num2 != explosionPointCount || num3 != subExplosionPointCount) { __instance.explosionPointCount = num2; __instance.subExplosionPointCount = num3; } return true; } private static int CountClusterNeighbours(Vector3 position, float now) { //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_0028: 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) int num = 0; for (int i = 0; i < 16; i++) { float num2 = _clusterTimes[i]; if (!(num2 > now) && !(now - num2 > 1.2f)) { Vector3 val = _clusterPositions[i] - position; if (((Vector3)(ref val)).sqrMagnitude <= 12.25f) { num++; } } } return num; } private static void Record(Vector3 position, float now) { //IL_000c: 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) int clusterWriteIndex = _clusterWriteIndex; _clusterPositions[clusterWriteIndex] = position; _clusterTimes[clusterWriteIndex] = now; clusterWriteIndex++; _clusterWriteIndex = ((clusterWriteIndex != 16) ? clusterWriteIndex : 0); } private static bool TryGetViewpoint(out Vector3 viewpoint) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) viewpoint = Vector3.zero; MainCamera instance = MainCamera.instance; if ((Object)(object)instance != (Object)null) { Transform transform = ((Component)instance).transform; if ((Object)(object)transform != (Object)null) { viewpoint = transform.position; return true; } } Character localCharacter = Character.localCharacter; CharacterRagdoll val = (((Object)(object)localCharacter != (Object)null) ? localCharacter.refs : null)?.ragdoll; Dictionary dictionary = (((Object)(object)val != (Object)null) ? val.partDict : null); if (dictionary == null || !dictionary.TryGetValue((BodypartType)2, out var value) || (Object)(object)value == (Object)null) { return false; } Transform transform2 = value.transform; if ((Object)(object)transform2 == (Object)null) { return false; } viewpoint = transform2.position; return true; } private static float[] CreateEmptyTimes() { float[] array = new float[16]; for (int i = 0; i < array.Length; i++) { array[i] = float.NegativeInfinity; } return array; } } internal sealed class EyeLookComponentCacheModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.EyeLookComponentCache, () => new PatchDefinition(PatchId.EyeLookComponentCache, EyeLookComponentCachePatch.Initialize, EyeLookComponentCachePatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(EyeLookComponentCachePatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, EyeLookComponentCachePatch.Reset)); } } internal static class EyeLookComponentCachePatch { private sealed class MouthEntry { internal AnimatedMouth Mouth; } private static ConditionalWeakTable _mouths; private static FieldRef> _characters; private static FieldRef _localCharacter; private static FieldRef _lastCharacter; private static FieldRef _lookDir; private static FieldRef _lookDelta; private static FieldRef _upDelta; private static FieldRef _rightDelta; private static FieldRef _eyePos; private static FieldRef _eyeTarget; private static FieldRef _lastViewDir; private static Func _getBodypart; private static int _eyePositionId; internal static void Initialize() { ResolveAndValidateTarget(); Type? typeFromHandle = typeof(PlayerEyeLook); FieldInfo fieldInfo = ScaleValidation.RequireInstanceField(typeFromHandle, "characters", typeof(List)); FieldInfo fieldInfo2 = ScaleValidation.RequireInstanceField(typeFromHandle, "localCharacter", typeof(Character)); FieldInfo fieldInfo3 = ScaleValidation.RequireInstanceField(typeFromHandle, "lastCharacter", typeof(Character)); FieldInfo fieldInfo4 = ScaleValidation.RequireInstanceField(typeFromHandle, "lookDir", typeof(Vector3)); FieldInfo fieldInfo5 = ScaleValidation.RequireInstanceField(typeFromHandle, "lookDelta", typeof(Vector3)); FieldInfo fieldInfo6 = ScaleValidation.RequireInstanceField(typeFromHandle, "UpDelta", typeof(float)); FieldInfo fieldInfo7 = ScaleValidation.RequireInstanceField(typeFromHandle, "RightDelta", typeof(float)); FieldInfo fieldInfo8 = ScaleValidation.RequireInstanceField(typeFromHandle, "eyePos", typeof(Vector2)); FieldInfo fieldInfo9 = ScaleValidation.RequireInstanceField(typeFromHandle, "eyeTarget", typeof(Vector2)); FieldInfo fieldInfo10 = ScaleValidation.RequireInstanceField(typeFromHandle, "lastViewDir", typeof(Vector3)); ScaleValidation.RequireInstanceField(typeFromHandle, "character", typeof(Character)); ScaleValidation.RequireInstanceField(typeFromHandle, "distance", typeof(float)); ScaleValidation.RequireInstanceField(typeFromHandle, "lookRange", typeof(float)); ScaleValidation.RequireInstanceField(typeFromHandle, "listenRange", typeof(float)); ScaleValidation.RequireInstanceField(typeFromHandle, "lookAngle", typeof(float)); ScaleValidation.RequireInstanceField(typeFromHandle, "lookAngleMax", typeof(float)); ScaleValidation.RequireInstanceField(typeFromHandle, "lookSmoothing", typeof(float)); ScaleValidation.RequireInstanceField(typeFromHandle, "xLookThreshold", typeof(float)); ScaleValidation.RequireInstanceField(typeFromHandle, "XMax", typeof(float)); ScaleValidation.RequireInstanceField(typeFromHandle, "YMax", typeof(float)); ScaleValidation.RequireInstanceField(typeFromHandle, "lookingAtCharacter", typeof(bool)); ScaleValidation.RequireInstanceField(typeFromHandle, "eyeRenderers", typeof(Renderer[])); ScaleValidation.RequireStaticField(typeof(Character), "AllCharacters", typeof(List)); ScaleValidation.RequireInstanceProperty(typeof(Character), "Center", typeof(Vector3)); ScaleValidation.RequireInstanceProperty(typeof(Character), "Head", typeof(Vector3)); ScaleValidation.RequireInstanceField(typeof(Character), "data", typeof(CharacterData)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "lookDirection", typeof(Vector3)); MethodInfo method = ScaleValidation.RequireInstanceMethod(typeof(Character), "GetBodypart", typeof(Bodypart), new Type[1] { typeof(BodypartType) }, requirePublic: false); ScaleValidation.RequireInstanceField(typeof(AnimatedMouth), "isSpeaking", typeof(bool)); if (!Enum.IsDefined(typeof(BodypartType), (object)(BodypartType)4) || !Enum.IsDefined(typeof(BodypartType), (object)(BodypartType)0)) { throw new InvalidOperationException("BodypartType.Head/Hip is no longer defined"); } FieldRef> obj = AccessTools.FieldRefAccess>(fieldInfo); FieldRef val = AccessTools.FieldRefAccess(fieldInfo2); FieldRef val2 = AccessTools.FieldRefAccess(fieldInfo3); FieldRef val3 = AccessTools.FieldRefAccess(fieldInfo4); FieldRef val4 = AccessTools.FieldRefAccess(fieldInfo5); FieldRef val5 = AccessTools.FieldRefAccess(fieldInfo6); FieldRef val6 = AccessTools.FieldRefAccess(fieldInfo7); FieldRef val7 = AccessTools.FieldRefAccess(fieldInfo8); FieldRef val8 = AccessTools.FieldRefAccess(fieldInfo9); FieldRef val9 = AccessTools.FieldRefAccess(fieldInfo10); Func func = ScaleExperimentalEmit.CreateDelegate>(method); if (obj == null || val == null || val2 == null || val3 == null || val4 == null || val5 == null || val6 == null || val7 == null || val8 == null || val9 == null || func == null) { throw new InvalidOperationException("EyeLookComponentCache accessor creation failed"); } _mouths = new ConditionalWeakTable(); _characters = obj; _localCharacter = val; _lastCharacter = val2; _lookDir = val3; _lookDelta = val4; _upDelta = val5; _rightDelta = val6; _eyePos = val7; _eyeTarget = val8; _lastViewDir = val9; _getBodypart = func; _eyePositionId = Shader.PropertyToID("_EyePosition"); } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(PlayerEyeLook), "Update", typeof(void), Type.EmptyTypes, requirePublic: false); } internal static void Reset() { _mouths = null; _characters = null; _localCharacter = null; _lastCharacter = null; _lookDir = null; _lookDelta = null; _upDelta = null; _rightDelta = null; _eyePos = null; _eyeTarget = null; _lastViewDir = null; _getBodypart = null; _eyePositionId = 0; } internal static bool Prefix(PlayerEyeLook __instance) { //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0283: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) //IL_0292: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Unknown result type (might be due to invalid IL or missing references) //IL_02c3: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Unknown result type (might be due to invalid IL or missing references) //IL_02fd: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) //IL_036d: Unknown result type (might be due to invalid IL or missing references) //IL_0372: Unknown result type (might be due to invalid IL or missing references) //IL_03e7: Unknown result type (might be due to invalid IL or missing references) //IL_03ec: Unknown result type (might be due to invalid IL or missing references) //IL_0401: Unknown result type (might be due to invalid IL or missing references) //IL_0406: Unknown result type (might be due to invalid IL or missing references) //IL_0408: Unknown result type (might be due to invalid IL or missing references) //IL_040d: Unknown result type (might be due to invalid IL or missing references) //IL_0416: Unknown result type (might be due to invalid IL or missing references) //IL_041b: Unknown result type (might be due to invalid IL or missing references) //IL_042b: Unknown result type (might be due to invalid IL or missing references) //IL_0430: Unknown result type (might be due to invalid IL or missing references) //IL_0459: Unknown result type (might be due to invalid IL or missing references) //IL_045e: Unknown result type (might be due to invalid IL or missing references) //IL_0492: Unknown result type (might be due to invalid IL or missing references) //IL_049f: Unknown result type (might be due to invalid IL or missing references) //IL_04b3: Unknown result type (might be due to invalid IL or missing references) //IL_04b8: Unknown result type (might be due to invalid IL or missing references) //IL_04c5: Unknown result type (might be due to invalid IL or missing references) //IL_04ca: Unknown result type (might be due to invalid IL or missing references) //IL_04e4: Unknown result type (might be due to invalid IL or missing references) //IL_04e6: Unknown result type (might be due to invalid IL or missing references) //IL_052a: Unknown result type (might be due to invalid IL or missing references) //IL_052f: Unknown result type (might be due to invalid IL or missing references) //IL_0539: Unknown result type (might be due to invalid IL or missing references) //IL_053e: Unknown result type (might be due to invalid IL or missing references) //IL_0555: Unknown result type (might be due to invalid IL or missing references) //IL_0557: Unknown result type (might be due to invalid IL or missing references) ConditionalWeakTable mouths = _mouths; FieldRef> characters = _characters; FieldRef localCharacter = _localCharacter; FieldRef lastCharacter = _lastCharacter; FieldRef lookDir = _lookDir; FieldRef lookDelta = _lookDelta; FieldRef upDelta = _upDelta; FieldRef rightDelta = _rightDelta; FieldRef eyePos = _eyePos; FieldRef eyeTarget = _eyeTarget; FieldRef lastViewDir = _lastViewDir; Func getBodypart = _getBodypart; if (mouths == null || characters == null || localCharacter == null || lastCharacter == null || lookDir == null || lookDelta == null || upDelta == null || rightDelta == null || eyePos == null || eyeTarget == null || lastViewDir == null || getBodypart == null) { RateLimitedDiagnostics.Hit("EyeLookComponentCache.accessors-unavailable"); return true; } Character val = localCharacter.Invoke(__instance); List allCharacters = Character.AllCharacters; if ((Object)(object)val == (Object)null || allCharacters == null) { RateLimitedDiagnostics.Hit("EyeLookComponentCache.local-or-roster-unavailable"); return true; } for (int i = 0; i < allCharacters.Count; i++) { Character val2 = allCharacters[i]; if ((Object)(object)val2 == (Object)null) { RateLimitedDiagnostics.Hit("EyeLookComponentCache.candidate-null"); return true; } if ((Object)(object)ResolveMouth(mouths, val2) == (Object)null) { RateLimitedDiagnostics.Hit("EyeLookComponentCache.mouth-unavailable"); return true; } } Renderer[] eyeRenderers = __instance.eyeRenderers; if (eyeRenderers == null) { RateLimitedDiagnostics.Hit("EyeLookComponentCache.eyeRenderers-null"); return true; } for (int j = 0; j < eyeRenderers.Length; j++) { if ((Object)(object)eyeRenderers[j] == (Object)null) { RateLimitedDiagnostics.Hit("EyeLookComponentCache.eyeRenderer-null"); return true; } } characters.Invoke(__instance) = allCharacters; __instance.distance = float.PositiveInfinity; for (int k = 0; k < allCharacters.Count; k++) { Character val3 = allCharacters[k]; if (!((Object)(object)val3 == (Object)null)) { float num = Vector3.Distance(val3.Center, val.Center); if (num < __instance.distance && (Object)(object)val3 != (Object)(object)val) { __instance.distance = num; __instance.character = val3; } AnimatedMouth val4 = ResolveMouth(mouths, val3); if (num < __instance.listenRange && val4.isSpeaking && (Object)(object)val3 != (Object)(object)val) { __instance.distance = num; __instance.character = val3; } } } Character character = __instance.character; if ((Object)(object)character != (Object)null) { Bodypart val5 = getBodypart(val, (BodypartType)4); if ((Object)(object)val5 == (Object)null || (Object)(object)val5.transform == (Object)null) { RateLimitedDiagnostics.Hit("EyeLookComponentCache.local-head-unavailable"); return true; } Vector3 val6 = character.Head - val.Head; Vector3 normalized = ((Vector3)(ref val6)).normalized; lookDir.Invoke(__instance) = normalized; Vector3 val7 = val5.transform.forward - normalized; lookDelta.Invoke(__instance) = val7; ((Component)__instance).transform.InverseTransformDirection(val7); upDelta.Invoke(__instance) = Vector3.Dot(val5.transform.up, lookDelta.Invoke(__instance)); rightDelta.Invoke(__instance) = Vector3.Dot(val5.transform.right, lookDelta.Invoke(__instance)); __instance.lookAngle = Vector3.Angle(val.data.lookDirection, lookDir.Invoke(__instance)); } if ((Object)(object)character != (Object)null && __instance.distance < __instance.lookRange && __instance.lookAngle < __instance.lookAngleMax) { eyeTarget.Invoke(__instance) = new Vector2(rightDelta.Invoke(__instance) * (0f - __instance.XMax), upDelta.Invoke(__instance) * __instance.YMax); __instance.lookingAtCharacter = true; } else { __instance.lookingAtCharacter = false; Bodypart val8 = getBodypart(val, (BodypartType)0); Bodypart val9 = getBodypart(val, (BodypartType)4); if ((Object)(object)val8 == (Object)null || (Object)(object)val8.transform == (Object)null || (Object)(object)val9 == (Object)null || (Object)(object)val9.transform == (Object)null) { RateLimitedDiagnostics.Hit("EyeLookComponentCache.local-bodyparts-unavailable"); return true; } Vector3 forward = val8.transform.forward; forward.y = 0f; Vector3 val10 = val.data.lookDirection - forward; float num2 = Vector3.Dot(val9.transform.right, val10); float num3 = Vector3.Dot(val9.transform.up, val10); eyeTarget.Invoke(__instance) = new Vector2(num2 * __instance.XMax, num3 * (0f - __instance.YMax)); } float num4 = 1f; if ((Object)(object)character != (Object)(object)lastCharacter.Invoke(__instance)) { num4 = 0.3f; } eyePos.Invoke(__instance) = Vector2.Lerp(eyePos.Invoke(__instance), eyeTarget.Invoke(__instance), Time.deltaTime * __instance.lookSmoothing * num4); Vector2 val11 = eyePos.Invoke(__instance); int eyePositionId = _eyePositionId; for (int l = 0; l < eyeRenderers.Length; l++) { eyeRenderers[l].material.SetVector(eyePositionId, Vector4.op_Implicit(val11)); } Bodypart val12 = getBodypart(val, (BodypartType)4); if ((Object)(object)val12 != (Object)null && (Object)(object)val12.transform != (Object)null) { Vector3 forward2 = val12.transform.forward; if (Vector3.Distance(lastViewDir.Invoke(__instance), forward2) > __instance.xLookThreshold) { lastViewDir.Invoke(__instance) = forward2; } } return false; } private static AnimatedMouth ResolveMouth(ConditionalWeakTable mouths, Character candidate) { MouthEntry orCreateValue = mouths.GetOrCreateValue(candidate); AnimatedMouth mouth = orCreateValue.Mouth; if ((Object)(object)mouth != (Object)null) { return mouth; } return orCreateValue.Mouth = ((Component)candidate).GetComponent(); } } internal sealed class ItemScaleRedundantWriteModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.ItemScaleRedundantWrite, () => new PatchDefinition(PatchId.ItemScaleRedundantWrite, ItemScaleRedundantWritePatch.Initialize, ItemScaleRedundantWritePatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(ItemScaleRedundantWritePatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, ItemScaleRedundantWritePatch.Reset)); } } internal static class ItemScaleRedundantWritePatch { private sealed class State { internal bool HasApplied; internal int CurrentScaleBits; internal int PreviousScaleBits; internal int ItemState; internal bool ApplyDirectly; internal bool IsMine; internal int PrimaryTransformId; internal int SecondaryTransformId; internal Vector3 PrimaryLocalScale; internal Vector3 SecondaryLocalScale; } private const string ColliderArrayTypeName = "UnityEngine.Collider[]"; private static ConditionalWeakTable _states; private static FieldRef _currentScale; private static FieldRef _previousScale; private static FieldRef _applyDirectly; private static Func _mainRenderer; private static Func _firstColliderTransform; internal static void Initialize() { ResolveAndValidateTarget(); FieldInfo fieldInfo = ScaleValidation.RequireInstanceField(typeof(ItemScaleSyncer), "currentScale", typeof(float)); FieldInfo fieldInfo2 = ScaleValidation.RequireInstanceField(typeof(ItemScaleSyncer), "previousScale", typeof(float)); FieldInfo fieldInfo3 = ScaleValidation.RequireInstanceField(typeof(ItemScaleSyncer), "_applyDirectlyToMeshAndCollider", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(ItemScaleSyncer), "_isInitialized", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(ItemComponent), "item", typeof(Item)); ScaleValidation.RequireInstanceProperty(typeof(Item), "itemState", typeof(ItemState)); if (!Enum.IsDefined(typeof(ItemState), (object)(ItemState)2)) { throw new InvalidOperationException("ItemState.InBackpack is no longer defined"); } FieldInfo field = ScaleValidation.RequireInstanceField(typeof(Item), "mainRenderer", typeof(Renderer)); FieldInfo arrayField = ScaleValidation.RequireInstanceFieldByTypeName(typeof(Item), "colliders", "UnityEngine.Collider[]"); ScaleValidation.RequireInstanceMethod(typeof(ItemScaleSyncer), "ApplyScale", typeof(void), new Type[1] { typeof(float) }, requirePublic: false); ScaleValidation.RequireInstanceMethod(typeof(ItemScaleSyncer), "OnScaleChanged", typeof(void), Type.EmptyTypes, requirePublic: false); ScaleValidation.RequireInstanceMethod(typeof(ItemScaleSyncer), "InitScale", typeof(void), Type.EmptyTypes, requirePublic: true); ScaleValidation.RequireInstanceMethodByTypeNames(typeof(ItemScaleSyncer), "RPC_SyncScale", typeof(void).FullName, new string[1] { typeof(float).FullName }); FieldRef obj = AccessTools.FieldRefAccess(fieldInfo); FieldRef val = AccessTools.FieldRefAccess(fieldInfo2); FieldRef val2 = AccessTools.FieldRefAccess(fieldInfo3); Func func = ScaleExperimentalEmit.CreateFieldGetter(field); Func func2 = ScaleExperimentalEmit.CreateFirstElementTransformGetter(arrayField); if (obj == null || val == null || val2 == null || func == null || func2 == null) { throw new InvalidOperationException("ItemScaleRedundantWrite accessor creation failed"); } _states = new ConditionalWeakTable(); _currentScale = obj; _previousScale = val; _applyDirectly = val2; _mainRenderer = func; _firstColliderTransform = func2; } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(ItemScaleSyncer), "Update", typeof(void), Type.EmptyTypes, requirePublic: true); } internal static void Reset() { _states = null; _currentScale = null; _previousScale = null; _applyDirectly = null; _mainRenderer = null; _firstColliderTransform = null; } internal static bool Prefix(ItemScaleSyncer __instance) { //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Expected I4, but got Unknown //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) //IL_0284: Unknown result type (might be due to invalid IL or missing references) //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Unknown result type (might be due to invalid IL or missing references) //IL_0297: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) ConditionalWeakTable states = _states; FieldRef currentScale = _currentScale; FieldRef previousScale = _previousScale; FieldRef applyDirectly = _applyDirectly; Func mainRenderer = _mainRenderer; Func firstColliderTransform = _firstColliderTransform; if (states == null || currentScale == null || previousScale == null || applyDirectly == null || mainRenderer == null || firstColliderTransform == null) { RateLimitedDiagnostics.Hit("ItemScaleRedundantWrite.state-unavailable"); return true; } Item item = ((ItemComponent)__instance).item; if ((Object)(object)item == (Object)null) { RateLimitedDiagnostics.Hit("ItemScaleRedundantWrite.item-null"); return true; } PhotonView photonView = ((MonoBehaviourPun)__instance).photonView; if ((Object)(object)photonView == (Object)null) { RateLimitedDiagnostics.Hit("ItemScaleRedundantWrite.photonView-null"); return true; } bool flag = applyDirectly.Invoke(__instance); Transform val2; Transform val3; if (flag) { Renderer val = mainRenderer(item); val2 = (((Object)(object)val != (Object)null) ? ((Component)val).transform : null); val3 = firstColliderTransform(item); if ((Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null) { RateLimitedDiagnostics.Hit("ItemScaleRedundantWrite.direct-targets-incomplete"); return true; } } else { val2 = ((Component)item).transform; val3 = null; if ((Object)(object)val2 == (Object)null) { RateLimitedDiagnostics.Hit("ItemScaleRedundantWrite.item-transform-null"); return true; } } float num = currentScale.Invoke(__instance); float num2 = previousScale.Invoke(__instance); bool isMine = photonView.IsMine; int num3 = (int)item.itemState; if (isMine && Mathf.Abs(num - num2) > 0.01f) { InvalidateAndRecord(states, __instance, num, num2, num3, flag, isMine, val2, val3, recordApplied: false); return true; } int num4 = BitConverter.SingleToInt32Bits(num); int num5 = BitConverter.SingleToInt32Bits(num2); int instanceID = ((Object)val2).GetInstanceID(); int num6 = (((Object)(object)val3 != (Object)null) ? ((Object)val3).GetInstanceID() : 0); Vector3 localScale = val2.localScale; Vector3 val4 = (((Object)(object)val3 != (Object)null) ? val3.localScale : Vector3.zero); State orCreateValue = states.GetOrCreateValue(__instance); if (orCreateValue.HasApplied && orCreateValue.CurrentScaleBits == num4 && orCreateValue.PreviousScaleBits == num5 && orCreateValue.ItemState == num3 && orCreateValue.ApplyDirectly == flag && orCreateValue.IsMine == isMine && orCreateValue.PrimaryTransformId == instanceID && orCreateValue.SecondaryTransformId == num6 && orCreateValue.PrimaryLocalScale == localScale && orCreateValue.SecondaryLocalScale == val4) { return false; } orCreateValue.CurrentScaleBits = num4; orCreateValue.PreviousScaleBits = num5; orCreateValue.ItemState = num3; orCreateValue.ApplyDirectly = flag; orCreateValue.IsMine = isMine; orCreateValue.PrimaryTransformId = instanceID; orCreateValue.SecondaryTransformId = num6; Vector3 val5 = (orCreateValue.PrimaryLocalScale = ((num3 == 2) ? (num * 0.5f) : num) * Vector3.one); orCreateValue.SecondaryLocalScale = (((Object)(object)val3 != (Object)null) ? val5 : Vector3.zero); orCreateValue.HasApplied = true; return true; } private static void InvalidateAndRecord(ConditionalWeakTable states, ItemScaleSyncer instance, float currentScale, float previousScale, int itemState, bool applyDirectly, bool isMine, Transform primary, Transform secondary, bool recordApplied) { //IL_0074: 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) State orCreateValue = states.GetOrCreateValue(instance); orCreateValue.HasApplied = recordApplied; orCreateValue.CurrentScaleBits = BitConverter.SingleToInt32Bits(currentScale); orCreateValue.PreviousScaleBits = BitConverter.SingleToInt32Bits(previousScale); orCreateValue.ItemState = itemState; orCreateValue.ApplyDirectly = applyDirectly; orCreateValue.IsMine = isMine; orCreateValue.PrimaryTransformId = (((Object)(object)primary != (Object)null) ? ((Object)primary).GetInstanceID() : 0); orCreateValue.SecondaryTransformId = (((Object)(object)secondary != (Object)null) ? ((Object)secondary).GetInstanceID() : 0); orCreateValue.PrimaryLocalScale = Vector3.zero; orCreateValue.SecondaryLocalScale = Vector3.zero; } } internal sealed class RemoteClusterAnimationThrottleModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.RemoteClusterAnimationThrottle, () => new PatchDefinition(PatchId.RemoteClusterAnimationThrottle, RemoteClusterAnimationThrottlePatch.Initialize, RemoteClusterAnimationThrottlePatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(RemoteClusterAnimationThrottlePatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, RemoteClusterAnimationThrottlePatch.Reset)); } } internal static class RemoteClusterAnimationThrottlePatch { private sealed class State { internal int LastTick = int.MinValue; internal float PendingDeltaTime; } private const int Interval = 2; private static FieldRef _character; private static FieldRef _firstFrame; private static FieldRef> _partList; private static Action _setPhysicsMats; private static Action _rotateCharacter; private static Action _resetRotation; private static Action _saveAdditionalTransformPositions; private static ConditionalWeakTable _states; private static bool _acquired; internal static void Initialize() { ResolveAndValidateTarget(); ValidateStructure(); FieldInfo fieldInfo = ScaleValidation.RequireInstanceField(typeof(CharacterRagdoll), "character", typeof(Character)); FieldInfo fieldInfo2 = ScaleValidation.RequireInstanceField(typeof(CharacterRagdoll), "firstFrame", typeof(bool)); FieldInfo fieldInfo3 = ScaleValidation.RequireInstanceField(typeof(CharacterRagdoll), "partList", typeof(List)); MethodInfo method = ScaleValidation.RequireInstanceMethod(typeof(CharacterRagdoll), "SetPhysicsMats", typeof(void), Type.EmptyTypes, requirePublic: false); MethodInfo method2 = ScaleValidation.RequireInstanceMethod(typeof(CharacterRagdoll), "RotateCharacter", typeof(void), Type.EmptyTypes, requirePublic: false); MethodInfo method3 = ScaleValidation.RequireInstanceMethod(typeof(CharacterRagdoll), "ResetRotation", typeof(void), Type.EmptyTypes, requirePublic: false); MethodInfo method4 = ScaleValidation.RequireInstanceMethod(typeof(CharacterRagdoll), "SaveAdditionalTransformPositions", typeof(void), Type.EmptyTypes, requirePublic: false); FieldRef obj = AccessTools.FieldRefAccess(fieldInfo); FieldRef val = AccessTools.FieldRefAccess(fieldInfo2); FieldRef> val2 = AccessTools.FieldRefAccess>(fieldInfo3); Action action = ScaleExperimentalEmit.CreateDelegate>(method); Action action2 = ScaleExperimentalEmit.CreateDelegate>(method2); Action action3 = ScaleExperimentalEmit.CreateDelegate>(method3); Action action4 = ScaleExperimentalEmit.CreateDelegate>(method4); if (obj == null || val == null || val2 == null) { throw new InvalidOperationException("RemoteClusterAnimationThrottle FieldRef creation failed"); } if (action == null || action2 == null || action3 == null || action4 == null) { throw new InvalidOperationException("RemoteClusterAnimationThrottle delegate creation failed"); } RemoteRagdollLod.Acquire(); _acquired = true; _states = new ConditionalWeakTable(); _character = obj; _firstFrame = val; _partList = val2; _setPhysicsMats = action; _rotateCharacter = action2; _resetRotation = action3; _saveAdditionalTransformPositions = action4; } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(CharacterRagdoll), "FixedUpdate", typeof(void), Type.EmptyTypes, requirePublic: true); } internal static void Reset() { _character = null; _firstFrame = null; _partList = null; _setPhysicsMats = null; _rotateCharacter = null; _resetRotation = null; _saveAdditionalTransformPositions = null; _states = null; if (_acquired) { _acquired = false; RemoteRagdollLod.Release(); } } [HarmonyPriority(200)] internal static bool Prefix(CharacterRagdoll __instance, bool __runOriginal) { if (!__runOriginal) { return false; } FieldRef character = _character; FieldRef firstFrame = _firstFrame; FieldRef> partList = _partList; ConditionalWeakTable states = _states; if (character == null || firstFrame == null || partList == null || states == null || (Object)(object)__instance == (Object)null) { return true; } if (firstFrame.Invoke(__instance)) { return Yield(states, __instance); } Character val = character.Invoke(__instance); if ((Object)(object)val == (Object)null) { return Yield(states, __instance); } CharacterRefs refs = val.refs; if (refs == null || (Object)(object)refs.animator == (Object)null || (Object)(object)refs.animations == (Object)null || (Object)(object)refs.rigCreator == (Object)null) { return Yield(states, __instance); } List list = partList.Invoke(__instance); if (list == null) { return Yield(states, __instance); } if (!RemoteRagdollLod.ShouldThrottleAnimation(val)) { return Yield(states, __instance); } float fixedDeltaTime = Time.fixedDeltaTime; if (!(fixedDeltaTime > 0f) || float.IsInfinity(fixedDeltaTime)) { return Yield(states, __instance); } int num = RemoteRagdollLod.PhysicsTick(); State orCreateValue = states.GetOrCreateValue(__instance); if (orCreateValue.LastTick == num) { return true; } if (orCreateValue.LastTick != num - 1) { orCreateValue.PendingDeltaTime = 0f; } orCreateValue.LastTick = num; orCreateValue.PendingDeltaTime = Mathf.Min(orCreateValue.PendingDeltaTime + fixedDeltaTime, fixedDeltaTime * 2f); int num2 = Math.Abs(((Object)__instance).GetInstanceID() % 2); if ((num + num2) % 2 != 0) { _setPhysicsMats(__instance); return false; } float pendingDeltaTime = orCreateValue.PendingDeltaTime; orCreateValue.PendingDeltaTime = 0f; RunReplacement(__instance, refs, list, pendingDeltaTime); return false; } private static bool Yield(ConditionalWeakTable states, CharacterRagdoll instance) { if (states.TryGetValue(instance, out var value) && value != null) { value.PendingDeltaTime = 0f; value.LastTick = int.MinValue; } return true; } private static void RunReplacement(CharacterRagdoll instance, CharacterRefs refs, List parts, float deltaTime) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) bool flag = false; try { _setPhysicsMats(instance); _rotateCharacter(instance); flag = true; RigBuilder ikRigBuilder = refs.ikRigBuilder; if ((Object)(object)ikRigBuilder != (Object)null) { ikRigBuilder.SyncLayers(); ikRigBuilder.Evaluate(deltaTime); } PlayableGraph playableGraph = refs.animator.playableGraph; if (((PlayableGraph)(ref playableGraph)).IsValid()) { ((PlayableGraph)(ref playableGraph)).Evaluate(deltaTime); } refs.animations.ConfigureIK(); for (int i = 0; i < parts.Count; i++) { parts[i].SaveAnimationData(); } _saveAdditionalTransformPositions(instance); } catch (Exception) { RateLimitedDiagnostics.Hit("RemoteClusterAnimationThrottle.replacement-failed"); } finally { if (flag) { try { _resetRotation(instance); for (int j = 0; j < parts.Count; j++) { parts[j].ResetTransform(); } } catch (Exception) { RateLimitedDiagnostics.Hit("RemoteClusterAnimationThrottle.reset-failed"); } } } } private static void ValidateStructure() { ScaleValidation.RequireInstanceField(typeof(Character), "refs", typeof(CharacterRefs)); ScaleValidation.RequireInstanceField(typeof(CharacterRefs), "ikRigBuilder", typeof(RigBuilder)); ScaleValidation.RequireInstanceField(typeof(CharacterRefs), "animator", typeof(Animator)); ScaleValidation.RequireInstanceField(typeof(CharacterRefs), "animations", typeof(CharacterAnimations)); ScaleValidation.RequireInstanceField(typeof(CharacterRefs), "rigCreator", typeof(RigCreator)); ScaleValidation.RequireInstanceMethod(typeof(CharacterAnimations), "ConfigureIK", typeof(void), Type.EmptyTypes, requirePublic: true); ScaleValidation.RequireInstanceMethod(typeof(Bodypart), "SaveAnimationData", typeof(void), Type.EmptyTypes, requirePublic: true); ScaleValidation.RequireInstanceMethod(typeof(Bodypart), "ResetTransform", typeof(void), Type.EmptyTypes, requirePublic: true); ScaleValidation.RequireInstanceMethod(typeof(RigBuilder), "SyncLayers", typeof(void), Type.EmptyTypes, requirePublic: true); ScaleValidation.RequireInstanceMethod(typeof(RigBuilder), "Evaluate", typeof(void), new Type[1] { typeof(float) }, requirePublic: true); ScaleValidation.RequireInstanceProperty(typeof(Animator), "playableGraph", typeof(PlayableGraph)); MethodInfo method = typeof(PlayableGraph).GetMethod("SetTimeUpdateMode", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(DirectorUpdateMode) }, null); MethodInfo method2 = typeof(PlayableGraph).GetMethod("Evaluate", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(float) }, null); if (method == null || method2 == null) { throw new MissingMethodException(typeof(PlayableGraph).FullName, "Evaluate/SetTimeUpdateMode"); } if (!Enum.IsDefined(typeof(DirectorUpdateMode), (object)(DirectorUpdateMode)3)) { throw new InvalidOperationException("DirectorUpdateMode.Manual is no longer defined"); } ScaleValidation.RequireInstanceMethod(typeof(CharacterRagdoll), "Start", typeof(void), Type.EmptyTypes, requirePublic: false); } } internal sealed class RemoteItemInterpolationThresholdModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.RemoteItemInterpolationThreshold, () => new PatchDefinition(PatchId.RemoteItemInterpolationThreshold, RemoteItemInterpolationThresholdPatch.Initialize, RemoteItemInterpolationThresholdPatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(RemoteItemInterpolationThresholdPatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, RemoteItemInterpolationThresholdPatch.Reset)); } } internal static class RemoteItemInterpolationThresholdPatch { private const string RigidbodyTypeName = "UnityEngine.Rigidbody"; private static FieldRef _item; private static FieldRef _photonView; private static FieldRef> _lastPos; private static FieldRef _shouldSync; private static FieldRef _debug; private static FieldRef _lastRecievedPosition; private static FieldRef> _remoteValue; private static FieldRef _sinceLastPackage; private static Func _rig; private static Func _rigPosition; private static Func _rigRotation; private static Func _dataPosition; private static Func _dataRotation; internal static void Initialize() { ResolveAndValidateTarget(); Type? typeFromHandle = typeof(ItemPhysicsSyncer); FieldInfo fieldInfo = ScaleValidation.RequireInstanceField(typeFromHandle, "m_item", typeof(Item)); FieldInfo fieldInfo2 = ScaleValidation.RequireInstanceField(typeFromHandle, "m_photonView", typeof(PhotonView)); FieldInfo fieldInfo3 = ScaleValidation.RequireInstanceField(typeFromHandle, "m_lastPos", typeof(Optionable)); FieldInfo fieldInfo4 = ScaleValidation.RequireInstanceField(typeFromHandle, "shouldSync", typeof(bool)); FieldInfo fieldInfo5 = ScaleValidation.RequireInstanceField(typeFromHandle, "debug", typeof(bool)); FieldInfo fieldInfo6 = ScaleValidation.RequireInstanceField(typeFromHandle, "lastRecievedPosition", typeof(Vector3)); ScaleValidation.RequireInstanceField(typeFromHandle, "forceSyncFrames", typeof(int)); Type baseType = typeFromHandle.BaseType; if (baseType == null || !baseType.IsGenericType || baseType.GetGenericTypeDefinition().FullName != "PhotonBinaryStreamSerializer`1") { throw new InvalidOperationException("ItemPhysicsSyncer base type structure mismatch"); } Type[] genericArguments = baseType.GetGenericArguments(); if (genericArguments.Length != 1 || genericArguments[0] != typeof(ItemPhysicsSyncData)) { throw new InvalidOperationException("ItemPhysicsSyncer stream payload type mismatch"); } FieldInfo field = baseType.GetField("RemoteValue", BindingFlags.Instance | BindingFlags.NonPublic); FieldInfo field2 = baseType.GetField("sinceLastPackage", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null || field.IsStatic || field.FieldType != typeof(Optionable)) { throw new InvalidOperationException("PhotonBinaryStreamSerializer.RemoteValue structure mismatch"); } if (field2 == null || field2.IsStatic || field2.FieldType != typeof(float)) { throw new InvalidOperationException("PhotonBinaryStreamSerializer.sinceLastPackage structure mismatch"); } ScaleValidation.RequireInstanceProperty(typeof(Item), "itemState", typeof(ItemState)); if (!Enum.IsDefined(typeof(ItemState), (object)(ItemState)0)) { throw new InvalidOperationException("ItemState.Ground is no longer defined"); } FieldInfo field3 = ScaleValidation.RequireInstanceFieldByTypeName(typeof(ItemPhysicsSyncData), "position", "Unity.Mathematics.float3"); FieldInfo field4 = ScaleValidation.RequireInstanceField(typeof(ItemPhysicsSyncData), "rotation", typeof(Quaternion)); ScaleValidation.RequireInstanceMethod(typeFromHandle, "ShouldSendData", typeof(bool), Type.EmptyTypes, requirePublic: true); ScaleValidation.RequireInstanceMethod(typeFromHandle, "GetDataToWrite", typeof(ItemPhysicsSyncData), Type.EmptyTypes, requirePublic: true); ScaleValidation.RequireInstanceMethod(typeFromHandle, "OnDataReceived", typeof(void), new Type[1] { typeof(ItemPhysicsSyncData) }, requirePublic: true); FieldInfo fieldInfo7 = ScaleValidation.RequireInstanceFieldByTypeName(typeof(Item), "rig", "UnityEngine.Rigidbody"); Type fieldType = fieldInfo7.FieldType; PropertyInfo property = ScaleValidation.RequireInstancePropertyByTypeName(fieldType, "position", "UnityEngine.Vector3", requireSetter: true); PropertyInfo property2 = ScaleValidation.RequireInstancePropertyByTypeName(fieldType, "rotation", "UnityEngine.Quaternion", requireSetter: true); ScaleValidation.RequireInstanceMethodByTypeNames(fieldType, "MovePosition", typeof(void).FullName, new string[1] { "UnityEngine.Vector3" }); ScaleValidation.RequireInstanceMethodByTypeNames(fieldType, "MoveRotation", typeof(void).FullName, new string[1] { "UnityEngine.Quaternion" }); FieldRef obj = AccessTools.FieldRefAccess(fieldInfo); FieldRef val = AccessTools.FieldRefAccess(fieldInfo2); FieldRef> val2 = AccessTools.FieldRefAccess>(fieldInfo3); FieldRef val3 = AccessTools.FieldRefAccess(fieldInfo4); FieldRef val4 = AccessTools.FieldRefAccess(fieldInfo5); FieldRef val5 = AccessTools.FieldRefAccess(fieldInfo6); FieldRef> val6 = AccessTools.FieldRefAccess>(field); FieldRef val7 = AccessTools.FieldRefAccess(field2); Func func = ScaleEmit.CreateUnityObjectFieldGetter(fieldInfo7); Func func2 = ScaleExperimentalEmit.CreateVector3Getter(fieldType, property); Func func3 = ScaleExperimentalEmit.CreateQuaternionGetter(fieldType, property2); Func func4 = ScaleExperimentalEmit.CreateStructVector3FieldGetter(field3); Func func5 = ScaleExperimentalEmit.CreateStructQuaternionFieldGetter(field4); if (obj == null || val == null || val2 == null || val3 == null || val4 == null || val5 == null || val6 == null || val7 == null || func == null || func2 == null || func3 == null || func4 == null || func5 == null) { throw new InvalidOperationException("RemoteItemInterpolationThreshold accessor creation failed"); } _item = obj; _photonView = val; _lastPos = val2; _shouldSync = val3; _debug = val4; _lastRecievedPosition = val5; _remoteValue = val6; _sinceLastPackage = val7; _rig = func; _rigPosition = func2; _rigRotation = func3; _dataPosition = func4; _dataRotation = func5; } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(ItemPhysicsSyncer), "FixedUpdate", typeof(void), Type.EmptyTypes, requirePublic: false); } internal static void Reset() { _item = null; _photonView = null; _lastPos = null; _shouldSync = null; _debug = null; _lastRecievedPosition = null; _remoteValue = null; _sinceLastPackage = null; _rig = null; _rigPosition = null; _rigRotation = null; _dataPosition = null; _dataRotation = null; } internal static bool Prefix(ItemPhysicsSyncer __instance) { //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_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) FieldRef item = _item; FieldRef photonView = _photonView; FieldRef> lastPos = _lastPos; FieldRef shouldSync = _shouldSync; FieldRef debug = _debug; FieldRef lastRecievedPosition = _lastRecievedPosition; FieldRef> remoteValue = _remoteValue; FieldRef sinceLastPackage = _sinceLastPackage; Func rig = _rig; Func rigPosition = _rigPosition; Func rigRotation = _rigRotation; Func dataPosition = _dataPosition; Func dataRotation = _dataRotation; if (item == null || photonView == null || lastPos == null || shouldSync == null || debug == null || lastRecievedPosition == null || remoteValue == null || sinceLastPackage == null || rig == null || rigPosition == null || rigRotation == null || dataPosition == null || dataRotation == null) { RateLimitedDiagnostics.Hit("RemoteItemInterpolationThreshold.accessors-unavailable"); return true; } if (debug.Invoke(__instance)) { return true; } Item val = item.Invoke(__instance); PhotonView val2 = photonView.Invoke(__instance); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { return true; } Object val3 = rig(val); if (val3 == (Object)null || !PhotonNetwork.InRoom || val2.IsMine) { return true; } if (!shouldSync.Invoke(__instance)) { return true; } Optionable val4 = remoteValue.Invoke(__instance); if (val4.IsNone) { return true; } if ((int)val.itemState != 0) { return true; } Optionable val5 = lastPos.Invoke(__instance); if (val5.IsNone) { return true; } int serializationRate = PhotonNetwork.SerializationRate; if (serializationRate <= 0) { return true; } double num = 1f / (float)serializationRate; float num2 = sinceLastPackage.Invoke(__instance) + Time.fixedDeltaTime * 0.6f; float num3 = (float)((double)num2 / num); ItemPhysicsSyncData value = val4.Value; Vector3 val6 = dataPosition(value); Vector3 val7 = Vector3.Lerp(val5.Value, val6, num3); Vector3 val8 = rigPosition(val3); Vector3 val9 = val7 - val8; if (((Vector3)(ref val9)).sqrMagnitude != 0f) { return true; } Quaternion val10 = rigRotation(val3); Quaternion val11 = dataRotation(value); if (val10.x != val11.x || val10.y != val11.y || val10.z != val11.z || val10.w != val11.w) { return true; } sinceLastPackage.Invoke(__instance) = num2; lastRecievedPosition.Invoke(__instance) = val7; return false; } } internal static class RemoteRagdollLod { private sealed class State { internal int Tier; internal int LastFrame = int.MinValue; internal bool LastResult; internal int LastItemId = int.MinValue; internal int FullFrames; internal int ThrottleTick = int.MinValue; internal bool ThrottleResult; internal int ThrottleItemId = int.MinValue; } internal const int TierFull = 0; internal const int TierPassiveRagdoll = 2; private const float EnterDistance = 60f; private const float ExitDistance = 50f; private const float FullRagdollControlThreshold = 0.9f; private const int WarmupFrames = 5; private const float ItemAttachRecencySeconds = 0.5f; private const string FixedJointTypeName = "UnityEngine.FixedJoint"; private static ConditionalWeakTable _states; private static FieldRef _bodypartCharacter; private static FieldRef _grabbedPlayer; private static FieldRef _grabbingPlayer; private static Func _grabJoint; private static int _refCount; internal static void Acquire() { ValidateStructure(); FieldInfo fieldInfo = ScaleValidation.RequireInstanceField(typeof(Bodypart), "character", typeof(Character)); FieldInfo field = ScaleValidation.RequireInstanceFieldByTypeName(typeof(CharacterData), "grabJoint", "UnityEngine.FixedJoint"); FieldInfo fieldInfo2 = ScaleValidation.RequireInstanceField(typeof(CharacterData), "grabbedPlayer", typeof(Character)); FieldInfo fieldInfo3 = ScaleValidation.RequireInstanceField(typeof(CharacterData), "grabbingPlayer", typeof(Character)); FieldRef obj = AccessTools.FieldRefAccess(fieldInfo); Func func = ScaleEmit.CreateUnityObjectFieldGetter(field); FieldRef val = AccessTools.FieldRefAccess(fieldInfo2); FieldRef val2 = AccessTools.FieldRefAccess(fieldInfo3); if (obj == null || val == null || val2 == null || func == null) { throw new InvalidOperationException("RemoteRagdollLod accessor creation failed"); } if (_states == null) { _states = new ConditionalWeakTable(); } _bodypartCharacter = obj; _grabbedPlayer = val; _grabbingPlayer = val2; _grabJoint = func; _refCount++; } internal static void Release() { if (_refCount > 0) { _refCount--; } if (_refCount <= 0) { _refCount = 0; _states = null; _bodypartCharacter = null; _grabbedPlayer = null; _grabbingPlayer = null; _grabJoint = null; } } internal static Character ResolveOwner(Bodypart part) { FieldRef bodypartCharacter = _bodypartCharacter; if (bodypartCharacter == null || (Object)(object)part == (Object)null) { return null; } return bodypartCharacter.Invoke(part); } internal static bool ShouldDowngrade(Character c) { ConditionalWeakTable states = _states; Func grabJoint = _grabJoint; FieldRef grabbedPlayer = _grabbedPlayer; FieldRef grabbingPlayer = _grabbingPlayer; if (states == null || grabJoint == null || grabbedPlayer == null || grabbingPlayer == null) { RateLimitedDiagnostics.Hit("RemoteRagdollLod.accessors-unavailable"); return false; } if ((Object)(object)c == (Object)null) { return false; } CharacterData data = c.data; CharacterRefs refs = c.refs; Character localCharacter = Character.localCharacter; if ((Object)(object)data == (Object)null || refs == null || (Object)(object)localCharacter == (Object)null) { return false; } int frameCount = Time.frameCount; State orCreateValue = states.GetOrCreateValue(c); int num = (((Object)(object)data.currentItem != (Object)null) ? ((Object)data.currentItem).GetInstanceID() : 0); if (orCreateValue.LastItemId == int.MinValue) { orCreateValue.LastItemId = num; } else if (orCreateValue.LastItemId != num) { orCreateValue.LastItemId = num; orCreateValue.Tier = 0; orCreateValue.FullFrames = 0; orCreateValue.LastResult = false; orCreateValue.LastFrame = frameCount; return false; } if (orCreateValue.LastFrame == frameCount) { return orCreateValue.LastResult; } bool num2 = orCreateValue.FullFrames >= 5; bool flag = num2 && Evaluate(c, data, localCharacter, grabJoint, grabbedPlayer, grabbingPlayer, orCreateValue.Tier); if (!num2) { orCreateValue.FullFrames++; } orCreateValue.Tier = (flag ? 2 : 0); orCreateValue.LastFrame = frameCount; orCreateValue.LastResult = flag; return flag; } internal static bool ShouldThrottleAnimation(Character c) { ConditionalWeakTable states = _states; Func grabJoint = _grabJoint; FieldRef grabbedPlayer = _grabbedPlayer; FieldRef grabbingPlayer = _grabbingPlayer; if (states == null || grabJoint == null || grabbedPlayer == null || grabbingPlayer == null) { return false; } if ((Object)(object)c == (Object)null) { return false; } CharacterData data = c.data; Character localCharacter = Character.localCharacter; if ((Object)(object)data == (Object)null || (Object)(object)localCharacter == (Object)null) { return false; } State orCreateValue = states.GetOrCreateValue(c); int num = (((Object)(object)data.currentItem != (Object)null) ? ((Object)data.currentItem).GetInstanceID() : 0); if (orCreateValue.ThrottleItemId != num) { orCreateValue.ThrottleItemId = num; orCreateValue.ThrottleResult = false; orCreateValue.ThrottleTick = PhysicsTick(); return false; } int num2 = PhysicsTick(); if (orCreateValue.ThrottleTick == num2) { return orCreateValue.ThrottleResult; } bool flag = PassesFallbacks(c, data, localCharacter, grabJoint, grabbedPlayer, grabbingPlayer); orCreateValue.ThrottleTick = num2; orCreateValue.ThrottleResult = flag; return flag; } internal static int PhysicsTick() { return Mathf.FloorToInt(Time.fixedTime / Time.fixedDeltaTime); } private static bool Evaluate(Character c, CharacterData data, Character local, Func grabJoint, FieldRef grabbedPlayerRef, FieldRef grabbingPlayerRef, int tier) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) if (!PassesFallbacks(c, data, local, grabJoint, grabbedPlayerRef, grabbingPlayerRef)) { return false; } if (!TryGetCenter(local, out var center) || !TryGetCenter(c, out var center2)) { return false; } float num = Vector3.Distance(center, center2); if (float.IsNaN(num)) { return false; } if (tier != 2) { return num >= 60f; } return !(num < 50f); } private static bool PassesFallbacks(Character c, CharacterData data, Character local, Func grabJoint, FieldRef grabbedPlayerRef, FieldRef grabbingPlayerRef) { if ((Object)(object)c == (Object)(object)local) { return false; } PhotonView photonView = ((MonoBehaviourPun)c).photonView; if ((Object)(object)photonView == (Object)null || photonView.IsMine) { return false; } if (!c.IsPlayerControlled) { return false; } if (c.warping) { return false; } if ((Object)(object)data.carrier != (Object)null || (Object)(object)data.carriedPlayer != (Object)null) { return false; } if (data.isCarried || (Object)(object)grabbedPlayerRef.Invoke(data) != (Object)null || (Object)(object)grabbingPlayerRef.Invoke(data) != (Object)null) { return false; } if (data.dead || data.fullyPassedOut) { return false; } if (grabJoint(data) != (Object)null) { return false; } if (data.isClimbing || data.isRopeClimbing || data.isVineClimbing) { return false; } if ((Object)(object)data.currentClimbHandle != (Object)null || data.isReaching || data.isKicking) { return false; } if (data.isKinecmatic) { return false; } if (data.sinceItemAttach < 0.5f) { return false; } if (!(data.currentRagdollControll >= 0.9f)) { return false; } if ((Object)(object)Character.observedCharacter == (Object)(object)c) { return false; } return true; } private static bool TryGetCenter(Character c, out Vector3 center) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_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) center = Vector3.zero; CharacterRagdoll val = c.refs?.ragdoll; if ((Object)(object)val == (Object)null) { return false; } Dictionary partDict = val.partDict; if (partDict == null || !partDict.TryGetValue((BodypartType)2, out var value) || (Object)(object)value == (Object)null) { return false; } Transform transform = value.transform; if ((Object)(object)transform == (Object)null) { return false; } center = transform.position; return true; } private static void ValidateStructure() { ScaleValidation.RequireStaticField(typeof(Character), "localCharacter", typeof(Character)); ScaleValidation.RequireStaticProperty(typeof(Character), "observedCharacter", typeof(Character)); ScaleValidation.RequireInstanceField(typeof(Character), "data", typeof(CharacterData)); ScaleValidation.RequireInstanceField(typeof(Character), "refs", typeof(CharacterRefs)); ScaleValidation.RequireInstanceField(typeof(Character), "isBot", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(Character), "isZombie", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(Character), "isScoutmaster", typeof(bool)); ScaleValidation.RequireInstanceProperty(typeof(Character), "IsPlayerControlled", typeof(bool)); ScaleValidation.RequireInstanceProperty(typeof(Character), "warping", typeof(bool)); ScaleValidation.RequireInstanceProperty(typeof(Character), "Center", typeof(Vector3)); ScaleValidation.RequireInheritedInstanceProperty(typeof(Character), "photonView", typeof(PhotonView)); ScaleValidation.RequireInstanceField(typeof(CharacterRefs), "ragdoll", typeof(CharacterRagdoll)); ScaleValidation.RequireInstanceField(typeof(CharacterRagdoll), "partDict", typeof(Dictionary)); ScaleValidation.RequireInheritedInstanceProperty(typeof(Bodypart), "transform", typeof(Transform)); if (!Enum.IsDefined(typeof(BodypartType), (object)(BodypartType)2)) { throw new InvalidOperationException("BodypartType.Torso is no longer defined"); } ScaleValidation.RequireInstanceField(typeof(CharacterData), "carrier", typeof(Character)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "carriedPlayer", typeof(Character)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "grabbedPlayer", typeof(Character)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "grabbingPlayer", typeof(Character)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "isCarried", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "currentClimbHandle", typeof(ClimbHandle)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "isReaching", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "isKicking", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "fullyPassedOut", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "isClimbing", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "isRopeClimbing", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "isVineClimbing", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "isKinecmatic", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "sinceItemAttach", typeof(float)); ScaleValidation.RequireInstanceProperty(typeof(CharacterData), "currentItem", typeof(Item)); ScaleValidation.RequireInstanceProperty(typeof(CharacterData), "dead", typeof(bool)); ScaleValidation.RequireInstanceProperty(typeof(CharacterData), "currentRagdollControll", typeof(float)); ScaleValidation.RequireInstanceMethod(typeof(CharacterMovement), "FixedUpdate", typeof(void), Type.EmptyTypes, requirePublic: false); ScaleValidation.RequireInstanceMethod(typeof(Bodypart), "Gravity", typeof(void), new Type[1] { typeof(Vector3) }, requirePublic: false); ScaleValidation.RequireInstanceMethod(typeof(Bodypart), "ToggleUseGravity", typeof(void), new Type[1] { typeof(bool) }, requirePublic: false); ScaleValidation.RequireInstanceMethod(typeof(Bodypart), "Drag", typeof(void), new Type[2] { typeof(float), typeof(bool) }, requirePublic: false); ScaleValidation.RequireInstanceMethod(typeof(Bodypart), "ApplyForces", typeof(void), Type.EmptyTypes, requirePublic: false); ScaleValidation.RequireInstanceMethod(typeof(Bodypart), "SaveAnimationData", typeof(void), Type.EmptyTypes, requirePublic: true); ScaleValidation.RequireInstanceMethod(typeof(Bodypart), "SnapToAnim", typeof(void), Type.EmptyTypes, requirePublic: true); ScaleValidation.RequireInstanceMethod(typeof(CharacterRagdoll), "SnapToAnimation", typeof(void), Type.EmptyTypes, requirePublic: true); } } internal sealed class RemoteRagdollLodAnimateModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.RemoteRagdollLodAnimate, () => new PatchDefinition(PatchId.RemoteRagdollLodAnimate, RemoteRagdollLodAnimatePatch.Initialize, RemoteRagdollLodAnimatePatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(RemoteRagdollLodAnimatePatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, RemoteRagdollLodAnimatePatch.Reset)); } } internal static class RemoteRagdollLodAnimatePatch { private static bool _acquired; internal static void Initialize() { ResolveAndValidateTarget(); RemoteRagdollLod.Acquire(); _acquired = true; } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(Bodypart), "Animate", typeof(void), new Type[2] { typeof(float), typeof(float) }, requirePublic: false); } internal static void Reset() { if (_acquired) { _acquired = false; RemoteRagdollLod.Release(); } } [HarmonyPriority(600)] internal static bool Prefix(Bodypart __instance) { Character val = RemoteRagdollLod.ResolveOwner(__instance); if ((Object)(object)val == (Object)null) { RateLimitedDiagnostics.Hit("RemoteRagdollLodAnimate.owner-unresolved"); return true; } return !RemoteRagdollLod.ShouldDowngrade(val); } } internal sealed class RemoteRagdollLodAnimatorModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.RemoteRagdollLodAnimator, () => new PatchDefinition(PatchId.RemoteRagdollLodAnimator, RemoteRagdollLodAnimatorPatch.Initialize, RemoteRagdollLodAnimatorPatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(RemoteRagdollLodAnimatorPatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, RemoteRagdollLodAnimatorPatch.Reset)); } } internal static class RemoteRagdollLodAnimatorPatch { private static FieldRef _character; private static FieldRef _emoting; private static FieldRef _sinceEmoteStart; private static Func _getAnimator; private static Action _setBool; private static Action _setFloat; private static Action _setAnimSpeed; private static int _emoteHash; private static int _inWaterHash; private static bool _acquired; internal static void Initialize() { ResolveAndValidateTarget(); FieldInfo fieldInfo = ScaleValidation.RequireInstanceField(typeof(CharacterAnimations), "character", typeof(Character)); FieldInfo fieldInfo2 = ScaleValidation.RequireInstanceField(typeof(CharacterAnimations), "emoting", typeof(bool)); FieldInfo fieldInfo3 = ScaleValidation.RequireInstanceField(typeof(CharacterAnimations), "sinceEmoteStart", typeof(float)); FieldInfo fieldInfo4 = ScaleValidation.RequireInstanceFieldByTypeName(typeof(CharacterRefs), "animator", "UnityEngine.Animator"); ScaleValidation.RequireInstanceField(typeof(Character), "data", typeof(CharacterData)); ScaleValidation.RequireInstanceField(typeof(Character), "input", typeof(CharacterInput)); ScaleValidation.RequireInstanceField(typeof(Character), "refs", typeof(CharacterRefs)); ScaleValidation.RequireInstanceField(typeof(CharacterRefs), "animationPositionTransform", typeof(Transform)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "myersDistance", typeof(float)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "inWater", typeof(float)); ScaleValidation.RequireInstanceField(typeof(CharacterInput), "movementInput", typeof(Vector2)); ScaleValidation.RequireInstanceField(typeof(CharacterInput), "jumpWasPressed", typeof(bool)); ScaleValidation.RequireInstanceMethod(typeof(CharacterAnimations), "LateUpdate", typeof(void), Type.EmptyTypes, requirePublic: false); ScaleValidation.RequireInstanceMethod(typeof(CharacterAnimations), "HandleIK", typeof(void), Type.EmptyTypes, requirePublic: false); MethodInfo method = ScaleValidation.RequireInstanceMethod(typeof(CharacterAnimations), "SetAnimSpeed", typeof(void), Type.EmptyTypes, requirePublic: false); FieldRef val = AccessTools.FieldRefAccess(fieldInfo); FieldRef val2 = AccessTools.FieldRefAccess(fieldInfo2); FieldRef val3 = AccessTools.FieldRefAccess(fieldInfo3); Func func = ScaleEmit.CreateUnityObjectFieldGetter(fieldInfo4); Type fieldType = fieldInfo4.FieldType; MethodInfo method2 = fieldType.GetMethod("StringToHash", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(string) }, null); MethodInfo method3 = fieldType.GetMethod("SetBool", BindingFlags.Instance | BindingFlags.Public, null, new Type[2] { typeof(int), typeof(bool) }, null); MethodInfo method4 = fieldType.GetMethod("SetFloat", BindingFlags.Instance | BindingFlags.Public, null, new Type[2] { typeof(int), typeof(float) }, null); if (method2 == null || method3 == null || method4 == null) { throw new MissingMethodException("UnityEngine.Animator", "hash/set accessors"); } Func obj = (Func)method2.CreateDelegate(typeof(Func)); Action action = EmitSetBool(fieldType, method3); Action action2 = EmitSetFloat(fieldType, method4); Action action3 = ScaleExperimentalEmit.CreateDelegate>(method); if (val == null || val2 == null || val3 == null || func == null || action == null || action2 == null || action3 == null) { throw new InvalidOperationException("RemoteRagdollLodAnimator FieldRef creation failed"); } RemoteRagdollLod.Acquire(); _acquired = true; _character = val; _emoting = val2; _sinceEmoteStart = val3; _getAnimator = func; _setBool = action; _setFloat = action2; _setAnimSpeed = action3; _emoteHash = obj("Emote"); _inWaterHash = obj("InWater"); } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(CharacterAnimations), "Update", typeof(void), Type.EmptyTypes, requirePublic: false); } internal static void Reset() { _character = null; _emoting = null; _sinceEmoteStart = null; _getAnimator = null; _setBool = null; _setFloat = null; _setAnimSpeed = null; _emoteHash = 0; _inWaterHash = 0; if (_acquired) { _acquired = false; RemoteRagdollLod.Release(); } } internal static bool Prefix(CharacterAnimations __instance) { //IL_00fb: Unknown result type (might be due to invalid IL or missing references) FieldRef character = _character; if (character == null) { RateLimitedDiagnostics.Hit("RemoteRagdollLodAnimator.accessor-unavailable"); return true; } Character val = character.Invoke(__instance); if ((Object)(object)val == (Object)null) { RateLimitedDiagnostics.Hit("RemoteRagdollLodAnimator.character-null"); return true; } if (!RemoteRagdollLod.ShouldDowngrade(val)) { return true; } CharacterData data = val.data; CharacterRefs refs = val.refs; Func getAnimator = _getAnimator; Action setBool = _setBool; Action setFloat = _setFloat; Action setAnimSpeed = _setAnimSpeed; FieldRef emoting = _emoting; FieldRef sinceEmoteStart = _sinceEmoteStart; if ((Object)(object)data == (Object)null || refs == null || (Object)(object)refs.animationPositionTransform == (Object)null || getAnimator == null || setBool == null || setFloat == null || setAnimSpeed == null || emoting == null || sinceEmoteStart == null) { return true; } Bodypart hip = refs.hip; Object val2 = getAnimator(refs); if ((Object)(object)hip == (Object)null || (Object)(object)hip.transform == (Object)null || val2 == (Object)null || (Object)(object)val.input == (Object)null) { return true; } refs.animationPositionTransform.position = hip.transform.position; setAnimSpeed(__instance); float deltaTime = Time.deltaTime; __instance.throwTime -= deltaTime; if (__instance.throwTime <= 0f) { __instance.throwTime = 0f; } sinceEmoteStart.Invoke(__instance) += deltaTime; if (emoting.Invoke(__instance) && (sinceEmoteStart.Invoke(__instance) > 2f || (sinceEmoteStart.Invoke(__instance) > 0.7f && (((Vector2)(ref val.input.movementInput)).magnitude > 0.1f || val.input.jumpWasPressed || data.sinceGrounded > 0.2f)))) { setBool(val2, _emoteHash, arg3: false); emoting.Invoke(__instance) = false; } setFloat(val2, _inWaterHash, data.inWater); data.myersDistance = 1000f; data.inWater = 1f; return false; } private static Action EmitSetBool(Type animatorType, MethodInfo setter) { DynamicMethod dynamicMethod = new DynamicMethod("PSO_RemoteAnimatorSetBool", typeof(void), new Type[3] { typeof(Object), typeof(int), typeof(bool) }, typeof(RemoteRagdollLodAnimatorPatch).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Castclass, animatorType); iLGenerator.Emit(OpCodes.Ldarg_1); iLGenerator.Emit(OpCodes.Ldarg_2); iLGenerator.Emit(OpCodes.Callvirt, setter); iLGenerator.Emit(OpCodes.Ret); return (Action)dynamicMethod.CreateDelegate(typeof(Action)); } private static Action EmitSetFloat(Type animatorType, MethodInfo setter) { DynamicMethod dynamicMethod = new DynamicMethod("PSO_RemoteAnimatorSetFloat", typeof(void), new Type[3] { typeof(Object), typeof(int), typeof(float) }, typeof(RemoteRagdollLodAnimatorPatch).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Castclass, animatorType); iLGenerator.Emit(OpCodes.Ldarg_1); iLGenerator.Emit(OpCodes.Ldarg_2); iLGenerator.Emit(OpCodes.Callvirt, setter); iLGenerator.Emit(OpCodes.Ret); return (Action)dynamicMethod.CreateDelegate(typeof(Action)); } } internal sealed class RemoteRagdollLodMovementForceModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.RemoteRagdollLodMovementForce, () => new PatchDefinition(PatchId.RemoteRagdollLodMovementForce, RemoteRagdollLodMovementForcePatch.Initialize, RemoteRagdollLodMovementForcePatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(RemoteRagdollLodMovementForcePatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, RemoteRagdollLodMovementForcePatch.Reset)); } } internal static class RemoteRagdollLodMovementForcePatch { private static bool _acquired; internal static void Initialize() { ResolveAndValidateTarget(); ScaleValidation.RequireInstanceField(typeof(CharacterData), "worldMovementInput_Lerp", typeof(Vector3)); RemoteRagdollLod.Acquire(); _acquired = true; } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(Bodypart), "AddMovementForce", typeof(void), new Type[1] { typeof(float) }, requirePublic: false); } internal static void Reset() { if (_acquired) { _acquired = false; RemoteRagdollLod.Release(); } } internal static bool Prefix(Bodypart __instance) { Character val = RemoteRagdollLod.ResolveOwner(__instance); if ((Object)(object)val == (Object)null) { RateLimitedDiagnostics.Hit("RemoteRagdollLodMovementForce.owner-unresolved"); return true; } return !RemoteRagdollLod.ShouldDowngrade(val); } } internal sealed class RemoteRagdollLodPhysicsModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.RemoteRagdollLodPhysics, () => new PatchDefinition(PatchId.RemoteRagdollLodPhysics, RemoteRagdollLodPhysicsPatch.Initialize, RemoteRagdollLodPhysicsPatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(RemoteRagdollLodPhysicsPatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, RemoteRagdollLodPhysicsPatch.Reset)); } } internal static class RemoteRagdollLodPhysicsPatch { private static FieldRef _character; private static Action _setPhysicsMats; private static Action _saveAdditionalTransformPositions; private static bool _acquired; internal static void Initialize() { ResolveAndValidateTarget(); FieldInfo fieldInfo = ScaleValidation.RequireInstanceField(typeof(CharacterRagdoll), "character", typeof(Character)); MethodInfo method = ScaleValidation.RequireInstanceMethod(typeof(CharacterRagdoll), "SaveAdditionalTransformPositions", typeof(void), Type.EmptyTypes, requirePublic: false); MethodInfo method2 = ScaleValidation.RequireInstanceMethod(typeof(CharacterRagdoll), "SetPhysicsMats", typeof(void), Type.EmptyTypes, requirePublic: false); FieldRef obj = AccessTools.FieldRefAccess(fieldInfo); Action action = ScaleExperimentalEmit.CreateDelegate>(method); Action action2 = ScaleExperimentalEmit.CreateDelegate>(method2); if (obj == null) { throw new InvalidOperationException("RemoteRagdollLodPhysics FieldRef creation failed"); } if (action == null || action2 == null) { throw new InvalidOperationException("RemoteRagdollLodPhysics height accessor creation failed"); } RemoteRagdollLod.Acquire(); _acquired = true; _character = obj; _setPhysicsMats = action2; _saveAdditionalTransformPositions = action; } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(CharacterRagdoll), "FixedUpdate", typeof(void), Type.EmptyTypes, requirePublic: true); } internal static void Reset() { _character = null; _setPhysicsMats = null; _saveAdditionalTransformPositions = null; if (_acquired) { _acquired = false; RemoteRagdollLod.Release(); } } internal static bool Prefix(CharacterRagdoll __instance) { FieldRef character = _character; if (character == null) { RateLimitedDiagnostics.Hit("RemoteRagdollLodPhysics.accessor-unavailable"); return true; } Character val = character.Invoke(__instance); if ((Object)(object)val == (Object)null) { RateLimitedDiagnostics.Hit("RemoteRagdollLodPhysics.character-null"); return true; } if (!RemoteRagdollLod.ShouldDowngrade(val)) { return true; } Action saveAdditionalTransformPositions = _saveAdditionalTransformPositions; if (saveAdditionalTransformPositions == null) { return true; } try { _setPhysicsMats(__instance); saveAdditionalTransformPositions(__instance); return false; } catch (Exception) { RateLimitedDiagnostics.Hit("RemoteRagdollLodPhysics.height-update-failed"); return true; } } } internal static class ScaleExperimentalEmit { internal static TDelegate CreateDelegate(MethodInfo method) where TDelegate : Delegate { if (method == null) { throw new ArgumentNullException("method"); } if (method.IsStatic || method.ContainsGenericParameters) { throw new InvalidOperationException("Unexpected method structure: " + method.Name); } return (TDelegate)method.CreateDelegate(typeof(TDelegate)); } internal static Func CreateFieldGetter(FieldInfo field) { if (field == null) { throw new ArgumentNullException("field"); } if (field.IsStatic || field.DeclaringType != typeof(TInstance) || field.FieldType != typeof(TValue)) { throw new InvalidOperationException("Unexpected field structure: " + field.Name); } DynamicMethod dynamicMethod = new DynamicMethod("PSO_GetField_" + field.Name, typeof(TValue), new Type[1] { typeof(TInstance) }, typeof(ScaleExperimentalEmit).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldfld, field); iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } internal static Func CreateFirstElementTransformGetter(FieldInfo arrayField) { if (arrayField == null) { throw new ArgumentNullException("arrayField"); } if (arrayField.IsStatic || arrayField.DeclaringType != typeof(TInstance)) { throw new InvalidOperationException("Unexpected field owner for " + arrayField.Name); } Type fieldType = arrayField.FieldType; if (!fieldType.IsArray || fieldType.GetArrayRank() != 1) { throw new InvalidOperationException(arrayField.Name + " is not a single-rank array"); } Type elementType = fieldType.GetElementType(); if (elementType == null || elementType.IsValueType || !typeof(Component).IsAssignableFrom(elementType)) { throw new InvalidOperationException(arrayField.Name + " is not a Component array"); } PropertyInfo property = typeof(Component).GetProperty("transform", BindingFlags.Instance | BindingFlags.Public); MethodInfo methodInfo = property?.GetGetMethod(nonPublic: false); if (property == null || methodInfo == null || property.PropertyType != typeof(Transform)) { throw new InvalidOperationException("Component.transform structure mismatch"); } DynamicMethod dynamicMethod = new DynamicMethod("PSO_FirstTransform_" + arrayField.Name, typeof(Transform), new Type[1] { typeof(TInstance) }, typeof(ScaleExperimentalEmit).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); Label label = iLGenerator.DefineLabel(); LocalBuilder local = iLGenerator.DeclareLocal(fieldType); LocalBuilder local2 = iLGenerator.DeclareLocal(elementType); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ldfld, arrayField); iLGenerator.Emit(OpCodes.Stloc, local); iLGenerator.Emit(OpCodes.Ldloc, local); iLGenerator.Emit(OpCodes.Brfalse, label); iLGenerator.Emit(OpCodes.Ldloc, local); iLGenerator.Emit(OpCodes.Ldlen); iLGenerator.Emit(OpCodes.Conv_I4); iLGenerator.Emit(OpCodes.Brfalse, label); iLGenerator.Emit(OpCodes.Ldloc, local); iLGenerator.Emit(OpCodes.Ldc_I4_0); iLGenerator.Emit(OpCodes.Ldelem_Ref); iLGenerator.Emit(OpCodes.Stloc, local2); iLGenerator.Emit(OpCodes.Ldloc, local2); iLGenerator.Emit(OpCodes.Brfalse, label); iLGenerator.Emit(OpCodes.Ldloc, local2); iLGenerator.Emit(OpCodes.Callvirt, methodInfo); iLGenerator.Emit(OpCodes.Ret); iLGenerator.MarkLabel(label); iLGenerator.Emit(OpCodes.Ldnull); iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } internal static Func CreateStructVector3FieldGetter(FieldInfo field) where TStruct : struct { if (field == null) { throw new ArgumentNullException("field"); } if (field.IsStatic || field.DeclaringType != typeof(TStruct)) { throw new InvalidOperationException("Unexpected field owner for " + field.Name); } MethodInfo methodInfo = null; if (field.FieldType != typeof(Vector3)) { MethodInfo[] methods = field.FieldType.GetMethods(BindingFlags.Static | BindingFlags.Public); foreach (MethodInfo methodInfo2 in methods) { if (methodInfo2.Name != "op_Implicit" || methodInfo2.ReturnType != typeof(Vector3)) { continue; } ParameterInfo[] parameters = methodInfo2.GetParameters(); if (parameters.Length == 1 && !(parameters[0].ParameterType != field.FieldType)) { if (methodInfo != null) { throw new InvalidOperationException("Ambiguous Vector3 conversion for " + field.FieldType.FullName); } methodInfo = methodInfo2; } } if (methodInfo == null) { throw new InvalidOperationException(field.FieldType.FullName + " has no implicit Vector3 conversion"); } } DynamicMethod dynamicMethod = new DynamicMethod("PSO_GetStructV3_" + field.Name, typeof(Vector3), new Type[1] { typeof(TStruct) }, typeof(ScaleExperimentalEmit).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarga_S, (byte)0); iLGenerator.Emit(OpCodes.Ldfld, field); if (methodInfo != null) { iLGenerator.Emit(OpCodes.Call, methodInfo); } iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } internal static Func CreateStructQuaternionFieldGetter(FieldInfo field) where TStruct : struct { if (field == null) { throw new ArgumentNullException("field"); } if (field.IsStatic || field.DeclaringType != typeof(TStruct) || field.FieldType != typeof(Quaternion)) { throw new InvalidOperationException("Unexpected field structure: " + field.Name); } DynamicMethod dynamicMethod = new DynamicMethod("PSO_GetStructQ_" + field.Name, typeof(Quaternion), new Type[1] { typeof(TStruct) }, typeof(ScaleExperimentalEmit).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarga_S, (byte)0); iLGenerator.Emit(OpCodes.Ldfld, field); iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } internal static Func CreateVector3Getter(Type declaringType, PropertyInfo property) { MethodInfo meth = RequireGetter(declaringType, property, typeof(Vector3)); DynamicMethod dynamicMethod = new DynamicMethod("PSO_GetV3_" + property.Name, typeof(Vector3), new Type[1] { typeof(Object) }, typeof(ScaleExperimentalEmit).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Castclass, declaringType); iLGenerator.Emit(OpCodes.Callvirt, meth); iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } internal static Func CreateQuaternionGetter(Type declaringType, PropertyInfo property) { MethodInfo meth = RequireGetter(declaringType, property, typeof(Quaternion)); DynamicMethod dynamicMethod = new DynamicMethod("PSO_GetQ_" + property.Name, typeof(Quaternion), new Type[1] { typeof(Object) }, typeof(ScaleExperimentalEmit).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Castclass, declaringType); iLGenerator.Emit(OpCodes.Callvirt, meth); iLGenerator.Emit(OpCodes.Ret); return (Func)dynamicMethod.CreateDelegate(typeof(Func)); } internal static Action CreateVector3Action(Type declaringType, MethodInfo target) { RequireInstanceVoid(declaringType, target, typeof(Vector3)); DynamicMethod dynamicMethod = new DynamicMethod("PSO_CallV3_" + target.Name, typeof(void), new Type[2] { typeof(Object), typeof(Vector3) }, typeof(ScaleExperimentalEmit).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Castclass, declaringType); iLGenerator.Emit(OpCodes.Ldarg_1); iLGenerator.Emit(OpCodes.Callvirt, target); iLGenerator.Emit(OpCodes.Ret); return (Action)dynamicMethod.CreateDelegate(typeof(Action)); } internal static Action CreateQuaternionAction(Type declaringType, MethodInfo target) { RequireInstanceVoid(declaringType, target, typeof(Quaternion)); DynamicMethod dynamicMethod = new DynamicMethod("PSO_CallQ_" + target.Name, typeof(void), new Type[2] { typeof(Object), typeof(Quaternion) }, typeof(ScaleExperimentalEmit).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Castclass, declaringType); iLGenerator.Emit(OpCodes.Ldarg_1); iLGenerator.Emit(OpCodes.Callvirt, target); iLGenerator.Emit(OpCodes.Ret); return (Action)dynamicMethod.CreateDelegate(typeof(Action)); } private static MethodInfo RequireGetter(Type declaringType, PropertyInfo property, Type expected) { if (declaringType == null) { throw new ArgumentNullException("declaringType"); } if (property == null) { throw new ArgumentNullException("property"); } if (property.DeclaringType != declaringType || property.PropertyType != expected || property.GetIndexParameters().Length != 0) { throw new InvalidOperationException("Unexpected property structure: " + property.Name); } MethodInfo getMethod = property.GetGetMethod(nonPublic: true); if (getMethod == null || getMethod.IsStatic) { throw new InvalidOperationException(property.Name + " getter is unavailable"); } if (!typeof(Object).IsAssignableFrom(declaringType)) { throw new InvalidOperationException(declaringType.FullName + " is not a UnityEngine.Object"); } return getMethod; } internal static Action CreateVector3EnumAction(Type declaringType, MethodInfo target) { if (declaringType == null) { throw new ArgumentNullException("declaringType"); } if (target == null) { throw new ArgumentNullException("target"); } if (target.DeclaringType != declaringType || target.IsStatic || target.ReturnType != typeof(void) || target.ContainsGenericParameters) { throw new InvalidOperationException("Unexpected method structure: " + target.Name); } ParameterInfo[] parameters = target.GetParameters(); if (parameters.Length != 2 || parameters[0].ParameterType != typeof(Vector3) || !parameters[1].ParameterType.IsEnum || Enum.GetUnderlyingType(parameters[1].ParameterType) != typeof(int)) { throw new InvalidOperationException("Unexpected parameter structure: " + target.Name); } if (!typeof(Object).IsAssignableFrom(declaringType)) { throw new InvalidOperationException(declaringType.FullName + " is not a UnityEngine.Object"); } DynamicMethod dynamicMethod = new DynamicMethod("PSO_CallV3Enum_" + target.Name, typeof(void), new Type[3] { typeof(Object), typeof(Vector3), typeof(int) }, typeof(ScaleExperimentalEmit).Module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Castclass, declaringType); iLGenerator.Emit(OpCodes.Ldarg_1); iLGenerator.Emit(OpCodes.Ldarg_2); iLGenerator.Emit(OpCodes.Callvirt, target); iLGenerator.Emit(OpCodes.Ret); return (Action)dynamicMethod.CreateDelegate(typeof(Action)); } private static void RequireInstanceVoid(Type declaringType, MethodInfo target, Type parameterType) { if (declaringType == null) { throw new ArgumentNullException("declaringType"); } if (target == null) { throw new ArgumentNullException("target"); } if (target.DeclaringType != declaringType || target.IsStatic || target.ReturnType != typeof(void) || target.ContainsGenericParameters) { throw new InvalidOperationException("Unexpected method structure: " + target.Name); } ParameterInfo[] parameters = target.GetParameters(); if (parameters.Length != 1 || parameters[0].ParameterType != parameterType) { throw new InvalidOperationException("Unexpected parameter structure: " + target.Name); } if (!typeof(Object).IsAssignableFrom(declaringType)) { throw new InvalidOperationException(declaringType.FullName + " is not a UnityEngine.Object"); } } } internal sealed class SleepingZombieScanModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.SleepingZombieScan, () => new PatchDefinition(PatchId.SleepingZombieScan, SleepingZombieScanPatch.Initialize, SleepingZombieScanPatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(SleepingZombieScanPatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, SleepingZombieScanPatch.Reset)); } } internal static class SleepingZombieScanPatch { private delegate bool CharacterPredicate(MushroomZombie instance, Character target); private delegate void ZeroArgAction(MushroomZombie instance); private static FieldRef _character; private static CharacterPredicate _targetIsValid; private static CharacterPredicate _hasLineOfSight; private static ZeroArgAction _wakeUpFromSleep; internal static void Initialize() { ResolveAndValidateTarget(); FieldInfo fieldInfo = ScaleValidation.RequireInstanceField(typeof(MushroomZombie), "character", typeof(Character)); ScaleValidation.RequireInstanceField(typeof(MushroomZombie), "visible", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(MushroomZombie), "distanceBeforeWakeup", typeof(float)); ScaleValidation.RequireInstanceField(typeof(MushroomZombie), "lookAngleBeforeWakeup", typeof(float)); ScaleValidation.RequireInstanceField(typeof(Character), "data", typeof(CharacterData)); ScaleValidation.RequireInstanceField(typeof(Character), "refs", typeof(CharacterRefs)); ScaleValidation.RequireInstanceField(typeof(CharacterRefs), "head", typeof(Bodypart)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "fallSeconds", typeof(float)); ScaleValidation.RequireStaticField(typeof(Character), "AllCharacters", typeof(List)); ScaleValidation.RequireInstanceProperty(typeof(Character), "Center", typeof(Vector3)); ScaleValidation.RequireStaticMethod(typeof(Vector3), "Distance", typeof(float), new Type[2] { typeof(Vector3), typeof(Vector3) }, requirePublic: true); ScaleValidation.RequireStaticMethod(typeof(Vector3), "Angle", typeof(float), new Type[2] { typeof(Vector3), typeof(Vector3) }, requirePublic: true); MethodInfo methodInfo = ScaleValidation.RequireInstanceMethod(typeof(MushroomZombie), "TargetIsValid", typeof(bool), new Type[1] { typeof(Character) }, requirePublic: false); MethodInfo methodInfo2 = ScaleValidation.RequireInstanceMethod(typeof(MushroomZombie), "HasLineOfSight", typeof(bool), new Type[1] { typeof(Character) }, requirePublic: false); MethodInfo methodInfo3 = ScaleValidation.RequireInstanceMethod(typeof(MushroomZombie), "WakeUpFromSleep", typeof(void), Type.EmptyTypes, requirePublic: false); CharacterPredicate characterPredicate = AccessTools.MethodDelegate(methodInfo, (object)null, true); CharacterPredicate characterPredicate2 = AccessTools.MethodDelegate(methodInfo2, (object)null, true); ZeroArgAction zeroArgAction = AccessTools.MethodDelegate(methodInfo3, (object)null, true); FieldRef val = AccessTools.FieldRefAccess(fieldInfo); if (characterPredicate == null || characterPredicate2 == null || zeroArgAction == null || val == null) { throw new InvalidOperationException("SleepingZombieScan delegate binding failed"); } _character = val; _targetIsValid = characterPredicate; _hasLineOfSight = characterPredicate2; _wakeUpFromSleep = zeroArgAction; } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(MushroomZombie), "DoSleeping", typeof(void), Type.EmptyTypes, requirePublic: false); } internal static void Reset() { _character = null; _targetIsValid = null; _hasLineOfSight = null; _wakeUpFromSleep = null; } internal static bool Prefix(MushroomZombie __instance) { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0106: 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_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0164: 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_016d: Unknown result type (might be due to invalid IL or missing references) FieldRef character = _character; CharacterPredicate targetIsValid = _targetIsValid; CharacterPredicate hasLineOfSight = _hasLineOfSight; ZeroArgAction wakeUpFromSleep = _wakeUpFromSleep; if (character == null || targetIsValid == null || hasLineOfSight == null || wakeUpFromSleep == null) { RateLimitedDiagnostics.Hit("SleepingZombieScan.accessors-unavailable"); return true; } Character val = character.Invoke(__instance); if ((Object)(object)val == (Object)null || (Object)(object)val.data == (Object)null) { RateLimitedDiagnostics.Hit("SleepingZombieScan.self-unavailable"); return true; } val.data.fallSeconds = 10f; if (!__instance.visible) { return false; } float distanceBeforeWakeup = __instance.distanceBeforeWakeup; if (!(distanceBeforeWakeup > 0f)) { RateLimitedDiagnostics.Hit("SleepingZombieScan.non-positive-threshold-fallback"); return true; } List allCharacters = Character.AllCharacters; if (allCharacters == null) { RateLimitedDiagnostics.Hit("SleepingZombieScan.roster-null"); return true; } Vector3 center = val.Center; float num = distanceBeforeWakeup * distanceBeforeWakeup; float lookAngleBeforeWakeup = __instance.lookAngleBeforeWakeup; for (int i = 0; i < allCharacters.Count; i++) { Character val2 = allCharacters[i]; if ((Object)(object)val2 == (Object)null) { RateLimitedDiagnostics.Hit("SleepingZombieScan.candidate-null"); return true; } if (!targetIsValid(__instance, val2)) { continue; } Vector3 val3 = val2.Center - center; if (((Vector3)(ref val3)).sqrMagnitude < num) { Bodypart val4 = val2.refs?.head; Transform val5 = (((Object)(object)val4 != (Object)null) ? val4.transform : null); if ((Object)(object)val5 == (Object)null) { RateLimitedDiagnostics.Hit("SleepingZombieScan.candidate-head-unavailable"); return true; } if (Vector3.Angle(val5.forward, center - val5.position) <= lookAngleBeforeWakeup && hasLineOfSight(__instance, val2)) { wakeUpFromSleep(__instance); break; } } } return false; } } internal sealed class TumbleWeedTargetScanModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.TumbleWeedTargetScan, () => new PatchDefinition(PatchId.TumbleWeedTargetScan, TumbleWeedTargetScanPatch.Initialize, TumbleWeedTargetScanPatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(TumbleWeedTargetScanPatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, TumbleWeedTargetScanPatch.Reset)); } } internal static class TumbleWeedTargetScanPatch { private sealed class TargetState { internal int LastScanTick = int.MinValue; internal bool HasTarget; internal Character Target; } private const int Interval = 5; private const float MaxScanDistance = 300f; private const string RigidbodyTypeName = "UnityEngine.Rigidbody"; private static FieldRef _photonView; private static Func _rig; private static FieldRef _rollForce; private static FieldRef _maxAngle; private static Action _addForce; private static ConditionalWeakTable _states; internal static void Initialize() { ResolveAndValidateTarget(); FieldInfo fieldInfo = ScaleValidation.RequireInstanceField(typeof(TumbleWeed), "photonView", typeof(PhotonView)); FieldInfo fieldInfo2 = ScaleValidation.RequireInstanceFieldByTypeName(typeof(TumbleWeed), "rig", "UnityEngine.Rigidbody"); FieldInfo fieldInfo3 = ScaleValidation.RequireInstanceField(typeof(TumbleWeed), "rollForce", typeof(float)); FieldInfo fieldInfo4 = ScaleValidation.RequireInstanceField(typeof(TumbleWeed), "maxAngle", typeof(float)); ScaleValidation.RequireInstanceMethodByTypeNames(typeof(TumbleWeed), "GetTarget", "Character", Array.Empty()); ScaleValidation.RequireStaticField(typeof(Character), "AllCharacters", typeof(List)); ScaleValidation.RequireInstanceProperty(typeof(Character), "Center", typeof(Vector3)); ScaleValidation.RequireInstanceField(typeof(Character), "data", typeof(CharacterData)); ScaleValidation.RequireInstanceProperty(typeof(CharacterData), "dead", typeof(bool)); ScaleValidation.RequireInheritedInstanceProperty(typeof(TumbleWeed), "transform", typeof(Transform)); ScaleValidation.RequireStaticMethod(typeof(Vector3), "Angle", typeof(float), new Type[2] { typeof(Vector3), typeof(Vector3) }, requirePublic: true); ScaleValidation.RequireStaticMethod(typeof(Vector3), "Distance", typeof(float), new Type[2] { typeof(Vector3), typeof(Vector3) }, requirePublic: true); Type fieldType = fieldInfo2.FieldType; MethodInfo method = fieldType.GetMethod("AddForce", BindingFlags.Instance | BindingFlags.Public, null, new Type[2] { typeof(Vector3), ResolveForceModeType(fieldType) }, null); if (method == null || method.IsStatic || method.ReturnType != typeof(void)) { throw new MissingMethodException(fieldType.FullName, "AddForce(Vector3, ForceMode)"); } FieldRef obj = AccessTools.FieldRefAccess(fieldInfo); Func func = ScaleEmit.CreateUnityObjectFieldGetter(fieldInfo2); FieldRef val = AccessTools.FieldRefAccess(fieldInfo3); FieldRef val2 = AccessTools.FieldRefAccess(fieldInfo4); Action action = ScaleExperimentalEmit.CreateVector3EnumAction(fieldType, method); if (obj == null || func == null || val == null || val2 == null || action == null) { throw new InvalidOperationException("TumbleWeedTargetScan accessor creation failed"); } _photonView = obj; _rig = func; _rollForce = val; _maxAngle = val2; _addForce = action; _states = new ConditionalWeakTable(); } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethodByTypeNames(typeof(TumbleWeed), "FixedUpdate", typeof(void).FullName, Array.Empty()); } internal static void Reset() { _photonView = null; _rig = null; _rollForce = null; _maxAngle = null; _addForce = null; _states = null; } internal static bool Prefix(TumbleWeed __instance) { //IL_009c: 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) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) FieldRef photonView = _photonView; Func rig = _rig; FieldRef rollForce = _rollForce; FieldRef maxAngle = _maxAngle; Action addForce = _addForce; ConditionalWeakTable states = _states; if (photonView == null || rig == null || rollForce == null || maxAngle == null || addForce == null || states == null || (Object)(object)__instance == (Object)null) { return true; } PhotonView val = photonView.Invoke(__instance); if ((Object)(object)val == (Object)null) { return true; } if (!val.IsMine) { return false; } Object val2 = rig(__instance); Transform transform = ((Component)__instance).transform; if (val2 == (Object)null || (Object)(object)transform == (Object)null) { return true; } List allCharacters = Character.AllCharacters; if (allCharacters == null) { return true; } Vector3 position = transform.position; TargetState orCreateValue = states.GetOrCreateValue(__instance); int num = Mathf.FloorToInt(Time.fixedTime / Time.fixedDeltaTime); bool flag = orCreateValue.LastScanTick == int.MinValue || num - orCreateValue.LastScanTick >= 5 || num < orCreateValue.LastScanTick; if (!flag && orCreateValue.HasTarget) { Character target = orCreateValue.Target; if ((Object)(object)target == (Object)null || (Object)(object)target.data == (Object)null || target.data.dead) { flag = true; } } if (flag) { if (!TryFindTarget(allCharacters, position, maxAngle.Invoke(__instance), out var target2)) { RateLimitedDiagnostics.Hit("TumbleWeedTargetScan.candidate-null"); return true; } orCreateValue.Target = target2; orCreateValue.HasTarget = (Object)(object)orCreateValue.Target != (Object)null; orCreateValue.LastScanTick = num; } Character target3 = orCreateValue.Target; Vector3 val3 = -Vector3.right; if ((Object)(object)target3 != (Object)null) { Vector3 val4 = target3.Center - position; val3 = ((Vector3)(ref val4)).normalized; } addForce(val2, val3 * rollForce.Invoke(__instance), 5); return false; } private static bool TryFindTarget(List all, Vector3 position, float maxAngle, out Character target) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: 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_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) float num = 90000f; Character val = null; for (int i = 0; i < all.Count; i++) { Character val2 = all[i]; if ((Object)(object)val2 == (Object)null) { target = null; return false; } Vector3 val3 = val2.Center - position; if (!(Vector3.Angle(-Vector3.right, val3) > maxAngle)) { float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; val = val2; } } } target = val; return true; } private static Type ResolveForceModeType(Type rigidbodyType) { Type type = rigidbodyType.Assembly.GetType("UnityEngine.ForceMode", throwOnError: false); if (type == null || !type.IsEnum || Enum.GetUnderlyingType(type) != typeof(int) || !Enum.IsDefined(type, "Acceleration") || Convert.ToInt32(Enum.Parse(type, "Acceleration")) != 5) { throw new InvalidOperationException("UnityEngine.ForceMode.Acceleration structure mismatch"); } return type; } } internal sealed class WeightRefreshCoalescingModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.WeightRefreshCoalescing, () => new PatchDefinition(PatchId.WeightRefreshCoalescing, WeightRefreshCoalescingPatch.Initialize, WeightRefreshCoalescingPatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(WeightRefreshCoalescingPatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, WeightRefreshCoalescingPatch.Reset)); } } internal static class WeightRefreshCoalescingPatch { private static bool _hasRun; private static int _lastRefreshFrame; private static int _lastSignature; internal static void Initialize() { ResolveAndValidateTarget(); ScaleValidation.RequireStaticMethod(typeof(PlayerHandler), "GetAllPlayerCharacters", typeof(List), Type.EmptyTypes, requirePublic: true); ScaleValidation.RequireStaticProperty(typeof(PlayerHandler), "Exists", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(Character), "refs", typeof(CharacterRefs)); ScaleValidation.RequireInstanceField(typeof(CharacterRefs), "afflictions", typeof(CharacterAfflictions)); ScaleValidation.RequireInstanceField(typeof(CharacterAfflictions), "physicalThorns", typeof(List)); ScaleValidation.RequireInstanceField(typeof(ThornOnMe), "stuckIn", typeof(bool)); ScaleValidation.RequireInstanceField(typeof(ThornOnMe), "type", typeof(int)); ScaleValidation.RequireInstanceMethod(typeof(ThornOnMe), "GetThornDamage", typeof(int), Type.EmptyTypes, requirePublic: true); ScaleValidation.RequireInstanceMethod(typeof(CharacterAfflictions), "UpdateWeight", typeof(void), Type.EmptyTypes, requirePublic: false); ScaleValidation.RequireInstanceProperty(typeof(Character), "player", typeof(Player)); ScaleValidation.RequireInstanceField(typeof(Character), "data", typeof(CharacterData)); ScaleValidation.RequireInstanceField(typeof(Player), "itemSlots", typeof(ItemSlot[])); ScaleValidation.RequireInstanceField(typeof(Player), "backpackSlot", typeof(BackpackSlot)); ScaleValidation.RequireInstanceMethod(typeof(Player), "GetItemSlot", typeof(ItemSlot), new Type[1] { typeof(byte) }, requirePublic: true); ScaleValidation.RequireInstanceProperty(typeof(ItemSlot), "prefab", typeof(Item)); ScaleValidation.RequireInstanceProperty(typeof(ItemSlot), "data", typeof(ItemInstanceData)); ScaleValidation.RequireInstanceField(typeof(BackpackSlot), "backpackType", typeof(BackpackType)); ScaleValidation.RequireInstanceMethod(typeof(BackpackSlot), "IsEmpty", typeof(bool), Type.EmptyTypes, requirePublic: true); ScaleValidation.RequireInstanceField(typeof(BackpackData), "itemSlots", typeof(ItemSlot[])); ScaleValidation.RequireInstanceField(typeof(CharacterData), "carriedPlayer", typeof(Character)); ScaleValidation.RequireInstanceField(typeof(CharacterData), "currentStickyItem", typeof(StickyItemComponent)); ScaleValidation.RequireInstanceProperty(typeof(CharacterData), "isSkeleton", typeof(bool)); ScaleValidation.RequireStaticField(typeof(StickyItemComponent), "ALL_STUCK_ITEMS", typeof(List)); ScaleValidation.RequireInstanceProperty(typeof(StickyItemComponent), "stuckToCharacter", typeof(Character)); ScaleValidation.RequireInstanceField(typeof(StickyItemComponent), "addWeightToStuckPlayer", typeof(int)); ScaleValidation.RequireInstanceField(typeof(StickyItemComponent), "addThornsToStuckPlayer", typeof(int)); if (!Enum.IsDefined(typeof(DataEntryKey), (object)(DataEntryKey)7)) { throw new InvalidOperationException("DataEntryKey.BackpackData is no longer defined"); } _hasRun = false; _lastRefreshFrame = 0; _lastSignature = 0; } internal static MethodInfo ResolveAndValidateTarget() { return ScaleValidation.RequireInstanceMethod(typeof(CharacterItems), "RefreshAllCharacterCarryWeightRPC", typeof(void), Type.EmptyTypes, requirePublic: true); } internal static void Reset() { _hasRun = false; _lastRefreshFrame = 0; _lastSignature = 0; } internal static bool Prefix() { if (!PlayerHandler.Exists) { _hasRun = false; _lastRefreshFrame = 0; _lastSignature = 0; return true; } List allPlayerCharacters = PlayerHandler.GetAllPlayerCharacters(); if (allPlayerCharacters == null) { RateLimitedDiagnostics.Hit("WeightRefreshCoalescing.roster-null"); _hasRun = false; _lastRefreshFrame = 0; _lastSignature = 0; return true; } int frameCount = Time.frameCount; if (!TryComputeSignature(allPlayerCharacters, out var signature)) { _hasRun = false; _lastRefreshFrame = 0; _lastSignature = 0; return true; } if (!_hasRun || frameCount != _lastRefreshFrame || _lastRefreshFrame > frameCount || signature != _lastSignature) { _hasRun = true; _lastRefreshFrame = frameCount; _lastSignature = signature; return true; } RateLimitedDiagnostics.Hit("WeightRefreshCoalescing.same-frame-duplicate-skipped"); return false; } private static bool TryComputeSignature(List characters, out int signature) { //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_0169: Expected I4, but got Unknown signature = 0; int num = 17; int count = characters.Count; num = num * 31 + count; num = num * 31 + BitConverter.SingleToInt32Bits(Ascents.etcDamageMultiplier); List aLL_STUCK_ITEMS = StickyItemComponent.ALL_STUCK_ITEMS; if (aLL_STUCK_ITEMS == null) { return false; } num = num * 31 + aLL_STUCK_ITEMS.Count; for (int i = 0; i < aLL_STUCK_ITEMS.Count; i++) { StickyItemComponent val = aLL_STUCK_ITEMS[i]; if ((Object)(object)val == (Object)null) { return false; } Character stuckToCharacter = val.stuckToCharacter; num = num * 31 + (((Object)(object)stuckToCharacter != (Object)null) ? ((Object)stuckToCharacter).GetInstanceID() : 0); num = num * 31 + val.addWeightToStuckPlayer; num = num * 31 + val.addThornsToStuckPlayer; } BackpackData val4 = default(BackpackData); for (int j = 0; j < count; j++) { Character val2 = characters[j]; if ((Object)(object)val2 == (Object)null) { return false; } CharacterData data = val2.data; Player player = val2.player; if ((Object)(object)data == (Object)null || (Object)(object)player == (Object)null) { return false; } num = num * 31 + ((Object)val2).GetInstanceID(); ItemSlot[] itemSlots = player.itemSlots; if (itemSlots == null) { return false; } num = num * 31 + itemSlots.Length; foreach (ItemSlot val3 in itemSlots) { if (val3 == null) { return false; } Item prefab = val3.prefab; num = num * 31 + (((Object)(object)prefab != (Object)null) ? ((Object)prefab).GetInstanceID() : 0); } BackpackSlot backpackSlot = player.backpackSlot; if (backpackSlot == null) { return false; } num = num * 31 + backpackSlot.backpackType; if (!((ItemSlot)backpackSlot).IsEmpty()) { ItemInstanceData data2 = ((ItemSlot)backpackSlot).data; if (data2 == null) { return false; } if (data2.TryGetDataEntry((DataEntryKey)7, ref val4) && val4 != null) { ItemSlot[] itemSlots2 = val4.itemSlots; if (itemSlots2 == null) { return false; } num = num * 31 + itemSlots2.Length; foreach (ItemSlot val5 in itemSlots2) { if (val5 == null) { return false; } Item prefab2 = val5.prefab; num = num * 31 + (((Object)(object)prefab2 != (Object)null) ? ((Object)prefab2).GetInstanceID() : 0); } } } ItemSlot itemSlot = player.GetItemSlot((byte)250); if (itemSlot == null) { return false; } Item prefab3 = itemSlot.prefab; num = num * 31 + (((Object)(object)prefab3 != (Object)null) ? ((Object)prefab3).GetInstanceID() : 0); Character carriedPlayer = data.carriedPlayer; num = num * 31 + (((Object)(object)carriedPlayer != (Object)null) ? ((Object)carriedPlayer).GetInstanceID() : 0); StickyItemComponent currentStickyItem = data.currentStickyItem; num = num * 31 + (((Object)(object)currentStickyItem != (Object)null) ? 1 : 0); if ((Object)(object)currentStickyItem != (Object)null) { num = num * 31 + ((Object)currentStickyItem).GetInstanceID(); num = num * 31 + currentStickyItem.addThornsToStuckPlayer; } num = num * 31 + (data.isSkeleton ? 1 : 0); CharacterAfflictions val6 = ((val2.refs != null) ? val2.refs.afflictions : null); if ((Object)(object)val6 == (Object)null || val6.physicalThorns == null) { return false; } List physicalThorns = val6.physicalThorns; num = num * 31 + physicalThorns.Count; for (int m = 0; m < physicalThorns.Count; m++) { ThornOnMe val7 = physicalThorns[m]; if ((Object)(object)val7 == (Object)null) { return false; } num = num * 31 + (val7.stuckIn ? 1 : 0); num = num * 31 + val7.type; num = num * 31 + val7.GetThornDamage(); } } signature = num; return true; } } } namespace PeakSafeOptimizer.Patches.Equivalent.MathAndScan { internal static class CampfirePatch { private static FieldRef> _charactersInRadius; internal static void Initialize() { ResolveAndValidateTarget(); FieldInfo fieldInfo = MathAndScanValidation.RequireInstanceField(typeof(Campfire), "_charactersInRadius", typeof(List)); if (fieldInfo.IsInitOnly) { throw new InvalidOperationException("Campfire._charactersInRadius is unexpectedly readonly"); } MathAndScanValidation.RequireStaticMethod(typeof(PlayerHandler), "GetAllPlayerCharacters", typeof(List), Type.EmptyTypes, requirePublic: true); MathAndScanValidation.RequireInstanceField(typeof(Character), "data", typeof(CharacterData)); MathAndScanValidation.RequireInstanceProperty(typeof(CharacterData), "dead", typeof(bool)); MathAndScanValidation.RequireInstanceProperty(typeof(Character), "Center", typeof(Vector3)); MathAndScanValidation.RequireStaticMethod(typeof(Vector3), "Distance", typeof(float), new Type[2] { typeof(Vector3), typeof(Vector3) }, requirePublic: true); _charactersInRadius = AccessTools.FieldRefAccess>(fieldInfo) ?? throw new InvalidOperationException("Campfire._charactersInRadius FieldRef creation failed"); } internal static MethodInfo ResolveAndValidateTarget() { return MathAndScanValidation.RequireInstanceMethod(typeof(Campfire), "EveryoneInRange", typeof(bool), new Type[1] { typeof(float) }, requirePublic: true); } internal static void Reset() { _charactersInRadius = null; } internal static bool Prefix(Campfire __instance, float range, ref bool __result) { //IL_003f: 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) //IL_0065: 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) FieldRef> charactersInRadius = _charactersInRadius; if (charactersInRadius == null) { RateLimitedDiagnostics.Hit("Campfire.charactersInRadius-fieldref-unavailable"); return true; } List allPlayerCharacters = PlayerHandler.GetAllPlayerCharacters(); List list = charactersInRadius.Invoke(__instance); if (list == null) { RateLimitedDiagnostics.Hit("Campfire.charactersInRadius-null-fallback-original"); return true; } list.Clear(); Vector3 position = ((Component)__instance).transform.position; bool flag = true; for (int i = 0; i < allPlayerCharacters.Count; i++) { Character val = allPlayerCharacters[i]; if (!val.data.dead) { if (!(Vector3.Distance(position, val.Center) > range)) { list.Add(val); } else { flag = false; } } } __result = flag; return false; } } internal sealed class MathAndScanPatchModule : IPatchModule { public void Register(PatchModuleContext context) { context.Register(PatchId.Campfire, () => new PatchDefinition(PatchId.Campfire, CampfirePatch.Initialize, CampfirePatch.ResolveAndValidateTarget, () => new HarmonyMethod(typeof(CampfirePatch), "Prefix", (Type[])null), null, null, null, requireCurrentMvid: true, CampfirePatch.Reset)); } } internal static class MathAndScanValidation { private const BindingFlags DeclaredInstance = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private const BindingFlags DeclaredStatic = BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; internal static FieldInfo RequireInstanceField(Type owner, string name, Type fieldType) { FieldInfo field = owner.GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { throw new MissingFieldException(owner.FullName, name); } if (field.DeclaringType != owner || field.IsStatic || field.FieldType != fieldType) { throw new InvalidOperationException("Unexpected field structure: " + owner.FullName + "." + name); } return field; } internal static FieldInfo RequireStaticField(Type owner, string name, Type fieldType) { FieldInfo field = owner.GetField(name, BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { throw new MissingFieldException(owner.FullName, name); } if (field.DeclaringType != owner || !field.IsStatic || field.FieldType != fieldType) { throw new InvalidOperationException("Unexpected static field structure: " + owner.FullName + "." + name); } return field; } internal static PropertyInfo RequireInstanceProperty(Type owner, string name, Type propertyType) { PropertyInfo property = owner.GetProperty(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); MethodInfo methodInfo = property?.GetGetMethod(nonPublic: true); if (property == null || property.DeclaringType != owner || property.PropertyType != propertyType || property.GetIndexParameters().Length != 0 || methodInfo == null || methodInfo.IsStatic) { throw new InvalidOperationException("Unexpected property structure: " + owner.FullName + "." + name); } return property; } internal static MethodInfo RequireInstanceMethod(Type owner, string name, Type returnType, Type[] parameterTypes, bool requirePublic) { MethodInfo? method = owner.GetMethod(name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, parameterTypes, null); ValidateMethod(method, owner, name, returnType, parameterTypes, requireStatic: false, requirePublic); return method; } internal static MethodInfo RequireStaticMethod(Type owner, string name, Type returnType, Type[] parameterTypes, bool requirePublic) { MethodInfo? method = owner.GetMethod(name, BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, parameterTypes, null); ValidateMethod(method, owner, name, returnType, parameterTypes, requireStatic: true, requirePublic); return method; } private static void ValidateMethod(MethodInfo method, Type owner, string name, Type returnType, Type[] parameterTypes, bool requireStatic, bool requirePublic) { if (method == null) { throw new MissingMethodException(owner.FullName, name); } if (method.DeclaringType != owner || method.IsStatic != requireStatic || method.ReturnType != returnType || method.ContainsGenericParameters || (requirePublic && !method.IsPublic)) { throw new InvalidOperationException("Unexpected method structure: " + owner.FullName + "." + name); } ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length != parameterTypes.Length) { throw new InvalidOperationException("Unexpected parameter count: " + owner.FullName + "." + name); } for (int i = 0; i < parameters.Length; i++) { if (parameters[i].ParameterType != parameterTypes[i]) { throw new InvalidOperationException($"Unexpected parameter {i}: {owner.FullName}.{name}"); } } } } } namespace PeakSafeOptimizer.Infrastructure { public sealed class BuildFingerprint { public static readonly Guid CurrentAssemblyCSharpMvid = new Guid("3f24c13b-87b6-4c9f-9c21-3c49b6ad17e1"); public Guid ActualMvid { get; } public string Sha256 { get; } public bool IsCurrent => ActualMvid == CurrentAssemblyCSharpMvid; private BuildFingerprint(Guid actualMvid, string sha256) { ActualMvid = actualMvid; Sha256 = sha256; } public static BuildFingerprint Capture() { Assembly assembly = typeof(CharacterData).Assembly; string sha = "unavailable"; try { using FileStream inputStream = File.OpenRead(assembly.Location); using SHA256 sHA = SHA256.Create(); sha = BitConverter.ToString(sHA.ComputeHash(inputStream)).Replace("-", string.Empty).ToLowerInvariant(); } catch (Exception ex) { sha = "unavailable:" + ex.GetType().Name; } return new BuildFingerprint(assembly.ManifestModule.ModuleVersionId, sha); } public string ToDiagnosticString() { return $"Assembly-CSharp fingerprint: MVID={ActualMvid}, expected={CurrentAssemblyCSharpMvid}, current={IsCurrent}, SHA256={Sha256}"; } } public sealed class LifecycleRegistry : IDisposable { private readonly List _cleanup = new List(); private readonly ManualLogSource _log; public LifecycleRegistry(ManualLogSource log) { _log = log; } public void Register(Action cleanup) { if (cleanup == null) { throw new ArgumentNullException("cleanup"); } _cleanup.Add(cleanup); } public void Dispose() { for (int num = _cleanup.Count - 1; num >= 0; num--) { try { _cleanup[num](); } catch (Exception arg) { ManualLogSource log = _log; if (log != null) { log.LogError((object)$"Lifecycle cleanup failed safely: {arg}"); } } } _cleanup.Clear(); } } public interface IPatchModule { void Register(PatchModuleContext context); } public sealed class PatchModuleContext { private readonly Dictionary> _factories = new Dictionary>(); private readonly List _cleanup = new List(); internal IReadOnlyDictionary> Factories => _factories; public void Register(PatchId id, Func factory) { if (factory == null) { throw new ArgumentNullException("factory"); } if (_factories.ContainsKey(id)) { throw new InvalidOperationException($"Module registered {id} more than once."); } _factories.Add(id, factory); } public void RegisterCleanup(Action cleanup) { if (cleanup == null) { throw new ArgumentNullException("cleanup"); } _cleanup.Add(cleanup); } internal void CommitCleanup(LifecycleRegistry lifecycle) { foreach (Action item in _cleanup) { lifecycle.Register(item); } } } public sealed class PatchRegistration { public PatchId Id { get; } public bool Enabled { get; } internal Func Factory { get; } internal PatchRegistration(PatchId id, bool enabled, Func factory) { Id = id; Enabled = enabled; Factory = factory; } } public sealed class ModuleDiscoveryFailure { public string Module { get; } public string Reason { get; } internal ModuleDiscoveryFailure(string module, string reason) { Module = module; Reason = reason; } } public sealed class PatchCatalogSnapshot { public IReadOnlyList Registrations { get; } public IReadOnlyList Failures { get; } internal PatchCatalogSnapshot(IReadOnlyList registrations, IReadOnlyList failures) { Registrations = registrations; Failures = failures; } } public static class PatchCatalog { public static PatchCatalogSnapshot Discover(Assembly assembly, OptimizerConfig config, LifecycleRegistry lifecycle, ManualLogSource log) { if (assembly == null) { throw new ArgumentNullException("assembly"); } if (config == null) { throw new ArgumentNullException("config"); } if (lifecycle == null) { throw new ArgumentNullException("lifecycle"); } Dictionary> factories = new Dictionary>(); List failures = new List(); IEnumerable source; try { source = assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { source = ex.Types.Where((Type type) => type != null); Exception[] array = ex.LoaderExceptions ?? Array.Empty(); foreach (Exception ex2 in array) { AddFailure(failures, log, "assembly type discovery", ex2); } } catch (Exception ex3) { AddFailure(failures, log, "assembly type discovery", ex3); source = Array.Empty(); } foreach (Type item in source.Where((Type type) => typeof(IPatchModule).IsAssignableFrom(type) && !type.IsAbstract && !type.IsInterface).OrderBy((Type type) => type.FullName, StringComparer.Ordinal)) { string text = item.FullName ?? item.Name; IPatchModule patchModule; try { patchModule = (IPatchModule)Activator.CreateInstance(item, nonPublic: true); } catch (Exception ex4) { AddFailure(failures, log, text + " construction", Unwrap(ex4)); continue; } PatchModuleContext patchModuleContext = new PatchModuleContext(); try { patchModule.Register(patchModuleContext); } catch (Exception ex5) { AddFailure(failures, log, text + " registration", Unwrap(ex5)); continue; } PatchId patchId = patchModuleContext.Factories.Keys.FirstOrDefault((PatchId id) => factories.ContainsKey(id)); if (patchModuleContext.Factories.Keys.Any((PatchId id) => factories.ContainsKey(id))) { AddFailure(failures, log, text + " registration", new InvalidOperationException($"PatchId {patchId} was already registered by another module.")); continue; } foreach (KeyValuePair> factory in patchModuleContext.Factories) { factories.Add(factory.Key, factory.Value); } patchModuleContext.CommitCleanup(lifecycle); } List list = new List(); foreach (PatchId value2 in Enum.GetValues(typeof(PatchId))) { factories.TryGetValue(value2, out var value); list.Add(new PatchRegistration(value2, config.IsEnabled(value2), value)); } return new PatchCatalogSnapshot(list, failures); } private static Exception Unwrap(Exception ex) { if (!(ex is TargetInvocationException { InnerException: not null } ex2)) { return ex; } return ex2.InnerException; } private static void AddFailure(List failures, ManualLogSource log, string module, Exception ex) { string text = ex.GetType().Name + ": " + ex.Message; failures.Add(new ModuleDiscoveryFailure(module, text)); if (log != null) { log.LogError((object)("Patch module failure isolated: " + module + ": " + text)); } } } internal static class PatchCompatibilityPolicy { private static readonly HashSet NetworkFacing = new HashSet { PatchId.HeatEmissionScan, PatchId.ItemScaleRedundantWrite, PatchId.RemoteItemInterpolationThreshold, PatchId.WeightRefreshCoalescing }; internal static CompatibilityLevel Escalate(PatchId id, CompatibilityLevel inferred) { if (!NetworkFacing.Contains(id) || inferred >= CompatibilityLevel.StrictIl) { return inferred; } return CompatibilityLevel.StrictIl; } } public enum CompatibilityLevel { Structural, Fingerprint, StrictIl } public sealed class PatchDefinition { public PatchId Id { get; } public Action Initialize { get; } public Func ResolveTarget { get; } public Func Prefix { get; } public Func Postfix { get; } public Func Transpiler { get; } public Func Finalizer { get; } public CompatibilityLevel Compatibility { get; } public bool RequiresCertifiedBuild { get; } public Action Reset { get; } public PatchDefinition(PatchId id, Action initialize, Func resolveTarget, Func prefix = null, Func postfix = null, Func transpiler = null, Func finalizer = null, bool requireCurrentMvid = false, Action reset = null) : this(id, initialize, resolveTarget, InferCompatibility(id, transpiler, requireCurrentMvid), prefix, postfix, transpiler, finalizer, reset, requireCurrentMvid) { } public PatchDefinition(PatchId id, Action initialize, Func resolveTarget, CompatibilityLevel compatibility, Func prefix = null, Func postfix = null, Func transpiler = null, Func finalizer = null, Action reset = null, bool requiresCertifiedBuild = false) { Id = id; Initialize = initialize ?? ((Action)delegate { }); ResolveTarget = resolveTarget ?? throw new ArgumentNullException("resolveTarget"); Prefix = prefix; Postfix = postfix; Transpiler = transpiler; Finalizer = finalizer; Compatibility = compatibility; Reset = reset; RequiresCertifiedBuild = requiresCertifiedBuild; } private static CompatibilityLevel InferCompatibility(PatchId id, Func transpiler, bool requireCurrentMvid) { CompatibilityLevel inferred = ((transpiler != null) ? CompatibilityLevel.StrictIl : (requireCurrentMvid ? CompatibilityLevel.Fingerprint : CompatibilityLevel.Structural)); return PatchCompatibilityPolicy.Escalate(id, inferred); } } public sealed class PatchInstaller { private sealed class PatchMethodRecord { internal string Kind { get; } internal MethodInfo Method { get; } internal bool Removed { get; set; } internal PatchMethodRecord(string kind, MethodInfo method) { Kind = kind; Method = method; } } private sealed class InstalledPatch { internal MethodBase Target; internal Action Reset; internal CompatibilityLevel Compatibility; internal readonly List Methods = new List(); } private const string CertifiedMode = "certified"; private const string StructuralMode = "structural-validation"; private readonly Harmony _harmony; private readonly BuildFingerprint _fingerprint; private readonly ManualLogSource _log; private Dictionary> _factories; private readonly Dictionary _installed = new Dictionary(); public string CompatibilityMode { get { BuildFingerprint fingerprint = _fingerprint; if (fingerprint == null || !fingerprint.IsCurrent) { return "structural-validation"; } return "certified"; } } public bool HasInstalledPatches => _installed.Count != 0; public PatchInstaller(Harmony harmony, BuildFingerprint fingerprint, ManualLogSource log) { _harmony = harmony; _fingerprint = fingerprint; _log = log; } public PatchStatus Install(PatchCatalogSnapshot catalog) { Dictionary> dictionary = new Dictionary>(); foreach (PatchRegistration registration in catalog.Registrations) { if (registration.Factory != null) { dictionary[registration.Id] = registration.Factory; } } _factories = dictionary; PatchStatus patchStatus = NewStatus(); foreach (ModuleDiscoveryFailure failure in catalog.Failures) { patchStatus.AddModuleFailure(failure); } foreach (PatchRegistration registration2 in catalog.Registrations) { if (registration2.Enabled) { InstallOne(registration2.Id, patchStatus); } else { patchStatus.Add(new PatchStatusEntry(registration2.Id.ToString(), enabled: false, PatchResult.SkippedDisabled, "disabled by configuration")); } } return patchStatus; } public bool IsInstalled(PatchId id) { return _installed.ContainsKey(id); } public PatchStatus Toggle(PatchId id, bool enabled) { PatchStatus patchStatus = NewStatus(); if (enabled) { InstallOne(id, patchStatus); } else { UninstallOne(id, patchStatus); } return patchStatus; } public PatchStatus UninstallAll() { PatchStatus patchStatus = NewStatus(); List list = new List(_installed.Keys); for (int i = 0; i < list.Count; i++) { UninstallOne(list[i], patchStatus); } return patchStatus; } private PatchStatus NewStatus() { return new PatchStatus { CompatibilityMode = CompatibilityMode, Fingerprint = _fingerprint }; } private void InstallOne(PatchId id, PatchStatus status) { string text = id.ToString(); if (_installed.TryGetValue(id, out var value)) { status.Add(new PatchStatusEntry(text, enabled: true, PatchResult.SkippedAlreadyInstalled, "already installed", value.Compatibility)); return; } if (_factories == null || !_factories.TryGetValue(id, out var value2) || value2 == null) { status.Add(new PatchStatusEntry(text, enabled: true, PatchResult.SkippedNoDefinition, "no definition registered")); return; } PatchDefinition patchDefinition; try { patchDefinition = value2(); } catch (Exception ex) { Fail(status, text, null, PatchResult.FailedFactory, "factory", ex); return; } if (patchDefinition == null) { Fail(status, text, null, PatchResult.FailedFactory, "factory", new InvalidOperationException("returned null")); return; } if (patchDefinition.Id != id) { Fail(status, text, patchDefinition.Compatibility, PatchResult.FailedFactory, "factory", new InvalidOperationException($"returned definition for {patchDefinition.Id}")); return; } CompatibilityLevel compatibility = patchDefinition.Compatibility; if (patchDefinition.RequiresCertifiedBuild) { BuildFingerprint fingerprint = _fingerprint; if (fingerprint == null || !fingerprint.IsCurrent) { status.Add(new PatchStatusEntry(text, enabled: true, PatchResult.SkippedUncertifiedBuild, "requires the audited Assembly-CSharp MVID until a method-level behavioral fingerprint exists", compatibility)); return; } } try { patchDefinition.Initialize(); } catch (Exception ex2) { ResetUninstalledDefinition(text, patchDefinition); PatchResult patchResult = ClassifyValidationFailure(ex2, PatchResult.FailedInitialize); if (patchResult == PatchResult.FailedInitialize) { Fail(status, text, compatibility, patchResult, "Initialize", ex2); } else { Reject(status, text, compatibility, patchResult, "Initialize", ex2); } return; } MethodBase methodBase; try { methodBase = patchDefinition.ResolveTarget() ?? throw new MissingMethodException("resolver returned null"); } catch (Exception ex3) { ResetUninstalledDefinition(text, patchDefinition); PatchResult patchResult2 = ClassifyValidationFailure(ex3, PatchResult.FailedResolve); if (patchResult2 == PatchResult.FailedResolve) { Fail(status, text, compatibility, patchResult2, "Resolve", ex3); } else { Reject(status, text, compatibility, patchResult2, "Resolve", ex3); } return; } HarmonyMethod val; HarmonyMethod val2; HarmonyMethod val3; HarmonyMethod val4; try { val = patchDefinition.Prefix?.Invoke(); val2 = patchDefinition.Postfix?.Invoke(); val3 = patchDefinition.Transpiler?.Invoke(); val4 = patchDefinition.Finalizer?.Invoke(); if (val == null && val2 == null && val3 == null && val4 == null) { throw new InvalidOperationException("definition supplied no Harmony method"); } } catch (Exception ex4) { ResetUninstalledDefinition(text, patchDefinition); Fail(status, text, compatibility, PatchResult.FailedHarmonyMethod, "HarmonyMethod", ex4); return; } try { _harmony.Patch(methodBase, val, val2, val3, val4, (HarmonyMethod)null); } catch (Exception ex5) { PatchResult patchResult3 = ((val3 != null && LooksLikeIlFailure(ex5)) ? PatchResult.SkippedIlMismatch : PatchResult.FailedPatch); if (patchResult3 == PatchResult.SkippedIlMismatch) { Reject(status, text, compatibility, patchResult3, "Patch", ex5); } else { Fail(status, text, compatibility, patchResult3, "Patch", ex5); } InstalledPatch installedPatch = CreateInstalled(methodBase, patchDefinition, val, val2, val3, val4); if (HasAttachedMethod(installedPatch)) { _installed[id] = installedPatch; ManualLogSource log = _log; if (log != null) { log.LogWarning((object)(text + " Patch threw after attaching at least one Harmony method; retained for verified cleanup.")); } } else { ResetUninstalledDefinition(text, patchDefinition); } return; } InstalledPatch value3 = CreateInstalled(methodBase, patchDefinition, val, val2, val3, val4); _installed[id] = value3; status.Add(new PatchStatusEntry(text, enabled: true, PatchResult.Applied, FormatMethod(methodBase), compatibility)); } private static void AddMethod(InstalledPatch installed, string kind, HarmonyMethod harmonyMethod) { MethodInfo methodInfo = harmonyMethod?.method; if (methodInfo != null) { installed.Methods.Add(new PatchMethodRecord(kind, methodInfo)); } } private static InstalledPatch CreateInstalled(MethodBase target, PatchDefinition definition, HarmonyMethod prefix, HarmonyMethod postfix, HarmonyMethod transpiler, HarmonyMethod finalizer) { InstalledPatch obj = new InstalledPatch { Target = target, Reset = definition.Reset, Compatibility = definition.Compatibility }; AddMethod(obj, "prefix", prefix); AddMethod(obj, "postfix", postfix); AddMethod(obj, "transpiler", transpiler); AddMethod(obj, "finalizer", finalizer); return obj; } private bool HasAttachedMethod(InstalledPatch installed) { for (int i = 0; i < installed.Methods.Count; i++) { if (IsStillAttached(installed.Target, installed.Methods[i].Method)) { return true; } } return false; } private void ResetUninstalledDefinition(string name, PatchDefinition definition) { if (definition.Reset == null) { return; } try { definition.Reset(); } catch (Exception ex) { ManualLogSource log = _log; if (log != null) { log.LogError((object)(name + " reset failed safely after an uninstalled initialization path: " + ex.GetType().Name + ": " + ex.Message)); } } } private void UninstallOne(PatchId id, PatchStatus status) { string text = id.ToString(); if (!_installed.TryGetValue(id, out var value)) { status.Add(new PatchStatusEntry(text, enabled: false, PatchResult.SkippedNotInstalled, "not installed")); return; } List list = new List(); foreach (PatchMethodRecord method in value.Methods) { if (method.Removed) { continue; } try { _harmony.Unpatch(value.Target, method.Method); method.Removed = true; } catch (Exception ex) { if (!IsStillAttached(value.Target, method.Method)) { method.Removed = true; ManualLogSource log = _log; if (log != null) { log.LogWarning((object)(text + " " + method.Kind + " Unpatch threw but the method is already detached: " + ex.GetType().Name + ": " + ex.Message)); } continue; } list.Add(method.Kind + ": " + ex.GetType().Name + ": " + ex.Message); ManualLogSource log2 = _log; if (log2 != null) { log2.LogError((object)(text + " " + method.Kind + " uninstall failed safely: " + ex.GetType().Name + ": " + ex.Message)); } } } if (list.Count > 0) { status.Add(new PatchStatusEntry(text, enabled: false, PatchResult.FailedUninstall, "uninstall incomplete, patch left installed (" + string.Join("; ", list) + ")", value.Compatibility)); return; } if (value.Reset != null) { try { value.Reset(); } catch (Exception ex2) { ManualLogSource log3 = _log; if (log3 != null) { log3.LogError((object)(text + " reset failed safely after uninstall: " + ex2.GetType().Name + ": " + ex2.Message)); } status.Add(new PatchStatusEntry(text, enabled: false, PatchResult.FailedUninstall, "Harmony methods detached but reset failed (" + ex2.GetType().Name + ": " + ex2.Message + ")", value.Compatibility)); return; } } _installed.Remove(id); status.Add(new PatchStatusEntry(text, enabled: false, PatchResult.Uninstalled, "uninstalled", value.Compatibility)); } private bool IsStillAttached(MethodBase target, MethodInfo patchMethod) { try { Patches patchInfo = Harmony.GetPatchInfo(target); if (patchInfo == null) { return false; } return Contains(patchInfo.Prefixes, patchMethod) || Contains(patchInfo.Postfixes, patchMethod) || Contains(patchInfo.Transpilers, patchMethod) || Contains(patchInfo.Finalizers, patchMethod); } catch (Exception ex) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)("Harmony patch-info query failed; assuming still attached: " + ex.GetType().Name + ": " + ex.Message)); } return true; } } private static bool Contains(IEnumerable patches, MethodInfo method) { if (patches == null) { return false; } foreach (Patch patch in patches) { if (patch != null && patch.PatchMethod == method) { return true; } } return false; } private static PatchResult ClassifyValidationFailure(Exception ex, PatchResult fallback) { if (LooksLikeIlFailure(ex)) { return PatchResult.SkippedIlMismatch; } if (ex is MissingMemberException || ex is TypeLoadException || ex is InvalidOperationException) { return PatchResult.SkippedStructureMismatch; } return fallback; } private static bool LooksLikeIlFailure(Exception ex) { for (Exception ex2 = ex; ex2 != null; ex2 = ex2.InnerException) { if (string.Equals(ex2.GetType().Name, "HarmonyException", StringComparison.Ordinal)) { return true; } string text = ex2.Message ?? string.Empty; if (text.IndexOf("IL ", StringComparison.Ordinal) >= 0 || text.IndexOf("instruction", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("pattern", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("audited", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("found 0", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } return false; } private void Reject(PatchStatus status, string name, CompatibilityLevel? level, PatchResult result, string stage, Exception ex) { string text = stage + ": " + ex.GetType().Name + ": " + ex.Message; status.Add(new PatchStatusEntry(name, enabled: true, result, text, level)); ManualLogSource log = _log; if (log != null) { log.LogWarning((object)$"{name} skipped safely ({result}) at {text}"); } } private void Fail(PatchStatus status, string name, CompatibilityLevel? level, PatchResult result, string stage, Exception ex) { string text = stage + ": " + ex.GetType().Name + ": " + ex.Message; status.Add(new PatchStatusEntry(name, enabled: true, result, text, level)); ManualLogSource log = _log; if (log != null) { log.LogError((object)(name + " patch failed safely at " + text)); } } private static string FormatMethod(MethodBase method) { return method.DeclaringType?.FullName + "." + method.Name; } } public enum PatchOutcome { Applied, Skipped, Failed } public enum PatchResult { Applied, Uninstalled, SkippedDisabled, SkippedNoDefinition, SkippedAlreadyInstalled, SkippedNotInstalled, SkippedStructureMismatch, SkippedIlMismatch, SkippedUncertifiedBuild, FailedFactory, FailedInitialize, FailedResolve, FailedHarmonyMethod, FailedPatch, FailedUninstall } public sealed class PatchStatusEntry { public string Name { get; } public bool Enabled { get; } public PatchResult Result { get; } public string Reason { get; } public CompatibilityLevel? Compatibility { get; } public PatchOutcome Outcome => Classify(Result); public PatchStatusEntry(string name, bool enabled, PatchResult result, string reason, CompatibilityLevel? compatibility = null) { Name = name; Enabled = enabled; Result = result; Reason = reason; Compatibility = compatibility; } private static PatchOutcome Classify(PatchResult result) { switch (result) { case PatchResult.Applied: case PatchResult.Uninstalled: return PatchOutcome.Applied; case PatchResult.SkippedDisabled: case PatchResult.SkippedNoDefinition: case PatchResult.SkippedAlreadyInstalled: case PatchResult.SkippedNotInstalled: case PatchResult.SkippedStructureMismatch: case PatchResult.SkippedIlMismatch: case PatchResult.SkippedUncertifiedBuild: return PatchOutcome.Skipped; default: return PatchOutcome.Failed; } } } public sealed class PatchStatus { internal const string LogPrefix = "PeakSafeOptimizer"; private readonly List _entries = new List(); private readonly List _moduleFailures = new List(); public IReadOnlyList Entries => _entries; public IReadOnlyList ModuleFailures => _moduleFailures; public string CompatibilityMode { get; internal set; } = "unknown"; public BuildFingerprint Fingerprint { get; internal set; } public int AppliedCount => _entries.Count((PatchStatusEntry x) => x.Outcome == PatchOutcome.Applied); public int SkippedCount => _entries.Count((PatchStatusEntry x) => x.Outcome == PatchOutcome.Skipped); public int FailedCount => _entries.Count((PatchStatusEntry x) => x.Outcome == PatchOutcome.Failed); internal void Add(PatchStatusEntry entry) { _entries.Add(entry); } internal void AddModuleFailure(ModuleDiscoveryFailure failure) { _moduleFailures.Add(failure); } public IReadOnlyList FormatReport() { int num = _entries.Count((PatchStatusEntry x) => x.Enabled); int appliedCount = AppliedCount; int skippedCount = SkippedCount; int failedCount = FailedCount; List list = new List { Line("report begin (per-patch compatibility gating)"), Line((Fingerprint != null) ? ($"build: MVID={Fingerprint.ActualMvid} expected={BuildFingerprint.CurrentAssemblyCSharpMvid} " + $"certified={Fingerprint.IsCurrent} SHA256={Fingerprint.Sha256}") : "build: fingerprint unavailable"), Line("compatibility mode: " + CompatibilityMode), Line(string.Equals(CompatibilityMode, "certified", StringComparison.Ordinal) ? "mode meaning: MVID matches the audited build; patch validation still runs and is still authoritative." : "mode meaning: MVID is unknown (game update or different build). Structural guards still validate independently; behavior-replacement patches requiring the audited build skip safely.") }; list.Add(Line($"totals: registered={_entries.Count}, enabled={num}, applied={appliedCount}, " + $"skipped={skippedCount}, failed={failedCount}, module-failures={_moduleFailures.Count}")); foreach (PatchStatusEntry item in _entries.Where((PatchStatusEntry x) => x.Outcome == PatchOutcome.Applied)) { list.Add(Line("applied : " + item.Name + " [" + Describe(item.Compatibility) + "] " + item.Reason)); } foreach (PatchStatusEntry item2 in _entries.Where((PatchStatusEntry x) => x.Outcome == PatchOutcome.Skipped)) { list.Add(Line($"skipped : {item2.Name} [{Describe(item2.Compatibility)}] {item2.Result}: {item2.Reason}")); } foreach (PatchStatusEntry item3 in _entries.Where((PatchStatusEntry x) => x.Outcome == PatchOutcome.Failed)) { list.Add(Line($"failed : {item3.Name} [{Describe(item3.Compatibility)}] {item3.Result}: {item3.Reason}")); } foreach (ModuleDiscoveryFailure moduleFailure in _moduleFailures) { list.Add(Line("module : " + moduleFailure.Module + " Failed: " + moduleFailure.Reason)); } list.Add(Line("guarantee: no patch was installed without passing its own compatibility check (Initialize structural/IL validation + target resolution + Harmony patch). " + $"{skippedCount} skipped, {failedCount} failed, {appliedCount} live.")); list.Add(Line("report end")); return list; } public string FormatSummary() { int num = _entries.Count((PatchStatusEntry x) => x.Enabled); string text = string.Join("; ", _entries.Select((PatchStatusEntry x) => $"{x.Name}={x.Result} ({x.Reason})")); string arg = string.Join("; ", _moduleFailures.Select((ModuleDiscoveryFailure x) => x.Module + "=Failed (" + x.Reason + ")")); string text2 = ((_moduleFailures.Count == 0) ? "" : $" Module failures={_moduleFailures.Count}: {arg}."); return $"Patch status ({CompatibilityMode}): enabled={num}, applied={AppliedCount}, " + $"skipped={SkippedCount}, failed={FailedCount}. {text}.{text2}"; } private static string Line(string body) { return "PeakSafeOptimizer | " + body; } private static string Describe(CompatibilityLevel? level) { if (!level.HasValue) { return "n/a"; } return level.Value.ToString(); } } } namespace PeakSafeOptimizer.Graphics { internal sealed class BoneWeightCap { private const SkinWeights Cap = (SkinWeights)2; private const float ReassertInterval = 2f; private const float StartupGrace = 5f; private readonly ManualLogSource _log; private bool _applied; private float _sinceReassert; private float _sinceStartup; private bool _hasSnapshot; private SkinWeights _snapshot; private bool _wrote; private SkinWeights _wroteValue; internal BoneWeightCap(ManualLogSource log) { _log = log; } internal void Update(float deltaTime) { if (_sinceStartup < 5f) { _sinceStartup += deltaTime; if (_sinceStartup < 5f) { return; } } ConfigEntry graphicsCapBoneWeights = OptimizerConfig.GraphicsCapBoneWeights; if (graphicsCapBoneWeights == null || !graphicsCapBoneWeights.Value) { if (_applied) { Restore("configuration"); } return; } _sinceReassert += deltaTime; if (!_applied || !(_sinceReassert < 2f)) { _sinceReassert = 0f; Apply(); } } internal void Shutdown() { if (_applied) { Restore("shutdown"); } } private void Apply() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Invalid comparison between Unknown and I4 //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) try { if (!_hasSnapshot) { _snapshot = QualitySettings.skinWeights; _hasSnapshot = true; ManualLogSource log = _log; if (log != null) { log.LogInfo((object)$"PeakSafeOptimizer | bone weight cap: launch value was {_snapshot}."); } } if ((int)QualitySettings.skinWeights > 2) { QualitySettings.skinWeights = (SkinWeights)2; _wroteValue = (SkinWeights)2; _wrote = true; } _applied = true; } catch (Exception ex) { ManualLogSource log2 = _log; if (log2 != null) { log2.LogError((object)("Bone weight cap apply failed safely: " + ex.GetType().Name + ": " + ex.Message)); } } } private void Restore(string reason) { //IL_0019: 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_004a: 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) _applied = false; if (!_hasSnapshot) { return; } try { if (_wrote && QualitySettings.skinWeights == _wroteValue) { QualitySettings.skinWeights = _snapshot; } _wrote = false; ManualLogSource log = _log; if (log != null) { log.LogInfo((object)$"PeakSafeOptimizer | bone weight cap restored {_snapshot} ({reason})."); } } catch (Exception ex) { ManualLogSource log2 = _log; if (log2 != null) { log2.LogError((object)("Bone weight cap restore failed safely: " + ex.GetType().Name + ": " + ex.Message)); } } } } } namespace PeakSafeOptimizer.Diagnostics { public static class RateLimitedDiagnostics { private sealed class ReasonState { internal long Count; internal long LastLogTicks; internal long LastLoggedCount; } private static readonly ConcurrentDictionary States = new ConcurrentDictionary(StringComparer.Ordinal); private static ManualLogSource _log; private static ConfigEntry _detailed; public static void Initialize(ManualLogSource log, ConfigEntry detailed) { _log = log; _detailed = detailed; } public static void Hit(string reason) { if (string.IsNullOrEmpty(reason)) { reason = "unspecified"; } ReasonState orAdd = States.GetOrAdd(reason, (string _) => new ReasonState()); long num = Interlocked.Increment(ref orAdd.Count); if (num == 1) { long ticks = DateTime.UtcNow.Ticks; Interlocked.Exchange(ref orAdd.LastLogTicks, ticks); Interlocked.Exchange(ref orAdd.LastLoggedCount, 1L); ManualLogSource log = _log; if (log != null) { log.LogInfo((object)("Repair reason '" + reason + "' first hit")); } return; } ConfigEntry detailed = _detailed; if (detailed == null || !detailed.Value) { return; } long ticks2 = DateTime.UtcNow.Ticks; long num2 = Interlocked.Read(in orAdd.LastLogTicks); if (ticks2 - num2 >= 300000000 && Interlocked.CompareExchange(ref orAdd.LastLogTicks, ticks2, num2) == num2) { long num3 = Interlocked.Exchange(ref orAdd.LastLoggedCount, num); ManualLogSource log2 = _log; if (log2 != null) { log2.LogInfo((object)$"Repair reason '{reason}' aggregate: {num - num3} new, {num} total (30s minimum interval)"); } } } public static void Reset() { States.Clear(); _log = null; _detailed = null; } } } namespace PeakSafeOptimizer.Config { public enum PatchId { RunBasedValues, Parachute, RopeSegmentGuard, IKItemGuard, EmoteWheelGuard, Campfire, HeatEmissionScan, RagdollPhysicsMats, ItemCollisionMode, GenericOptimizerRange, CampfireProtectionMerge, ZombieScanRange, ZombieSpawnScanRange, WeightRefreshCoalescing, SleepingZombieScan, ItemScaleRedundantWrite, RemoteItemInterpolationThreshold, EyeLookComponentCache, ExplosionScale, ItemDatabaseNameLookup, IsLookedAtScan, ItemAudioManagerHash, BarAfflictionLayout, AnimatedMouthMaterial, RemoteRagdollLodPhysics, RemoteRagdollLodAnimate, RemoteRagdollLodMovementForce, RemoteRagdollLodAnimator, DetailBodypartThrottle, CollisionCharacterLookup, AnimatorValuesHash, PlayerNameUiWrites, PocketBehaviorGuard, BodypartDragIdentity, LightVolumeSampleCache, TumbleWeedTargetScan, RemoteClusterAnimationThrottle, SnowballContactSnapshot, SnowballContactConsume, CollisionContactsNoAlloc, BodypartMovementForceIdentity } public sealed class OptimizerConfig { private readonly Dictionary> _patches; private readonly Dictionary, List> _byEntry; internal static ConfigEntry GraphicsCapBoneWeights; internal static ConfigEntry CollisionCallbackReuse; public ConfigEntry DetailedDiagnostics { get; } private OptimizerConfig(Dictionary> patches, ConfigEntry detailedDiagnostics) { _patches = patches; DetailedDiagnostics = detailedDiagnostics; _byEntry = new Dictionary, List>(); foreach (KeyValuePair> patch in patches) { if (!_byEntry.TryGetValue(patch.Value, out var value)) { value = new List(1); _byEntry.Add(patch.Value, value); } value.Add(patch.Key); } } public bool IsEnabled(PatchId id) { if (_patches.TryGetValue(id, out var value)) { return value.Value; } return false; } public bool TryGetPatchIds(ConfigEntryBase changedSetting, out IReadOnlyList ids) { foreach (KeyValuePair, List> item in _byEntry) { if ((object)item.Key == changedSetting) { ids = item.Value; return true; } } ids = null; return false; } public static OptimizerConfig Bind(ConfigFile config) { Dictionary> patches = new Dictionary> { [PatchId.RunBasedValues] = BindPatch(config, PatchId.RunBasedValues, defaultValue: true), [PatchId.Parachute] = BindPatch(config, PatchId.Parachute, defaultValue: true), [PatchId.RopeSegmentGuard] = BindPatch(config, PatchId.RopeSegmentGuard, defaultValue: true), [PatchId.IKItemGuard] = BindPatch(config, PatchId.IKItemGuard, defaultValue: true), [PatchId.EmoteWheelGuard] = BindPatch(config, PatchId.EmoteWheelGuard, defaultValue: true), [PatchId.Campfire] = BindPatch(config, PatchId.Campfire, defaultValue: true), [PatchId.HeatEmissionScan] = BindPatch(config, PatchId.HeatEmissionScan, defaultValue: true), [PatchId.RagdollPhysicsMats] = BindPatch(config, PatchId.RagdollPhysicsMats, defaultValue: true), [PatchId.ItemCollisionMode] = BindPatch(config, PatchId.ItemCollisionMode, defaultValue: true), [PatchId.GenericOptimizerRange] = BindPatch(config, PatchId.GenericOptimizerRange, defaultValue: true), [PatchId.CampfireProtectionMerge] = BindPatch(config, PatchId.CampfireProtectionMerge, defaultValue: true), [PatchId.ZombieScanRange] = BindExperimental(config, PatchId.ZombieScanRange, defaultValue: true), [PatchId.ZombieSpawnScanRange] = BindExperimental(config, PatchId.ZombieSpawnScanRange, defaultValue: true), [PatchId.WeightRefreshCoalescing] = BindExperimental(config, PatchId.WeightRefreshCoalescing, defaultValue: true), [PatchId.SleepingZombieScan] = BindExperimental(config, PatchId.SleepingZombieScan, defaultValue: true), [PatchId.ItemScaleRedundantWrite] = BindExperimental(config, PatchId.ItemScaleRedundantWrite, defaultValue: true), [PatchId.RemoteItemInterpolationThreshold] = BindExperimental(config, PatchId.RemoteItemInterpolationThreshold, defaultValue: true), [PatchId.EyeLookComponentCache] = BindExperimental(config, PatchId.EyeLookComponentCache, defaultValue: true), [PatchId.ExplosionScale] = BindExperimental(config, PatchId.ExplosionScale, defaultValue: true), [PatchId.ItemDatabaseNameLookup] = BindPatch(config, PatchId.ItemDatabaseNameLookup, defaultValue: true), [PatchId.IsLookedAtScan] = BindPatch(config, PatchId.IsLookedAtScan, defaultValue: true), [PatchId.ItemAudioManagerHash] = BindPatch(config, PatchId.ItemAudioManagerHash, defaultValue: true), [PatchId.BarAfflictionLayout] = BindPatch(config, PatchId.BarAfflictionLayout, defaultValue: true), [PatchId.AnimatedMouthMaterial] = BindPatch(config, PatchId.AnimatedMouthMaterial, defaultValue: true), [PatchId.DetailBodypartThrottle] = BindExperimental(config, PatchId.DetailBodypartThrottle, defaultValue: false), [PatchId.CollisionCharacterLookup] = BindPatch(config, PatchId.CollisionCharacterLookup, defaultValue: true), [PatchId.AnimatorValuesHash] = BindPatch(config, PatchId.AnimatorValuesHash, defaultValue: true), [PatchId.PlayerNameUiWrites] = BindPatch(config, PatchId.PlayerNameUiWrites, defaultValue: true), [PatchId.PocketBehaviorGuard] = BindPatch(config, PatchId.PocketBehaviorGuard, defaultValue: true), [PatchId.BodypartDragIdentity] = BindPatch(config, PatchId.BodypartDragIdentity, defaultValue: true), [PatchId.LightVolumeSampleCache] = BindPatch(config, PatchId.LightVolumeSampleCache, defaultValue: true), [PatchId.TumbleWeedTargetScan] = BindExperimental(config, PatchId.TumbleWeedTargetScan, defaultValue: true), [PatchId.RemoteClusterAnimationThrottle] = BindExperimental(config, PatchId.RemoteClusterAnimationThrottle, defaultValue: false), [PatchId.CollisionContactsNoAlloc] = BindPatch(config, PatchId.CollisionContactsNoAlloc, defaultValue: true), [PatchId.BodypartMovementForceIdentity] = BindPatch(config, PatchId.BodypartMovementForceIdentity, defaultValue: true) }; BindGroup(config, patches, "Experimental", "RemoteRagdollLod", false, "Distance tier for remote characters: beyond RemoteRagdollLodEnterDistance a remote, fully controlled, non-interacting player stops evaluating its animation graph, joint animation, movement force and Animator parameters, and becomes a passive ragdoll carried by physics and the network. Gravity, drag and force flushing keep running. Off by default: a distant character visibly freezes its pose. One switch for all four patches, which are only coherent together.", PatchId.RemoteRagdollLodPhysics, PatchId.RemoteRagdollLodAnimate, PatchId.RemoteRagdollLodMovementForce, PatchId.RemoteRagdollLodAnimator); BindGroup(config, patches, "Fixes", "SnowballContactGuard", true, "Makes Snowball keep a value copy of its collision instead of the engine's Collision instance (Snowball.cs:105 is the only cross-frame Collision reference in the game). Equivalent on its own, and the prerequisite for Experimental.CollisionCallbackReuse. One switch for the writing and the reading half, which are useless apart.", PatchId.SnowballContactSnapshot, PatchId.SnowballContactConsume); CollisionCallbackReuse = config.Bind("Experimental", "CollisionCallbackReuse", false, "Set Physics.reuseCollisionCallbacks so the engine stops allocating a Collision object plus a ContactPoint[] for every reported collision. Only applied when both Snowball guards installed successfully, because Snowball is the only place in the game that keeps a Collision reference across frames. Off by default because it is a process-wide engine flag: the game side is audited and guarded, but any other mod that keeps a Collision past its callback would start reading a reused instance."); GraphicsCapBoneWeights = config.Bind("Graphics", "CapBoneWeights", false, "Limit QualitySettings.skinWeights to two bones per vertex. Bones per vertex is a per-vertex cost of every skinned character, so it scales with how many players are on screen, and the game exposes no setting for it. Only ever lowered, never raised, and the launch value is restored when this is turned off. Off by default: joint deformation (shoulders, hips) becomes a little coarser."); ConfigEntry detailedDiagnostics = config.Bind("Diagnostics", "DetailedLogging", true, "Emit per-reason aggregate repair diagnostics no more frequently than every 30 seconds."); return new OptimizerConfig(patches, detailedDiagnostics); } private static ConfigEntry BindPatch(ConfigFile config, PatchId id, bool defaultValue) { return config.Bind("Fixes", id.ToString(), defaultValue, $"Enable the independent {id} optimization/fix lane."); } private static ConfigEntry BindExperimental(ConfigFile config, PatchId id, bool defaultValue) { return config.Bind("Experimental", id.ToString(), defaultValue, $"Enable the independent experimental {id} lane."); } private static void BindGroup(ConfigFile config, Dictionary> patches, string section, string key, bool defaultValue, string description, params PatchId[] members) { ConfigEntry value = config.Bind(section, key, defaultValue, description); for (int i = 0; i < members.Length; i++) { patches.Add(members[i], value); } } } }