using System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BoneLib; using BoneLib.BoneMenu; using DropProne; using DropProne.Config; using DropProne.Menu; using DropProne.Patches; using DropProne.Prone; using HarmonyLib; using Il2CppSLZ.Marrow; using MelonLoader; using MelonLoader.Preferences; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("DropProne")] [assembly: AssemblyDescription("Go prone in BONELAB. Crawl, take cover, stay flat.")] [assembly: AssemblyCompany(null)] [assembly: AssemblyProduct("DropProne")] [assembly: AssemblyFileVersion("1.1.0")] [assembly: MelonInfo(typeof(DropProneMod), "DropProne", "1.1.0", "Rocner", null)] [assembly: MelonGame("Stress Level Zero", "BONELAB")] [assembly: MelonColor(255, 90, 150, 90)] [assembly: MelonAuthorColor(255, 120, 200, 255)] [assembly: MelonAdditionalDependencies(new string[] { "BoneLib" })] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyVersion("1.1.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 DropProne { public sealed class DropProneMod : MelonMod { private static bool _levelReady; public override void OnInitializeMelon() { //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) Step("preferences", Prefs.Load); Step("patches", delegate { RigPatches.Apply(((MelonBase)this).HarmonyInstance); }); Step("menu", MenuPage.Build); Step("level loaded hook", delegate { Hooking.OnLevelLoaded += OnLevelLoaded; }); Step("level unloaded hook", delegate { Hooking.OnLevelUnloaded += OnLevelUnloaded; }); ((MelonBase)this).LoggerInstance.Msg("DropProne ready. Binding: " + Prefs.Bind.ToString() + ", key: " + ((object)Prefs.Key/*cast due to .constrained prefix*/).ToString() + "."); } private void Step(string name, Action action) { try { action(); } catch (Exception ex) { ((MelonBase)this).LoggerInstance.Error("Init step '" + name + "' failed: " + ex); } } private static void OnLevelLoaded(LevelInfo info) { ProneDriver.ForceReset(rigIsAlive: false); RigBinding.Forget(); ProneInput.Forget(); Diagnostics.Stop(); _levelReady = true; } private static void OnLevelUnloaded() { _levelReady = false; ProneDriver.ForceReset(rigIsAlive: false); RigBinding.Forget(); ProneInput.Forget(); Diagnostics.Stop(); } public override void OnUpdate() { try { Run(Time.deltaTime); } catch (Exception ex) { ((MelonBase)this).LoggerInstance.Error("Update failed: " + ex); ProneDriver.ForceReset(rigIsAlive: true); } } private void Run(float dt) { if (!(dt <= 0f) && _levelReady && RigBinding.Bind(dt)) { Diagnostics.Tick(dt); ProneInput.Tick(dt); if (Prefs.Enabled) { Drive(); } ProneDriver.Tick(dt); if (RigPatches.Applied == 0) { ProneDriver.InjectCrouchInput(); } if (!RigPatches.CrouchHoldPatched) { ProneDriver.DriveOffsets(); } } } private void Drive() { if (Prefs.HoldMode) { if (ProneInput.Held) { ProneDriver.TryEngage("hold"); } else { ProneDriver.Release("released"); } } else if (ProneInput.Pressed) { ProneDriver.Toggle("input"); } } public override void OnDeinitializeMelon() { try { Hooking.OnLevelLoaded -= OnLevelLoaded; } catch { } try { Hooking.OnLevelUnloaded -= OnLevelUnloaded; } catch { } try { ProneDriver.ForceReset(rigIsAlive: true); } catch { } try { RigBinding.Forget(); } catch { } try { Prefs.Save(); } catch { } } } internal static class BuildInfo { public const string Name = "DropProne"; public const string Description = "Go prone in BONELAB. Crawl, take cover, stay flat."; public const string Author = "Rocner"; public const string Company = null; public const string Version = "1.1.0"; } } namespace DropProne.Prone { internal static class CrouchLimits { private static bool _captured; private static SoftJointLimit _linearLimit; private static SoftJointLimitSpring _linearSpring; private static Vector3 _targetPosition; private static JointDrive _yDrive; private static float _colliderHeight; private static Vector3 _colliderCenter; public static bool Applied { get; private set; } public static bool Captured => _captured; public static float BaseLimit { get { if (!_captured) { return -1f; } return ((SoftJointLimit)(ref _linearLimit)).limit; } } public static void HoldExtended(float bonus) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) PhysicsRig physics = RigBinding.Physics; if ((Object)(object)physics == (Object)null || bonus <= 0f || !Capture(physics)) { return; } try { ConfigurableJoint kneePelvisJoint = physics.kneePelvisJoint; if (!((Object)(object)kneePelvisJoint == (Object)null)) { SoftJointLimit linearLimit = _linearLimit; ((SoftJointLimit)(ref linearLimit)).limit = ((SoftJointLimit)(ref _linearLimit)).limit + bonus; kneePelvisJoint.linearLimit = linearLimit; Applied = true; } } catch (Exception ex) { Melon.Logger.Error("Extending the knee joint failed: " + ex); Restore(); } } public static void ApplySetLimit(float minMeters, float maxMeters) { PhysicsRig physics = RigBinding.Physics; if ((Object)(object)physics == (Object)null || !Capture(physics)) { return; } try { physics.SetKneePelvisLimit(minMeters, maxMeters); Applied = true; } catch (Exception ex) { Melon.Logger.Error("SetKneePelvisLimit failed: " + ex); Restore(); } } public static void Restore() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0053: 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) if (!Applied && !_captured) { return; } PhysicsRig physics = RigBinding.Physics; if ((Object)(object)physics != (Object)null) { try { ConfigurableJoint kneePelvisJoint = physics.kneePelvisJoint; if ((Object)(object)kneePelvisJoint != (Object)null) { kneePelvisJoint.linearLimit = _linearLimit; kneePelvisJoint.linearLimitSpring = _linearSpring; kneePelvisJoint.targetPosition = _targetPosition; kneePelvisJoint.yDrive = _yDrive; } CapsuleCollider kneePelvisCol = physics.kneePelvisCol; if ((Object)(object)kneePelvisCol != (Object)null) { kneePelvisCol.height = _colliderHeight; kneePelvisCol.center = _colliderCenter; } } catch (Exception ex) { Melon.Logger.Error("Restoring crouch limits failed: " + ex); } } Applied = false; _captured = false; } public static void Forget() { Applied = false; _captured = false; } public static string Describe() { //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) //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) PhysicsRig physics = RigBinding.Physics; if ((Object)(object)physics == (Object)null) { return "no physics rig"; } try { ConfigurableJoint kneePelvisJoint = physics.kneePelvisJoint; CapsuleCollider kneePelvisCol = physics.kneePelvisCol; object obj; if (!((Object)(object)kneePelvisJoint != (Object)null)) { obj = "n/a"; } else { SoftJointLimit linearLimit = kneePelvisJoint.linearLimit; obj = ((SoftJointLimit)(ref linearLimit)).limit.ToString("0.000"); } string value = (string)obj; object obj2; if (!((Object)(object)kneePelvisJoint != (Object)null)) { obj2 = "n/a"; } else { Vector3 targetPosition = kneePelvisJoint.targetPosition; obj2 = ((Vector3)(ref targetPosition)).ToString("F3"); } string value2 = (string)obj2; string value3 = (((Object)(object)kneePelvisCol != (Object)null) ? kneePelvisCol.height.ToString("0.000") : "n/a"); string value4 = (_captured ? ((SoftJointLimit)(ref _linearLimit)).limit.ToString("0.000") : "not captured"); return $"linearLimit={value} (stock {value4}) targetPosition={value2} capsuleHeight={value3}"; } catch (Exception ex) { return "unreadable (" + ex.Message + ")"; } } private static bool Capture(PhysicsRig rig) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0062: 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) if (_captured) { return true; } try { ConfigurableJoint kneePelvisJoint = rig.kneePelvisJoint; if ((Object)(object)kneePelvisJoint != (Object)null) { _linearLimit = kneePelvisJoint.linearLimit; _linearSpring = kneePelvisJoint.linearLimitSpring; _targetPosition = kneePelvisJoint.targetPosition; _yDrive = kneePelvisJoint.yDrive; } CapsuleCollider kneePelvisCol = rig.kneePelvisCol; if ((Object)(object)kneePelvisCol != (Object)null) { _colliderHeight = kneePelvisCol.height; _colliderCenter = kneePelvisCol.center; } _captured = true; return true; } catch (Exception ex) { Melon.Logger.Error("Reading crouch limits failed, leaving them alone: " + ex); return false; } } } internal static class Diagnostics { private const float MinUsefulTravel = 0.15f; private static float _watch; private static readonly bool[] _lastLeft = new bool[4]; private static readonly bool[] _lastRight = new bool[4]; private static readonly string[] ButtonNames = new string[4] { "Thumbstick", "A", "B", "Menu" }; private static float _calibrate; private static bool _seeded; private static float _heightLow; private static float _heightHigh; private static float _crouchAtLow; private static float _crouchAtHigh; private static float _offsetAtLow; private static float _offsetAtHigh; private static float _targetAtLow; private static float _targetAtHigh; public static bool Watching => _watch > 0f; public static bool Calibrating => _calibrate > 0f; public static bool HasSuggestion { get; private set; } public static float SuggestedCrouchDrive { get; private set; } public static float SuggestedFeetOffset { get; private set; } public static void Report() { //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_0337: Unknown result type (might be due to invalid IL or missing references) Instance logger = Melon.Logger; logger.Msg("---- DropProne rig report ----"); logger.Msg($"prone: engaged={ProneDriver.Engaged} depth={ProneDriver.Depth:0.00} limitsApplied={CrouchLimits.Applied}"); if (!RigBinding.Ready) { logger.Msg("rig: not bound (load into a level first)"); logger.Msg("------------------------------"); return; } float num = RigBinding.HeadHeight(); logger.Msg($"body: headAboveFeet={((num < 0f) ? "n/a" : (num.ToString("0.000") + "m"))} grounded={RigBinding.Grounded()} fallen={RigBinding.Fallen()}"); try { PhysicsRig physics = RigBinding.Physics; logger.Msg($"physics: footSupported={physics.footSupported:0.000} pelvisHeightMult={physics.pelvisHeightMult:0.000} footballRadius={physics.footballRadius:0.000}"); } catch (Exception ex) { logger.Msg("physics: unreadable (" + ex.Message + ")"); } try { RemapRig remap = RigBinding.Remap; logger.Msg($"remap: vertState={remap.vertState} travState={remap.travState}"); logger.Msg($"remap: crouchTarget={remap._crouchTarget:0.000} feetOffset={remap._feetOffset:0.000} crouchSpeedLimit={remap._crouchSpeedLimit:0.000} spineCrouchOff={remap._spineCrouchOff:0.000}"); } catch (Exception ex2) { logger.Msg("remap: unreadable (" + ex2.Message + ")"); } logger.Msg("speed: " + ProneDriver.DescribeSpeed()); try { OpenControllerRig controller = RigBinding.Controller; if ((Object)(object)controller != (Object)null) { logger.Msg($"controller: crouch={((ControllerRig)controller)._crouch:0.000} crouchInput={((ControllerRig)controller)._crouchInput} vrVertState={controller.vrVertState}"); } } catch (Exception ex3) { logger.Msg("controller: unreadable (" + ex3.Message + ")"); } logger.Msg("kneePelvis: " + CrouchLimits.Describe()); logger.Msg("------------------------------"); } public static void Calibrate(float seconds) { if (!RigBinding.Ready) { Melon.Logger.Warning("No rig yet — load into a level first."); return; } if (ProneDriver.Active) { Melon.Logger.Warning("Stand up first — while prone the mod is writing these fields itself."); return; } _calibrate = seconds; _seeded = false; HasSuggestion = false; Melon.Logger.Msg($"Calibrating for {seconds:0}s: stand up all the way, then crouch as low as the game lets you."); } public static void ApplySuggestion() { if (!HasSuggestion) { Melon.Logger.Warning("Nothing to apply — run Calibrate first."); return; } Prefs.CrouchDrive = SuggestedCrouchDrive; Prefs.ProneFeetOffset = SuggestedFeetOffset; Prefs.ProneCrouchTarget = SuggestedFeetOffset; Prefs.Save(); Melon.Logger.Msg($"Applied: Crouch Drive = {SuggestedCrouchDrive:0.00}, Feet Offset = {SuggestedFeetOffset:0.000}."); } public static void WatchInputs(float seconds) { _watch = seconds; Array.Clear(_lastLeft, 0, _lastLeft.Length); Array.Clear(_lastRight, 0, _lastRight.Length); Melon.Logger.Msg($"Watching controller inputs for {seconds:0}s — press things."); } public static void Tick(float dt) { TickWatch(dt); TickCalibrate(dt); } public static void Stop() { _watch = 0f; _calibrate = 0f; } private static void TickCalibrate(float dt) { if (!(_calibrate <= 0f)) { _calibrate -= dt; Sample(); if (_calibrate <= 0f) { Finish(); } } } private static void Sample() { float num = RigBinding.HeadHeight(); if (num <= 0f) { return; } float crouch; float feetOffset; float crouchTarget; try { OpenControllerRig controller = RigBinding.Controller; RemapRig remap = RigBinding.Remap; if ((Object)(object)controller == (Object)null || (Object)(object)remap == (Object)null) { return; } crouch = ((ControllerRig)controller)._crouch; feetOffset = remap._feetOffset; crouchTarget = remap._crouchTarget; } catch { return; } if (!_seeded) { _seeded = true; _heightLow = (_heightHigh = num); _crouchAtLow = (_crouchAtHigh = crouch); _offsetAtLow = (_offsetAtHigh = feetOffset); _targetAtLow = (_targetAtHigh = crouchTarget); return; } if (num < _heightLow) { _heightLow = num; _crouchAtLow = crouch; _offsetAtLow = feetOffset; _targetAtLow = crouchTarget; } if (num > _heightHigh) { _heightHigh = num; _crouchAtHigh = crouch; _offsetAtHigh = feetOffset; _targetAtHigh = crouchTarget; } } private static void Finish() { Instance logger = Melon.Logger; logger.Msg("---- DropProne calibration ----"); if (!_seeded) { logger.Msg("No samples captured."); logger.Msg("-------------------------------"); return; } float num = _heightHigh - _heightLow; logger.Msg($"headAboveFeet: tallest {_heightHigh:0.000}m, lowest {_heightLow:0.000}m (travel {num:0.000}m)"); logger.Msg($"crouch: standing {_crouchAtHigh:0.000}, crouched {_crouchAtLow:0.000}"); logger.Msg($"feetOffset: standing {_offsetAtHigh:0.000}, crouched {_offsetAtLow:0.000}"); logger.Msg($"crouchTarget: standing {_targetAtHigh:0.000}, crouched {_targetAtLow:0.000}"); logger.Msg("kneePelvis: " + CrouchLimits.Describe()); if (num < 0.15f) { logger.Msg($"Only {num:0.000}m of travel seen — stand fully then crouch fully and run it again."); logger.Msg("-------------------------------"); return; } SuggestedFeetOffset = _offsetAtLow + (_offsetAtLow - _offsetAtHigh) * 0.55f; SuggestedCrouchDrive = (Mathf.Approximately(_crouchAtLow, 0f) ? Prefs.CrouchDrive : (_crouchAtLow * 1.4f)); HasSuggestion = true; logger.Msg($"suggested Crouch Drive = {SuggestedCrouchDrive:0.00}"); logger.Msg($"suggested Feet Offset = {SuggestedFeetOffset:0.000}"); logger.Msg("Use 'Apply Suggested' in the Calibrate page to write them in."); logger.Msg("-------------------------------"); } private static void TickWatch(float dt) { if (!(_watch <= 0f)) { _watch -= dt; if (_watch <= 0f) { Melon.Logger.Msg("Input watch finished."); return; } SampleButtons(RigBinding.LeftController, _lastLeft, "left"); SampleButtons(RigBinding.RightController, _lastRight, "right"); } } private static void SampleButtons(BaseController controller, bool[] last, string hand) { if ((Object)(object)controller == (Object)null) { return; } bool[] array = new bool[4]; try { array[0] = controller.GetThumbStick(); array[1] = controller.GetAButton(); array[2] = controller.GetBButton(); array[3] = controller.GetMenuButton(); } catch { return; } for (int i = 0; i < array.Length; i++) { if (array[i] != last[i]) { last[i] = array[i]; if (array[i]) { Melon.Logger.Msg("input: " + hand + " " + ButtonNames[i]); } } } } } internal static class ProneDriver { private const float AirborneGrace = 0.4f; private static bool _speedCaptured; private static bool _touchedRig; private static float _baseMaxVelocity; private static float _airborneTimer; private static int _captureFrame = -1; public static float PlayerCrouch { get; private set; } public static bool Engaged { get; private set; } public static float Depth { get; private set; } public static bool Active => Depth > 0.001f; public static bool Toggle(string source) { if (!Engaged) { return TryEngage(source); } return Release(source); } public static bool TryEngage(string source) { if (!Prefs.Enabled) { return false; } if (Engaged) { return true; } if (!RigBinding.Ready) { Melon.Logger.Warning("No player rig yet, cannot go prone."); return false; } if (Prefs.StandWhenAirborne && !RigBinding.Grounded()) { if (Prefs.LogEvents) { Melon.Logger.Msg("Not prone: airborne."); } return false; } Engaged = true; _airborneTimer = 0f; CaptureSpeed(); if (Prefs.UseSetLimit) { CrouchLimits.ApplySetLimit(Prefs.ProneMin, Prefs.ProneMax); } if (Prefs.LogEvents) { Melon.Logger.Msg("Prone (" + source + ")."); } return true; } public static bool Release(string reason) { if (!Engaged) { return false; } Engaged = false; if (Prefs.LogEvents) { Melon.Logger.Msg("Standing (" + reason + ")."); } return true; } public static void Tick(float dt) { if (Engaged) { Safety(dt); } float num = (Engaged ? 1f : 0f); float num2 = (Engaged ? Prefs.EnterTime : Prefs.ExitTime); Depth = Mathf.MoveTowards(Depth, num, dt / Mathf.Max(0.01f, num2)); if (RigBinding.Ready) { if (Active) { HoldDown(); } else if (_touchedRig) { LetGo(); } } } public static void InjectCrouchInput() { if (!Active || !Prefs.DriveCrouchInput) { return; } ControllerRig controller = (ControllerRig)(object)RigBinding.Controller; if ((Object)(object)controller == (Object)null) { return; } try { if (_captureFrame != Time.frameCount) { _captureFrame = Time.frameCount; PlayerCrouch = controller._crouch; } float num = Prefs.CrouchDrive * Depth; controller._crouch = ((num < 0f) ? Mathf.Min(PlayerCrouch, num) : Mathf.Max(PlayerCrouch, num)); controller._crouchInput = true; } catch { } } public static void DriveOffsets() { if (!Active || !Prefs.ForceFeetOffset) { return; } RemapRig remap = RigBinding.Remap; if ((Object)(object)remap == (Object)null) { return; } try { remap._feetOffset = Mathf.Lerp(remap._feetOffset, Prefs.ProneFeetOffset, Depth); remap._crouchTarget = Mathf.Lerp(remap._crouchTarget, Prefs.ProneCrouchTarget, Depth); _touchedRig = true; } catch { } } public static void ForceReset(bool rigIsAlive) { Engaged = false; Depth = 0f; _airborneTimer = 0f; if (rigIsAlive) { LetGo(); return; } CrouchLimits.Forget(); _speedCaptured = false; _touchedRig = false; } public static string DescribeSpeed() { RemapRig remap = RigBinding.Remap; if ((Object)(object)remap == (Object)null) { return "no remap rig"; } try { string value = (_speedCaptured ? _baseMaxVelocity.ToString("0.00") : "not captured"); return $"maxVelocity={remap.maxVelocity:0.00} currentMax={remap.currentMaxVelocity:0.00} baseline={value}"; } catch (Exception ex) { return "unreadable (" + ex.Message + ")"; } } private static void Safety(float dt) { if (RigBinding.Fallen()) { Release("ragdolled"); } else { if (!Prefs.StandWhenAirborne) { return; } if (RigBinding.Grounded()) { _airborneTimer = 0f; return; } _airborneTimer += dt; if (_airborneTimer > 0.4f) { Release("airborne"); } } } private static void HoldDown() { RemapRig remap = RigBinding.Remap; if ((Object)(object)remap == (Object)null) { return; } if (Prefs.ExtendJoint) { CrouchLimits.HoldExtended(Prefs.JointBonus * Depth); } try { if (_speedCaptured) { remap.maxVelocity = Mathf.Lerp(_baseMaxVelocity, Prefs.CrawlSpeed, Depth); } if (Prefs.SetVertState && Depth > 0.6f) { remap.vertState = (VertState)3; OpenControllerRig controller = RigBinding.Controller; if ((Object)(object)controller != (Object)null) { controller.vrVertState = (VrVertState)4; } } _touchedRig = true; } catch { } } private static void LetGo() { RemapRig remap = RigBinding.Remap; if ((Object)(object)remap != (Object)null) { try { if (_speedCaptured) { remap.maxVelocity = _baseMaxVelocity; } if (Prefs.SetVertState) { remap.vertState = (VertState)0; } OpenControllerRig controller = RigBinding.Controller; if ((Object)(object)controller != (Object)null && Prefs.SetVertState) { controller.vrVertState = (VrVertState)0; } } catch { } } CrouchLimits.Restore(); _speedCaptured = false; _touchedRig = false; } private static void CaptureSpeed() { if (_speedCaptured) { return; } RemapRig remap = RigBinding.Remap; if ((Object)(object)remap == (Object)null) { return; } try { _baseMaxVelocity = remap.maxVelocity; _speedCaptured = _baseMaxVelocity > 0.01f; } catch { } } } internal static class ProneInput { private enum ButtonKind { Stick, A, B } private const float CrouchThreshold = 0.85f; private static float _crouchHeld; private static bool _crouchFired; public static bool Pressed { get; private set; } public static bool Held { get; private set; } public static void Tick(float dt) { //IL_0028: 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_0041: Unknown result type (might be due to invalid IL or missing references) Pressed = false; Held = false; try { ReadBinding(dt); } catch { _crouchHeld = 0f; _crouchFired = false; } try { if ((int)Prefs.Key != 0) { if (Input.GetKeyDown(Prefs.Key)) { Pressed = true; } if (Input.GetKey(Prefs.Key)) { Held = true; } } } catch { } } public static void Forget() { _crouchHeld = 0f; _crouchFired = false; Pressed = false; Held = false; } private static void ReadBinding(float dt) { switch (Prefs.Bind) { case ProneBind.LeftStickClick: ReadButton(RigBinding.LeftController, ButtonKind.Stick); break; case ProneBind.RightStickClick: ReadButton(RigBinding.RightController, ButtonKind.Stick); break; case ProneBind.LeftBButton: ReadButton(RigBinding.LeftController, ButtonKind.B); break; case ProneBind.RightBButton: ReadButton(RigBinding.RightController, ButtonKind.B); break; case ProneBind.LeftAButton: ReadButton(RigBinding.LeftController, ButtonKind.A); break; case ProneBind.RightAButton: ReadButton(RigBinding.RightController, ButtonKind.A); break; case ProneBind.HoldCrouch: ReadHoldCrouch(dt); break; } } private static void ReadButton(BaseController controller, ButtonKind kind) { if ((Object)(object)controller == (Object)null) { return; } switch (kind) { case ButtonKind.Stick: if (controller.GetThumbStickDown()) { Pressed = true; } if (controller.GetThumbStick()) { Held = true; } break; case ButtonKind.A: if (controller.GetAButtonDown()) { Pressed = true; } if (controller.GetAButton()) { Held = true; } break; case ButtonKind.B: if (controller.GetBButtonDown()) { Pressed = true; } if (controller.GetBButton()) { Held = true; } break; } } private static void ReadHoldCrouch(float dt) { ControllerRig controller = (ControllerRig)(object)RigBinding.Controller; if ((Object)(object)controller == (Object)null) { _crouchHeld = 0f; _crouchFired = false; return; } if (Mathf.Abs(ProneDriver.Active ? ProneDriver.PlayerCrouch : controller._crouch) < 0.85f) { _crouchHeld = 0f; _crouchFired = false; return; } Held = true; _crouchHeld += dt; if (!(_crouchHeld < Prefs.HoldCrouchTime) && !_crouchFired) { _crouchFired = true; Pressed = true; } } } internal static class RigBinding { private static float _retry; public static RigManager Manager { get; private set; } public static PhysicsRig Physics { get; private set; } public static RemapRig Remap { get; private set; } public static OpenControllerRig Controller { get; private set; } public static BaseController LeftController { get; private set; } public static BaseController RightController { get; private set; } public static bool Ready { get { if ((Object)(object)Physics != (Object)null) { return (Object)(object)Remap != (Object)null; } return false; } } public static void Forget() { Manager = null; Physics = null; Remap = null; Controller = null; LeftController = null; RightController = null; _retry = 0f; } public static bool Bind(float dt) { if (Ready) { return true; } _retry -= dt; if (_retry > 0f) { return false; } _retry = 0.5f; try { Manager = Player.RigManager; Physics = Player.PhysicsRig; Remap = Player.RemapRig; Controller = Player.ControllerRig; LeftController = Player.LeftController; RightController = Player.RightController; } catch (Exception ex) { Melon.Logger.Error("Binding the player rig failed: " + ex); Forget(); return false; } return Ready; } public static float HeadHeight() { //IL_0055: 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) try { Transform head = Player.Head; PhysicsRig physics = Physics; if ((Object)(object)head == (Object)null || (Object)(object)physics == (Object)null) { return -1f; } Transform val = (((Object)(object)physics.feet != (Object)null) ? physics.feet.transform : null); if ((Object)(object)val == (Object)null) { return -1f; } return head.position.y - val.position.y; } catch { return -1f; } } public static bool Grounded() { try { PhysicsRig physics = Physics; return (Object)(object)physics != (Object)null && physics.footSupported > 0.25f; } catch { return true; } } public static bool Fallen() { try { PhysicsRig physics = Physics; return (Object)(object)physics != (Object)null && physics.manualFallenState; } catch { return false; } } } } namespace DropProne.Patches { internal static class RigPatches { public static int Applied { get; private set; } public static bool CrouchHoldPatched { get; private set; } public static void Apply(Harmony harmony) { if (harmony != null) { Patch(harmony, typeof(OpenControllerRig), "OnEarlyUpdate", "AfterControllerUpdate"); Patch(harmony, typeof(OpenControllerRig), "OnUpdate", "AfterControllerUpdate"); if (Applied == 0) { Patch(harmony, typeof(ControllerRig), "OnUpdate", "AfterControllerUpdate"); } CrouchHoldPatched = Patch(harmony, typeof(RemapRig), "CrouchHold", "AfterCrouchHold"); if (Applied == 0) { Melon.Logger.Error("No rig hooks landed. Prone will still try to drive the rig from OnUpdate, but it may fight the game."); } } } private static bool Patch(Harmony harmony, Type type, string method, string postfixName) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method(type, method, (Type[])null, (Type[])null); if (methodInfo == null) { Melon.Logger.Warning(type.Name + "." + method + " not found, skipping that hook."); return false; } MethodInfo methodInfo2 = AccessTools.Method(typeof(RigPatches), postfixName, (Type[])null, (Type[])null); harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Applied++; Melon.Logger.Msg($"Hooked {type.Name}.{method}."); return true; } catch (Exception ex) { Melon.Logger.Error($"Patching {type.Name}.{method} failed: " + ex); return false; } } private static void AfterControllerUpdate() { ProneDriver.InjectCrouchInput(); } private static void AfterCrouchHold() { ProneDriver.DriveOffsets(); } } } namespace DropProne.Menu { internal static class MenuPage { private static readonly Color Accent = new Color(0.4f, 0.68f, 0.4f); private static readonly string[] BindNames = new string[8] { "Menu / key only", "Left stick click", "Right stick click", "Left B button", "Right B button", "Left A button", "Right A button", "Hold crouch" }; public static void Build() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) Page root; try { root = Page.Root.CreatePage("Drop Prone", Accent, 0, true); } catch (Exception ex) { Melon.Logger.Error("BoneMenu root page failed: " + ex); return; } Section("main", delegate { BuildMain(root); }); Section("feel", delegate { BuildFeel(root); }); Section("depth", delegate { BuildDepth(root); }); Section("diagnostics", delegate { BuildDiagnostics(root); }); } private static void Section(string name, Action build) { try { build(); } catch (Exception ex) { Melon.Logger.Error("BoneMenu section '" + name + "' failed: " + ex); } } private static void BuildMain(Page root) { //IL_0006: 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) //IL_006b: 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_00d8: Unknown result type (might be due to invalid IL or missing references) root.CreateBool("Enabled", Accent, Prefs.Enabled, (Action)delegate(bool value) { Prefs.Enabled = value; Prefs.Save(); if (!value) { ProneDriver.Release("disabled"); } }); root.CreateFunction("Go Prone / Stand", Accent, (Action)delegate { ProneDriver.Toggle("menu"); }); root.CreateInt("Binding", Accent, (int)Prefs.Bind, 1, 0, 7, (Action)delegate(int value) { Prefs.Bind = (ProneBind)value; Prefs.Save(); ProneInput.Forget(); Melon.Logger.Msg("Binding: " + BindNames[Mathf.Clamp(value, 0, 7)]); }); root.CreateBool("Hold Instead Of Toggle", Accent, Prefs.HoldMode, (Action)delegate(bool value) { Prefs.HoldMode = value; Prefs.Save(); ProneDriver.Release("binding changed"); }); root.CreateFloat("Hold Crouch Time", Accent, Prefs.HoldCrouchTime, 0.05f, 0.1f, 3f, (Action)delegate(float value) { Prefs.HoldCrouchTime = value; Prefs.Save(); }); } private static void BuildFeel(Page root) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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_00e4: 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_014d: Unknown result type (might be due to invalid IL or missing references) Page obj = root.CreatePage("Feel", Accent, 0, true); obj.CreateFloat("Crawl Speed", Accent, Prefs.CrawlSpeed, 0.05f, 0.05f, 6f, (Action)delegate(float value) { Prefs.CrawlSpeed = value; Prefs.Save(); }); obj.CreateFloat("Drop Time", Accent, Prefs.EnterTime, 0.05f, 0.05f, 3f, (Action)delegate(float value) { Prefs.EnterTime = value; Prefs.Save(); }); obj.CreateFloat("Stand Time", Accent, Prefs.ExitTime, 0.05f, 0.05f, 3f, (Action)delegate(float value) { Prefs.ExitTime = value; Prefs.Save(); }); obj.CreateBool("Stand When Airborne", Accent, Prefs.StandWhenAirborne, (Action)delegate(bool value) { Prefs.StandWhenAirborne = value; Prefs.Save(); }); obj.CreateBool("Set Prone Vert State", Accent, Prefs.SetVertState, (Action)delegate(bool value) { Prefs.SetVertState = value; Prefs.Save(); }); obj.CreateBool("Log Events", Accent, Prefs.LogEvents, (Action)delegate(bool value) { Prefs.LogEvents = value; Prefs.Save(); }); } private static void BuildDepth(Page root) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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_00c6: 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_013f: 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_01c7: Unknown result type (might be due to invalid IL or missing references) Page obj = root.CreatePage("Depth", Accent, 0, true); obj.CreateBool("Drive Crouch Input", Accent, Prefs.DriveCrouchInput, (Action)delegate(bool value) { Prefs.DriveCrouchInput = value; Prefs.Save(); }); obj.CreateFloat("Crouch Drive", Accent, Prefs.CrouchDrive, 0.1f, -4f, 4f, (Action)delegate(float value) { Prefs.CrouchDrive = value; Prefs.Save(); }); obj.CreateBool("Extend Knee Joint", Accent, Prefs.ExtendJoint, (Action)delegate(bool value) { Prefs.ExtendJoint = value; Prefs.Save(); if (!value) { CrouchLimits.Restore(); } }); obj.CreateFloat("Joint Travel Bonus", Accent, Prefs.JointBonus, 0.05f, 0f, 1.5f, (Action)delegate(float value) { Prefs.JointBonus = value; Prefs.Save(); }); obj.CreateBool("Force Feet Offset", Accent, Prefs.ForceFeetOffset, (Action)delegate(bool value) { Prefs.ForceFeetOffset = value; Prefs.Save(); }); obj.CreateFloat("Prone Feet Offset", Accent, Prefs.ProneFeetOffset, 0.05f, -3f, 3f, (Action)delegate(float value) { Prefs.ProneFeetOffset = value; Prefs.Save(); }); obj.CreateFloat("Prone Crouch Target", Accent, Prefs.ProneCrouchTarget, 0.05f, -3f, 3f, (Action)delegate(float value) { Prefs.ProneCrouchTarget = value; Prefs.Save(); }); obj.CreateFunction("Restore Joint", Accent, (Action)CrouchLimits.Restore); BuildLegacy(obj); } private static void BuildLegacy(Page depth) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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) Page obj = depth.CreatePage("SetKneePelvisLimit", Accent, 0, true); obj.CreateBool("Use SetKneePelvisLimit", Accent, Prefs.UseSetLimit, (Action)delegate(bool value) { Prefs.UseSetLimit = value; Prefs.Save(); if (!value) { CrouchLimits.Restore(); } }); obj.CreateFloat("Prone Min", Accent, Prefs.ProneMin, 0.02f, 0f, 1.2f, (Action)delegate(float value) { Prefs.ProneMin = value; Prefs.Save(); Reapply(); }); obj.CreateFloat("Prone Max", Accent, Prefs.ProneMax, 0.05f, 0.2f, 3f, (Action)delegate(float value) { Prefs.ProneMax = value; Prefs.Save(); Reapply(); }); } private static void BuildDiagnostics(Page root) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: 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) Page obj = root.CreatePage("Diagnostics", Accent, 0, true); obj.CreateFunction("Calibrate (12s)", Accent, (Action)delegate { Diagnostics.Calibrate(12f); }); obj.CreateFunction("Apply Suggested", Accent, (Action)Diagnostics.ApplySuggestion); obj.CreateFunction("Report Rig State", Accent, (Action)Diagnostics.Report); obj.CreateFunction("Watch Inputs (10s)", Accent, (Action)delegate { Diagnostics.WatchInputs(10f); }); obj.CreateFunction("Stop", Accent, (Action)Diagnostics.Stop); } private static void Reapply() { if (CrouchLimits.Applied && Prefs.UseSetLimit) { CrouchLimits.Restore(); CrouchLimits.ApplySetLimit(Prefs.ProneMin, Prefs.ProneMax); } } } } namespace DropProne.Config { internal enum ProneBind { MenuAndKeyOnly, LeftStickClick, RightStickClick, LeftBButton, RightBButton, LeftAButton, RightAButton, HoldCrouch } internal static class Prefs { private static MelonPreferences_Category _category; private static MelonPreferences_Entry _enabled; private static MelonPreferences_Entry _bind; private static MelonPreferences_Entry _holdMode; private static MelonPreferences_Entry _key; private static MelonPreferences_Entry _holdCrouchTime; private static MelonPreferences_Entry _enterTime; private static MelonPreferences_Entry _exitTime; private static MelonPreferences_Entry _crawlSpeed; private static MelonPreferences_Entry _driveCrouchInput; private static MelonPreferences_Entry _crouchDrive; private static MelonPreferences_Entry _extendJoint; private static MelonPreferences_Entry _jointBonus; private static MelonPreferences_Entry _useSetLimit; private static MelonPreferences_Entry _proneMin; private static MelonPreferences_Entry _proneMax; private static MelonPreferences_Entry _forceFeetOffset; private static MelonPreferences_Entry _proneFeetOffset; private static MelonPreferences_Entry _proneCrouchTarget; private static MelonPreferences_Entry _setVertState; private static MelonPreferences_Entry _standWhenAirborne; private static MelonPreferences_Entry _logEvents; public static bool Enabled { get { return _enabled?.Value ?? true; } set { if (_enabled != null) { _enabled.Value = value; } } } public static ProneBind Bind { get { return (ProneBind)Mathf.Clamp(_bind?.Value ?? 1, 0, 7); } set { if (_bind != null) { _bind.Value = (int)value; } } } public static bool HoldMode { get { return _holdMode?.Value ?? false; } set { if (_holdMode != null) { _holdMode.Value = value; } } } public static KeyCode Key { get { MelonPreferences_Entry key = _key; if (key != null) { return (KeyCode)key.Value; } return (KeyCode)99; } set { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected I4, but got Unknown if (_key != null) { _key.Value = (int)value; } } } public static float HoldCrouchTime { get { return Mathf.Clamp(_holdCrouchTime?.Value ?? 0.55f, 0.1f, 3f); } set { if (_holdCrouchTime != null) { _holdCrouchTime.Value = value; } } } public static float EnterTime { get { return Mathf.Clamp(_enterTime?.Value ?? 0.45f, 0.05f, 3f); } set { if (_enterTime != null) { _enterTime.Value = value; } } } public static float ExitTime { get { return Mathf.Clamp(_exitTime?.Value ?? 0.35f, 0.05f, 3f); } set { if (_exitTime != null) { _exitTime.Value = value; } } } public static float CrawlSpeed { get { return Mathf.Clamp(_crawlSpeed?.Value ?? 0.7f, 0.05f, 6f); } set { if (_crawlSpeed != null) { _crawlSpeed.Value = value; } } } public static bool DriveCrouchInput { get { return _driveCrouchInput?.Value ?? true; } set { if (_driveCrouchInput != null) { _driveCrouchInput.Value = value; } } } public static float CrouchDrive { get { return Mathf.Clamp(_crouchDrive?.Value ?? (-1.4f), -4f, 4f); } set { if (_crouchDrive != null) { _crouchDrive.Value = value; } } } public static bool ExtendJoint { get { return _extendJoint?.Value ?? true; } set { if (_extendJoint != null) { _extendJoint.Value = value; } } } public static float JointBonus { get { return Mathf.Clamp(_jointBonus?.Value ?? 0.35f, 0f, 1.5f); } set { if (_jointBonus != null) { _jointBonus.Value = value; } } } public static bool UseSetLimit { get { return _useSetLimit?.Value ?? false; } set { if (_useSetLimit != null) { _useSetLimit.Value = value; } } } public static float ProneMin { get { return Mathf.Clamp(_proneMin?.Value ?? 0.12f, 0f, 1.2f); } set { if (_proneMin != null) { _proneMin.Value = value; } } } public static float ProneMax { get { return Mathf.Clamp(_proneMax?.Value ?? 1.6f, 0.2f, 3f); } set { if (_proneMax != null) { _proneMax.Value = value; } } } public static bool ForceFeetOffset { get { return _forceFeetOffset?.Value ?? true; } set { if (_forceFeetOffset != null) { _forceFeetOffset.Value = value; } } } public static float ProneFeetOffset { get { return Mathf.Clamp(_proneFeetOffset?.Value ?? (-1.15f), -3f, 3f); } set { if (_proneFeetOffset != null) { _proneFeetOffset.Value = value; } } } public static float ProneCrouchTarget { get { return Mathf.Clamp(_proneCrouchTarget?.Value ?? (-1.15f), -3f, 3f); } set { if (_proneCrouchTarget != null) { _proneCrouchTarget.Value = value; } } } public static bool SetVertState { get { return _setVertState?.Value ?? true; } set { if (_setVertState != null) { _setVertState.Value = value; } } } public static bool StandWhenAirborne { get { return _standWhenAirborne?.Value ?? true; } set { if (_standWhenAirborne != null) { _standWhenAirborne.Value = value; } } } public static bool LogEvents { get { return _logEvents?.Value ?? true; } set { if (_logEvents != null) { _logEvents.Value = value; } } } public static void Load() { _category = MelonPreferences.CreateCategory("DropProne"); _enabled = _category.CreateEntry("Enabled", true, "Enabled", (string)null, false, false, (ValueValidator)null, (string)null); _bind = _category.CreateEntry("Bind", 1, "Controller Binding", (string)null, false, false, (ValueValidator)null, (string)null); _holdMode = _category.CreateEntry("HoldMode", false, "Hold Instead Of Toggle", (string)null, false, false, (ValueValidator)null, (string)null); _key = _category.CreateEntry("Key", 99, "Keyboard Key", (string)null, false, false, (ValueValidator)null, (string)null); _holdCrouchTime = _category.CreateEntry("HoldCrouchTime", 0.55f, "Hold Crouch Time (s)", (string)null, false, false, (ValueValidator)null, (string)null); _enterTime = _category.CreateEntry("EnterTime", 0.45f, "Drop Time (s)", (string)null, false, false, (ValueValidator)null, (string)null); _exitTime = _category.CreateEntry("ExitTime", 0.35f, "Stand Time (s)", (string)null, false, false, (ValueValidator)null, (string)null); _crawlSpeed = _category.CreateEntry("CrawlSpeed2", 0.7f, "Crawl Speed", (string)null, false, false, (ValueValidator)null, (string)null); _driveCrouchInput = _category.CreateEntry("DriveCrouchInput", true, "Drive Crouch Input", (string)null, false, false, (ValueValidator)null, (string)null); _crouchDrive = _category.CreateEntry("CrouchDrive", -1.4f, "Crouch Drive", (string)null, false, false, (ValueValidator)null, (string)null); _extendJoint = _category.CreateEntry("ExtendJoint", true, "Extend Knee Joint", (string)null, false, false, (ValueValidator)null, (string)null); _jointBonus = _category.CreateEntry("JointBonus", 0.35f, "Joint Travel Bonus (m)", (string)null, false, false, (ValueValidator)null, (string)null); _useSetLimit = _category.CreateEntry("UseSetLimit", false, "Use SetKneePelvisLimit", (string)null, false, false, (ValueValidator)null, (string)null); _proneMin = _category.CreateEntry("ProneMin", 0.12f, "Prone Min (m)", (string)null, false, false, (ValueValidator)null, (string)null); _proneMax = _category.CreateEntry("ProneMax", 1.6f, "Prone Max (m)", (string)null, false, false, (ValueValidator)null, (string)null); _forceFeetOffset = _category.CreateEntry("ForceFeetOffset", true, "Force Feet Offset", (string)null, false, false, (ValueValidator)null, (string)null); _proneFeetOffset = _category.CreateEntry("ProneFeetOffset", -1.15f, "Prone Feet Offset", (string)null, false, false, (ValueValidator)null, (string)null); _proneCrouchTarget = _category.CreateEntry("ProneCrouchTarget", -1.15f, "Prone Crouch Target", (string)null, false, false, (ValueValidator)null, (string)null); _setVertState = _category.CreateEntry("SetVertState", true, "Set Prone Vert State", (string)null, false, false, (ValueValidator)null, (string)null); _standWhenAirborne = _category.CreateEntry("StandWhenAirborne", true, "Stand When Airborne", (string)null, false, false, (ValueValidator)null, (string)null); _logEvents = _category.CreateEntry("LogEvents", true, "Log Events", (string)null, false, false, (ValueValidator)null, (string)null); } public static void Save() { try { MelonPreferences_Category category = _category; if (category != null) { category.SaveToFile(false); } } catch { } } } }