Decompiled source of EilifPaths v1.4.0

EilifPaths.dll

Decompiled 2 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
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.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("EilifPaths")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.4.0.0")]
[assembly: AssemblyInformationalVersion("1.4.0+5a86245ed19a4e0bda8f09872dec10e534468f66")]
[assembly: AssemblyProduct("EilifPaths")]
[assembly: AssemblyTitle("EilifPaths")]
[assembly: AssemblyVersion("1.4.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 EilifPaths
{
	internal static class BedFire
	{
		internal const float DefaultExtraRange = 8f;

		internal static ConfigEntry<float> ExtraRange;

		internal static void Bind(ConfigFile config)
		{
			ExtraRange = config.Bind<float>("Bed", "extraFireRange", 8f, "Extra metres of reach for the bed's \"needs a fire nearby\" check, added on top of the fireplace's own heat area. 0 = vanilla (the bed must sit inside the fire's heat collider, roughly touching it). 8 = the Eilif default, comfortably more than double the vanilla reach. Client-side; it only affects your own bed claims and sleeps.");
		}

		internal static string Describe()
		{
			float num = ((ExtraRange != null) ? ExtraRange.Value : 0f);
			if (!(num <= 0f))
			{
				return "+" + num.ToString("0.##", CultureInfo.InvariantCulture) + "m";
			}
			return "vanilla";
		}
	}
	[HarmonyPatch(typeof(Bed), "CheckFire")]
	internal static class Patch_Bed_CheckFire
	{
		private static bool Prefix(Bed __instance, ref bool __result)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				ConfigEntry<float> extraRange = BedFire.ExtraRange;
				if (extraRange == null)
				{
					return true;
				}
				float value = extraRange.Value;
				if (!(value > 0f))
				{
					return true;
				}
				if ((Object)(object)__instance == (Object)null)
				{
					return true;
				}
				Vector3 position = ((Component)__instance).transform.position;
				EffectArea val = EffectArea.IsPointInsideArea(position, (Type)1, value);
				if (!Object.op_Implicit((Object)(object)val))
				{
					return true;
				}
				LogHit(position, val, value);
				__result = true;
				return false;
			}
			catch (Exception ex)
			{
				try
				{
					if (EilifPathsPlugin.Log != null)
					{
						EilifPathsPlugin.Log.LogWarning((object)("[EilifPaths] bed fire check failed, using vanilla: " + ex.Message));
					}
				}
				catch
				{
				}
				return true;
			}
		}

		private static void LogHit(Vector3 bedPos, EffectArea area, float extra)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (EilifPathsPlugin.Log != null)
				{
					float num = Vector3.Distance(bedPos, ((Component)area).transform.position);
					float radius = area.GetRadius();
					EilifPathsPlugin.Log.LogInfo((object)("[EilifPaths] bed fire check passed with +" + extra.ToString("0.##", CultureInfo.InvariantCulture) + "m: heat source '" + ((Object)area).name + "' at " + num.ToString("0.##", CultureInfo.InvariantCulture) + "m, its own heat radius " + radius.ToString("0.##", CultureInfo.InvariantCulture) + "m."));
				}
			}
			catch
			{
			}
		}
	}
	[BepInPlugin("net.eilif.paths", "Eilif Paths", "1.4.0")]
	public class EilifPathsPlugin : BaseUnityPlugin
	{
		public enum PathType
		{
			None,
			Path,
			PavedRoad,
			Wood,
			Stone,
			Iron,
			HardWood
		}

		public const string PluginGuid = "net.eilif.paths";

		public const string PluginName = "Eilif Paths";

		public const string PluginVersion = "1.4.0";

		private const string OldModGuid = "Menthus.bepinex.plugins.UsefulPaths";

		internal static ManualLogSource Log;

		private const float GroundCheckRate = 0.4f;

		internal static readonly Dictionary<PathType, ConfigEntry<float>> Movement = new Dictionary<PathType, ConfigEntry<float>>();

		internal static readonly Dictionary<PathType, ConfigEntry<float>> StaminaDrain = new Dictionary<PathType, ConfigEntry<float>>();

		internal static readonly Dictionary<PathType, ConfigEntry<float>> ActionStamina = new Dictionary<PathType, ConfigEntry<float>>();

		internal static PathType Current { get; private set; } = PathType.None;

		internal static bool OldModPresent { get; private set; }

		private void BindSurface(PathType type, float move, float stam, float action)
		{
			string text = type.ToString();
			Movement[type] = ((BaseUnityPlugin)this).Config.Bind<float>(text, "movement", move, "Speed multiplier while on " + text + " (1.0 = vanilla, >1 = faster).");
			StaminaDrain[type] = ((BaseUnityPlugin)this).Config.Bind<float>(text, "staminadrain", stam, "Stamina-cost multiplier for ordinary movement while on " + text + ": running, jumping, swimming, dodging, being encumbered (1.0 = vanilla, <1 = drains less).");
			ActionStamina[type] = ((BaseUnityPlugin)this).Config.Bind<float>(text, "actionstamina", action, "Stamina-cost multiplier for tools and weapons while on " + text + ": attacks, blocking, bow draw, building, hoe and cultivator terrain work, repairs, fishing. 1 = vanilla cost, 0 = free.");
		}

		private void Awake()
		{
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			BindSurface(PathType.Path, 1.4f, 0.25f, 1f);
			BindSurface(PathType.PavedRoad, 1.4f, 0.25f, 1f);
			BindSurface(PathType.Wood, 1.4f, 0.25f, 0f);
			BindSurface(PathType.Stone, 1.4f, 0.25f, 0f);
			BindSurface(PathType.Iron, 1.4f, 0.25f, 0f);
			BindSurface(PathType.HardWood, 1.4f, 0.25f, 0f);
			BedFire.Bind(((BaseUnityPlugin)this).Config);
			StationRange.Bind(((BaseUnityPlugin)this).Config);
			OldModPresent = Chainloader.PluginInfos != null && Chainloader.PluginInfos.ContainsKey("Menthus.bepinex.plugins.UsefulPaths");
			if (OldModPresent)
			{
				Log.LogWarning((object)"========================================================================");
				Log.LogWarning((object)"[EilifPaths] The OLD 'Useful_Paths' (Menthus.bepinex.plugins.UsefulPaths)");
				Log.LogWarning((object)"[EilifPaths] mod is ALSO loaded. It is superseded by EilifPaths and its");
				Log.LogWarning((object)"[EilifPaths] path/road detection is broken on current Valheim. To avoid");
				Log.LogWarning((object)"[EilifPaths] DOUBLE-APPLYING bonuses on built floors, EilifPaths is ceding");
				Log.LogWarning((object)"[EilifPaths] Wood/Stone/Iron/HardWood floors to the old mod and handling");
				Log.LogWarning((object)"[EilifPaths] ONLY dirt Path + PavedRoad here. >>> Please DISABLE Useful_Paths");
				Log.LogWarning((object)"[EilifPaths] in the r2modman UI (and re-export the pack) for correct values.");
				Log.LogWarning((object)"========================================================================");
			}
			((MonoBehaviour)this).InvokeRepeating("UpdateGround", 0f, 0.4f);
			Harmony val = new Harmony("net.eilif.paths");
			int num = 0;
			int num2 = 0;
			Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(typeof(EilifPathsPlugin).Assembly);
			foreach (Type type in typesFromAssembly)
			{
				try
				{
					if (type.GetCustomAttributes(typeof(HarmonyPatch), inherit: true).Length != 0)
					{
						num2++;
						val.CreateClassProcessor(type).Patch();
						num++;
					}
				}
				catch (Exception ex)
				{
					Log.LogError((object)("[EilifPaths] could not apply patch class " + ((type != null) ? type.Name : "?") + ": " + ex.Message));
				}
			}
			ToolStamina.Apply(val);
			Log.LogInfo((object)("[EilifPaths] Eilif Paths v1.4.0 loaded. Surfaces (speed / movement stamina / tool stamina): Path x" + F(Movement[PathType.Path]) + "/x" + F(StaminaDrain[PathType.Path]) + "/x" + F(ActionStamina[PathType.Path]) + ", PavedRoad x" + F(Movement[PathType.PavedRoad]) + "/x" + F(StaminaDrain[PathType.PavedRoad]) + "/x" + F(ActionStamina[PathType.PavedRoad]) + ", floors x" + F(Movement[PathType.Wood]) + "/x" + F(StaminaDrain[PathType.Wood]) + "/x" + F(ActionStamina[PathType.Wood]) + ". Polling every " + 0.4f.ToString("0.0", CultureInfo.InvariantCulture) + "s. Bed fire range: " + BedFire.Describe() + ". Workstation attachment range: " + StationRange.Describe() + ". Core patch classes: " + num + "/" + num2 + " applied."));
		}

		private static string F(ConfigEntry<float> c)
		{
			return c.Value.ToString("0.##", CultureInfo.InvariantCulture);
		}

		private void UpdateGround()
		{
			//IL_00a0: 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_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: 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_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_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected I4, but got Unknown
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			ToolStamina.SanityReset();
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				SetCurrent(PathType.None);
				return;
			}
			PathType pathType = PathType.None;
			if (!OldModPresent)
			{
				try
				{
					Collider lastGroundCollider = ((Character)localPlayer).GetLastGroundCollider();
					if ((Object)(object)lastGroundCollider != (Object)null)
					{
						WearNTear componentInParent = ((Component)lastGroundCollider).GetComponentInParent<WearNTear>();
						if ((Object)(object)componentInParent != (Object)null)
						{
							MaterialType materialType = componentInParent.m_materialType;
							switch ((int)materialType)
							{
							case 0:
								pathType = PathType.Wood;
								break;
							case 1:
								pathType = PathType.Stone;
								break;
							case 2:
								pathType = PathType.Iron;
								break;
							case 3:
								pathType = PathType.HardWood;
								break;
							}
						}
					}
				}
				catch (Exception ex)
				{
					Log.LogWarning((object)("[EilifPaths] floor check failed: " + ex.Message));
				}
			}
			if (pathType == PathType.None)
			{
				try
				{
					Vector3 position = ((Component)localPlayer).transform.position;
					Heightmap val = Heightmap.FindHeightmap(position);
					if ((Object)(object)val != (Object)null)
					{
						Vector3 val2 = position;
						val2.x -= 0.5f;
						val2.z -= 0.5f;
						int num = default(int);
						int num2 = default(int);
						val.WorldToVertexMask(val2, ref num, ref num2);
						Color paintMask = val.GetPaintMask(num, num2);
						if (paintMask.b > 0.5f)
						{
							pathType = PathType.PavedRoad;
						}
						else if (paintMask.r > 0.5f)
						{
							pathType = PathType.Path;
						}
					}
				}
				catch (Exception ex2)
				{
					Log.LogWarning((object)("[EilifPaths] paint check failed: " + ex2.Message));
				}
			}
			SetCurrent(pathType);
		}

		private static void SetCurrent(PathType t)
		{
			if (t != Current)
			{
				Current = t;
				if (t == PathType.None)
				{
					Log.LogInfo((object)"[EilifPaths] terrain: None (vanilla speed/stamina)");
					return;
				}
				float value = Movement[t].Value;
				float value2 = StaminaDrain[t].Value;
				float value3 = ActionStamina[t].Value;
				Log.LogInfo((object)(string.Format("[EilifPaths] terrain: {0} (x{1} speed, ", t, value.ToString("0.##", CultureInfo.InvariantCulture)) + "x" + value2.ToString("0.##", CultureInfo.InvariantCulture) + " movement stamina, x" + value3.ToString("0.##", CultureInfo.InvariantCulture) + " tool stamina)"));
			}
		}

		internal static float MoveMult()
		{
			if (Current != PathType.None)
			{
				return Movement[Current].Value;
			}
			return 1f;
		}

		internal static float StamMult()
		{
			if (Current != PathType.None)
			{
				return StaminaDrain[Current].Value;
			}
			return 1f;
		}

		internal static float ActionMult()
		{
			if (Current != PathType.None)
			{
				return ActionStamina[Current].Value;
			}
			return 1f;
		}

		internal static float CostMult()
		{
			if (Current == PathType.None)
			{
				return 1f;
			}
			if (ToolStamina.Active)
			{
				return ActionMult();
			}
			if (ToolStamina.Degraded)
			{
				return Mathf.Max(ActionMult(), StamMult());
			}
			return StamMult();
		}
	}
	[HarmonyPatch(typeof(Player), "GetJogSpeedFactor")]
	internal static class Patch_GetJogSpeedFactor
	{
		private static void Postfix(ref float __result)
		{
			if (EilifPathsPlugin.Current != EilifPathsPlugin.PathType.None)
			{
				__result *= EilifPathsPlugin.MoveMult();
			}
		}
	}
	[HarmonyPatch(typeof(Player), "GetRunSpeedFactor")]
	internal static class Patch_GetRunSpeedFactor
	{
		private static void Postfix(ref float __result)
		{
			if (EilifPathsPlugin.Current != EilifPathsPlugin.PathType.None)
			{
				__result *= EilifPathsPlugin.MoveMult();
			}
		}
	}
	[HarmonyPatch(typeof(Player), "UseStamina")]
	internal static class Patch_UseStamina
	{
		private static void Prefix(Player __instance, ref float v)
		{
			try
			{
				if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && EilifPathsPlugin.Current != EilifPathsPlugin.PathType.None)
				{
					v *= EilifPathsPlugin.CostMult();
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(Character), "UpdateWalking")]
	internal static class Patch_UpdateWalking
	{
		private static void Prefix(Character __instance, out float __state)
		{
			__state = (((Object)(object)__instance != (Object)null) ? __instance.m_walkSpeed : 0f);
			if ((Object)(object)__instance != (Object)null && (Object)(object)__instance == (Object)(object)Player.m_localPlayer && EilifPathsPlugin.Current != EilifPathsPlugin.PathType.None)
			{
				__instance.m_walkSpeed *= EilifPathsPlugin.MoveMult();
			}
		}

		private static void Postfix(Character __instance, float __state)
		{
			if ((Object)(object)__instance != (Object)null)
			{
				__instance.m_walkSpeed = __state;
			}
		}
	}
	internal static class StationRange
	{
		internal const float DefaultExtraRange = 10f;

		internal static ConfigEntry<float> ExtraRange;

		private static readonly HashSet<string> Reported = new HashSet<string>();

		internal static void Bind(ConfigFile config)
		{
			ExtraRange = config.Bind<float>("Workstation", "extraAttachmentRange", 10f, "Extra metres of reach between a crafting station and its upgrades/attachments, for EVERY station (workbench, forge, black forge, galdr table, artisan table, ...). Added on top of each attachment piece's own built-in distance, which is 5 m for most of them, so the default 10 gives about 15 m. Applies to both halves of the rule at once: where the game lets you place the attachment, and whether the station counts it towards its level. 0 = vanilla. Client-side; it only affects your own placement and your own crafting UI.");
		}

		internal static string Describe()
		{
			float v = ((ExtraRange != null) ? ExtraRange.Value : 0f);
			if (!IsActive(v))
			{
				return "vanilla";
			}
			return "+" + v.ToString("0.##", CultureInfo.InvariantCulture) + "m";
		}

		internal static bool IsActive(float v)
		{
			if (v > 0f && !float.IsNaN(v))
			{
				return !float.IsInfinity(v);
			}
			return false;
		}

		internal static void LogOnce(string prefabName, float baseRange, float newRange)
		{
			try
			{
				if (EilifPathsPlugin.Log != null)
				{
					string text = prefabName ?? "?";
					if (!Reported.Contains(text))
					{
						Reported.Add(text);
						EilifPathsPlugin.Log.LogInfo((object)("[EilifPaths] workstation attachment '" + text + "': reach " + baseRange.ToString("0.##", CultureInfo.InvariantCulture) + "m -> " + newRange.ToString("0.##", CultureInfo.InvariantCulture) + "m."));
					}
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(StationExtension), "Awake")]
	internal static class Patch_StationExtension_Awake
	{
		private static void Postfix(StationExtension __instance)
		{
			try
			{
				ConfigEntry<float> extraRange = StationRange.ExtraRange;
				if (extraRange == null)
				{
					return;
				}
				float value = extraRange.Value;
				if (StationRange.IsActive(value) && !((Object)(object)__instance == (Object)null))
				{
					float maxStationDistance = __instance.m_maxStationDistance;
					if (!float.IsNaN(maxStationDistance) && !float.IsInfinity(maxStationDistance))
					{
						StationRange.LogOnce(newRange: __instance.m_maxStationDistance = maxStationDistance + value, prefabName: CleanName(((Object)__instance).name), baseRange: maxStationDistance);
					}
				}
			}
			catch (Exception ex)
			{
				try
				{
					if (EilifPathsPlugin.Log != null)
					{
						EilifPathsPlugin.Log.LogWarning((object)("[EilifPaths] workstation attachment range failed, using vanilla: " + ex.Message));
					}
				}
				catch
				{
				}
			}
		}

		private static string CleanName(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return "?";
			}
			int num = name.IndexOf("(Clone)", StringComparison.Ordinal);
			if (num <= 0)
			{
				return name;
			}
			return name.Substring(0, num);
		}
	}
	internal static class ToolStamina
	{
		private sealed class Site
		{
			internal readonly Type Owner;

			internal readonly string Method;

			internal readonly Type[] Args;

			internal readonly string What;

			internal Site(Type owner, string method, Type[] args, string what)
			{
				Owner = owner;
				Method = method;
				Args = args;
				What = what;
			}

			internal string Label()
			{
				return ((Owner != null) ? Owner.Name : "?") + "." + Method;
			}
		}

		private static int s_depth;

		private static bool s_leakReported;

		internal static bool Active => s_depth > 0;

		internal static bool Degraded { get; private set; }

		private static void ScopePrefix()
		{
			try
			{
				if (s_depth < int.MaxValue)
				{
					s_depth++;
				}
			}
			catch
			{
			}
		}

		private static void ScopeFinalizer()
		{
			try
			{
				if (s_depth > 0)
				{
					s_depth--;
				}
			}
			catch
			{
			}
		}

		internal static void SanityReset()
		{
			if (s_depth == 0)
			{
				return;
			}
			int num = s_depth;
			s_depth = 0;
			if (s_leakReported)
			{
				return;
			}
			s_leakReported = true;
			try
			{
				if (EilifPathsPlugin.Log != null)
				{
					EilifPathsPlugin.Log.LogWarning((object)("[EilifPaths] tool/weapon stamina context was left open (depth " + num + ") and has been reset. Stamina costs are correct again; this notice is logged once."));
				}
			}
			catch
			{
			}
		}

		private static Site[] Sites()
		{
			return new Site[9]
			{
				new Site(typeof(Attack), "Update", new Type[1] { typeof(float) }, "melee and ranged swings"),
				new Site(typeof(Attack), "FireProjectileBurst", new Type[0], "projectile bursts"),
				new Site(typeof(Humanoid), "BlockAttack", new Type[2]
				{
					typeof(HitData),
					typeof(Character)
				}, "blocking and parry"),
				new Site(typeof(Player), "UpdatePlacement", new Type[2]
				{
					typeof(bool),
					typeof(float)
				}, "building, hoe and cultivator, piece removal"),
				new Site(typeof(Player), "Repair", new Type[2]
				{
					typeof(ItemData),
					typeof(Piece)
				}, "repairs"),
				new Site(typeof(Player), "UpdateAttackBowDraw", new Type[2]
				{
					typeof(ItemData),
					typeof(float)
				}, "bow and crossbow draw"),
				new Site(typeof(Player), "UpdateActionQueue", new Type[1] { typeof(float) }, "crossbow reload"),
				new Site(typeof(FishingFloat), "FixedUpdate", new Type[0], "fishing"),
				new Site(typeof(SE_Harpooned), "UpdateStatusEffect", new Type[1] { typeof(float) }, "harpoon drag")
			};
		}

		internal static void Apply(Harmony harmony)
		{
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Expected O, but got Unknown
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Expected O, but got Unknown
			try
			{
				if (harmony == null)
				{
					MarkDegraded("Harmony instance was null");
					return;
				}
				MethodInfo methodInfo = AccessTools.Method(typeof(ToolStamina), "ScopePrefix", (Type[])null, (Type[])null);
				MethodInfo methodInfo2 = AccessTools.Method(typeof(ToolStamina), "ScopeFinalizer", (Type[])null, (Type[])null);
				if (methodInfo == null || methodInfo2 == null)
				{
					MarkDegraded("the patch bodies themselves could not be resolved");
					return;
				}
				int num = 0;
				Site[] array = Sites();
				Site[] array2 = array;
				foreach (Site site in array2)
				{
					try
					{
						MethodBase methodBase = AccessTools.Method(site.Owner, site.Method, site.Args, (Type[])null);
						if (methodBase == null)
						{
							MarkDegraded("could not find " + site.Label() + " (" + site.What + ")");
						}
						else
						{
							harmony.CreateProcessor(methodBase).AddPrefix(new HarmonyMethod(methodInfo)).AddFinalizer(new HarmonyMethod(methodInfo2))
								.Patch();
							num++;
						}
					}
					catch (Exception ex)
					{
						MarkDegraded("could not hook " + site.Label() + " (" + site.What + "): " + ex.Message);
					}
				}
				try
				{
					if (EilifPathsPlugin.Log != null)
					{
						EilifPathsPlugin.Log.LogInfo((object)("[EilifPaths] tool/weapon stamina hooks: " + num + "/" + array.Length + " applied" + (Degraded ? " (DEGRADED - see the errors above)" : "") + "."));
					}
				}
				catch
				{
				}
			}
			catch (Exception ex2)
			{
				MarkDegraded("hook setup failed: " + ex2.Message);
			}
		}

		private static void MarkDegraded(string reason)
		{
			Degraded = true;
			try
			{
				if (EilifPathsPlugin.Log != null)
				{
					EilifPathsPlugin.Log.LogError((object)("[EilifPaths] tool/weapon stamina hook problem: " + reason + ". Falling back to the safer of the two multipliers for charges that can no longer be classified (vanilla cost on paths and roads, 0.25 on built floors)."));
				}
			}
			catch
			{
			}
		}
	}
}