Decompiled source of Odins Free Refills v1.0.8

plugins/OdinsFreeRefills.dll

Decompiled 19 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("OdinsFreeRefills")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.8.0")]
[assembly: AssemblyInformationalVersion("1.0.8+f8984ab2d6529ccc7311f8189e16fe631100b357")]
[assembly: AssemblyProduct("OdinsFreeRefills")]
[assembly: AssemblyTitle("OdinsFreeRefills")]
[assembly: AssemblyVersion("1.0.8.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 OdinsFreeRefills
{
	[BepInPlugin("hevyh2o.valheim.odinsfreerefills", "Odin's Free Refills", "1.0.8")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "hevyh2o.valheim.odinsfreerefills";

		public const string Name = "Odin's Free Refills";

		public const string Version = "1.0.8";

		private const string LegacyConfigName = "com.jekkle.valheim.cartursafestamina.cfg";

		internal static ConfigEntry<float> SafeRadius;

		internal static ConfigEntry<bool> AffectSprint;

		internal static ConfigEntry<bool> AffectJump;

		internal static ConfigEntry<bool> AffectBuild;

		internal static ConfigEntry<bool> AffectSwim;

		internal static ConfigEntry<bool> AffectAttacks;

		internal static ConfigEntry<bool> AffectSneak;

		internal static ConfigEntry<string> IgnoredCreatures;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_014c: Expected O, but got Unknown
			bool num = !File.Exists(((BaseUnityPlugin)this).Config.ConfigFilePath);
			SafeRadius = ((BaseUnityPlugin)this).Config.Bind<float>("General", "SafeRadius", 25f, new ConfigDescription("How close (in metres) a hostile creature must be before Odin closes the tab and stamina costs return.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 200f), Array.Empty<object>()));
			AffectSprint = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AffectSprint", true, "Odin covers running. Also keeps the bar topping up while you wall-run.");
			AffectJump = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AffectJump", true, "Odin covers jumping.");
			AffectBuild = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AffectBuild", true, "Odin covers hammer work: placing, repairing and removing pieces.");
			AffectSwim = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AffectSwim", true, "Odin covers swimming, and the bar refills while you're in the water. Heads-up: with an empty bar never reached, you also can't drown when no threat is near.");
			AffectAttacks = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AffectAttacks", true, "Odin covers tool and weapon swings (woodcutting and mining included), and the bar refills mid-swing and mid-dodge.");
			AffectSneak = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AffectSneak", true, "Odin covers crouch-walking.");
			IgnoredCreatures = ((BaseUnityPlugin)this).Config.Bind<string>("General", "IgnoredCreatures", "", "Creatures that should never close the tab, separated by commas. Use the prefab name or the name shown in game. Handy for modded critters flagged hostile that never actually attack.");
			if (num)
			{
				ImportLegacyConfig();
			}
			_harmony = new Harmony("hevyh2o.valheim.odinsfreerefills");
			_harmony.PatchAll(typeof(Plugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Odin's Free Refills 1.0.8 loaded. The mead is on Odin.");
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private void ImportLegacyConfig()
		{
			//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_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Expected O, but got Unknown
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Expected O, but got Unknown
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			//IL_007e: Expected O, but got Unknown
			string text = Path.Combine(Paths.ConfigPath, "com.jekkle.valheim.cartursafestamina.cfg");
			if (File.Exists(text))
			{
				ConfigFile val = new ConfigFile(text, false)
				{
					SaveOnConfigSet = false
				};
				CopyFrom<float>(val, SafeRadius);
				CopyFrom<bool>(val, AffectSprint);
				CopyFrom<bool>(val, AffectJump);
				CopyFrom<bool>(val, AffectBuild);
				CopyFrom<bool>(val, AffectSwim);
				CopyFrom<bool>(val, AffectAttacks);
				CopyFrom<bool>(val, AffectSneak);
				CopyFrom<string>(val, IgnoredCreatures);
				((BaseUnityPlugin)this).Config.Save();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Imported settings from Cartur's Safe Stamina.");
			}
		}

		private static void CopyFrom<T>(ConfigFile legacy, ConfigEntry<T> target)
		{
			ConfigDefinition definition = ((ConfigEntryBase)target).Definition;
			target.Value = legacy.Bind<T>(definition.Section, definition.Key, (T)((ConfigEntryBase)target).DefaultValue, (ConfigDescription)null).Value;
		}
	}
	[HarmonyPatch(typeof(SEMan), "ModifyRunStaminaDrain")]
	internal static class RunDrainPatch
	{
		private static void Postfix(ref float drain, bool minZero, Character ___m_character)
		{
			if (minZero && Plugin.AffectSprint.Value && ThreatRadar.LocalPlayerSafe(___m_character))
			{
				drain = 0f;
			}
		}
	}
	[HarmonyPatch(typeof(SEMan), "ModifyJumpStaminaUsage")]
	internal static class JumpCostPatch
	{
		private static void Postfix(ref float staminaUse, bool minZero, Character ___m_character)
		{
			if (minZero && Plugin.AffectJump.Value && ThreatRadar.LocalPlayerSafe(___m_character))
			{
				staminaUse = 0f;
			}
		}
	}
	[HarmonyPatch(typeof(SEMan), "ModifySwimStaminaUsage")]
	internal static class SwimCostPatch
	{
		private static void Postfix(ref float staminaUse, bool minZero, Character ___m_character)
		{
			if (minZero && Plugin.AffectSwim.Value && ThreatRadar.LocalPlayerSafe(___m_character))
			{
				staminaUse = 0f;
			}
		}
	}
	[HarmonyPatch(typeof(SEMan), "ModifySneakStaminaUsage")]
	internal static class SneakCostPatch
	{
		private static void Postfix(ref float staminaUse, bool minZero, Character ___m_character)
		{
			if (minZero && Plugin.AffectSneak.Value && ThreatRadar.LocalPlayerSafe(___m_character))
			{
				staminaUse = 0f;
			}
		}
	}
	[HarmonyPatch(typeof(Player), "GetBuildStamina")]
	internal static class BuildCostPatch
	{
		private static void Postfix(Player __instance, ref float __result)
		{
			if (Plugin.AffectBuild.Value && ThreatRadar.LocalPlayerSafe((Character)(object)__instance))
			{
				__result = 0f;
			}
		}
	}
	[HarmonyPatch(typeof(Attack), "GetAttackStamina")]
	internal static class AttackCostPatch
	{
		private static void Postfix(ref float __result, Humanoid ___m_character)
		{
			if (__result > 0f && Plugin.AffectAttacks.Value && ThreatRadar.LocalPlayerSafe((Character)(object)___m_character))
			{
				__result = 0f;
			}
		}
	}
	[HarmonyPatch(typeof(Player), "UpdateStats", new Type[] { typeof(float) })]
	internal static class RegenPatch
	{
		private static void Postfix(Player __instance, float dt, ref float ___m_stamina, float ___m_staminaRegenTimer)
		{
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !((Character)__instance).InIntro() && !((Character)__instance).IsTeleporting() && !(___m_staminaRegenTimer > 0f) && VanillaBlockedRegenWeCover(__instance) && ThreatRadar.AllClear(__instance))
			{
				float maxStamina = ((Character)__instance).GetMaxStamina();
				if (!(___m_stamina >= maxStamina))
				{
					float num = __instance.m_staminaRegen + (1f - ___m_stamina / maxStamina) * __instance.m_staminaRegen * __instance.m_staminaRegenTimeMultiplier;
					float num2 = 1f;
					((Character)__instance).GetSEMan().ModifyStaminaRegen(ref num2);
					___m_stamina = Mathf.Min(maxStamina, ___m_stamina + num * num2 * dt * Game.m_staminaRegenRate);
				}
			}
		}

		private static bool VanillaBlockedRegenWeCover(Player p)
		{
			if (((Character)p).IsEncumbered())
			{
				return false;
			}
			if (((Character)p).IsSwimming() && !((Character)p).IsOnGround())
			{
				return Plugin.AffectSwim.Value;
			}
			if (((Character)p).InAttack() || ((Character)p).InDodge())
			{
				return Plugin.AffectAttacks.Value;
			}
			if (((Character)p).IsWallRunning())
			{
				return Plugin.AffectSprint.Value;
			}
			return false;
		}
	}
	internal static class ThreatRadar
	{
		private const float ScanInterval = 0.25f;

		private static float _nextScanTime;

		private static bool _allClear;

		private static string _ignoredSource;

		private static readonly HashSet<string> IgnoredNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		internal static bool LocalPlayerSafe(Character c)
		{
			Player val = (Player)(object)((c is Player) ? c : null);
			if (val != null && (Object)(object)val == (Object)(object)Player.m_localPlayer)
			{
				return AllClear(val);
			}
			return false;
		}

		internal static bool AllClear(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			float time = Time.time;
			if (time < _nextScanTime)
			{
				return _allClear;
			}
			_nextScanTime = time + 0.25f;
			_allClear = !AnyThreatWithin(player, Plugin.SafeRadius.Value);
			return _allClear;
		}

		private static bool AnyThreatWithin(Player player, float radius)
		{
			//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_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			float num = radius * radius;
			Vector3 position = ((Component)player).transform.position;
			foreach (Character allCharacter in Character.GetAllCharacters())
			{
				if (!((Object)(object)allCharacter == (Object)null) && !((Object)(object)allCharacter == (Object)(object)player) && !allCharacter.IsDead())
				{
					Vector3 val = ((Component)allCharacter).transform.position - position;
					if (!(((Vector3)(ref val)).sqrMagnitude > num) && BaseAI.IsEnemy((Character)(object)player, allCharacter) && !IsIgnored(allCharacter))
					{
						return true;
					}
				}
			}
			return false;
		}

		private static bool IsIgnored(Character c)
		{
			RefreshIgnoredNames();
			if (IgnoredNames.Count == 0)
			{
				return false;
			}
			if (IgnoredNames.Contains(Utils.GetPrefabName(((Component)c).gameObject)))
			{
				return true;
			}
			if (Localization.instance != null)
			{
				return IgnoredNames.Contains(Localization.instance.Localize(c.m_name));
			}
			return false;
		}

		private static void RefreshIgnoredNames()
		{
			string text = Plugin.IgnoredCreatures.Value ?? string.Empty;
			if (text == _ignoredSource)
			{
				return;
			}
			_ignoredSource = text;
			IgnoredNames.Clear();
			string[] array = text.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (text2.Length > 0)
				{
					IgnoredNames.Add(text2);
				}
			}
		}
	}
	internal static class BuildInfo
	{
		public const string Version = "1.0.8";
	}
}