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 RunBasedPassives v0.4.1
plugins/RunBasedPassives.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using MoreUIPanel; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("RunBasedPassives")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("RunBasedPassives")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("d3524128-8d57-4661-a37a-6231cfd2059c")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace RunBasedPassives; [BepInPlugin("cn_xc.RunBasedPassives", "RunBasedPassives", "0.4.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { private ConfigEntry<bool> enableJump; private ConfigEntry<bool> enableStrength; private ConfigEntry<bool> enableStamina; private ConfigEntry<bool> enableHealth; private ConfigEntry<bool> enableSprintSpeed; private ConfigEntry<bool> enableCrouchRestore; private ConfigEntry<bool> verboseLogging; private ConfigEntry<int> sprintSpeedCap; public static int JumpLevel; public static int StrengthLevel; public static int StaminaLevel; public static int HealthLevel; public static int SprintSpeedLevel; public static int CrouchRestoreLevel; public static int JumpCount; public static int GrabCount; public static float MoveDistance; public static int HealCount; public static float SprintDistance; public static float CrouchRestoreAmount; public static float LastEnergyCurrent = -1f; private static int _lastLogJump; private static int _lastLogGrab; private static int _lastLogHeal; private static int _lastLogCrouch; private static float _lastLogMove; private static float _lastLogSprint; private Harmony harmony; private static FieldRef<PlayerController, int> jumpExtraRef; private static FieldRef<PlayerHealth, int> maxHealthRef; private static FieldRef<PlayerAvatar, string> steamIDRef; private static FieldRef<PlayerAvatar, bool> isLocalRef; private static FieldRef<PlayerHealth, PlayerAvatar> healthPlayerAvatarRef; private static FieldRef<StatsManager, SortedDictionary<string, Dictionary<string, int>>> dictOfDictsRef; private static FieldRef<PlayerAvatar, bool> crouchRestActiveRef; private static FieldRef<PlayerAvatar, float> crouchRestRef; private static FieldRef<StatsManager, string> saveFileCurrentRef; private bool _uiRegistered; private float _staminaBase = -1f; private float _originalSprintSpeed = -1f; private string _lastSaveFile = ""; private int GetJumpThreshold() { return 80 + JumpLevel * 40; } private int GetGrabThreshold() { return 50 + StrengthLevel * 10; } private float GetMoveThreshold() { return 500f + (float)StaminaLevel * 200f; } private int GetHealThreshold() { return 10 + HealthLevel * 3; } private float GetSprintThreshold() { return 300f + (float)SprintSpeedLevel * 100f; } private float GetCrouchThreshold() { return 80f + (float)CrouchRestoreLevel * 20f; } private void Awake() { //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Expected O, but got Unknown //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Expected O, but got Unknown //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Expected O, but got Unknown //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Expected O, but got Unknown //IL_02a4: Unknown result type (might be due to invalid IL or missing references) //IL_02b0: Expected O, but got Unknown //IL_02dd: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Expected O, but got Unknown enableJump = ((BaseUnityPlugin)this).Config.Bind<bool>("Toggles", "EnableJump", true, "启用跳跃升级"); enableStrength = ((BaseUnityPlugin)this).Config.Bind<bool>("Toggles", "EnableStrength", true, "启用力量升级"); enableStamina = ((BaseUnityPlugin)this).Config.Bind<bool>("Toggles", "EnableStamina", true, "启用耐力升级"); enableHealth = ((BaseUnityPlugin)this).Config.Bind<bool>("Toggles", "EnableHealth", true, "启用生命升级"); enableSprintSpeed = ((BaseUnityPlugin)this).Config.Bind<bool>("Toggles", "EnableSprintSpeed", true, "启用冲刺速度升级"); enableCrouchRestore = ((BaseUnityPlugin)this).Config.Bind<bool>("Toggles", "EnableCrouchRestore", true, "启用蹲伏恢复升级"); verboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "VerboseLogging", false, "详细日志输出(用于调试)"); sprintSpeedCap = ((BaseUnityPlugin)this).Config.Bind<int>("Thresholds", "SprintSpeedCap", 0, new ConfigDescription("冲刺速度封顶等级(0=不封顶)", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, int.MaxValue), Array.Empty<object>())); jumpExtraRef = AccessTools.FieldRefAccess<PlayerController, int>("JumpExtra"); maxHealthRef = AccessTools.FieldRefAccess<PlayerHealth, int>("maxHealth"); steamIDRef = AccessTools.FieldRefAccess<PlayerAvatar, string>("steamID"); isLocalRef = AccessTools.FieldRefAccess<PlayerAvatar, bool>("isLocal"); healthPlayerAvatarRef = AccessTools.FieldRefAccess<PlayerHealth, PlayerAvatar>("playerAvatar"); dictOfDictsRef = AccessTools.FieldRefAccess<StatsManager, SortedDictionary<string, Dictionary<string, int>>>("dictionaryOfDictionaries"); crouchRestActiveRef = AccessTools.FieldRefAccess<PlayerAvatar, bool>("upgradeCrouchRestActive"); crouchRestRef = AccessTools.FieldRefAccess<PlayerAvatar, float>("upgradeCrouchRest"); saveFileCurrentRef = AccessTools.FieldRefAccess<StatsManager, string>("saveFileCurrent"); Patches.isLocalRef = isLocalRef; Patches.steamIDRef = steamIDRef; Patches.healthPlayerAvatarRef = healthPlayerAvatarRef; Patches.crouchRestActiveRef = crouchRestActiveRef; Patches.crouchRestRef = crouchRestRef; Patches.pluginLogger = ((BaseUnityPlugin)this).Logger; Patches.verboseLogging = verboseLogging; Harmony.DEBUG = true; harmony = new Harmony("cn_xc.RunBasedPassives"); harmony.Patch((MethodBase)AccessTools.Method(typeof(PlayerAvatar), "Jump", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Patches), "JumpPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(PhysGrabObject), "GrabStarted", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "GrabStartedPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(PlayerAvatar), "Update", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(Patches), "PlayerAvatarUpdatePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(PlayerHealth), "Heal", (Type[])null, (Type[])null), new HarmonyMethod(typeof(Patches), "HealPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); SceneManager.sceneLoaded += OnSceneLoaded; ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Harmony 补丁总数: {harmony.GetPatchedMethods().Count()}"); ((BaseUnityPlugin)this).Logger.LogInfo((object)"RunBasedPassives v0.4.1 loaded"); if (verboseLogging.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"详细日志已开启(仅在经验变化时输出)"); } } private void OnDestroy() { SceneManager.sceneLoaded -= OnSceneLoaded; if (_uiRegistered) { Plugin.UnregisterLine("runbasedpassives_stats"); } harmony.UnpatchAll((string)null); } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { ResetCounters(); } private void ResetCounters() { string text = saveFileCurrentRef.Invoke(StatsManager.instance) ?? ""; if (_lastSaveFile != text) { _lastSaveFile = text; JumpCount = 0; GrabCount = 0; MoveDistance = 0f; HealCount = 0; SprintDistance = 0f; CrouchRestoreAmount = 0f; if (verboseLogging.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"[场景加载] 检测到存档切换,经验已清零"); } } else { JumpCount %= GetJumpThreshold(); GrabCount %= GetGrabThreshold(); MoveDistance %= GetMoveThreshold(); HealCount %= GetHealThreshold(); SprintDistance %= GetSprintThreshold(); CrouchRestoreAmount %= GetCrouchThreshold(); if (verboseLogging.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[场景加载] 经验已继承: 跳跃:{JumpCount}/{GetJumpThreshold()} 力量:{GrabCount}/{GetGrabThreshold()} 耐力:{MoveDistance:F0}/{GetMoveThreshold()} 生命:{HealCount}/{GetHealThreshold()} 冲刺:{SprintDistance:F0}/{GetSprintThreshold()} 蹲伏:{CrouchRestoreAmount:F0}/{GetCrouchThreshold()}"); } } _staminaBase = -1f; _originalSprintSpeed = -1f; LastEnergyCurrent = -1f; Patches.ResetState(); } private void Update() { if ((Object)(object)PlayerAvatar.instance == (Object)null) { return; } bool flag = SemiFunc.RunIsLevel() || SemiFunc.RunIsShop(); if (flag && !_uiRegistered) { Plugin.RegisterLine("runbasedpassives_stats", (Func<string>)BuildDisplayText); _uiRegistered = true; } else if (!flag && _uiRegistered) { Plugin.UnregisterLine("runbasedpassives_stats"); _uiRegistered = false; } if (!flag) { return; } string steamID = GetSteamID(); if (!string.IsNullOrEmpty(steamID)) { JumpLevel = ReadGameDict("playerUpgradeExtraJump", steamID); StrengthLevel = ReadGameDict("playerUpgradeStrength", steamID); StaminaLevel = ReadGameDict("playerUpgradeStamina", steamID); HealthLevel = ReadGameDict("playerUpgradeHealth", steamID); SprintSpeedLevel = ReadGameDict("playerUpgradeSpeed", steamID); CrouchRestoreLevel = ReadGameDict("playerUpgradeCrouchRest", steamID); } if (_staminaBase <= 0f && (Object)(object)PlayerController.instance != (Object)null) { _staminaBase = PlayerController.instance.EnergyStart; } CheckUpgrades(); ApplyStats(); if (verboseLogging.Value) { bool flag2 = (int)CrouchRestoreAmount != _lastLogCrouch; if (JumpCount != _lastLogJump || GrabCount != _lastLogGrab || (int)MoveDistance != (int)_lastLogMove || HealCount != _lastLogHeal || (int)SprintDistance != (int)_lastLogSprint || flag2) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[状态] 跳跃:{JumpCount}/{GetJumpThreshold()} Lv.{JumpLevel} | 力量:{GrabCount}/{GetGrabThreshold()} Lv.{StrengthLevel} | 耐力:{MoveDistance:F0}/{GetMoveThreshold()} Lv.{StaminaLevel} | 生命:{HealCount}/{GetHealThreshold()} Lv.{HealthLevel} | 冲刺:{SprintDistance:F0}/{GetSprintThreshold()} Lv.{SprintSpeedLevel} | 蹲伏:{CrouchRestoreAmount:F0}/{GetCrouchThreshold()} Lv.{CrouchRestoreLevel}"); _lastLogJump = JumpCount; _lastLogGrab = GrabCount; _lastLogMove = MoveDistance; _lastLogHeal = HealCount; _lastLogSprint = SprintDistance; _lastLogCrouch = (int)CrouchRestoreAmount; } } } private int ReadGameDict(string dictName, string sid) { SortedDictionary<string, Dictionary<string, int>> sortedDictionary = dictOfDictsRef.Invoke(StatsManager.instance); if (sortedDictionary != null && sortedDictionary.TryGetValue(dictName, out var value) && value != null && value.TryGetValue(sid, out var value2)) { return value2; } return 0; } private void CheckUpgrades() { string steamID = GetSteamID(); if (string.IsNullOrEmpty(steamID)) { return; } bool flag = false; if (enableJump.Value && JumpCount >= GetJumpThreshold()) { JumpCount -= GetJumpThreshold(); JumpLevel++; StatsManager instance = StatsManager.instance; if (instance != null) { instance.DictionaryUpdateValue("playerUpgradeExtraJump", steamID, JumpLevel); } if (verboseLogging.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[升级] 跳跃升级至 Lv.{JumpLevel}"); } flag = true; } if (enableStrength.Value && GrabCount >= GetGrabThreshold()) { GrabCount -= GetGrabThreshold(); StrengthLevel++; StatsManager instance2 = StatsManager.instance; if (instance2 != null) { instance2.DictionaryUpdateValue("playerUpgradeStrength", steamID, StrengthLevel); } if (verboseLogging.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[升级] 力量升级至 Lv.{StrengthLevel}"); } flag = true; } if (enableStamina.Value && MoveDistance >= GetMoveThreshold()) { MoveDistance -= GetMoveThreshold(); StaminaLevel++; StatsManager instance3 = StatsManager.instance; if (instance3 != null) { instance3.DictionaryUpdateValue("playerUpgradeStamina", steamID, StaminaLevel); } if (verboseLogging.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[升级] 耐力升级至 Lv.{StaminaLevel}"); } flag = true; } if (enableHealth.Value && HealCount >= GetHealThreshold()) { HealCount -= GetHealThreshold(); HealthLevel++; StatsManager instance4 = StatsManager.instance; if (instance4 != null) { instance4.DictionaryUpdateValue("playerUpgradeHealth", steamID, HealthLevel); } if (verboseLogging.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[升级] 生命升级至 Lv.{HealthLevel}"); } flag = true; } if (enableSprintSpeed.Value && SprintDistance >= GetSprintThreshold()) { SprintDistance -= GetSprintThreshold(); SprintSpeedLevel++; StatsManager instance5 = StatsManager.instance; if (instance5 != null) { instance5.DictionaryUpdateValue("playerUpgradeSpeed", steamID, SprintSpeedLevel); } if (verboseLogging.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[升级] 冲刺速度升级至 Lv.{SprintSpeedLevel}"); } flag = true; } if (enableCrouchRestore.Value && CrouchRestoreAmount >= GetCrouchThreshold()) { CrouchRestoreAmount -= GetCrouchThreshold(); CrouchRestoreLevel++; StatsManager instance6 = StatsManager.instance; if (instance6 != null) { instance6.DictionaryUpdateValue("playerUpgradeCrouchRest", steamID, CrouchRestoreLevel); } if (verboseLogging.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"[升级] 蹲伏恢复升级至 Lv.{CrouchRestoreLevel}"); } flag = true; } if (flag && (Object)(object)StatsUI.instance != (Object)null) { StatsUI.instance.Fetch(); } } private void ApplyStats() { PlayerController instance = PlayerController.instance; PlayerAvatar instance2 = PlayerAvatar.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null) { return; } if (enableJump.Value) { jumpExtraRef.Invoke(instance) = JumpLevel; } if (enableStrength.Value) { PhysGrabber physGrabber = instance2.physGrabber; if ((Object)(object)physGrabber != (Object)null) { physGrabber.grabStrength = 1f + (float)StrengthLevel; } } if (enableStamina.Value) { float num = ((_staminaBase > 0f) ? _staminaBase : 100f); instance.EnergyStart = num + (float)(StaminaLevel * 10); if (instance.EnergyCurrent > instance.EnergyStart) { instance.EnergyCurrent = instance.EnergyStart; } } if (enableHealth.Value) { PlayerHealth playerHealth = instance2.playerHealth; if ((Object)(object)playerHealth != (Object)null) { maxHealthRef.Invoke(playerHealth) = 100 + HealthLevel * 20; } } if (enableSprintSpeed.Value) { if (_originalSprintSpeed < 0f) { _originalSprintSpeed = instance.SprintSpeed; } int num2 = SprintSpeedLevel; if (sprintSpeedCap.Value > 0 && num2 > sprintSpeedCap.Value) { num2 = sprintSpeedCap.Value; } instance.SprintSpeed = _originalSprintSpeed + (float)num2 * 1f; } } private string GetSteamID() { PlayerAvatar instance = PlayerAvatar.instance; if ((Object)(object)instance == (Object)null) { return null; } return steamIDRef.Invoke(instance); } private string BuildDisplayText() { StringBuilder stringBuilder = new StringBuilder(); if (enableJump.Value) { stringBuilder.AppendLine($"跳跃 Lv.{JumpLevel} ({JumpCount}/{GetJumpThreshold()})"); } if (enableStrength.Value) { stringBuilder.AppendLine($"力量 Lv.{StrengthLevel} ({GrabCount}/{GetGrabThreshold()})"); } if (enableStamina.Value) { stringBuilder.AppendLine($"耐力 Lv.{StaminaLevel} ({MoveDistance:F0}/{GetMoveThreshold()})"); } if (enableHealth.Value) { stringBuilder.AppendLine($"生命 Lv.{HealthLevel} ({HealCount}/{GetHealThreshold()})"); } if (enableSprintSpeed.Value) { stringBuilder.AppendLine($"冲刺 Lv.{SprintSpeedLevel} ({SprintDistance:F0}/{GetSprintThreshold()})"); } if (enableCrouchRestore.Value) { stringBuilder.AppendLine($"蹲伏 Lv.{CrouchRestoreLevel} ({CrouchRestoreAmount:F0}/{GetCrouchThreshold()})"); } return stringBuilder.ToString().TrimEnd(Array.Empty<char>()); } } public static class Patches { internal static FieldRef<PlayerAvatar, bool> isLocalRef; internal static FieldRef<PlayerAvatar, string> steamIDRef; internal static FieldRef<PlayerHealth, PlayerAvatar> healthPlayerAvatarRef; internal static FieldRef<PlayerAvatar, bool> crouchRestActiveRef; internal static FieldRef<PlayerAvatar, float> crouchRestRef; internal static ManualLogSource pluginLogger; internal static ConfigEntry<bool> verboseLogging; private static Vector3 lastPos; private static Vector3 lastSprintPos; private static bool lastPosInit; private static bool lastSprintPosInit; private static readonly HashSet<int> grabbedThisLevel = new HashSet<int>(); private static bool IsInGameplay => SemiFunc.RunIsLevel() || SemiFunc.RunIsShop(); public static void ResetState() { lastPosInit = (lastSprintPosInit = false); grabbedThisLevel.Clear(); } public static void JumpPrefix(PlayerAvatar __instance) { if (IsInGameplay && isLocalRef.Invoke(__instance)) { Plugin.JumpCount++; } } public static void GrabStartedPostfix(PhysGrabObject __instance) { if (!IsInGameplay || SemiFunc.RunIsShop()) { return; } int instanceID = ((Object)__instance).GetInstanceID(); if (grabbedThisLevel.Contains(instanceID)) { return; } List<PhysGrabber> playerGrabbing = __instance.playerGrabbing; if (playerGrabbing == null) { return; } foreach (PhysGrabber item in playerGrabbing) { if ((Object)(object)item.playerAvatar != (Object)null && isLocalRef.Invoke(item.playerAvatar)) { grabbedThisLevel.Add(instanceID); Plugin.GrabCount++; break; } } } public static void PlayerAvatarUpdatePostfix(PlayerAvatar __instance) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_003c: 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_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: 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_00ad: 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) if (!IsInGameplay || !isLocalRef.Invoke(__instance)) { return; } Vector3 position = ((Component)__instance).transform.position; if (!lastPosInit) { lastPos = position; lastPosInit = true; return; } float num = Vector3.Distance(position, lastPos); Plugin.MoveDistance += num; lastPos = position; if ((Object)(object)PlayerController.instance != (Object)null && PlayerController.instance.sprinting) { if (!lastSprintPosInit) { lastSprintPos = position; lastSprintPosInit = true; return; } float num2 = Vector3.Distance(position, lastSprintPos); Plugin.SprintDistance += num2; } lastSprintPos = position; lastSprintPosInit = true; if (crouchRestActiveRef.Invoke(__instance)) { PlayerController instance = PlayerController.instance; if (!((Object)(object)instance != (Object)null)) { return; } float energyCurrent = instance.EnergyCurrent; if (Plugin.LastEnergyCurrent >= 0f) { float num3 = energyCurrent - Plugin.LastEnergyCurrent; if (num3 > 0f) { Plugin.CrouchRestoreAmount += num3; } } Plugin.LastEnergyCurrent = energyCurrent; } else { Plugin.LastEnergyCurrent = -1f; } } public static void HealPrefix(int healAmount, PlayerHealth __instance) { if (IsInGameplay && !SemiFunc.RunIsShop() && healAmount > 0) { PlayerAvatar val = healthPlayerAvatarRef.Invoke(__instance); if (!((Object)(object)val == (Object)null) && isLocalRef.Invoke(val)) { Plugin.HealCount++; } } } }