Decompiled source of AnActualCartographer v1.2.1

AnActualCartographer.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
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(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("AnActualCartographer")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Use a cartography table and the map fog lifts 5x further as you explore. Configurable.")]
[assembly: AssemblyFileVersion("1.2.1.0")]
[assembly: AssemblyInformationalVersion("1.2.1+8eb0aedda7691ecd76f81201a62d1512fb4812be")]
[assembly: AssemblyProduct("AnActualCartographer")]
[assembly: AssemblyTitle("AnActualCartographer")]
[assembly: AssemblyVersion("1.2.1.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 AnActualCartographer
{
	internal static class CartographyState
	{
		private const string KeyPrefix = "AnActualCartographer.unlocked.";

		private static Minimap _capturedFrom;

		private static float _baseRadius;

		private static Player _cachedPlayer;

		private static long _cachedWorldUid;

		private static bool _cachedUnlocked;

		private static float _lastApplied = -1f;

		internal static bool IsWidening { get; private set; }

		internal static void ApplyTo(Minimap minimap, Player player)
		{
			if (!((Object)(object)minimap == (Object)null))
			{
				float num = BaseRadiusFor(minimap);
				bool flag = (IsWidening = ModConfig.Enabled.Value && IsUnlocked(player));
				float num2 = (minimap.m_exploreRadius = (flag ? Widen(minimap, num, ModConfig.ExploreRadiusMultiplier.Value) : num));
				if (ModConfig.VerboseLogging.Value && !Mathf.Approximately(num2, _lastApplied))
				{
					Plugin.Log.LogInfo((object)$"Explore radius {num2}m (vanilla {num}m, widened={flag}).");
				}
				_lastApplied = num2;
			}
		}

		private static float Widen(Minimap minimap, float baseRadius, float multiplier)
		{
			float pixelSize = minimap.m_pixelSize;
			if (pixelSize <= 0f)
			{
				return baseRadius * multiplier;
			}
			int num = Mathf.Max(1, Mathf.CeilToInt(baseRadius / pixelSize));
			int num2 = Mathf.RoundToInt((float)num * multiplier);
			int num3 = Mathf.Max(num, minimap.m_textureSize);
			return (float)Mathf.Clamp(num2, num, num3) * pixelSize;
		}

		internal static bool Unlock(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			long num = CurrentWorldUid();
			if (num == 0L)
			{
				return false;
			}
			string key = KeyFor(num);
			if (player.m_customData.ContainsKey(key))
			{
				return false;
			}
			player.m_customData[key] = "1";
			InvalidateCache();
			if (ModConfig.VerboseLogging.Value)
			{
				Plugin.Log.LogInfo((object)$"Cartography unlocked for world {num}.");
			}
			return true;
		}

		internal static bool IsUnlocked(Player player)
		{
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			long num = CurrentWorldUid();
			if (num == 0L)
			{
				return false;
			}
			if (_cachedPlayer == player && _cachedWorldUid == num)
			{
				return _cachedUnlocked;
			}
			_cachedPlayer = player;
			_cachedWorldUid = num;
			_cachedUnlocked = player.m_customData.ContainsKey(KeyFor(num));
			return _cachedUnlocked;
		}

		private static float BaseRadiusFor(Minimap minimap)
		{
			if (_capturedFrom != minimap)
			{
				_capturedFrom = minimap;
				_baseRadius = minimap.m_exploreRadius;
				_lastApplied = -1f;
				InvalidateCache();
			}
			return _baseRadius;
		}

		private static string KeyFor(long worldUid)
		{
			return "AnActualCartographer.unlocked." + worldUid.ToString(CultureInfo.InvariantCulture);
		}

		private static long CurrentWorldUid()
		{
			ZNet instance = ZNet.instance;
			if ((Object)(object)instance == (Object)null || ZNet.World == null)
			{
				return 0L;
			}
			return instance.GetWorldUID();
		}

		private static void InvalidateCache()
		{
			_cachedPlayer = null;
			_cachedWorldUid = 0L;
			_cachedUnlocked = false;
			ExploreSkip.Invalidate();
		}
	}
	internal static class ExploreSkip
	{
		private static FieldRef<Minimap, BitArray> _exploredRef;

		private static bool _resolved;

		private static int _lastPx = int.MinValue;

		private static int _lastPy = int.MinValue;

		private static int _lastNum = -1;

		internal static void Invalidate()
		{
			_lastPx = int.MinValue;
			_lastPy = int.MinValue;
			_lastNum = -1;
		}

		internal static bool CanSkip(Minimap minimap, Vector3 p, float radius)
		{
			//IL_0044: 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)
			if ((Object)(object)minimap == (Object)null)
			{
				return false;
			}
			if (!CartographyState.IsWidening)
			{
				return false;
			}
			BitArray bitArray = Explored(minimap);
			if (bitArray == null)
			{
				return false;
			}
			float pixelSize = minimap.m_pixelSize;
			if (pixelSize <= 0f)
			{
				return false;
			}
			int num = (int)Mathf.Ceil(radius / pixelSize);
			int num2 = minimap.m_textureSize / 2;
			int num3 = Utils.RoundToInt(p.x / pixelSize + (float)num2);
			int num4 = Utils.RoundToInt(p.z / pixelSize + (float)num2);
			bool num5 = num3 == _lastPx && num4 == _lastPy && num == _lastNum;
			_lastPx = num3;
			_lastPy = num4;
			_lastNum = num;
			if (!num5)
			{
				return false;
			}
			int num6 = num4 * minimap.m_textureSize + num3;
			if (num6 < 0 || num6 >= bitArray.Length)
			{
				return false;
			}
			return bitArray[num6];
		}

		private static BitArray Explored(Minimap minimap)
		{
			if (!_resolved)
			{
				_resolved = true;
				try
				{
					_exploredRef = AccessTools.FieldRefAccess<Minimap, BitArray>("m_explored");
				}
				catch (Exception ex)
				{
					_exploredRef = null;
					Plugin.Log.LogWarning((object)("Minimap.m_explored not found (" + ex.GetType().Name + "); explore-skip disabled, the map still works but large radii will cost more."));
				}
			}
			FieldRef<Minimap, BitArray> exploredRef = _exploredRef;
			if (exploredRef == null)
			{
				return null;
			}
			return exploredRef.Invoke(minimap);
		}
	}
	internal static class ModConfig
	{
		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<float> ExploreRadiusMultiplier;

		internal static ConfigEntry<bool> ShowUnlockMessage;

		internal static ConfigEntry<string> UnlockMessage;

		internal static ConfigEntry<bool> VerboseLogging;

		internal static void Bind(ConfigFile config)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Expected O, but got Unknown
			Enabled = config.Bind<bool>("Cartography Table", "Enabled", true, "Widen the fog-lifting radius once you have used a cartography table in this world. Turn this off to play vanilla without uninstalling: while off the mod is inert, and will not widen anything, announce anything, or record a new unlock. An unlock already earned is kept and takes effect again when you turn this back on.");
			ExploreRadiusMultiplier = config.Bind<float>("Cartography Table", "ExploreRadiusMultiplier", 5f, new ConfigDescription("How much further the fog lifts once the table has been used. 5 means five times as far as vanilla, so the 128m the fog normally clears becomes 640m. Counted in whole fog-map pixels, which is how the game explores, so the multiplier lands on the distance you actually watch clear.\nCapped at 10. The game re-walks the whole circle every 2 seconds, and the cost grows with the square of this number: 10 is about 1,700 cells a tick, 30 was about 15,000 and showed up as a hitch every 2 seconds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>()));
			ShowUnlockMessage = config.Bind<bool>("Cartography Table", "ShowUnlockMessage", true, "Show a centre-screen message the first time you use a table in a world. Shown once per world, not on every use.");
			UnlockMessage = config.Bind<string>("Cartography Table", "UnlockMessage", "You read the land with a cartographer's eye", "Text for that message.");
			VerboseLogging = config.Bind<bool>("Advanced", "VerboseLogging", false, "Log the unlock and the resulting explore radius to the BepInEx console.");
		}
	}
	[BepInPlugin("com.ljindustries.valheim.anactualcartographer", "AnActualCartographer", "1.2.1")]
	public class Plugin : BaseUnityPlugin
	{
		public const string ModGuid = "com.ljindustries.valheim.anactualcartographer";

		public const string ModName = "AnActualCartographer";

		public const string ModVersion = "1.2.1";

		internal static ManualLogSource Log;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ModConfig.Bind(((BaseUnityPlugin)this).Config);
			_harmony = new Harmony("com.ljindustries.valheim.anactualcartographer");
			Type[] types = typeof(Plugin).Assembly.GetTypes();
			foreach (Type type in types)
			{
				try
				{
					_harmony.CreateClassProcessor(type).Patch();
				}
				catch (Exception ex)
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("Harmony skip " + type.FullName + ": " + ex.GetType().Name + ": " + ex.Message));
				}
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
}
namespace AnActualCartographer.Patches
{
	internal static class MapTableUse
	{
		internal static void Handle(Humanoid user, ItemData item)
		{
			if (ModConfig.Enabled.Value && item == null)
			{
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)user != (Object)(object)localPlayer) && CartographyState.Unlock(localPlayer) && ModConfig.ShowUnlockMessage.Value)
				{
					((Character)localPlayer).Message((MessageType)2, ModConfig.UnlockMessage.Value, 0, (Sprite)null, false);
				}
			}
		}
	}
	[HarmonyPatch(typeof(MapTable), "OnRead", new Type[]
	{
		typeof(Switch),
		typeof(Humanoid),
		typeof(ItemData)
	})]
	internal static class MapTableReadPatch
	{
		private static void Postfix(Humanoid user, ItemData item)
		{
			MapTableUse.Handle(user, item);
		}
	}
	[HarmonyPatch(typeof(MapTable), "OnWrite", new Type[]
	{
		typeof(Switch),
		typeof(Humanoid),
		typeof(ItemData)
	})]
	internal static class MapTableWritePatch
	{
		private static void Postfix(Humanoid user, ItemData item)
		{
			MapTableUse.Handle(user, item);
		}
	}
	[HarmonyPatch(typeof(Minimap), "Explore", new Type[]
	{
		typeof(Vector3),
		typeof(float)
	})]
	internal static class MinimapExplorePatch
	{
		private static bool Prefix(Minimap __instance, Vector3 p, float radius)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return !ExploreSkip.CanSkip(__instance, p, radius);
		}
	}
	[HarmonyPatch(typeof(Minimap), "UpdateExplore", new Type[]
	{
		typeof(float),
		typeof(Player)
	})]
	internal static class MinimapUpdateExplorePatch
	{
		private static void Prefix(Minimap __instance, Player player)
		{
			CartographyState.ApplyTo(__instance, player);
		}
	}
}