Decompiled source of Pathfinder v2.0.11

Pathfinder.dll

Decompiled 5 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Pathfinder")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Crystal")]
[assembly: AssemblyProduct("Pathfinder")]
[assembly: AssemblyCopyright("Copyright © 2023 Crystal Ferrai")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("deb680b1-786f-4e93-8793-25e19b570fef")]
[assembly: AssemblyFileVersion("2.0.11.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("2.0.11.0")]
namespace Pathfinder;

[BepInPlugin("dev.crystal.pathfinder", "Pathfinder", "2.0.11.0")]
[BepInProcess("valheim.exe")]
[BepInProcess("valheim_server.exe")]
public class PathfinderPlugin : BaseUnityPlugin
{
	[HarmonyPatch(typeof(Minimap))]
	private static class Minimap_Patches
	{
		private enum TranspilerState
		{
			Searching,
			Checking,
			Finishing
		}

		[HarmonyPatch("UpdateExplore")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> UpdateExplore_Transpiler(IEnumerable<CodeInstruction> instructions)
		{
			TranspilerState state = TranspilerState.Searching;
			CodeInstruction previous = null;
			foreach (CodeInstruction instruction in instructions)
			{
				switch (state)
				{
				case TranspilerState.Searching:
					if (instruction.opcode == OpCodes.Ldarg_0)
					{
						previous = instruction;
						state = TranspilerState.Checking;
					}
					else
					{
						yield return instruction;
					}
					break;
				case TranspilerState.Checking:
					if (instruction.opcode == OpCodes.Ldfld && ((FieldInfo)instruction.operand).Name == "m_exploreRadius")
					{
						yield return new CodeInstruction(OpCodes.Ldarg_2, (object)null);
						yield return new CodeInstruction(OpCodes.Call, (object)typeof(Minimap_Patches).GetMethod("GetExploreRadius", BindingFlags.Static | BindingFlags.NonPublic));
						state = TranspilerState.Finishing;
					}
					else
					{
						yield return previous;
						yield return instruction;
						state = TranspilerState.Searching;
					}
					previous = null;
					break;
				case TranspilerState.Finishing:
					yield return instruction;
					break;
				}
			}
		}

		private static float GetExploreRadius(Player player)
		{
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			float num;
			if (((Character)player).InInterior())
			{
				num = Mathf.Max(LandExploreRadius.Value * 0.2f, 10f);
				sRadiusHudText.text = $"Pathfinder: radius={num:0.0}";
				return num;
			}
			float num2 = 1f;
			List<Player> list = new List<Player>();
			sGetPlayersInRangeMethod.Invoke(null, new object[3]
			{
				((Component)player).transform.position,
				21f,
				list
			});
			float num3 = ((!list.Any((Player p) => ((Character)p).IsAttachedToShip())) ? LandExploreRadius.Value : SeaExploreRadius.Value);
			float num4 = Mathf.Max(GetColorMagnitude(EnvMan.instance.m_dirLight.color * EnvMan.instance.m_dirLight.intensity), GetColorMagnitude(RenderSettings.ambientLight));
			num2 += (num4 - 1f) * DaylightRadiusScale.Value;
			float num5 = 0f;
			GameObject[] psystems = EnvMan.instance.GetCurrentEnvironment().m_psystems;
			foreach (GameObject obj in psystems)
			{
				if (((Object)obj).name.Equals("Mist", StringComparison.InvariantCultureIgnoreCase))
				{
					num5 += 0.5f;
				}
				if (((Object)obj).name.Equals("SnowStorm", StringComparison.InvariantCultureIgnoreCase))
				{
					num5 += 0.7f * num4;
				}
			}
			float num6 = Mathf.Clamp(RenderSettings.fogDensity * 10f + num5, 0f, 1.5f);
			num2 -= num6 * WeatherRadiusScale.Value;
			float num7 = Mathf.Clamp(((Component)player).transform.position.y - ZoneSystem.instance.m_waterLevel, 0f, 400f) / 100f * Mathf.Max(0.05f, 1f - num5);
			num2 += num7 * AltitudeRadiusBonus.Value;
			float locationModifier = GetLocationModifier(player, num7);
			num2 += locationModifier;
			if (num2 > 5f)
			{
				num2 = 5f;
			}
			if (num2 < 0.2f)
			{
				num2 = 0.2f;
			}
			num = Mathf.Clamp(num3 * num2, 20f, 2000f);
			if (DisplayVariables.Value)
			{
				sVariablesHudText.text = string.Format("Pathfinder Variables\nRadius: {0:0.0}\nBase: {1:0.#}\nMultiplier: {2:0.000}\n\nLight: {3}\nWeather: {4}\nAltitude: {5}\nLocation: {6}", num, num3, num2, ((num4 - 1f) * DaylightRadiusScale.Value).ToString("+0.000;-0.000;0.000"), ((0f - num6) * WeatherRadiusScale.Value).ToString("+0.000;-0.000;0.000"), (num7 * AltitudeRadiusBonus.Value).ToString("+0.000;-0.000;0.000"), locationModifier.ToString("+0.000;-0.000;0.000"));
			}
			if (DisplayCurrentRadiusValue.Value)
			{
				sRadiusHudText.text = $"Pathfinder: radius={num:0.0}";
			}
			return num;
		}

		private static float GetColorMagnitude(Color color)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: 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)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			return Mathf.Sqrt(color.r * color.r + color.g * color.g + color.b * color.b);
		}

		private static float GetLocationModifier(Player player, float altitude)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Invalid comparison between Unknown and I4
			//IL_0053: 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: Invalid comparison between Unknown and I4
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Invalid comparison between Unknown and I4
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			float num = ForestRadiusPenalty.Value + altitude * AltitudeRadiusBonus.Value * ForestRadiusPenalty.Value;
			Biome currentBiome = player.GetCurrentBiome();
			if ((int)currentBiome != 1)
			{
				if ((int)currentBiome != 8)
				{
					if ((int)currentBiome == 16)
					{
						return ((WorldGenerator.GetForestFactor(((Component)player).transform.position) < 0.8f) ? (0f - num) : 0f) + 0.1f * DaylightRadiusScale.Value;
					}
					return 0f;
				}
				return 0f - num - 0.25f * DaylightRadiusScale.Value;
			}
			if (!WorldGenerator.InForest(((Component)player).transform.position))
			{
				return 0f;
			}
			return 0f - num;
		}
	}

	[HarmonyPatch(typeof(Hud))]
	private static class Hud_Patches
	{
		[HarmonyPatch("Awake")]
		[Harmony]
		[HarmonyPostfix]
		private static void Awake_Postfix(Hud __instance)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0018: 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_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Expected O, but got Unknown
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Pathfinder_RadiusText");
			val.AddComponent<CanvasRenderer>();
			val.transform.localPosition = Vector3.zero;
			RectTransform obj = val.AddComponent<RectTransform>();
			((Transform)obj).SetParent(__instance.m_rootObject.transform);
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(0f, 0f);
			obj.anchorMax = val2;
			Vector2 pivot = (obj.anchorMin = val2);
			obj.pivot = pivot;
			obj.offsetMin = new Vector2(10f, 5f);
			obj.offsetMax = new Vector2(210f, 165f);
			sRadiusHudText = val.AddComponent<Text>();
			((Graphic)sRadiusHudText).raycastTarget = false;
			sRadiusHudText.font = Font.CreateDynamicFontFromOSFont(new string[3] { "Segoe UI", "Helvetica", "Arial" }, 12);
			sRadiusHudText.fontStyle = (FontStyle)1;
			((Graphic)sRadiusHudText).color = Color.white;
			sRadiusHudText.fontSize = 12;
			sRadiusHudText.alignment = (TextAnchor)6;
			((Shadow)val.AddComponent<Outline>()).effectColor = Color.black;
			val.SetActive(DisplayCurrentRadiusValue.Value);
			GameObject val4 = new GameObject("Pathfinder_VariableText");
			val4.AddComponent<CanvasRenderer>();
			val4.transform.localPosition = Vector3.zero;
			RectTransform obj2 = val4.AddComponent<RectTransform>();
			((Transform)obj2).SetParent(__instance.m_rootObject.transform);
			((Vector2)(ref val2))..ctor(0f, 0f);
			obj2.anchorMax = val2;
			pivot = (obj2.anchorMin = val2);
			obj2.pivot = pivot;
			obj2.offsetMin = new Vector2(240f, 5f);
			obj2.offsetMax = new Vector2(440f, 165f);
			sVariablesHudText = val4.AddComponent<Text>();
			((Graphic)sVariablesHudText).raycastTarget = false;
			sVariablesHudText.font = Font.CreateDynamicFontFromOSFont(new string[3] { "Segoe UI", "Helvetica", "Arial" }, 12);
			sVariablesHudText.fontStyle = (FontStyle)1;
			((Graphic)sVariablesHudText).color = Color.white;
			sVariablesHudText.fontSize = 12;
			sVariablesHudText.alignment = (TextAnchor)6;
			((Shadow)val4.AddComponent<Outline>()).effectColor = Color.black;
			val4.SetActive(DisplayVariables.Value);
		}
	}

	public const string ModId = "dev.crystal.pathfinder";

	public static ConfigEntry<float> LandExploreRadius;

	public static ConfigEntry<float> SeaExploreRadius;

	public static ConfigEntry<float> AltitudeRadiusBonus;

	public static ConfigEntry<float> ForestRadiusPenalty;

	public static ConfigEntry<float> DaylightRadiusScale;

	public static ConfigEntry<float> WeatherRadiusScale;

	public static ConfigEntry<bool> DisplayCurrentRadiusValue;

	public static ConfigEntry<bool> DisplayVariables;

	private static Harmony sMinimapHarmony;

	private static Harmony sHudHarmony;

	private static Text sRadiusHudText;

	private static Text sVariablesHudText;

	private static readonly MethodInfo sGetPlayersInRangeMethod;

	static PathfinderPlugin()
	{
		sGetPlayersInRangeMethod = typeof(Player).GetMethod("GetPlayersInRange", BindingFlags.Static | BindingFlags.NonPublic);
	}

	private void Awake()
	{
		//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01dc: Expected O, but got Unknown
		//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_01eb: Expected O, but got Unknown
		LandExploreRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Base", "LandExploreRadius", 200f, "The radius around the player to uncover while travelling on land near sea level. Higher values may cause performance issues. Max allowed is 2000. Game default is 100.");
		LandExploreRadius.SettingChanged += Config_SettingChanged;
		SeaExploreRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Base", "SeaExploreRadius", 300f, "The radius around the player to uncover while travelling on a boat. Higher values may cause performance issues. Max allowed is 2000. Game default is 100.");
		SeaExploreRadius.SettingChanged += Config_SettingChanged;
		AltitudeRadiusBonus = ((BaseUnityPlugin)this).Config.Bind<float>("Multipliers", "AltitudeRadiusBonus", 0.5f, "Bonus multiplier to apply to land exploration radius based on altitude. For every 100 units above sea level (smooth scale), add this value multiplied by LandExploreRadius to the total. For example, with a radius of 200 and a multiplier of 0.5, radius is 200 at sea level, 250 at 50 altitude, 300 at 100 altitude, 400 at 200 altitude, etc. For reference, a typical mountain peak is around 170 altitude. Accepted range 0-2. Set to 0 to disable.");
		AltitudeRadiusBonus.SettingChanged += Config_SettingChanged;
		ForestRadiusPenalty = ((BaseUnityPlugin)this).Config.Bind<float>("Multipliers", "ForestRadiusPenalty", 0.3f, "Penalty to apply to land exploration radius when in a forest (black forest, forested parts of meadows and plains). This value is multiplied by the base land exploration radius and subtraced from the total. Accepted range 0-1. Set to 0 to disable.");
		ForestRadiusPenalty.SettingChanged += Config_SettingChanged;
		DaylightRadiusScale = ((BaseUnityPlugin)this).Config.Bind<float>("Multipliers", "DaylightRadiusScale", 0.2f, "Influences how much daylight (directional and ambient light) affects exploration radius. This value is multiplied by the base land or sea exploration radius and added to the total. Accepted range 0-1. Set to 0 to disable.");
		DaylightRadiusScale.SettingChanged += Config_SettingChanged;
		WeatherRadiusScale = ((BaseUnityPlugin)this).Config.Bind<float>("Multipliers", "WeatherRadiusScale", 0.5f, "Influences how much the current weather affects exploration radius. This value is multiplied by the base land or sea exploration radius and added to the total. Accepted range 0-1. Set to 0 to disable.");
		WeatherRadiusScale.SettingChanged += Config_SettingChanged;
		DisplayCurrentRadiusValue = ((BaseUnityPlugin)this).Config.Bind<bool>("Miscellaneous", "DisplayCurrentRadiusValue", false, "Enabling this will display the currently computed exploration radius in the bottom left of the in-game Hud. Useful if you are trying to tweak config values and want to see the result.");
		DisplayCurrentRadiusValue.SettingChanged += DisplayRadiusValue_SettingChanged;
		DisplayVariables = ((BaseUnityPlugin)this).Config.Bind<bool>("Miscellaneous", "DisplayVariables", false, "Enabling this will display on the Hud the values of various variables that go into calculating the exploration radius. Mostly useful for debugging and tweaking the config.");
		DisplayVariables.SettingChanged += DisplayVariablesValue_SettingChanged;
		ClampConfig();
		sMinimapHarmony = new Harmony("dev.crystal.pathfinder_Minimap");
		sHudHarmony = new Harmony("dev.crystal.pathfinder_Hud");
		sMinimapHarmony.PatchAll(typeof(Minimap_Patches));
		sHudHarmony.PatchAll(typeof(Hud_Patches));
	}

	private void Config_SettingChanged(object sender, EventArgs e)
	{
		ClampConfig();
	}

	private void DisplayRadiusValue_SettingChanged(object sender, EventArgs e)
	{
		((Component)sRadiusHudText).gameObject.SetActive(DisplayCurrentRadiusValue.Value);
		if (!DisplayCurrentRadiusValue.Value)
		{
			sRadiusHudText.text = string.Empty;
		}
	}

	private void DisplayVariablesValue_SettingChanged(object sender, EventArgs e)
	{
		((Component)sVariablesHudText).gameObject.SetActive(DisplayVariables.Value);
		if (!DisplayVariables.Value)
		{
			sVariablesHudText.text = string.Empty;
		}
	}

	private void OnDestroy()
	{
		sMinimapHarmony.UnpatchSelf();
		sHudHarmony.UnpatchSelf();
	}

	private static void ClampConfig()
	{
		if (LandExploreRadius.Value < 0f)
		{
			LandExploreRadius.Value = 0f;
		}
		if (LandExploreRadius.Value > 2000f)
		{
			LandExploreRadius.Value = 2000f;
		}
		if (SeaExploreRadius.Value < 0f)
		{
			SeaExploreRadius.Value = 0f;
		}
		if (SeaExploreRadius.Value > 2000f)
		{
			SeaExploreRadius.Value = 2000f;
		}
		if (AltitudeRadiusBonus.Value < 0f)
		{
			AltitudeRadiusBonus.Value = 0f;
		}
		if (AltitudeRadiusBonus.Value > 2f)
		{
			AltitudeRadiusBonus.Value = 2f;
		}
		if (ForestRadiusPenalty.Value < 0f)
		{
			ForestRadiusPenalty.Value = 0f;
		}
		if (ForestRadiusPenalty.Value > 1f)
		{
			ForestRadiusPenalty.Value = 1f;
		}
		if (DaylightRadiusScale.Value < 0f)
		{
			DaylightRadiusScale.Value = 0f;
		}
		if (DaylightRadiusScale.Value > 1f)
		{
			DaylightRadiusScale.Value = 1f;
		}
		if (WeatherRadiusScale.Value < 0f)
		{
			WeatherRadiusScale.Value = 0f;
		}
		if (WeatherRadiusScale.Value > 1f)
		{
			WeatherRadiusScale.Value = 1f;
		}
	}
}