Decompiled source of IronShoulders v0.1.0

IronShoulders.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using IronShoulders.Core;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
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: AssemblyCompany("Kastante")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0+2d7713dd322538148341ef632b5e28d42bf116a6")]
[assembly: AssemblyProduct("IronShoulders")]
[assembly: AssemblyTitle("IronShoulders")]
[assembly: AssemblyVersion("0.1.0.0")]
namespace IronShoulders
{
	internal static class GameState
	{
		internal static readonly FieldRef<Skills, Dictionary<SkillType, Skill>> Data = AccessTools.FieldRefAccess<Skills, Dictionary<SkillType, Skill>>("m_skillData");

		internal static void EnsureSkill(Player player)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Expected O, but got Unknown
			if (!Object.op_Implicit((Object)(object)player) || (Object)(object)Plugin.Instance == (Object)null)
			{
				return;
			}
			Skills skills = ((Character)player).GetSkills();
			if (!Object.op_Implicit((Object)(object)skills))
			{
				return;
			}
			Plugin.Instance.UpdateIcon(skills);
			Dictionary<SkillType, Skill> dictionary = Data.Invoke(skills);
			if (!dictionary.ContainsKey(Plugin.Carrying))
			{
				SkillDef val = skills.m_skills.Find((SkillDef def) => def.m_skill == Plugin.Carrying);
				if (val != null)
				{
					dictionary.Add(Plugin.Carrying, new Skill(val));
				}
			}
		}

