using System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BoneLib; using BoneLib.BoneMenu; using HarmonyLib; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSLZ.Bonelab; using Il2CppSLZ.Marrow; using Il2CppSLZ.Marrow.Interaction; using MelonLoader; using MelonLoader.Preferences; using UnityEngine; using WallGrabJump; using WallGrabJump.Compatibility; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(WallGrabJumpMod), "WallGrabJump", "1.0.2", "Cesar", null)] [assembly: MelonGame("Stress Level Zero", "BONELAB")] [assembly: MelonAdditionalDependencies(new string[] { "BoneLib" })] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("WallGrabJump")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.2.0")] [assembly: AssemblyInformationalVersion("1.0.2")] [assembly: AssemblyProduct("WallGrabJump")] [assembly: AssemblyTitle("WallGrabJump")] [assembly: AssemblyVersion("1.0.2.0")] namespace WallGrabJump { internal enum ClimbSource { None, Vanilla, ClimbAnything } internal struct ClimbHold { internal ClimbSource Source; internal Handedness Side; internal Hand Hand; internal Grip Grip; internal object State; internal Vector3 Anchor; internal Collider Surface; internal bool Valid => Source != ClimbSource.None; } internal static class ClimbDetector { internal static int Snapshot(out ClimbHold left, out ClimbHold right) { left = Evaluate(Player.LeftHand, (Handedness)1); right = Evaluate(Player.RightHand, (Handedness)2); return (left.Valid ? 1 : 0) + (right.Valid ? 1 : 0); } private static ClimbHold Evaluate(Hand hand, Handedness side) { //IL_000a: 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_00be: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) ClimbHold result = new ClimbHold { Side = side, Hand = hand }; if ((Object)(object)hand == (Object)null || !PlayerState.IsLocalHand(hand)) { return default(ClimbHold); } try { HandReciever attachedReceiver = hand.AttachedReceiver; Grip val = (((Object)(object)attachedReceiver != (Object)null) ? ((Il2CppObjectBase)attachedReceiver).TryCast() : null); if ((Object)(object)val != (Object)null && IsClimbingGrip(val)) { result.Source = ClimbSource.Vanilla; result.Grip = val; result.Anchor = ((Component)hand).transform.position; result.Surface = SurfaceOf(val); return result; } } catch (Exception ex) { Log.Debug("Vanilla climb check failed (" + ex.GetType().Name + ")"); } ClimbHold result2 = ClimbAnythingCompatibility.Evaluate(hand, side); if (!result2.Valid) { return default(ClimbHold); } return result2; } internal static bool IsClimbingGrip(Grip grip) { try { if ((Object)(object)grip == (Object)null) { return false; } if ((Object)(object)((Il2CppObjectBase)grip).TryCast() != (Object)null) { return false; } if ((Object)(object)((Il2CppObjectBase)grip).TryCast() != (Object)null) { return true; } if (!((HandReciever)grip).HasHost) { return false; } return ((HandReciever)grip).IsStatic; } catch { return false; } } private static Collider SurfaceOf(Grip grip) { try { if ((Object)(object)((Il2CppObjectBase)grip).TryCast() != (Object)null) { return null; } return ((Component)grip).GetComponentInParent(); } catch { return null; } } } internal sealed class InputController { private enum Phase { Unknown, Released, Held } private Phase _phase; private int _sampledFrame = -1; private bool _pressedThisFrame; internal void Reset() { _phase = Phase.Unknown; _sampledFrame = -1; _pressedThisFrame = false; } internal bool PressedThisFrame() { int frameCount = Time.frameCount; if (_sampledFrame == frameCount) { return _pressedThisFrame; } _sampledFrame = frameCount; _pressedThisFrame = false; bool readable; bool flag = ReadA(out readable); if (!readable) { _phase = Phase.Unknown; return false; } if (!flag) { _phase = Phase.Released; return false; } _pressedThisFrame = _phase == Phase.Released; _phase = Phase.Held; return _pressedThisFrame; } private static bool ReadA(out bool readable) { readable = false; try { if (!Player.ControllersExist) { return false; } BaseController rightController = Player.RightController; if ((Object)(object)rightController == (Object)null) { return false; } readable = true; return rightController.GetAButton(); } catch { readable = false; return false; } } } internal static class PlayerState { private static PhysicsRig _bodiesOwner; private static Rigidbody[] _bodies; internal static bool IsValid { get { if (HelperMethods.IsLoading()) { return false; } if ((Object)(object)Player.RigManager != (Object)null) { return (Object)(object)Player.PhysicsRig != (Object)null; } return false; } } internal static Transform Head => Player.Head; internal static Rigidbody Pelvis { get { PhysicsRig physicsRig = Player.PhysicsRig; PhysTorso val = (((Object)(object)physicsRig != (Object)null) ? physicsRig.torso : null); if (!((Object)(object)val != (Object)null)) { return null; } return val.rbPelvis; } } internal static Rigidbody Chest { get { PhysicsRig physicsRig = Player.PhysicsRig; PhysTorso val = (((Object)(object)physicsRig != (Object)null) ? physicsRig.torso : null); if (!((Object)(object)val != (Object)null)) { return null; } return val.rbChest; } } internal static Vector3 BodyCentre { get { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) Rigidbody chest = Chest; if ((Object)(object)chest != (Object)null) { return chest.position; } Rigidbody pelvis = Pelvis; if ((Object)(object)pelvis != (Object)null) { return pelvis.position; } Transform head = Head; if (!((Object)(object)head != (Object)null)) { return Vector3.zero; } return head.position; } } internal static Vector3 Velocity { get { //IL_0016: 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) Rigidbody pelvis = Pelvis; if (!((Object)(object)pelvis != (Object)null)) { return Vector3.zero; } return pelvis.velocity; } } internal static bool IsLocalHand(Hand hand) { if ((Object)(object)hand == (Object)null) { return false; } RigManager rigManager = Player.RigManager; if ((Object)(object)rigManager != (Object)null) { return (Object)(object)hand.manager == (Object)(object)rigManager; } return false; } internal static bool TryGetMarrowClimbNormal(out Vector3 normal) { //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_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Invalid comparison between Unknown and I4 //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Invalid comparison between Unknown and I4 //IL_004b: 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_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Invalid comparison between Unknown and I4 normal = Vector3.zero; PhysicsRig physicsRig = Player.PhysicsRig; if ((Object)(object)physicsRig == (Object)null) { return false; } StepState stepState = physicsRig._stepState; if ((int)stepState != 4 && (int)stepState != 3 && (int)stepState != 5) { return false; } Vector3 climbingNormal = physicsRig.climbingNormal; if (((Vector3)(ref climbingNormal)).sqrMagnitude < 0.25f) { return false; } normal = ((Vector3)(ref climbingNormal)).normalized; return true; } internal static Rigidbody[] RigBodies() { PhysicsRig physicsRig = Player.PhysicsRig; if ((Object)(object)physicsRig == (Object)null) { _bodiesOwner = null; _bodies = null; return null; } if (_bodies != null && (Object)(object)_bodiesOwner == (Object)(object)physicsRig) { return _bodies; } try { Il2CppArrayBase componentsInChildren = ((Component)physicsRig).GetComponentsInChildren(true); if (componentsInChildren == null) { return null; } int num = 0; for (int i = 0; i < componentsInChildren.Length; i++) { if ((Object)(object)componentsInChildren[i] != (Object)null) { num++; } } Rigidbody[] array = (Rigidbody[])(object)new Rigidbody[num]; int num2 = 0; for (int j = 0; j < componentsInChildren.Length; j++) { if (num2 >= num) { break; } Rigidbody val = componentsInChildren[j]; if ((Object)(object)val != (Object)null) { array[num2++] = val; } } _bodies = array; _bodiesOwner = physicsRig; return _bodies; } catch (Exception ex) { Log.Debug("Could not gather rig rigidbodies (" + ex.GetType().Name + ")"); return null; } } internal static void DropCaches() { _bodies = null; _bodiesOwner = null; } } internal static class Prefs { internal static MelonPreferences_Category Category; internal static MelonPreferences_Entry Enabled; internal static MelonPreferences_Entry JumpStrength; internal static MelonPreferences_Entry LookInfluence; internal static MelonPreferences_Entry OutwardPush; internal static MelonPreferences_Entry UpwardBoost; internal static MelonPreferences_Entry OutwardFloor; internal static MelonPreferences_Entry AimStrictness; internal static MelonPreferences_Entry StaminaCost; internal static MelonPreferences_Entry DebugLogging; internal const float DefaultJumpStrength = 1.8f; internal const float DefaultLookInfluence = 2f; internal const float DefaultOutwardPush = 0.9f; internal const float DefaultUpwardBoost = 1.65f; internal const float DefaultOutwardFloor = 0.35f; internal const float DefaultAimStrictness = 180f; internal const float DefaultStaminaCost = 10f; internal static bool EnabledValue { get { if (Enabled != null) { return Enabled.Value; } return true; } } internal static float JumpStrengthValue => Sane(JumpStrength, 1.8f); internal static float LookInfluenceValue => Sane(LookInfluence, 2f); internal static float OutwardPushValue => Sane(OutwardPush, 0.9f); internal static float UpwardBoostValue => Sane(UpwardBoost, 1.65f); internal static float OutwardFloorValue => Sane(OutwardFloor, 0.35f); internal static float AimStrictnessValue => Sane(AimStrictness, 180f); internal static float StaminaCostValue => Sane(StaminaCost, 10f); internal static bool DebugLoggingValue { get { if (DebugLogging != null) { return DebugLogging.Value; } return false; } } private static float Sane(MelonPreferences_Entry entry, float fallback) { if (entry == null) { return fallback; } float value = entry.Value; if (!float.IsNaN(value) && !float.IsInfinity(value)) { return value; } return fallback; } internal static void Setup() { Category = MelonPreferences.CreateCategory("WallGrabJump", "Wall Grab Jump"); Enabled = Category.CreateEntry("Enabled", true, "Enabled", "Master switch for the wall jump.", false, false, (ValueValidator)null, (string)null); JumpStrength = Category.CreateEntry("JumpStrength", 1.8f, "Jump Strength", "Multiplier on the push. 1.0 is a controlled shove off the wall.", false, false, (ValueValidator)null, (string)null); LookInfluence = Category.CreateEntry("LookInfluence", 2f, "Look Influence", "How strongly your head direction steers the jump.", false, false, (ValueValidator)null, (string)null); OutwardPush = Category.CreateEntry("OutwardPush", 0.9f, "Outward Push", "How hard the jump shoves away from the wall face. Lower this if jumps feel like being kicked off the wall.", false, false, (ValueValidator)null, (string)null); UpwardBoost = Category.CreateEntry("UpwardBoost", 1.65f, "Upward Boost", "How much lift is mixed into every jump.", false, false, (ValueValidator)null, (string)null); OutwardFloor = Category.CreateEntry("OutwardFloor", 0.35f, "Outward Floor", "Guaranteed separation from the wall, whatever you are looking at. 0 removes the floor entirely.", false, false, (ValueValidator)null, (string)null); AimStrictness = Category.CreateEntry("AimStrictness", 180f, "Aim Strictness", "Max degrees your look may differ from straight off the wall before the jump is refused. 180 = never refuse.", false, false, (ValueValidator)null, (string)null); StaminaCost = Category.CreateEntry("StaminaCost", 10f, "Stamina Cost %", "Percent of max climbing stamina a wall jump costs. Only used when ClimbStamina is installed.", false, false, (ValueValidator)null, (string)null); DebugLogging = Category.CreateEntry("DebugLogging", false, "Debug Logging", "Verbose per-jump logging for troubleshooting.", false, false, (ValueValidator)null, (string)null); } } internal static class RegrabGuard { private static float _blockUntil = float.NegativeInfinity; private static bool _installed; internal static void Suppress(float seconds) { float num = Time.time + seconds; if (num > _blockUntil) { _blockUntil = num; } } internal static void Clear() { _blockUntil = float.NegativeInfinity; } internal static void ApplyPatches(Harmony harmony) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got Unknown if (!_installed) { MethodInfo method = typeof(Grip).GetMethod("OnGrabConfirm", AccessTools.all); MethodInfo method2 = typeof(RegrabGuard).GetMethod("OnGrabConfirmPrefix", AccessTools.all); if (method == null || method2 == null) { Log.Warning("Grip.OnGrabConfirm not found; the brief anti-regrab window after a vanilla wall jump is off."); return; } harmony.Patch((MethodBase)method, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _installed = true; } } private static bool OnGrabConfirmPrefix(Grip __instance, Hand hand) { try { if (Time.time >= _blockUntil) { return true; } if ((Object)(object)hand == (Object)null || !PlayerState.IsLocalHand(hand)) { return true; } if ((Object)(object)__instance == (Object)null || !ClimbDetector.IsClimbingGrip(__instance)) { return true; } return false; } catch { return true; } } } public class WallGrabJumpMod : MelonMod { private static Instance _logger; private WallJumpController _controller; private bool _wasEnabled = true; private Action _onLevelLoaded; private Action _onLevelUnloaded; private Action _onPlayerDeath; public override void OnInitializeMelon() { _logger = ((MelonBase)this).LoggerInstance; try { Prefs.Setup(); } catch (Exception ex) { Log.Warning("Could not create preferences (" + ex.GetType().Name + "); running on defaults."); } _controller = new WallJumpController(); RegrabGuard.ApplyPatches(((MelonBase)this).HarmonyInstance); ClimbAnythingCompatibility.Initialize(((MelonBase)this).HarmonyInstance); ClimbStaminaCompatibility.Initialize(); _onLevelLoaded = delegate { ResetAll(); }; _onLevelUnloaded = ResetAll; _onPlayerDeath = delegate(RigManager rig) { RigManager rigManager = Player.RigManager; if ((Object)(object)rig != (Object)null && (Object)(object)rigManager != (Object)null && (Object)(object)rig == (Object)(object)rigManager) { ResetAll(); } }; Hooking.OnLevelLoaded += _onLevelLoaded; Hooking.OnLevelUnloaded += _onLevelUnloaded; Hooking.OnPlayerDeath += _onPlayerDeath; SetupMenu(); Log.Msg("Initialized."); } public override void OnLateInitializeMelon() { ClimbAnythingCompatibility.Retry(((MelonBase)this).HarmonyInstance); ClimbStaminaCompatibility.Retry(); } public override void OnDeinitializeMelon() { Hooking.OnLevelLoaded -= _onLevelLoaded; Hooking.OnLevelUnloaded -= _onLevelUnloaded; Hooking.OnPlayerDeath -= _onPlayerDeath; } public override void OnUpdate() { if (_controller == null) { return; } bool enabledValue = Prefs.EnabledValue; if (enabledValue != _wasEnabled) { _wasEnabled = enabledValue; if (!enabledValue) { ResetAll(); } } if (enabledValue) { _controller.Tick(); } } public override void OnFixedUpdate() { if (_controller != null && _wasEnabled) { _controller.FixedTick(Time.fixedDeltaTime); } } private void ResetAll() { _controller?.Reset(); ClimbAnythingCompatibility.ClearSuppression(); RegrabGuard.Clear(); PlayerState.DropCaches(); } private static void SetupMenu() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) try { if (Prefs.Category == null) { Log.Warning("Preferences are unavailable, so there is no menu to build; the mod runs on defaults."); return; } Page obj = Page.Root.CreatePage("Wall Grab Jump", Color.cyan, 0, true); obj.CreateBool("Enabled", Color.cyan, Prefs.EnabledValue, (Action)delegate(bool value) { if (Prefs.Enabled != null) { Prefs.Enabled.Value = value; } }); obj.CreateFloat("Jump Strength", Color.cyan, Prefs.JumpStrengthValue, 0.1f, 0.5f, 3f, (Action)delegate(float value) { if (Prefs.JumpStrength != null) { Prefs.JumpStrength.Value = value; } }); obj.CreateFloat("Upward Boost", Color.cyan, Prefs.UpwardBoostValue, 0.05f, 0f, 3f, (Action)delegate(float value) { if (Prefs.UpwardBoost != null) { Prefs.UpwardBoost.Value = value; } }); obj.CreateFloat("Stamina Cost %", Color.cyan, Prefs.StaminaCostValue, 5f, 0f, 50f, (Action)delegate(float value) { if (Prefs.StaminaCost != null) { Prefs.StaminaCost.Value = value; } }); } catch (Exception ex) { Log.Warning("Could not build the BoneMenu page (" + ex.GetType().Name + "); preferences still work from the config file."); } } internal static void LogMsg(string message) { Instance logger = _logger; if (logger != null) { logger.Msg(message); } } internal static void LogWarn(string message) { Instance logger = _logger; if (logger != null) { logger.Warning(message); } } } internal static class Log { internal static void Msg(string message) { WallGrabJumpMod.LogMsg(message); } internal static void Warning(string message) { WallGrabJumpMod.LogWarn(message); } internal static void Debug(string message) { if (Prefs.DebugLoggingValue) { WallGrabJumpMod.LogMsg("[debug] " + message); } } } internal sealed class WallJumpController { private const float BaseJumpSpeed = 3.5f; private const float AbsoluteMaxDeltaV = 16f; private const float OutwardInfluence = 0.9f; private const float UpInfluence = 0.55f; private const float MinOutwardDot = 0.35f; private const float MinVerticalComponent = -0.3f; private const float MinOutwardVertical = -0.25f; private const float MinOutwardHorizontal = 0.2f; private const float MaxIntoWallCancel = 1.5f; private const float PushDuration = 0.09f; private const float CooldownSeconds = 0.25f; private const float RegrabBlanketSeconds = 0.3f; private const float SuccessAmplitude = 0.55f; private const float SuccessSeconds = 0.09f; private const float SuccessFrequency = 150f; private const float DeniedAmplitude = 0.22f; private const float DeniedSeconds = 0.035f; private const float DeniedFrequency = 110f; private readonly InputController _input = new InputController(); private float _readyAt = float.NegativeInfinity; private bool _pushing; private Vector3 _pushDirection; private float _pushBudget; private float _pushApplied; private float _pushElapsed; internal void Reset() { _input.Reset(); _readyAt = float.NegativeInfinity; CancelPush(); } private void CancelPush() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) _pushing = false; _pushDirection = Vector3.zero; _pushBudget = 0f; _pushApplied = 0f; _pushElapsed = 0f; } internal void Tick() { //IL_008b: 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_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: 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) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) ClimbAnythingCompatibility.Tick(); if (!_input.PressedThisFrame() || !PlayerState.IsValid || Time.time < _readyAt || ClimbDetector.Snapshot(out var left, out var right) == 0) { return; } if (ClimbStaminaCompatibility.ClimbingBlocked) { Deny(left, right); Log.Debug("Wall jump refused: ClimbStamina has climbing blocked"); return; } if (!ClimbStaminaCompatibility.CanAfford()) { Deny(left, right); Log.Debug("Wall jump refused: not enough stamina"); return; } float num = Mathf.Clamp(Prefs.AimStrictnessValue, 0f, 180f); if (num < 179.5f) { Vector3 val = FindOutward(left, right); Vector3 val2 = LookDirection(); if (val != Vector3.zero && val2 != Vector3.zero && Vector3.Angle(val2, val) > num) { Deny(left, right); Log.Debug($"Wall jump refused: looking {Vector3.Angle(val2, val):0} deg off the wall (limit {num:0})"); return; } } Execute(left, right); } private void Deny(ClimbHold left, ClimbHold right) { _readyAt = Time.time + 0.25f; if (left.Valid) { Pulse((Handedness)1, 0.035f, 110f, 0.22f); } if (right.Valid) { Pulse((Handedness)2, 0.035f, 110f, 0.22f); } } private void Execute(ClimbHold left, ClimbHold right) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0033: 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_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_0046: 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_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: 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_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00be: 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_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_02ad: Unknown result type (might be due to invalid IL or missing references) //IL_02cb: Unknown result type (might be due to invalid IL or missing references) Vector3 val = FindOutward(left, right); Vector3 val2 = Compose(LookDirection(), val) * (3.5f * Mathf.Clamp(Prefs.JumpStrengthValue, 0.05f, 6f)); if (val != Vector3.zero) { float num = Vector3.Dot(PlayerState.Velocity, -val); if (num > 0f) { val2 += val * Mathf.Min(num, 1.5f); } } float num2 = ((Vector3)(ref val2)).magnitude; if (!IsFinite(num2) || !IsFinite(val2.x) || !IsFinite(val2.y) || !IsFinite(val2.z)) { Log.Debug("Wall jump aborted: computed a non-finite velocity"); return; } if (num2 > 16f) { val2 = val2 / num2 * 16f; num2 = 16f; } if (num2 < 0.01f) { return; } int num3 = Release(left) + Release(right); if (num3 == 0) { _readyAt = Time.time + 0.25f; Log.Debug("Wall jump aborted: nothing could be released"); return; } ClimbStaminaCompatibility.Spend(); ClimbAnythingCompatibility.SuppressAfterJump(left, right, 0.3f); RegrabGuard.Suppress(0.3f); _pushDirection = val2 / num2; _pushBudget = num2; _pushApplied = 0f; _pushElapsed = 0f; _pushing = true; _readyAt = Time.time + 0.25f; if (left.Valid) { Pulse((Handedness)1, 0.09f, 150f, 0.55f); } if (right.Valid) { Pulse((Handedness)2, 0.09f, 150f, 0.55f); } Log.Debug($"Wall jump: {num3} hand(s) released, dV={num2:0.00} m/s, dir=({_pushDirection.x:0.00}, {_pushDirection.y:0.00}, {_pushDirection.z:0.00}), outward={((val == Vector3.zero) ? "none" : $"({val.x:0.00}, {val.y:0.00}, {val.z:0.00})")}"); } private static int Release(ClimbHold hold) { if (!hold.Valid) { return 0; } try { switch (hold.Source) { case ClimbSource.Vanilla: if ((Object)(object)hold.Grip == (Object)null || (Object)(object)hold.Hand == (Object)null) { return 0; } hold.Grip.ForceDetach(hold.Hand); return 1; case ClimbSource.ClimbAnything: return ClimbAnythingCompatibility.Release(hold) ? 1 : 0; } } catch (Exception ex) { Log.Debug("Release failed (" + ex.GetType().Name + ")"); } return 0; } private static bool IsFinite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } private static Vector3 LookDirection() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) Transform head = PlayerState.Head; if ((Object)(object)head == (Object)null) { return Vector3.zero; } Vector3 forward = head.forward; if (!(((Vector3)(ref forward)).sqrMagnitude < 1E-06f)) { return ((Vector3)(ref forward)).normalized; } return Vector3.zero; } internal static Vector3 Compose(Vector3 look, Vector3 outward) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: 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_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0086: 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_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: 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_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0117: 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_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0144: 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_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Clamp(Prefs.LookInfluenceValue, 0f, 5f); float num2 = Mathf.Clamp(Prefs.OutwardPushValue, 0f, 5f); float num3 = Mathf.Clamp(Prefs.UpwardBoostValue, 0f, 5f); Vector3 val = look * num + outward * num2 + Vector3.up * num3; if (((Vector3)(ref val)).sqrMagnitude < 1E-06f) { val = ((outward != Vector3.zero) ? (outward + Vector3.up * 0.5f) : Vector3.up); } Vector3 normalized = ((Vector3)(ref val)).normalized; normalized = ClampVertical(normalized, outward); float num4 = Mathf.Clamp(Prefs.OutwardFloorValue, 0f, 0.95f); if (outward != Vector3.zero && num4 > 0f) { float num5 = Vector3.Dot(normalized, outward); if (num5 < num4) { Vector3 val2 = normalized - outward * num5; if (((Vector3)(ref val2)).sqrMagnitude < 1E-06f) { val2 = Vector3.up - outward * outward.y; } if (((Vector3)(ref val2)).sqrMagnitude < 1E-06f) { return outward; } Vector3 val3 = outward * num4 + ((Vector3)(ref val2)).normalized * Mathf.Sqrt(1f - num4 * num4); normalized = ((Vector3)(ref val3)).normalized; normalized = ClampVertical(normalized, outward); } } return normalized; } private static Vector3 ClampVertical(Vector3 direction, Vector3 outward) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: 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) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) if (direction.y >= -0.3f) { return direction; } Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(direction.x, 0f, direction.z); if (((Vector3)(ref val)).sqrMagnitude < 1E-06f) { ((Vector3)(ref val))..ctor(outward.x, 0f, outward.z); } if (((Vector3)(ref val)).sqrMagnitude < 1E-06f) { return Vector3.up; } float num = -0.3f; val = ((Vector3)(ref val)).normalized * Mathf.Sqrt(1f - num * num); return new Vector3(val.x, num, val.z); } private static Vector3 FindOutward(ClimbHold left, ClimbHold right) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) Vector3 val; if (left.Valid && right.Valid) { val = (left.Anchor + right.Anchor) * 0.5f; } else if (left.Valid) { val = left.Anchor; } else { if (!right.Valid) { return Vector3.zero; } val = right.Anchor; } Vector3 bodyCentre = PlayerState.BodyCentre; if (TryCastToSurface(bodyCentre, val, out var normal) || TryClosestPoint(left, right, bodyCentre, out normal) || PlayerState.TryGetMarrowClimbNormal(out normal)) { Vector3 val2 = LimitDownward(normal); if (val2 != Vector3.zero) { return val2; } } Vector3 val3 = bodyCentre - val; val3.y = 0f; if (((Vector3)(ref val3)).sqrMagnitude > 0.0025f) { return ((Vector3)(ref val3)).normalized; } return Vector3.zero; } private static bool TryCastToSurface(Vector3 body, Vector3 anchor, out Vector3 normal) { //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_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0043: 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_0046: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: 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_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) normal = Vector3.zero; Vector3 val = anchor - body; float magnitude = ((Vector3)(ref val)).magnitude; if (magnitude < 0.05f) { return false; } try { Transform val2 = null; PhysicsRig physicsRig = Player.PhysicsRig; if ((Object)(object)physicsRig != (Object)null) { val2 = ((Component)physicsRig).transform.root; } Il2CppStructArray val3 = Physics.RaycastAll(body, val / magnitude, magnitude + 0.4f, -5, (QueryTriggerInteraction)1); if (val3 == null) { return false; } float num = float.MaxValue; float num2 = magnitude * 0.5f; for (int i = 0; i < ((Il2CppArrayBase)(object)val3).Length; i++) { RaycastHit val4 = ((Il2CppArrayBase)(object)val3)[i]; if (((RaycastHit)(ref val4)).distance < num2 || ((RaycastHit)(ref val4)).distance >= num) { continue; } Collider collider = ((RaycastHit)(ref val4)).collider; if (!((Object)(object)collider == (Object)null) && (!((Object)(object)val2 != (Object)null) || !((Object)(object)((Component)collider).transform.root == (Object)(object)val2))) { Vector3 normal2 = ((RaycastHit)(ref val4)).normal; if (!(((Vector3)(ref normal2)).sqrMagnitude < 0.25f)) { num = ((RaycastHit)(ref val4)).distance; normal2 = ((RaycastHit)(ref val4)).normal; normal = ((Vector3)(ref normal2)).normalized; } } } return num < float.MaxValue; } catch (Exception ex) { Log.Debug("Surface cast failed (" + ex.GetType().Name + ")"); return false; } } private static bool TryClosestPoint(ClimbHold left, ClimbHold right, Vector3 body, out Vector3 normal) { //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_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) normal = Vector3.zero; Vector3 val = Vector3.zero; int num = 0; for (int i = 0; i < 2; i++) { ClimbHold climbHold = ((i == 0) ? left : right); if (!climbHold.Valid || (Object)(object)climbHold.Surface == (Object)null) { continue; } try { Vector3 val2 = body - climbHold.Surface.ClosestPoint(body); if (!(((Vector3)(ref val2)).sqrMagnitude < 0.0004f)) { val += ((Vector3)(ref val2)).normalized; num++; } } catch { } } if (num == 0 || ((Vector3)(ref val)).sqrMagnitude < 1E-06f) { return false; } normal = ((Vector3)(ref val)).normalized; return true; } private static Vector3 LimitDownward(Vector3 normal) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0063: 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) //IL_0035: Unknown result type (might be due to invalid IL or missing references) if (normal.y >= -0.25f) { return normal; } Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(normal.x, 0f, normal.z); if (((Vector3)(ref val)).sqrMagnitude < 0.040000003f) { return Vector3.zero; } float num = -0.25f; val = ((Vector3)(ref val)).normalized * Mathf.Sqrt(1f - num * num); return new Vector3(val.x, num, val.z); } internal void FixedTick(float fixedDeltaTime) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) if (!_pushing) { return; } if (fixedDeltaTime <= 0f || !PlayerState.IsValid) { CancelPush(); return; } Rigidbody[] array = PlayerState.RigBodies(); if (array == null || array.Length == 0) { CancelPush(); return; } _pushElapsed += fixedDeltaTime; float num = _pushBudget * (fixedDeltaTime / 0.09f); float num2 = _pushBudget - _pushApplied; if (num > num2) { num = num2; } if (num > 1E-05f) { _pushApplied += num; Vector3 val = _pushDirection * num; foreach (Rigidbody val2 in array) { if (!((Object)(object)val2 == (Object)null) && !val2.isKinematic) { val2.AddForce(val, (ForceMode)2); } } } if (_pushApplied >= _pushBudget - 1E-05f || _pushElapsed >= 0.09f) { CancelPush(); } } private static void Pulse(Handedness side, float seconds, float frequency, float amplitude) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 try { if (!Player.ControllersExist) { return; } BaseController val = (((int)side == 1) ? Player.LeftController : Player.RightController); if (!((Object)(object)val == (Object)null)) { Haptor haptor = val.haptor; if (!((Object)(object)haptor == (Object)null) && haptor.hapticsAllowed) { haptor.SENDHAPTIC(0f, seconds, frequency, Mathf.Clamp01(amplitude)); } } } catch (Exception ex) { Log.Debug("Haptic pulse failed (" + ex.GetType().Name + ")"); } } } } namespace WallGrabJump.Compatibility { internal static class ClimbAnythingCompatibility { private const float GripHeldThreshold = 0.01f; private const float UnreadableGripGrace = 1.5f; private static bool _looked; private static Harmony _harmony; private static object _melon; private static FieldInfo _leftStateField; private static FieldInfo _rightStateField; private static FieldInfo _handField; private static FieldInfo _climbPointField; private static FieldInfo _isClimbingField; private static MethodInfo _stopClimbing; private static object _leftState; private static object _rightState; private static bool _leftSuppressed; private static bool _rightSuppressed; private static float _leftUnreadableSince = -1f; private static float _rightUnreadableSince = -1f; private static float _blockAllUntil = float.NegativeInfinity; private static int _faults; private static float _lastFaultAt = float.NegativeInfinity; private const int MaxFaults = 5; private const float FaultWindow = 10f; internal static bool Active { get; private set; } internal static void Initialize(Harmony harmony) { _harmony = harmony; if (!_looked) { MelonBase val = MelonBase.FindMelon("ClimbAnything", "Waspothegreat"); if (val != null) { _looked = true; TryBind(val); } } } internal static void Retry(Harmony harmony) { if (_harmony == null) { _harmony = harmony; } if (!_looked && _harmony != null) { _looked = true; MelonBase val = MelonBase.FindMelon("ClimbAnything", "Waspothegreat"); if (val != null) { TryBind(val); } } } private static void TryBind(MelonBase melon) { //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Expected O, but got Unknown try { Type type = ((object)melon).GetType(); _leftStateField = type.GetField("_leftHandState", BindingFlags.Instance | BindingFlags.NonPublic); _rightStateField = type.GetField("_rightHandState", BindingFlags.Instance | BindingFlags.NonPublic); Type nestedType = type.GetNestedType("HandState", BindingFlags.Public | BindingFlags.NonPublic); _handField = nestedType?.GetField("Hand", BindingFlags.Instance | BindingFlags.Public); _climbPointField = nestedType?.GetField("ClimbPoint", BindingFlags.Instance | BindingFlags.Public); _isClimbingField = nestedType?.GetField("IsClimbing", BindingFlags.Instance | BindingFlags.Public); MethodInfo method = type.GetMethod("StartClimbing", BindingFlags.Instance | BindingFlags.NonPublic); _stopClimbing = type.GetMethod("StopClimbing", BindingFlags.Instance | BindingFlags.NonPublic); if (!ShapeIsSupported(method, nestedType)) { Log.Warning("ClimbAnything is installed but its internals don't match the supported layout (verified against 1.0.0 / package 1.0.1). Wall jumping from ClimbAnything holds is disabled; vanilla climbing still works and ClimbAnything itself is untouched."); return; } _melon = melon; _harmony.Patch((MethodBase)method, new HarmonyMethod(typeof(ClimbAnythingCompatibility), "StartClimbingPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Active = true; MelonInfoAttribute info = melon.Info; Log.Msg("ClimbAnything " + (((info != null) ? info.Version : null) ?? "?") + " detected — wall jumping works from its holds, and a hand that jumps needs a fresh grip before it can climb again."); } catch (Exception ex) { Active = false; Log.Warning($"Could not set up ClimbAnything compatibility ({ex.GetType().Name}: {ex.Message}). " + "Vanilla wall jumping still works; ClimbAnything itself is untouched."); } } private static bool ShapeIsSupported(MethodInfo startClimbing, Type handStateType) { if (handStateType == null || startClimbing == null || _stopClimbing == null) { return false; } if (_leftStateField == null || _rightStateField == null) { return false; } if (_handField == null || _climbPointField == null || _isClimbingField == null) { return false; } if (_handField.FieldType != typeof(Hand)) { return false; } if (_isClimbingField.FieldType != typeof(bool)) { return false; } if (!typeof(Object).IsAssignableFrom(_climbPointField.FieldType)) { return false; } ParameterInfo[] parameters = startClimbing.GetParameters(); if (parameters.Length != 2 || parameters[0].ParameterType != handStateType) { return false; } ParameterInfo[] parameters2 = _stopClimbing.GetParameters(); if (parameters2.Length != 1 || parameters2[0].ParameterType != handStateType) { return false; } return true; } internal static ClimbHold Evaluate(Hand hand, Handedness side) { //IL_001b: 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_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) if (!Active || (Object)(object)hand == (Object)null) { return default(ClimbHold); } try { object obj = StateFor(side); if (obj == null) { return default(ClimbHold); } if (!(bool)_isClimbingField.GetValue(obj)) { return default(ClimbHold); } object? value = _climbPointField.GetValue(obj); Object val = (Object)((value is Object) ? value : null); if (val == (Object)null) { return default(ClimbHold); } object? value2 = _handField.GetValue(obj); Hand val2 = (Hand)((value2 is Hand) ? value2 : null); if ((Object)(object)val2 != (Object)null && (Object)(object)val2 != (Object)(object)hand) { return default(ClimbHold); } ClimbHold result = new ClimbHold { Source = ClimbSource.ClimbAnything, Side = side, Hand = hand, State = obj, Anchor = ((Component)hand).transform.position }; GameObject val3 = ((Il2CppObjectBase)val).TryCast(); if ((Object)(object)val3 != (Object)null) { result.Anchor = val3.transform.position; Transform parent = val3.transform.parent; if ((Object)(object)parent != (Object)null) { result.Surface = ((Component)parent).GetComponent(); } } return result; } catch (Exception e) { Fault(e); return default(ClimbHold); } } private static object StateFor(Handedness side) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 if (_melon == null) { return null; } if ((int)side == 1) { return _leftState ?? (_leftState = _leftStateField.GetValue(_melon)); } if ((int)side == 2) { return _rightState ?? (_rightState = _rightStateField.GetValue(_melon)); } return null; } internal static bool Release(ClimbHold hold) { if (!Active || hold.Source != ClimbSource.ClimbAnything || hold.State == null) { return false; } try { _stopClimbing.Invoke(_melon, new object[1] { hold.State }); return true; } catch (Exception e) { Fault(e); return false; } } internal static void SuppressAfterJump(ClimbHold left, ClimbHold right, float blanketSeconds) { _blockAllUntil = Time.time + blanketSeconds; if (left.Valid) { _leftSuppressed = true; _leftUnreadableSince = -1f; } if (right.Valid) { _rightSuppressed = true; _rightUnreadableSince = -1f; } } internal static void Tick() { if (_leftSuppressed || _rightSuppressed) { if (_leftSuppressed && GripReleased((Handedness)1, ref _leftUnreadableSince)) { _leftSuppressed = false; Log.Debug("Left hand may climb again (grip released)"); } if (_rightSuppressed && GripReleased((Handedness)2, ref _rightUnreadableSince)) { _rightSuppressed = false; Log.Debug("Right hand may climb again (grip released)"); } } } private static bool GripReleased(Handedness side, ref float unreadableSince) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 float time = Time.time; try { BaseController val = null; if (Player.ControllersExist) { val = (((int)side == 1) ? Player.LeftController : Player.RightController); } if ((Object)(object)val == (Object)null) { if (unreadableSince < 0f) { unreadableSince = time; } return time - unreadableSince >= 1.5f; } unreadableSince = -1f; return val.GetGripForce() <= 0.01f; } catch { if (unreadableSince < 0f) { unreadableSince = time; } return time - unreadableSince >= 1.5f; } } internal static void ClearSuppression() { _leftSuppressed = false; _rightSuppressed = false; _leftUnreadableSince = -1f; _rightUnreadableSince = -1f; _blockAllUntil = float.NegativeInfinity; } private static bool StartClimbingPrefix(object __0) { //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Invalid comparison between Unknown and I4 //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Invalid comparison between Unknown and I4 if (!Active) { return true; } if (!_leftSuppressed && !_rightSuppressed && Time.time >= _blockAllUntil) { return true; } try { if (Time.time < _blockAllUntil) { return false; } if (__0 == _leftState) { return !_leftSuppressed; } if (__0 == _rightState) { return !_rightSuppressed; } object? value = _handField.GetValue(__0); Hand val = (Hand)((value is Hand) ? value : null); if ((Object)(object)val == (Object)null) { return true; } Handedness handedness = val.handedness; if ((int)handedness != 1) { if ((int)handedness == 2) { return !_rightSuppressed; } return true; } return !_leftSuppressed; } catch (Exception e) { Fault(e); return true; } } private static void Fault(Exception e) { float realtimeSinceStartup = Time.realtimeSinceStartup; if (realtimeSinceStartup - _lastFaultAt > 10f) { _faults = 0; } _lastFaultAt = realtimeSinceStartup; _faults++; if (_faults == 1) { Log.Warning("Error talking to ClimbAnything: " + e.GetType().Name + ": " + e.Message); } if (_faults >= 5 && Active) { Active = false; ClearSuppression(); Log.Warning("Disabling ClimbAnything compatibility after repeated errors. Vanilla wall jumping continues, and ClimbAnything runs exactly as it does unpatched."); } } } internal static class ClimbStaminaCompatibility { private static bool _looked; private static object _controller; private static FieldInfo _staminaField; private static FieldInfo _drainField; private static PropertyInfo _maxProp; private static FieldInfo _blockedField; private static FieldInfo _enabledField; private static MelonPreferences_Entry _enabledEntry; private static int _faults; private const int MaxFaults = 3; internal static bool Active { get; private set; } internal static bool ClimbingBlocked { get { if (!Active) { return false; } try { return (bool)_blockedField.GetValue(null); } catch (Exception e) { Fault(e); return false; } } } internal static void Initialize() { if (!_looked && MelonBase.FindMelon("ClimbStamina", "Cesar") != null && TryBind(final: false)) { _looked = true; } } internal static void Retry() { if (!_looked) { _looked = true; if (MelonBase.FindMelon("ClimbStamina", "Cesar") != null) { TryBind(final: true); } } } private static bool TryBind(bool final) { try { MelonBase val = MelonBase.FindMelon("ClimbStamina", "Cesar"); if (val == null) { return false; } Type type = ((object)val).GetType(); _enabledField = type.Assembly.GetType("ClimbStamina.Prefs")?.GetField("Enabled", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (_enabledField != null && _enabledField.FieldType != typeof(MelonPreferences_Entry)) { _enabledField = null; } _blockedField = type.GetField("ClimbBlocked", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); object obj = type.GetField("_stamina", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(val); if (obj == null) { if (final) { Log.Warning("ClimbStamina is installed but its stamina controller could not be reached; wall jumping will not cost stamina. ClimbStamina itself is untouched."); } return false; } Type type2 = obj.GetType(); _staminaField = type2.GetField("_stamina", BindingFlags.Instance | BindingFlags.NonPublic); _drainField = type2.GetField("_timeSinceDrain", BindingFlags.Instance | BindingFlags.NonPublic); _maxProp = type2.GetProperty("MaxStamina", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (!ShapeIsSupported()) { Log.Warning("ClimbStamina is installed but its internals don't match the supported layout (verified against 1.3.4). Wall jumping will not cost stamina; ClimbStamina itself is untouched."); return true; } _controller = obj; Active = true; MelonInfoAttribute info = val.Info; Log.Msg("ClimbStamina " + (((info != null) ? info.Version : null) ?? "?") + " detected — wall jumps draw from its stamina pool."); return true; } catch (Exception ex) { Active = false; Log.Warning($"Could not set up ClimbStamina integration ({ex.GetType().Name}: {ex.Message}). " + "Wall jumping works and costs nothing; ClimbStamina itself is untouched."); return true; } } private static bool ShapeIsSupported() { if (_staminaField == null || _staminaField.FieldType != typeof(float)) { return false; } if (_drainField == null || _drainField.FieldType != typeof(float)) { return false; } if (_maxProp == null || _maxProp.PropertyType != typeof(float) || !_maxProp.CanRead) { return false; } if (_blockedField == null || _blockedField.FieldType != typeof(bool)) { return false; } return true; } private static bool PoolIsLive() { if (_enabledField == null) { return true; } try { if (_enabledEntry == null) { _enabledEntry = _enabledField.GetValue(null) as MelonPreferences_Entry; } return _enabledEntry == null || _enabledEntry.Value; } catch (Exception e) { Fault(e); return true; } } internal static float CostOfJump() { if (!Active || !PoolIsLive()) { return 0f; } try { float num = (float)_maxProp.GetValue(_controller); float num2 = Mathf.Clamp(Prefs.StaminaCostValue, 0f, 100f); return num * (num2 / 100f); } catch (Exception e) { Fault(e); return 0f; } } internal static float Current() { if (!Active) { return float.MaxValue; } try { return (float)_staminaField.GetValue(_controller); } catch (Exception e) { Fault(e); return float.MaxValue; } } internal static bool CanAfford() { if (!Active) { return true; } float num = CostOfJump(); if (!(num <= 0f)) { return Current() >= num; } return true; } internal static void Spend() { if (!Active) { return; } try { float num = CostOfJump(); if (!(num <= 0f)) { float num2 = (float)_staminaField.GetValue(_controller); float num3 = Mathf.Max(0f, num2 - num); _staminaField.SetValue(_controller, num3); _drainField.SetValue(_controller, 0f); Log.Debug($"Wall jump cost {num:0.0} stamina ({num2:0.0} -> {num3:0.0})"); } } catch (Exception e) { Fault(e); } } private static void Fault(Exception e) { _faults++; if (_faults == 1) { Log.Warning("ClimbStamina integration error: " + e.GetType().Name + ": " + e.Message); } if (_faults >= 3 && Active) { Active = false; _controller = null; Log.Warning("Disabling the ClimbStamina integration after repeated errors. Wall jumping continues without a stamina cost; ClimbStamina itself is untouched."); } } } }