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 CarryWeightSkill v1.0.1
plugins/CarrySkill.dll
Decompiled 2 weeks agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using CarrySkill.Patches; using HarmonyLib; using Jotunn.Configs; using Jotunn.Managers; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("Carry Skill")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Carry Skill")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("e6b72c5a-9fe8-49d7-855e-8165656a6777")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 CarrySkill { [BepInPlugin("shadymods.carryskill.carry_weight", "Carry Weight Skill", "1.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class CarrySkillPlugin : BaseUnityPlugin { public const string PluginGuid = "shadymods.carryskill.carry_weight"; public const string PluginName = "Carry Weight Skill"; public const string PluginVersion = "1.0.1"; public const string SkillIdentifier = "com.shadymods.carryskill.carry_weight_v1"; public static SkillType CarrySkillType { get; private set; } internal static ManualLogSource CarrySkillLog { get; private set; } internal static ConfigEntry<bool> LogXpGain { get; private set; } internal static ConfigEntry<float> XpLogIntervalSeconds { get; private set; } private void Awake() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Expected O, but got Unknown //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0094: 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_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Expected O, but got Unknown //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Expected O, but got Unknown //IL_00c6: Expected O, but got Unknown CarrySkillLog = ((BaseUnityPlugin)this).Logger; LogXpGain = ((BaseUnityPlugin)this).Config.Bind<bool>("Logging", "LogCarryXp", false, "When true, logs carry skill XP gains (accumulator progress), current level, and progress to the next level."); XpLogIntervalSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Logging", "XpLogIntervalSeconds", 1f, "Seconds between XP log lines while training. Use 0 for every physics frame (LogDebug, very verbose)."); CarrySkillType = SkillManager.Instance.AddSkill(new SkillConfig { Identifier = "com.shadymods.carryskill.carry_weight_v1", Name = "Carry Weight", Description = "Gain skill while sprinting or swimming with a heavy load (50%+ of max weight). No XP while over-encumbered. Heavier loads train faster. Each level adds +3 carry weight (up to +300 at level 100).", IncreaseStep = 1f }); Harmony val = new Harmony("shadymods.carryskill.carry_weight"); val.PatchAll(); Game.isModded = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Carry Weight Skill loaded."); TryPatchGetMaxCarryWeight(val); TryPatchUpdateWalking(val); TryPatchSwimming(val); } private static void TryPatchSwimming(Harmony harmony) { //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Expected O, but got Unknown //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Expected O, but got Unknown Type[] array = new Type[2] { typeof(Vector3), typeof(float) }; MethodBase methodBase = AccessTools.DeclaredMethod(typeof(Player), "OnSwimming", array, (Type[])null) ?? AccessTools.DeclaredMethod(typeof(Character), "OnSwimming", array, (Type[])null) ?? AccessTools.DeclaredMethod(typeof(Humanoid), "OnSwimming", array, (Type[])null); if (methodBase != null) { MethodInfo methodInfo = AccessTools.Method(typeof(CarrySkillPatches), "OnSwimming_Postfix", new Type[3] { typeof(Character), typeof(Vector3), typeof(float) }, (Type[])null); if (methodInfo == null) { CarrySkillLog.LogError((object)"CarrySkill: Could not resolve OnSwimming_Postfix — swim carry XP will not apply."); return; } try { harmony.Patch(methodBase, (HarmonyMethod)null, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); return; } catch (Exception ex) { CarrySkillLog.LogError((object)("CarrySkill: Manual OnSwimming patch failed: " + ex)); return; } } MethodInfo methodInfo2 = AccessTools.DeclaredMethod(typeof(Character), "UpdateSwimming", new Type[1] { typeof(float) }, (Type[])null); if (methodInfo2 == null) { CarrySkillLog.LogError((object)"CarrySkill: Could not resolve Player/Character.OnSwimming or Character.UpdateSwimming — swim carry XP will not apply."); return; } MethodInfo methodInfo3 = AccessTools.Method(typeof(CarrySkillPatches), "UpdateSwimming_Postfix", new Type[2] { typeof(Character), typeof(float) }, (Type[])null); if (methodInfo3 == null) { CarrySkillLog.LogError((object)"CarrySkill: Could not resolve UpdateSwimming_Postfix — swim carry XP will not apply."); return; } try { harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(methodInfo3), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } catch (Exception ex2) { CarrySkillLog.LogError((object)("CarrySkill: Manual UpdateSwimming patch failed: " + ex2)); } } private static void TryPatchGetMaxCarryWeight(Harmony harmony) { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(Player), "GetMaxCarryWeight", Type.EmptyTypes, (Type[])null); if (methodInfo == null) { CarrySkillLog.LogError((object)"CarrySkill: Could not resolve Player.GetMaxCarryWeight() — carry weight bonus will not apply."); return; } MethodInfo methodInfo2 = AccessTools.Method(typeof(CarrySkillPatches), "GetMaxCarryWeight_Postfix", new Type[2] { typeof(Player), typeof(float).MakeByRefType() }, (Type[])null); if (methodInfo2 == null) { CarrySkillLog.LogError((object)"CarrySkill: Could not resolve GetMaxCarryWeight_Postfix — carry weight bonus will not apply."); return; } try { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } catch (Exception ex) { CarrySkillLog.LogError((object)("CarrySkill: Manual GetMaxCarryWeight patch failed: " + ex)); } } private static void TryPatchUpdateWalking(Harmony harmony) { //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(Character), "UpdateWalking", new Type[1] { typeof(float) }, (Type[])null); if (methodInfo == null) { CarrySkillLog.LogError((object)"CarrySkill: Could not resolve Character.UpdateWalking(float) — run/sprint carry XP will not apply."); return; } MethodInfo methodInfo2 = AccessTools.Method(typeof(CarrySkillPatches), "UpdateWalking_Postfix", new Type[2] { typeof(Character), typeof(float) }, (Type[])null); if (methodInfo2 == null) { CarrySkillLog.LogError((object)"CarrySkill: Could not resolve UpdateWalking_Postfix — run/sprint carry XP will not apply."); return; } try { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } catch (Exception ex) { CarrySkillLog.LogError((object)("CarrySkill: Manual UpdateWalking patch failed: " + ex)); } } } } namespace CarrySkill.Patches { public static class CarrySkillPatches { private const float MinFill = 0.5f; private const float MaxLerpFill = 1f; private const float SwimVelThreshold = 0.1f; private const float SwimVelThresholdHeavy = 0.001f; private static float _xpAccumForLog; private static float _xpLogWindowStart = -1f; private static float _lastZeroGainWarningTime = -1000f; private static bool _loggedMissingSkillsGetSkill; private static readonly MethodInfo SkillsGetSkill = AccessTools.Method(typeof(Skills), "GetSkill", new Type[1] { typeof(SkillType) }, (Type[])null); internal static void GetMaxCarryWeight_Postfix(Player __instance, ref float __result) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)__instance == (Object)null) && ((Character)__instance).IsPlayer()) { Skills skills = ((Character)__instance).GetSkills(); if (!((Object)(object)skills == (Object)null)) { float skillLevel = skills.GetSkillLevel(CarrySkillPlugin.CarrySkillType); __result += skillLevel * 3f; } } } internal static void UpdateWalking_Postfix(Character __instance, float dt) { if (!(dt <= 0f)) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && !((Character)val).IsDead() && !((Character)val).IsSwimming() && !((Character)val).IsEncumbered() && Traverse.Create((object)__instance).Field("m_running").GetValue<bool>()) { TryApplyRunCarryXp(val, dt, "Run"); } } } internal static void OnSwimming_Postfix(Character __instance, Vector3 targetVel, float dt) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && !((Character)val).IsDead() && !((Character)val).IsEncumbered() && TryGetFill(val, out var fill)) { float num = ((fill >= 0.5f) ? 0.001f : 0.1f); bool flag = ((Vector3)(ref targetVel)).magnitude > num; if (!flag && fill >= 0.5f && TryGetSwimMoveSpeed(val, out var horizontalSpeed)) { flag = horizontalSpeed > num; } if (flag) { TryApplySwimCarryXp(val, dt); } } } internal static void UpdateSwimming_Postfix(Character __instance, float dt) { if (dt <= 0f) { return; } Player val = (Player)(object)((__instance is Player) ? __instance : null); if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && !((Character)val).IsDead() && ((Character)val).IsSwimming() && !((Character)val).IsEncumbered() && TryGetSwimMoveSpeed(val, out var horizontalSpeed)) { float fill; float num = ((TryGetFill(val, out fill) && fill >= 0.5f) ? 0.001f : 0.1f); if (!(horizontalSpeed <= num)) { TryApplySwimCarryXp(val, dt); } } } private static bool TryGetSwimMoveSpeed(Player player, out float horizontalSpeed) { //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) horizontalSpeed = 0f; Rigidbody value = Traverse.Create((object)player).Field("m_body").GetValue<Rigidbody>(); if ((Object)(object)value == (Object)null) { return false; } Vector3 linearVelocity = value.linearVelocity; linearVelocity.y = 0f; horizontalSpeed = ((Vector3)(ref linearVelocity)).magnitude; return true; } private static void TryApplyRunCarryXp(Player player, float dt, string sourceLabel) { Skills skills = ((Character)player).GetSkills(); if (!((Object)(object)skills == (Object)null) && !(dt <= 0f) && TryGetFill(player, out var fill) && !(fill < 0.5f)) { float num = WeightFillMultiplier(fill); float raiseFactor = GetIncreaseStep(skills, (SkillType)102) * num * dt; ApplyCarrySkillXp(player, skills, raiseFactor, sourceLabel); } } private static void TryApplySwimCarryXp(Player player, float dt) { Skills skills = ((Character)player).GetSkills(); if (!((Object)(object)skills == (Object)null) && !(dt <= 0f) && TryGetFill(player, out var fill) && !(fill < 0.5f)) { float num = WeightFillMultiplier(fill); float raiseFactor = GetIncreaseStep(skills, (SkillType)103) * num * dt; ApplyCarrySkillXp(player, skills, raiseFactor, "Swim"); } } private static bool TryGetFill(Player player, out float fill) { fill = 0f; float maxCarryWeight = player.GetMaxCarryWeight(); if (maxCarryWeight <= 0f) { return false; } float totalWeight = ((Humanoid)player).GetInventory().GetTotalWeight(); fill = Mathf.Clamp01(totalWeight / maxCarryWeight); return true; } private static void ApplyCarrySkillXp(Player player, Skills skills, float raiseFactor, string sourceLabel) { //IL_004f: 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) Skill orCreateCarrySkill = GetOrCreateCarrySkill(skills); if (orCreateCarrySkill == null) { if (!_loggedMissingSkillsGetSkill && CarrySkillPlugin.CarrySkillLog != null) { _loggedMissingSkillsGetSkill = true; CarrySkillPlugin.CarrySkillLog.LogError((object)"CarrySkill: Skills.GetSkill reflection failed — carry XP logging may be incomplete."); } ((Character)player).RaiseSkill(CarrySkillPlugin.CarrySkillType, raiseFactor); return; } float nextLevelRequirement = GetNextLevelRequirement(orCreateCarrySkill); float accumulator = orCreateCarrySkill.m_accumulator; float level = orCreateCarrySkill.m_level; ((Character)player).RaiseSkill(CarrySkillPlugin.CarrySkillType, raiseFactor); float num = ComputeAccumulatorGain(accumulator, level, nextLevelRequirement, orCreateCarrySkill.m_accumulator, orCreateCarrySkill.m_level); if (raiseFactor > 1E-08f && num <= 0f && CarrySkillPlugin.CarrySkillLog != null && Time.time - _lastZeroGainWarningTime > 30f) { _lastZeroGainWarningTime = Time.time; CarrySkillPlugin.CarrySkillLog.LogWarning((object)($"CarryWeight: RaiseSkill had no accumulator gain (factor={raiseFactor:E3}). " + "At skill 100, or if a status blocks skill XP, this is normal.")); } LogCarryXpIfEnabled(num, orCreateCarrySkill, sourceLabel); } private static Skill GetOrCreateCarrySkill(Skills skills) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) Skill val = TryGetCarrySkillInstance(skills); if (val != null) { return val; } if (SkillsGetSkill == null) { return null; } object? obj = SkillsGetSkill.Invoke(skills, new object[1] { CarrySkillPlugin.CarrySkillType }); return (Skill)((obj is Skill) ? obj : null); } private static Skill TryGetCarrySkillInstance(Skills skills) { //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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected I4, but got Unknown //IL_0041: 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_0045: 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_005a: 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_0049: 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) Dictionary<SkillType, Skill> value = Traverse.Create((object)skills).Field("m_skillData").GetValue<Dictionary<SkillType, Skill>>(); if (value == null) { return null; } SkillType carrySkillType = CarrySkillPlugin.CarrySkillType; if (value.TryGetValue(carrySkillType, out var value2)) { return value2; } int num = (int)carrySkillType; if (num != 0 && num != int.MinValue) { SkillType val = (SkillType)Math.Abs(num); if (val != carrySkillType && value.TryGetValue(val, out value2)) { return value2; } SkillType val2 = (SkillType)(-num); if (val2 != carrySkillType && value.TryGetValue(val2, out value2)) { return value2; } } return null; } private static float GetNextLevelRequirement(Skill skill) { return Traverse.Create((object)skill).Method("GetNextLevelRequirement", Array.Empty<object>()).GetValue<float>(); } private static float ComputeAccumulatorGain(float accBefore, float levelBefore, float nextReqBefore, float accAfter, float levelAfter) { if (levelAfter > levelBefore) { return nextReqBefore - accBefore + accAfter; } return accAfter - accBefore; } private static void LogCarryXpIfEnabled(float accumulatorGain, Skill skill, string sourceLabel) { if (!CarrySkillPlugin.LogXpGain.Value || CarrySkillPlugin.CarrySkillLog == null || accumulatorGain <= 0f) { return; } float value = CarrySkillPlugin.XpLogIntervalSeconds.Value; float time = Time.time; if (value <= 0f) { WriteXpLogLine(accumulatorGain, skill, sourceLabel, singleFrame: true); return; } if (_xpLogWindowStart < 0f) { _xpLogWindowStart = time; } _xpAccumForLog += accumulatorGain; if (!(time - _xpLogWindowStart < value)) { WriteXpLogLine(_xpAccumForLog, skill, sourceLabel, singleFrame: false); _xpAccumForLog = 0f; _xpLogWindowStart = time; } } private static void WriteXpLogLine(float accumulatorDelta, Skill skill, string sourceLabel, bool singleFrame) { float level = skill.m_level; float nextLevelRequirement = GetNextLevelRequirement(skill); float accumulator = skill.m_accumulator; float num = ((level >= 99.999f) ? 0f : Mathf.Max(0f, nextLevelRequirement - accumulator)); string text = string.Format("{0}: +{1:F4} skill XP (accumulator){2} | ", sourceLabel, accumulatorDelta, singleFrame ? "" : " [sum over interval]") + $"level {level:F2} | {num:F2} until next level"; if (singleFrame) { CarrySkillPlugin.CarrySkillLog.LogDebug((object)text); } else { CarrySkillPlugin.CarrySkillLog.LogInfo((object)text); } } private static float WeightFillMultiplier(float fillClamped01) { if (fillClamped01 >= 1f) { return 2f; } float num = (fillClamped01 - 0.5f) / 0.5f; return Mathf.Lerp(1f, 2f, num); } private static float GetIncreaseStep(Skills skills, SkillType type) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) if (skills?.m_skills == null) { return 1f; } foreach (SkillDef skill in skills.m_skills) { if (skill.m_skill == type) { return skill.m_increseStep; } } return 1f; } } }