		internal static float LearnedLevel(Player player)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)player) || !Object.op_Implicit((Object)(object)((Character)player).GetSkills()))
			{
				return 0f;
			}
			if (!Data.Invoke(((Character)player).GetSkills()).TryGetValue(Plugin.Carrying, out var value))
			{
				return 0f;
			}
			return value.m_level;
		}
	}
	[HarmonyPatch(typeof(Skill), "Raise")]
	internal static class CarryingProgression
	{
		private static bool Prefix(Skill __instance, float factor, ref bool __result)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected I4, but got Unknown
			//IL_0063: Expected I4, but got Unknown
			if (!Progression.TryRaise((int)__instance.m_info.m_skill, (int)Plugin.Carrying, ref __instance.m_level, ref __instance.m_accumulator, factor, __instance.m_info.m_increseStep, Plugin.Instance.Tracker.Awarding ? Plugin.Instance.Tracker.AwardWorldMultiplier : Game.m_skillGainRate, out var leveled, Plugin.Instance.Active))
			{
				return true;
			}
			__result = leveled;
			return false;
		}
	}
	[HarmonyPatch(typeof(SEMan), "ModifyRaiseSkill")]
	internal static class IntervalSkillEffects
	{
		private static void Postfix(Character ___m_character, SkillType skill, ref float multiplier)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			MovementTracker tracker = Plugin.Instance.Tracker;
			if (tracker.Awarding && skill == Plugin.Carrying && (Object)(object)___m_character == (Object)(object)Player.m_localPlayer)
			{
				multiplier = tracker.AwardSkillMultiplier;
			}
		}
	}
	[HarmonyPatch(typeof(Player), "OnDeath")]
	internal static class PlayerDied
	{
		private static void Postfix(Player __instance)
		{
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				Plugin.Instance.Tracker.Reset();
			}
		}
	}
	[HarmonyPatch(typeof(Player), "TeleportTo")]
	internal static class PlayerTeleporting
	{
		private static void Prefix(Player __instance)
		{
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				Plugin.Instance.Tracker.Reset();
			}
		}
	}
	[HarmonyPatch(typeof(SEMan), "ModifyMaxCarryWeight")]
	internal static class CarryReward
	{
		private static void Postfix(Character ___m_character, ref float limit)
		{
			Plugin instance = Plugin.Instance;
			Player val = (Player)(object)((___m_character is Player) ? ___m_character : null);
			if (!((Object)(object)instance == (Object)null) && instance.Active && Object.op_Implicit((Object)(object)val))
			{
				double num = (double)limit + instance.Settings.Current.CarryBonus(GameState.LearnedLevel(val));
				if (Balance.Finite(num) && num <= 3.4028234663852886E+38)
				{
					limit = (float)num;
				}
			}
		}
	}
	[HarmonyPatch(typeof(Player), "SetLocalPlayer")]
	internal static class LocalPlayerReady
	{
		private static void Postfix(Player __instance)
		{
			Plugin.Instance.Tracker.Reset();
			GameState.EnsureSkill(__instance);
		}
	}
	[HarmonyPatch(typeof(Skills), "Load")]
	internal static class SkillsLoaded
	{
		private static void Postfix(Skills __instance)
		{
			Player component = ((Component)__instance).GetComponent<Player>();
			if ((Object)(object)component == (Object)(object)Player.m_localPlayer)
			{
				Plugin.Instance.Tracker.Reset();
			}
			GameState.EnsureSkill(component);
		}
	}
	[HarmonyPatch(typeof(SkillsDialog), "Setup")]
	internal static class SkillListReady
	{
		private static void Prefix(Player player)
		{
			GameState.EnsureSkill(player);
		}
	}
	internal sealed class MovementTracker
	{
		private static readonly FieldRef<Character, Rigidbody> Body = AccessTools.FieldRefAccess<Character, Rigidbody>("m_body");

		private static readonly FieldRef<Character, Rigidbody> Ground = AccessTools.FieldRefAccess<Character, Rigidbody>("m_lastGroundBody");

		private static readonly FieldRef<Character, bool> Sliding = AccessTools.FieldRefAccess<Character, bool>("m_sliding");

		private static readonly FieldRef<Character, bool> Slipping = AccessTools.FieldRefAccess<Character, bool>("m_slipping");

		private static readonly FieldRef<Character, bool> IceShoes = AccessTools.FieldRefAccess<Character, bool>("m_iceShoes");

		internal readonly RunStaminaMeter Stamina = new RunStaminaMeter();

		private Player owner;

		private bool sampled;

		private bool inStep;

		private Vector3 position;

		private Vector3 supportLocalPosition;

		private Rigidbody support;

		private float seconds;

		private float weight;

		private float capacity;

		private double expectedDistance;

		private double spent;

		private bool running;

		private bool hadSupport;

		private MotionBlock block;

		private float skillMultiplier;

		private float worldMultiplier;

		internal bool Awarding { get; private set; }

		internal float AwardSkillMultiplier => skillMultiplier;

		internal float AwardWorldMultiplier => worldMultiplier;

		internal static bool LocalOwner(Player player)
		{
			if (!Object.op_Implicit((Object)(object)player) || (Object)(object)player != (Object)(object)Player.m_localPlayer)
			{
				return false;
			}
			ZNetView component = ((Component)player).GetComponent<ZNetView>();
			if (Object.op_Implicit((Object)(object)component) && component.IsValid())
			{
				return component.IsOwner();
			}
			return false;
		}

		private static MotionBlock Block(Player player)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			MotionBlock motionBlock = MotionBlock.None;
			if (!LocalOwner(player))
			{
				motionBlock |= MotionBlock.NotLocalOwner;
			}
			Vector3 moveDir = ((Character)player).GetMoveDir();
			if (((Vector3)(ref moveDir)).magnitude <= 0.1f)
			{
				motionBlock |= MotionBlock.NoInput;
			}
			if (!((Character)player).IsOnGround())
			{
				motionBlock |= MotionBlock.Airborne;
			}
			if (((Character)player).IsEncumbered())
			{
				motionBlock |= MotionBlock.Overloaded;
			}
			if (((Character)player).IsSwimming())
			{
				motionBlock |= MotionBlock.Swimming;
			}
			if (((Character)player).IsFlying())
			{
				motionBlock |= MotionBlock.Flying;
			}
			if (((Character)player).IsRiding())
			{
				motionBlock |= MotionBlock.Riding;
			}
			if (((Character)player).IsAttached())
			{
				motionBlock |= MotionBlock.Attached;
			}
			if (Object.op_Implicit((Object)(object)((Character)player).GetStandingOnShip()) || ((Character)player).IsAttachedToShip())
			{
				motionBlock |= MotionBlock.Ship;
			}
			if (((Character)player).IsKnockedBack() || ((Character)player).IsStaggering())
			{
				motionBlock |= MotionBlock.Knockback;
			}
			if (((Character)player).InDodge())
			{
				motionBlock |= MotionBlock.Dodge;
			}
			if (Sliding.Invoke((Character)(object)player) || (Slipping.Invoke((Character)(object)player) && !IceShoes.Invoke((Character)(object)player)))
			{
				motionBlock |= MotionBlock.Sliding;
			}
			if (((Character)player).IsDead() || ((Character)player).InIntro() || ((Character)player).InCutscene() || ((Character)player).IsTeleporting())
			{
				motionBlock |= MotionBlock.Unavailable;
			}
			if (((Character)player).InAttack())
			{
				motionBlock |= MotionBlock.Attack;
			}
			return motionBlock;
		}

		private static Point Point(Vector3 vector)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			return new Point(vector.x, vector.y, vector.z);
		}

		internal void Begin(Player player)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: 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)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Instance.Active || !LocalOwner(player))
			{
				Reset();
				return;
			}
			if ((Object)(object)owner != (Object)(object)player)
			{
				Reset();
				owner = player;
			}
			MotionBlock end = Block(player);
			if (sampled)
			{
				Vector3 vector = (Object.op_Implicit((Object)(object)support) ? (support.position + support.rotation * supportLocalPosition) : position);
				double distance = Motion.OwnDistance(Point(Body.Invoke((Character)(object)player).position), Point(vector), expectedDistance, block, end, (Object)(object)support == (Object)(object)Ground.Invoke((Character)(object)player) && (!hadSupport || Object.op_Implicit((Object)(object)support)));
				double num = Plugin.Instance.Settings.Current.Experience(seconds, distance, weight, capacity, running, spent);
				if (num > 0.0)
				{
					Awarding = true;
					try
					{
						((Character)player).RaiseSkill(Plugin.Carrying, (float)num);
					}
					finally
					{
						Awarding = false;
					}
				}
			}
			sampled = false;
			inStep = true;
			Stamina.BeginStep(player);
		}

		internal void End(Player player, float dt)
		{
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0133: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			if (!inStep || (Object)(object)owner != (Object)(object)player || !Plugin.Instance.Active || !LocalOwner(player))
			{
				Reset();
				return;
			}
			spent = Stamina.EndStep();
			inStep = false;
			block = Block(player);
			if (block != MotionBlock.None || !Balance.Finite(dt) || dt <= 0f)
			{
				sampled = false;
				return;
			}
			position = Body.Invoke((Character)(object)player).position;
			support = Ground.Invoke((Character)(object)player);
			hadSupport = Object.op_Implicit((Object)(object)support);
			supportLocalPosition = (Object.op_Implicit((Object)(object)support) ? (Quaternion.Inverse(support.rotation) * (position - support.position)) : Vector3.zero);
			Vector3 val = (Object.op_Implicit((Object)(object)support) ? support.GetPointVelocity(position) : Vector3.zero);
			Vector3 val2 = Body.Invoke((Character)(object)player).linearVelocity - val;
			expectedDistance = ((Vector3)(ref val2)).magnitude * dt;
			seconds = dt;
			weight = ((Humanoid)player).GetInventory().GetTotalWeight();
			capacity = player.GetMaxCarryWeight();
			running = ((Character)player).IsRunning();
			if (!running)
			{
				spent = 0.0;
			}
			skillMultiplier = 1f;
			((Character)player).GetSEMan().ModifyRaiseSkill(Plugin.Carrying, ref skillMultiplier);
			worldMultiplier = Game.m_skillGainRate;
			sampled = true;
		}

		internal void Reset()
		{
			owner = null;
			support = null;
			sampled = (inStep = false);
			Awarding = false;
			Stamina.Reset();
		}
	}
	[HarmonyPatch(typeof(Character), "CustomFixedUpdate")]
	internal static class PhysicsStep
	{
		private static void Prefix(Character __instance)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (Object.op_Implicit((Object)(object)val) && (Object)(object)val == (Object)(object)Player.m_localPlayer)
			{
				Plugin.Instance.Tracker.Begin(val);
			}
		}

		private static void Postfix(Character __instance, float dt)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (Object.op_Implicit((Object)(object)val) && (Object)(object)val == (Object)(object)Player.m_localPlayer)
			{
				Plugin.Instance.Tracker.End(val, dt);
			}
		}

		private static Exception Finalizer(Character __instance, Exception __exception)
		{
			if (__exception != null && (Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				Plugin.Instance.Tracker.Reset();
			}
			return __exception;
		}
	}
	[HarmonyPatch(typeof(Player), "CheckRun")]
	internal static class RunningContext
	{
		private static void Prefix(Player __instance, out object __state)
		{
			__state = Plugin.Instance.Tracker.Stamina.EnterRun(__instance);
		}

		private static Exception Finalizer(object __state, Exception __exception)
		{
			Plugin.Instance.Tracker.Stamina.ExitRun(__state);
			return __exception;
		}
	}
	[HarmonyPatch(typeof(Player), "RPC_UseStamina")]
	internal static class StaminaUsed
	{
		private static void Prefix(float ___m_stamina, out float __state)
		{
			__state = ___m_stamina;
		}

		private static void Postfix(Player __instance, float ___m_stamina, float __state)
		{
			Plugin.Instance.Tracker.Stamina.Record(__instance, __state, ___m_stamina);
		}
	}
	[BepInPlugin("kastante.IronShoulders", "IronShoulders", "0.1.0")]
	[BepInDependency("com.jotunn.jotunn", "2.30.2")]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	[SynchronizationMode(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Guid = "kastante.IronShoulders";

		public const string Version = "0.1.0";

		public const string SkillIdentifier = "kastante.IronShoulders.carrying";

		internal static Plugin Instance;

		internal static SkillType Carrying;

		internal readonly ConfigurationState Settings = new ConfigurationState();

		internal readonly MovementTracker Tracker = new MovementTracker();

		private readonly List<ConfigEntry<double>> balanceEntries = new List<ConfigEntry<double>>();

		private ConfigEntry<bool> modEnabled;

		private bool dirty;

		private bool synchronizing;

		private Harmony harmony;

		private SkillConfig skillConfig;

		internal bool Active
		{
			get
			{
				if (modEnabled.Value && Settings.Enabled && !dirty)
				{
					return !synchronizing;
				}
				return false;
			}
		}

		private void Awake()
		{
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Expected O, but got Unknown
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Expected I4, but got Unknown
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Expected I4, but got Unknown
			//IL_0272: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Expected O, but got Unknown
			//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a7: Expected I4, but got Unknown
			Instance = this;
			modEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, Description("Enable training and carry bonus; retain saved skill when disabled."));
			Bind("Progression", "WalkTrainingHours", 35.0, "Active walking hours from level 0 to 100 at full load, without Rested.");
			Bind("Progression", "RunTrainingHours", 25.0, "Active running hours with full stamina bonus, without Rested.");
			Bind("Progression", "MinLoadRatio", 0.3, "No training at or below this fraction of current maximum carry weight.");
			Bind("Progression", "FullLoadRatio", 0.6, "Full training coefficient at this fraction of current maximum carry weight.");
			Bind("Progression", "MovementSpeedForFullXp", 1.0, "Own ground movement speed (m/s) needed to count all active time.");
			Bind("Progression", "StaminaBonusMax", 0.15, "Maximum relative bonus for stamina actually spent running.");
			Bind("Progression", "StaminaPerMeterReference", 1.0, "Running stamina spent per metre for the full stamina bonus.");
			Bind("Reward", "MaxCarryBonus", 150.0, "Additional carry weight at learned level 100, before the world multiplier.");
			((BaseUnityPlugin)this).Config.SettingChanged += SettingsChanged;
			SynchronizationManager.OnSyncingConfiguration += SyncStarting;
			SynchronizationManager.OnConfigurationSynchronized += SyncFinished;
			ApplySettings();
			skillConfig = new SkillConfig
			{
				Identifier = "kastante.IronShoulders.carrying",
				Name = "$ironshoulders_carrying",
				Description = "$ironshoulders_carrying_description",
				IncreaseStep = 1f
			};
			Carrying = SkillManager.Instance.AddSkill(skillConfig);
			if ((int)Carrying == 0)
			{
				throw new InvalidOperationException("Cannot register carrying skill");
			}
			CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
			string text = "English";
			localization.AddTranslation(ref text, new Dictionary<string, string>
			{
				{ "ironshoulders_carrying", "Carrying" },
				{
					"skill_" + (int)Carrying,
					"Carrying"
				},
				{ "ironshoulders_carrying_description", "Increase carry weight by travelling on foot with a load." }
			});
			text = "Russian";
			localization.AddTranslation(ref text, new Dictionary<string, string>
			{
				{ "ironshoulders_carrying", "Переноска" },
				{
					"skill_" + (int)Carrying,
					"Переноска"
				},
				{ "ironshoulders_carrying_description", "Увеличивает грузоподъёмность при передвижении пешком с грузом." }
			});
			harmony = new Harmony("kastante.IronShoulders");
			harmony.PatchAll(typeof(Plugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("IronShoulders 0.1.0; skill=" + (int)Carrying + ". Game acceptance pending."));
		}

		private static ConfigDescription Description(string text)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			return new ConfigDescription(text, (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} });
		}

		private void Bind(string section, string key, double value, string description)
		{
			balanceEntries.Add(((BaseUnityPlugin)this).Config.Bind<double>(section, key, value, Description(description)));
		}

		private void SettingsChanged(object sender, SettingChangedEventArgs args)
		{
			dirty = true;
			Tracker.Reset();
		}

		private void SyncStarting(object sender, SyncingConfigurationEventArgs args)
		{
			synchronizing = true;
			Tracker.Reset();
		}

		private void SyncFinished(object sender, ConfigurationSynchronizationEventArgs args)
		{
			synchronizing = false;
			dirty = true;
			Tracker.Reset();
		}

		private void ApplySettings()
		{
			BalanceInput input = new BalanceInput
			{
				WalkTrainingHours = balanceEntries[0].Value,
				RunTrainingHours = balanceEntries[1].Value,
				MinLoadRatio = balanceEntries[2].Value,
				FullLoadRatio = balanceEntries[3].Value,
				MovementSpeedForFullXp = balanceEntries[4].Value,
				StaminaBonusMax = balanceEntries[5].Value,
				StaminaPerMeterReference = balanceEntries[6].Value,
				MaxCarryBonus = balanceEntries[7].Value
			};
			if (!Settings.Apply(modEnabled.Value, input, out var error))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Rejected balance settings; retaining the last valid snapshot (defaults on first load): " + error));
			}
			dirty = false;
			Tracker.Reset();
		}

		private void Update()
		{
			if (dirty && !synchronizing)
			{
				ApplySettings();
			}
			if (!Active || !Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				Tracker.Reset();
			}
		}

		internal void UpdateIcon(Skills skills)
		{
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			Sprite val = null;
			if (Object.op_Implicit((Object)(object)ObjectDB.instance))
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("BeltStrength");
				ItemDrop val2 = (Object.op_Implicit((Object)(object)itemPrefab) ? itemPrefab.GetComponent<ItemDrop>() : null);
				if (Object.op_Implicit((Object)(object)val2) && val2.m_itemData.m_shared.m_icons != null && val2.m_itemData.m_shared.m_icons.Length != 0)
				{
					val = val2.m_itemData.m_shared.m_icons[0];
				}
			}
			if (!Object.op_Implicit((Object)(object)val))
			{
				SkillDef val3 = skills.m_skills.Find((SkillDef def) => (int)def.m_skill == 102);
				if (val3 != null)
				{
					val = val3.m_icon;
				}
			}
			skillConfig.Icon = val;
			SkillDef val4 = skills.m_skills.Find((SkillDef def) => def.m_skill == Carrying);
			if (val4 != null)
			{
				val4.m_icon = val;
			}
			if (GameState.Data.Invoke(skills).TryGetValue(Carrying, out var value))
			{
				value.m_info.m_icon = val;
			}
		}

		private void OnDestroy()
		{
			((BaseUnityPlugin)this).Config.SettingChanged -= SettingsChanged;
			SynchronizationManager.OnSyncingConfiguration -= SyncStarting;
			SynchronizationManager.OnConfigurationSynchronized -= SyncFinished;
			Tracker.Reset();
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchAll("kastante.IronShoulders");
			}
			if ((Object)(object)Instance == (Object)(object)this)
			{
				Instance = null;
			}
		}
	}
}
namespace IronShoulders.Core
{
	public sealed class BalanceInput
	{
		public double WalkTrainingHours = 35.0;

