Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of SureFooted v1.3.4
SureFooted.dll
Decompiled 2 weeks agousing System; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SureFooted { internal sealed class ConfigurationManagerAttributes { public string Category; public string DispName; public int? Order; } internal static class Grip { internal static readonly int CrouchingHash = ZSyncAnimation.GetHash("crouching"); internal const float VanillaSlideAngle = 38f; private const float BraceDelay = 0.6f; private const float ClimbRise = 2f; private const float SteepDelay = 0.6f; private const float LoseDelay = 0.25f; private const float AngleHysteresis = 3f; private const float BlendTime = 0.5f; private const float UphillStart = 0.15f; private const float UphillKeep = 0.05f; private static float s_angle; private static float s_uphill; private static string s_decision; private static bool s_reported; private static float s_nextLog; private static bool s_onSlope; private static float s_steepTime; private static float s_slopeOffTime; private static float s_stillTime; private static bool s_ascending; private static float s_ascentFromY; private static float s_levelTime; private static float s_rise; private static float s_poseUntil; private static float s_poseSince; private static float s_steepSince; private static bool s_wasSneaking; private static bool s_wasMoving; private static bool s_standUp; internal static bool Steep { get; private set; } internal static bool Climbing { get; private set; } internal static bool Pose { get; private set; } internal static bool PoseShowing { get { if (!Pose) { return Time.time < s_poseUntil; } return true; } } internal static void Report(float angle, float uphill, string decision) { s_angle = angle; s_uphill = uphill; s_decision = decision; s_reported = true; } internal static void Update(Player player, float dt, bool moving, bool running, bool sneaking) { //IL_012c: Unknown result type (might be due to invalid IL or missing references) bool flag = s_reported; s_reported = false; if (s_wasSneaking && !sneaking) { s_standUp = true; } else if (moving != s_wasMoving || running) { s_standUp = false; } s_wasSneaking = sneaking; s_wasMoving = moving; if (!Plugin.Enabled.Value) { bool num = (Pose = (s_onSlope = (s_ascending = false))); Climbing = num; Steep = num; s_stillTime = 0f; return; } int value = Plugin.MaxGripAngle.Value; bool steep = Steep; float num2 = 38f - (Steep ? 3f : 0f); Steep = Debounce(Steep, flag && s_angle > num2 && s_angle <= (float)value, 0.6f, dt, ref s_steepTime); float num3 = (float)Plugin.BraceMinAngle.Value - (s_onSlope ? 3f : 0f); s_onSlope = Sticky(s_onSlope, flag && s_angle >= num3 && s_angle <= (float)value, dt, ref s_slopeOffTime); float y = ((Component)player).transform.position.y; if (!moving || !Steep || (flag && s_uphill < -0.15f)) { s_ascending = false; } else if (flag && s_uphill > (s_ascending ? 0.05f : 0.15f)) { if (!s_ascending) { s_ascentFromY = y; } s_ascending = true; s_levelTime = 0f; } else if (flag && s_ascending && (s_levelTime += dt) >= 0.25f) { s_ascending = false; } s_rise = (s_ascending ? (y - s_ascentFromY) : 0f); Climbing = s_ascending && (Climbing || Pose || s_rise >= 2f); bool pose = Pose; string why; if (!Plugin.BraceAnimation.Value || s_standUp || Busy(player)) { Pose = false; s_stillTime = 0f; why = ((!Plugin.BraceAnimation.Value) ? "pose setting off" : (s_standUp ? "sneak turned off" : "busy")); } else if (moving) { Pose = Climbing && !running; s_stillTime = 0f; why = (Pose ? "climbing" : (running ? "sprinting" : ((!Steep) ? "moving, not on steep ground" : ((!s_ascending) ? "moving, not heading uphill" : "ascending, not risen enough yet")))); } else { s_stillTime = (s_onSlope ? (s_stillTime + dt) : 0f); Pose = s_onSlope && (Pose || (s_stillTime >= 0.6f && s_angle <= (float)value)); why = ((!Pose) ? (s_onSlope ? "stopped, waiting for the delay" : "stopped, not on a slope") : (Steep ? "stopped on steep ground" : "stopped on a slope")); } if (Pose) { s_poseUntil = Time.time + 0.5f; } if (Plugin.DebugLog.Value) { LogChanges(player, flag, moving, running, sneaking, steep, pose, why); } } private static void LogChanges(Player player, bool onGround, bool moving, bool running, bool sneaking, bool wasSteep, bool wasPose, string why) { //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) float time = Time.time; string text = (onGround ? $"{s_angle:0}° {s_decision}" : "in the air or on a ship"); string text2 = $"{text} | steep {Steep} ascending {s_ascending} rise {s_rise:0.0}m climbing {Climbing} " + $"uphill {s_uphill:0.00} | moving {moving} sprint {running} sneak {sneaking}"; if (Steep != wasSteep) { Plugin.Log.LogInfo((object)("STEEP " + (Steep ? "ON" : $"OFF after {time - s_steepSince:0.00}s") + " | " + text2)); s_steepSince = time; } if (Pose != wasPose) { Plugin.Log.LogInfo((object)("POSE " + (Pose ? "ON" : $"OFF after {time - s_poseSince:0.00}s") + ": " + why + " | " + text2)); s_poseSince = time; } if (!(time < s_nextLog) && (moving || (onGround && s_angle >= 10f))) { s_nextLog = time + 0.5f; Vector3 velocity = ((Character)player).GetVelocity(); Plugin.Log.LogInfo((object)($"{text2} | pose {Pose} standUp {s_standUp} crouching {((Character)player).IsCrouching()} | " + $"stamina {player.GetStamina():0} speed {((Vector3)(ref velocity)).magnitude:0.0} up {velocity.y:0.0}")); } } private static bool Sticky(bool current, bool now, float dt, ref float offTime) { if (now) { offTime = 0f; return true; } offTime += dt; if (current) { return offTime < 0.25f; } return false; } private static bool Debounce(bool current, bool now, float onDelay, float dt, ref float time) { time = ((now == current) ? Mathf.Max(0f, time - 3f * dt) : (time + dt)); if (time < (current ? 0.25f : onDelay)) { return current; } time = 0f; return now; } private static bool Busy(Player p) { if (!((Character)p).IsDead() && !((Character)p).InAttack() && !((Character)p).IsDrawingBow() && !((Character)p).IsBlocking() && !((Character)p).InDodge() && !((Character)p).IsStaggering() && !((Character)p).InPlaceMode() && !((Character)p).InEmote() && !((Character)p).IsSitting() && !((Character)p).IsAttached() && !((Character)p).InBed() && !((Character)p).IsSwimming()) { return ((Character)p).IsFlying(); } return true; } } [HarmonyPatch(typeof(Character), "ApplySlide")] internal static class ApplySlidePatch { private static bool Prefix(Character __instance, ref Vector3 currentVel, ref float ___m_slippage, Vector3 ___m_lastGroundNormal, Vector3 ___m_moveDir, float ___m_lastGroundTouch, bool ___m_slipping, Rigidbody ___m_body) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0099: 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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: 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_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !Plugin.Enabled.Value) { return true; } float num = Mathf.Acos(Mathf.Clamp01(___m_lastGroundNormal.y)) * 57.29578f; string text = ((num <= 38f) ? "vanilla: gentle" : ((num > (float)Plugin.MaxGripAngle.Value) ? "vanilla: steeper than max grip" : (___m_slipping ? "vanilla: ice" : (__instance.IsAttached() ? "vanilla: attached" : ((___m_lastGroundTouch > 0f) ? "vanilla: no contact this tick" : null))))); float num2; if (!(((Vector3)(ref ___m_moveDir)).sqrMagnitude >= 0.01f)) { num2 = 0f; } else { Vector3 val = Vector3.ProjectOnPlane(___m_moveDir, ___m_lastGroundNormal); num2 = ((Vector3)(ref val)).normalized.y; } float uphill = num2; Grip.Report(num, uphill, text ?? "grip"); if (text != null) { return true; } ___m_slippage = 0f; currentVel.y = (0f - (___m_lastGroundNormal.x * currentVel.x + ___m_lastGroundNormal.z * currentVel.z)) / ___m_lastGroundNormal.y; ___m_body.AddForce(-Vector3.ProjectOnPlane(Physics.gravity, ___m_lastGroundNormal), (ForceMode)5); return false; } } [HarmonyPatch(typeof(Player), "GetJogSpeedFactor")] internal static class JogSpeedPatch { private static void Postfix(Player __instance, ref float __result) { if (Grip.Climbing && (Object)(object)__instance == (Object)(object)Player.m_localPlayer && ((Character)__instance).m_speed > 0f) { __result = ((Character)__instance).m_crouchSpeed / ((Character)__instance).m_speed; } } } [HarmonyPatch(typeof(Player), "UpdateCrouch")] internal static class UpdateCrouchPatch { private static bool Prefix(Player __instance, float dt, bool ___m_crouchToggled, Vector3 ___m_moveDir, bool ___m_running, ZSyncAnimation ___m_zanim) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return true; } Grip.Update(__instance, dt, ((Vector3)(ref ___m_moveDir)).magnitude >= 0.1f, ___m_running, ___m_crouchToggled); if (!Grip.Pose || ___m_crouchToggled) { return true; } ___m_zanim.SetBool(Grip.CrouchingHash, true); return false; } } [HarmonyPatch(typeof(Player), "IsCrouching")] internal static class IsCrouchingPatch { private static void Postfix(Player __instance, bool ___m_crouchToggled, ref bool __result) { if (__result && !___m_crouchToggled && Grip.PoseShowing && (Object)(object)__instance == (Object)(object)Player.m_localPlayer) { __result = false; } } } [BepInPlugin("vh.surefooted", "SureFooted", "1.3.4")] public class Plugin : BaseUnityPlugin { public const string Guid = "vh.surefooted"; public const string Name = "SureFooted"; public const string Version = "1.3.4"; private const string Slopes = "1. Slopes"; private const string Bracing = "2. Bracing"; private const string Debug = "3. Debug"; internal static ManualLogSource Log; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<int> MaxGripAngle; internal static ConfigEntry<bool> BraceAnimation; internal static ConfigEntry<int> BraceMinAngle; internal static ConfigEntry<bool> DebugLog; private Harmony _harmony; private FileSystemWatcher _watcher; private DateTime _lastReload; private static ConfigurationManagerAttributes Display(string category, string name, int order) { return new ConfigurationManagerAttributes { Category = category, DispName = name, Order = order }; } private void Awake() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Expected O, but got Unknown //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Expected O, but got Unknown //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Expected O, but got Unknown //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Expected O, but got Unknown //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1. Slopes", "Enabled", true, new ConfigDescription("Master switch. Off restores vanilla sliding, climbing and speed on slopes.", (AcceptableValueBase)null, new object[1] { Display("1. Slopes", "Enabled", 2) })); MaxGripAngle = ((BaseUnityPlugin)this).Config.Bind<int>("1. Slopes", "MaxGripAngle", 60, new ConfigDescription("Steepest ground, in degrees, you can stand and climb on without sliding. Vanilla slides you off anything steeper than 38°. On ground between 38° and this, going up is climbing, at crouch speed with no stamina cost; going down or across is normal walking; sprint to run either way, for the usual sprint stamina. Steeper ground than this behaves as in vanilla: you slide, and sprinting into it still runs up it. Default 60.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(39, 85), new object[1] { Display("1. Slopes", "Max grip angle (°)", 1) })); BraceAnimation = ((BaseUnityPlugin)this).Config.Bind<bool>("2. Bracing", "BraceAnimation", true, new ConfigDescription("Crouch into a braced stance when you stop on a slope, and crouch-walk while climbing up (going down and sprinting are upright). It's only a pose: you aren't sneaking, jump still jumps, and stamina regenerates normally. Off stands and walks upright; climbing is still at crouch speed.", (AcceptableValueBase)null, new object[1] { Display("2. Bracing", "Brace and climb crouched", 2) })); BraceMinAngle = ((BaseUnityPlugin)this).Config.Bind<int>("2. Bracing", "BraceMinAngle", 38, new ConfigDescription("Slope, in degrees, from which standing still braces. Default 38, where vanilla starts sliding you, and there you brace as soon as you stop. Set it lower to brace on gentler slopes too, after a moment.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 85), new object[1] { Display("2. Bracing", "Brace from angle (°)", 1) })); DebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("3. Debug", "DebugLog", false, new ConfigDescription("Write what the mod sees to BepInEx\\LogOutput.log: every time the steep-ground state or the crouched pose switches on or off, with the reason and how long it lasted, and twice a second while you're moving or on a slope the slope angle, whether it grips or leaves you to vanilla and why, and your sneak, sprint, stamina and speed. For troubleshooting; leave it off otherwise.", (AcceptableValueBase)null, new object[1] { Display("3. Debug", "Debug log", 1) })); _harmony = new Harmony("vh.surefooted"); _harmony.PatchAll(); SetupWatcher(); Log.LogInfo((object)$"Loaded: grip up to {MaxGripAngle.Value}°."); } private void OnDestroy() { _watcher?.Dispose(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private void SetupWatcher() { _watcher = new FileSystemWatcher(Paths.ConfigPath, Path.GetFileName(((BaseUnityPlugin)this).Config.ConfigFilePath)); _watcher.Changed += ReloadConfig; _watcher.Created += ReloadConfig; _watcher.Renamed += ReloadConfig; _watcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; _watcher.EnableRaisingEvents = true; } private void ReloadConfig(object sender, FileSystemEventArgs e) { if ((DateTime.Now - _lastReload).TotalSeconds < 1.0 || !File.Exists(((BaseUnityPlugin)this).Config.ConfigFilePath)) { return; } _lastReload = DateTime.Now; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; try { ((BaseUnityPlugin)this).Config.Reload(); Log.LogInfo((object)"Configuration reloaded."); } catch (Exception ex) { Log.LogError((object)("Error reloading configuration: " + ex.Message)); } finally { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = true; } } } }