Decompiled source of MapTeleport v1.0.0

Landoria.MapTeleport.dll

Decompiled a day ago
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Threading;
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: AssemblyTitle("Landoria.MapTeleport")]
[assembly: AssemblyDescription("Teleport by modifier-clicking the Valheim map.")]
[assembly: AssemblyCompany("Landoria")]
[assembly: AssemblyProduct("Landoria.MapTeleport")]
[assembly: ComVisible(false)]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.24120")]
[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 Landoria.MapTeleport
{
	internal static class ConfigWatcher
	{
		private const int ReloadDelayMilliseconds = 250;

		private const int MaximumReloadAttempts = 5;

		private static ConfigFile config;

		private static string configPath;

		private static ManualLogSource logger;

		private static FileSystemWatcher watcher;

		private static long lastChangeTicks;

		private static int reloadPending;

		private static int reloadAttempts;

		private static long ignoredWriteTicks;

		private static string displayName;

		private static Action restoreDefaults;

		private static Action applyConfiguration;

		internal static void Initialize(ConfigFile configFile, ManualLogSource logSource, string configurationDisplayName, Action restoreDefaultsAction, Action applyConfigurationAction = null)
		{
			Dispose();
			config = configFile;
			logger = logSource;
			displayName = configurationDisplayName;
			restoreDefaults = restoreDefaultsAction;
			applyConfiguration = applyConfigurationAction;
			configPath = Path.GetFullPath(config.ConfigFilePath);
			watcher = new FileSystemWatcher(Path.GetDirectoryName(configPath), Path.GetFileName(configPath));
			watcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.CreationTime;
			watcher.Changed += OnChanged;
			watcher.Created += OnChanged;
			watcher.Deleted += OnChanged;
			watcher.Renamed += OnRenamed;
			watcher.EnableRaisingEvents = true;
		}

		internal static void IgnoreCurrentFileVersion()
		{
			if (string.IsNullOrEmpty(configPath) || !File.Exists(configPath))
			{
				return;
			}
			try
			{
				Interlocked.Exchange(ref ignoredWriteTicks, File.GetLastWriteTimeUtc(configPath).Ticks);
				Interlocked.Exchange(ref reloadPending, 0);
			}
			catch (IOException)
			{
				ManualLogSource obj = logger;
				if (obj != null)
				{
					obj.LogDebug((object)"Could not mark the internal configuration write.");
				}
			}
		}

		internal static void Update()
		{
			if (Volatile.Read(in reloadPending) == 0 || !ReloadDelayElapsed())
			{
				return;
			}
			Interlocked.Exchange(ref reloadPending, 0);
			try
			{
				bool flag = !File.Exists(configPath);
				if (flag)
				{
					restoreDefaults?.Invoke();
				}
				else
				{
					config.Reload();
				}
				applyConfiguration?.Invoke();
				reloadAttempts = 0;
				logger.LogInfo((object)(flag ? "Recreated the deleted configuration with default values." : "Reloaded configuration after a file change."));
				ShowReloadMessage(flag);
			}
			catch (Exception exception)
			{
				RetryReload(exception);
			}
		}

		internal static void Dispose()
		{
			if (watcher != null)
			{
				watcher.EnableRaisingEvents = false;
				watcher.Dispose();
				watcher = null;
			}
			Interlocked.Exchange(ref reloadPending, 0);
			Interlocked.Exchange(ref ignoredWriteTicks, 0L);
			reloadAttempts = 0;
			displayName = null;
			restoreDefaults = null;
			applyConfiguration = null;
		}

		private static void OnChanged(object sender, FileSystemEventArgs eventArgs)
		{
			QueueReload();
		}

		private static void OnRenamed(object sender, RenamedEventArgs eventArgs)
		{
			QueueReload();
		}

		private static void QueueReload()
		{
			if (!IsIgnoredWrite())
			{
				Interlocked.Exchange(ref lastChangeTicks, DateTime.UtcNow.Ticks);
				Interlocked.Exchange(ref reloadPending, 1);
				reloadAttempts = 0;
			}
		}

		private static bool IsIgnoredWrite()
		{
			try
			{
				long num = (File.Exists(configPath) ? File.GetLastWriteTimeUtc(configPath).Ticks : 0);
				return num != 0L && num == Interlocked.Read(in ignoredWriteTicks);
			}
			catch (IOException)
			{
				return false;
			}
		}

		private static bool ReloadDelayElapsed()
		{
			return DateTime.UtcNow.Ticks - Interlocked.Read(in lastChangeTicks) >= 2500000;
		}

		private static void RetryReload(Exception exception)
		{
			reloadAttempts++;
			logger.LogWarning((object)("Configuration reload failed: " + exception.Message));
			if (reloadAttempts < 5)
			{
				Interlocked.Exchange(ref lastChangeTicks, DateTime.UtcNow.Ticks);
				Interlocked.Exchange(ref reloadPending, 1);
			}
		}

		private static void ShowReloadMessage(bool recreated)
		{
			Player localPlayer = Player.m_localPlayer;
			if (localPlayer != null)
			{
				((Character)localPlayer).Message((MessageType)1, recreated ? (displayName + " configuration restored to defaults.") : (displayName + " configuration reloaded."), 0, (Sprite)null, false);
			}
		}
	}
	[HarmonyPatch(typeof(Minimap), "OnMapLeftClick")]
	internal static class MapTeleportPatch
	{
		private static readonly MethodInfo IsExploredMethod = AccessTools.Method(typeof(Minimap), "IsExplored", new Type[1] { typeof(Vector3) }, (Type[])null);

		private static bool Prefix(Minimap __instance)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: 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)
			if ((Object)(object)Player.m_localPlayer == (Object)null || WorldGenerator.instance == null || (Object)(object)ZoneSystem.instance == (Object)null || !IsTeleportKeyHeld() || !TryGetMapPosition(__instance, out var position))
			{
				return true;
			}
			Player localPlayer = Player.m_localPlayer;
			if (!IsExplored(__instance, position))
			{
				((Character)localPlayer).Message((MessageType)2, "You can only teleport to explored locations.", 0, (Sprite)null, false);
				return false;
			}
			int value = Plugin.MinimumTeleportDistance.Value;
			if (IsTooClose(((Component)localPlayer).transform.position, position, value))
			{
				((Character)localPlayer).Message((MessageType)2, $"Select a destination at least {value} m away.", 0, (Sprite)null, false);
				return false;
			}
			if (!CanTeleport(localPlayer))
			{
				return false;
			}
			position.y = WorldGenerator.instance.GetHeight(position.x, position.z);
			((Character)localPlayer).TeleportTo(position, ((Component)localPlayer).transform.rotation, true);
			__instance.SetMapMode((MapMode)1);
			return false;
		}

		private static bool CanTeleport(Player player)
		{
			if (player.IsSensed())
			{
				((Character)player).Message((MessageType)2, "$msg_bedenemiesnearby", 0, (Sprite)null, false);
				return false;
			}
			if (!ZoneSystem.instance.GetGlobalKey((GlobalKeys)35) && !((Humanoid)player).IsTeleportable(false))
			{
				((Character)player).Message((MessageType)2, "$msg_noteleport", 0, (Sprite)null, false);
				return false;
			}
			return true;
		}

		private static bool IsTooClose(Vector3 currentPosition, Vector3 destination, int minimumDistance)
		{
			//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)
			float num = destination.x - currentPosition.x;
			float num2 = destination.z - currentPosition.z;
			return num * num + num2 * num2 < (float)(minimumDistance * minimumDistance);
		}

		private static bool IsExplored(Minimap map, Vector3 destination)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			bool flag = default(bool);
			int num;
			if (IsExploredMethod != null)
			{
				object obj = IsExploredMethod.Invoke(map, new object[1] { destination });
				if (obj is bool)
				{
					flag = (bool)obj;
					num = 1;
				}
				else
				{
					num = 0;
				}
			}
			else
			{
				num = 0;
			}
			return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
		}

		private static bool IsTeleportKeyHeld()
		{
			return Plugin.TeleportKey.Value switch
			{
				ModifierKey.LeftAlt => ZInput.GetKey((KeyCode)308, true), 
				ModifierKey.LeftCtrl => ZInput.GetKey((KeyCode)306, true), 
				ModifierKey.LeftShift => ZInput.GetKey((KeyCode)304, true), 
				_ => false, 
			};
		}

		private static bool TryGetMapPosition(Minimap map, out Vector3 position)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: 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_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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_005c: 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_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)map.m_mapImageLarge).transform;
			RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null);
			Vector2 val2 = default(Vector2);
			if ((Object)(object)val == (Object)null || !RectTransformUtility.ScreenPointToLocalPointInRectangle(val, Vector2.op_Implicit(ZInput.pointerPosition), (Camera)null, ref val2))
			{
				position = Vector3.zero;
				return false;
			}
			Vector2 val3 = Rect.PointToNormalized(val.rect, val2);
			Rect uvRect = map.m_mapImageLarge.uvRect;
			float num = ((Rect)(ref uvRect)).xMin + val3.x * ((Rect)(ref uvRect)).width;
			float num2 = ((Rect)(ref uvRect)).yMin + val3.y * ((Rect)(ref uvRect)).height;
			float num3 = (float)map.m_textureSize / 2f;
			position = new Vector3((num * (float)map.m_textureSize - num3) * map.m_pixelSize, 0f, (num2 * (float)map.m_textureSize - num3) * map.m_pixelSize);
			return true;
		}
	}
	internal enum ModifierKey
	{
		LeftAlt,
		LeftCtrl,
		LeftShift
	}
	[BepInPlugin("Landoria.MapTeleport", "Landoria.MapTeleport", "1.0.0")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "Landoria.MapTeleport";

		public const string PluginName = "Landoria.MapTeleport";

		public const string PluginVersion = "1.0.0";

		private Harmony _harmony;

		internal static ConfigEntry<ModifierKey> TeleportKey { get; private set; }

		internal static ConfigEntry<int> MinimumTeleportDistance { get; private set; }

		private void Awake()
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			TeleportKey = ((BaseUnityPlugin)this).Config.Bind<ModifierKey>("Controls", "TeleportKey", ModifierKey.LeftShift, "Modifier held while left-clicking the large map: LeftAlt, LeftCtrl, or LeftShift.");
			MinimumTeleportDistance = ((BaseUnityPlugin)this).Config.Bind<int>("Teleport", "MinimumDistance", 200, new ConfigDescription("Minimum map teleport distance in meters (100-1000).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(100, 1000), Array.Empty<object>()));
			ConfigWatcher.Initialize(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger, "MapTeleport", RestoreDefaults);
			_harmony = new Harmony("Landoria.MapTeleport");
			_harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Landoria.MapTeleport 1.0.0 loaded.");
		}

		private void Update()
		{
			ConfigWatcher.Update();
		}

		private void RestoreDefaults()
		{
			TeleportKey.Value = ModifierKey.LeftShift;
			MinimumTeleportDistance.Value = 200;
			((BaseUnityPlugin)this).Config.Save();
			ConfigWatcher.IgnoreCurrentFileVersion();
		}

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