		public double RunTrainingHours = 25.0;

		public double MinLoadRatio = 0.3;

		public double FullLoadRatio = 0.6;

		public double MovementSpeedForFullXp = 1.0;

		public double StaminaBonusMax = 0.15;

		public double StaminaPerMeterReference = 1.0;

		public double MaxCarryBonus = 150.0;
	}
	public sealed class Balance
	{
		public readonly double WalkTrainingHours;

		public readonly double RunTrainingHours;

		public readonly double MinLoadRatio;

		public readonly double FullLoadRatio;

		public readonly double MovementSpeedForFullXp;

		public readonly double StaminaBonusMax;

		public readonly double StaminaPerMeterReference;

		public readonly double MaxCarryBonus;

		public readonly double BaseXpPerSecond;

		public readonly double RunMultiplier;

		public static Balance Default => new Balance(new BalanceInput());

		private Balance(BalanceInput input)
		{
			WalkTrainingHours = input.WalkTrainingHours;
			RunTrainingHours = input.RunTrainingHours;
			MinLoadRatio = input.MinLoadRatio;
			FullLoadRatio = input.FullLoadRatio;
			MovementSpeedForFullXp = input.MovementSpeedForFullXp;
			StaminaBonusMax = input.StaminaBonusMax;
			StaminaPerMeterReference = input.StaminaPerMeterReference;
			MaxCarryBonus = input.MaxCarryBonus;
			BaseXpPerSecond = Progression.TotalCost / (WalkTrainingHours * 3600.0);
			RunMultiplier = WalkTrainingHours / (RunTrainingHours * (1.0 + StaminaBonusMax));
		}

		public static bool Finite(double value)
		{
			if (!double.IsNaN(value))
			{
				return !double.IsInfinity(value);
			}
			return false;
		}

		private static bool Positive(double value)
		{
			if (Finite(value))
			{
				return value > 0.0;
			}
			return false;
		}

		public static bool TryCreate(BalanceInput input, out Balance result, out string error)
		{
			result = null;
			error = null;
			if (input == null)
			{
				error = "Missing balance settings";
			}
			else if (!Positive(input.WalkTrainingHours * 3600.0) || !Positive(input.RunTrainingHours * 3600.0))
			{
				error = "Training hours must be finite and positive";
			}
			else if (!Finite(input.MinLoadRatio) || !Finite(input.FullLoadRatio) || input.MinLoadRatio < 0.0 || input.MinLoadRatio >= input.FullLoadRatio || input.FullLoadRatio > 1.0)
			{
				error = "Load ratios must satisfy 0 <= MinLoadRatio < FullLoadRatio <= 1";
			}
			else if (!Positive(input.MovementSpeedForFullXp) || !Positive(input.StaminaPerMeterReference))
			{
				error = "Movement speed and stamina reference must be finite and positive";
			}
			else if (!Finite(input.StaminaBonusMax) || input.StaminaBonusMax < 0.0 || !Finite(input.MaxCarryBonus) || input.MaxCarryBonus < 0.0 || input.MaxCarryBonus > 1.7014117331926443E+38)
			{
				error = "Bonuses must be finite, nonnegative and representable by the game";
			}
			else if (!Positive(input.RunTrainingHours * (1.0 + input.StaminaBonusMax)) || input.WalkTrainingHours < input.RunTrainingHours * (1.0 + input.StaminaBonusMax))
			{
				error = "WalkTrainingHours must be >= RunTrainingHours * (1 + StaminaBonusMax)";
			}
			if (error != null)
			{
				return false;
			}
			Balance balance = new Balance(input);
			if (!Positive(balance.BaseXpPerSecond) || !Positive(balance.RunMultiplier) || balance.BaseXpPerSecond * balance.RunMultiplier * (1.0 + balance.StaminaBonusMax) > 3.4028234663852886E+38 || balance.BaseXpPerSecond > 3.4028234663852886E+38)
			{
				error = "Derived experience rate is outside the supported range";
				return false;
			}
			result = balance;
			return true;
		}

		public double LoadFactor(double weight, double capacity)
		{
			if (!Finite(weight) || !Positive(capacity) || weight < 0.0 || weight > capacity)
			{
				return 0.0;
			}
			return Clamp01((weight / capacity - MinLoadRatio) / (FullLoadRatio - MinLoadRatio));
		}

		public double Experience(double seconds, double distance, double weight, double capacity, bool running, double stamina)
		{
			if (!Positive(seconds) || !Positive(distance))
			{
				return 0.0;
			}
			double num = Math.Min(seconds, distance / MovementSpeedForFullXp);
			double num2 = ((running && Finite(stamina) && stamina > 0.0) ? (1.0 + StaminaBonusMax * Clamp01(stamina / distance / StaminaPerMeterReference)) : 1.0);
			double num3 = BaseXpPerSecond * num * LoadFactor(weight, capacity) * (running ? RunMultiplier : 1.0) * num2;
			if (!Finite(num3) || !(num3 > 0.0) || !(num3 <= 3.4028234663852886E+38))
			{
				return 0.0;
			}
			return num3;
		}

		public double CarryBonus(double learnedLevel)
		{
			if (!Finite(learnedLevel))
			{
				return 0.0;
			}
			return MaxCarryBonus * Clamp01(learnedLevel / 100.0);
		}

		public static double Clamp01(double value)
		{
			return Math.Max(0.0, Math.Min(1.0, value));
		}
	}
	public sealed class ConfigurationState
	{
		public Balance Current { get; private set; } = Balance.Default;

		public bool Enabled { get; private set; } = true;

		public bool Apply(bool enabled, BalanceInput input, out string error)
		{
			Enabled = enabled;
			if (!Balance.TryCreate(input, out var result, out error))
			{
				return false;
			}
			Current = result;
			return true;
		}
	}
	[Flags]
	public enum MotionBlock
	{
		None = 0,
		NotLocalOwner = 1,
		NoInput = 2,
		Airborne = 4,
		Overloaded = 8,
		Swimming = 0x10,
		Flying = 0x20,
		Riding = 0x40,
		Attached = 0x80,
		Ship = 0x100,
		Knockback = 0x200,
		Dodge = 0x400,
		Sliding = 0x800,
		Unavailable = 0x1000,
		Attack = 0x2000
	}
	public struct Point
	{
		public readonly double X;

		public readonly double Y;

		public readonly double Z;

		public Point(double x, double y, double z)
		{
			X = x;
			Y = y;
			Z = z;
		}

		public static double Distance(Point a, Point b)
		{
			double num = a.X - b.X;
			double num2 = a.Y - b.Y;
			double num3 = a.Z - b.Z;
			return Math.Sqrt(num * num + num2 * num2 + num3 * num3);
		}
	}
	public static class Motion
	{
		public static double OwnDistance(Point current, Point carriedStart, double expectedDistance, MotionBlock start, MotionBlock end, bool sameSupport)
		{
			if (start != MotionBlock.None || end != MotionBlock.None || !sameSupport || !Balance.Finite(expectedDistance) || expectedDistance < 0.0)
			{
				return 0.0;
			}
			double num = Point.Distance(current, carriedStart);
			double num2 = Math.Max(0.25, expectedDistance * 3.0);
			if (!Balance.Finite(num) || !(num <= num2))
			{
				return 0.0;
			}
			return num;
		}
	}
	public sealed class RunStaminaMeter
	{
		private object actor;

		private object context;

		private bool active;

		private double spent;

		public void BeginStep(object owner)
		{
			Reset();
			actor = owner;
			active = true;
		}

		public object EnterRun(object owner)
		{
			object result = context;
			context = owner;
			return result;
		}

		public void ExitRun(object previous)
		{
			context = previous;
		}

		public void Record(object owner, double before, double after)
		{
			if (active && actor == owner && context == owner && Balance.Finite(before) && Balance.Finite(after) && before > after)
			{
				spent += Math.Max(0.0, before) - Math.Max(0.0, after);
			}
		}

		public double EndStep()
		{
			double result = spent;
			Reset();
			return result;
		}

		public void Reset()
		{
			active = false;
			actor = (context = null);
			spent = 0.0;
		}
	}
	public static class Progression
	{
		public static readonly double TotalCost = SumCost();

		public static double Cost(double level)
		{
			return 0.5 * Math.Pow(Math.Floor(level + 1.0), 1.5) + 0.5;
		}

		private static double SumCost()
		{
			double num = 0.0;
			for (int i = 0; i < 100; i++)
			{
				num += Cost(i);
			}
			return num;
		}

		public static bool TryRaise(int skill, int carryingSkill, ref float level, ref float accumulator, double factor, double increaseStep, double worldMultiplier, out bool leveled, bool enabled = true)
		{
			leveled = false;
			if (skill != carryingSkill)
			{
				return false;
			}
			if (!enabled)
			{
				return true;
			}
			double num = factor * increaseStep * worldMultiplier;
			if (!Balance.Finite(num) || num <= 0.0)
			{
				return true;
			}
			if (!Balance.Finite(level) || level < 0f)
			{
				level = 0f;
			}
			if (level >= 100f)
			{
				level = 100f;
				accumulator = 0f;
				return true;
			}
			double num2 = ((Balance.Finite(accumulator) && accumulator > 0f) ? accumulator : 0f);
			num2 += num;
			while (level < 100f && num2 >= Cost(level))
			{
				num2 -= Cost(level);
				level = Math.Min(100f, level + 1f);
				leveled = true;
			}
			accumulator = ((level >= 100f) ? 0f : ((float)num2));
			return true;
		}
	}
}