Decompiled source of ExtraSnapsToggle v1.1.0

ExtraSnapsToggle.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
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 TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("ExtraSnapsToggle")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0+0d2f3c7f7db6dada502cfc8d5eb5dc46ecbb32bd")]
[assembly: AssemblyProduct("ExtraSnapsToggle")]
[assembly: AssemblyTitle("ExtraSnapsToggle")]
[assembly: AssemblyVersion("1.1.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 ExtraSnapsToggle
{
	internal static class BuildHint
	{
		private sealed class TextState
		{
			public TMP_Text Text;

			public string Vanilla;

			public string Modded;
		}

		private sealed class WidthState
		{
			public LayoutElement Layout;

			public float Vanilla;

			public float Modded;
		}

		private const string KeyboardPath = "BuildHints/Keyboard";

		private const string AltPlaceName = "AltPlace";

		private const string OffColor = "#FFA13E";

		private static readonly string[] RewrittenByExtraSnaps = new string[2] { "Snap", "AltPlace" };

		private static readonly string[] AddedByExtraSnaps = new string[2] { "ToggleSnapMode", "CurrentSnapMode" };

		private static readonly List<TextState> texts = new List<TextState>();

		private static readonly List<WidthState> widths = new List<WidthState>();

		private static Transform keyboard;

		private static GameObject hint;

		private static TMP_Text label;

		private static TMP_Text key;

		internal static void BeforeExtraSnaps(KeyHints hints)
		{
			texts.Clear();
			widths.Clear();
			hint = null;
			label = null;
			key = null;
			keyboard = ((Component)hints).transform.Find("BuildHints/Keyboard");
			if ((Object)(object)keyboard == (Object)null)
			{
				ExtraSnapsTogglePlugin.Log.LogWarning((object)"BuildHints/Keyboard not found, the key hints are left as they are");
				return;
			}
			string[] rewrittenByExtraSnaps = RewrittenByExtraSnaps;
			foreach (string text in rewrittenByExtraSnaps)
			{
				Transform val = keyboard.Find(text);
				if (!((Object)(object)val == (Object)null))
				{
					TMP_Text[] componentsInChildren = ((Component)val).GetComponentsInChildren<TMP_Text>(true);
					foreach (TMP_Text val2 in componentsInChildren)
					{
						texts.Add(new TextState
						{
							Text = val2,
							Vanilla = val2.text,
							Modded = val2.text
						});
					}
					LayoutElement[] componentsInChildren2 = ((Component)val).GetComponentsInChildren<LayoutElement>(true);
					foreach (LayoutElement val3 in componentsInChildren2)
					{
						widths.Add(new WidthState
						{
							Layout = val3,
							Vanilla = val3.preferredWidth,
							Modded = val3.preferredWidth
						});
					}
				}
			}
			Create(keyboard.Find("AltPlace"));
		}

		internal static void AfterExtraSnaps()
		{
			foreach (TextState text in texts)
			{
				if ((Object)(object)text.Text != (Object)null)
				{
					text.Modded = text.Text.text;
				}
			}
			foreach (WidthState width in widths)
			{
				if ((Object)(object)width.Layout != (Object)null)
				{
					width.Modded = width.Layout.preferredWidth;
				}
			}
			Refresh();
		}

		private static void Create(Transform template)
		{
			if ((Object)(object)template == (Object)null)
			{
				ExtraSnapsTogglePlugin.Log.LogWarning((object)"BuildHints/Keyboard/AltPlace not found, the key hint is not shown");
				return;
			}
			hint = Object.Instantiate<GameObject>(((Component)template).gameObject, template.parent);
			((Object)hint).name = "ExtraSnapsToggle";
			Transform val = hint.transform.Find("Text");
			Transform val2 = hint.transform.Find("key_bkg/Key");
			label = (((Object)(object)val == (Object)null) ? null : ((Component)val).GetComponent<TMP_Text>());
			key = (((Object)(object)val2 == (Object)null) ? null : ((Component)val2).GetComponent<TMP_Text>());
		}

		internal static void Refresh()
		{
			bool off = ExtraSnapsTogglePlugin.Off;
			RefreshOwn(off);
			RefreshExtraSnaps(off);
		}

		private static void RefreshOwn(bool off)
		{
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)hint == (Object)null)
			{
				return;
			}
			hint.SetActive(ExtraSnapsTogglePlugin.ShowKeyHint.Value);
			if ((Object)(object)label != (Object)null)
			{
				string text = (off ? ("<color=#FFA13E>" + ExtraSnapsTogglePlugin.Text("выкл", "off") + "</color>") : ExtraSnapsTogglePlugin.Text("вкл", "on"));
				label.text = ExtraSnapsTogglePlugin.Text("Мод привязок", "Extra Snaps") + "<br>" + text;
				LayoutElement component = ((Component)label).GetComponent<LayoutElement>();
				if ((Object)(object)component != (Object)null)
				{
					component.preferredWidth = (ExtraSnapsTogglePlugin.Russian ? 120f : 100f);
				}
			}
			if ((Object)(object)key != (Object)null)
			{
				key.text = ((object)ExtraSnapsTogglePlugin.ToggleKey.Value/*cast due to .constrained prefix*/).ToString();
			}
		}

		private static void RefreshExtraSnaps(bool off)
		{
			if ((Object)(object)keyboard == (Object)null || !ExtraSnaps.ModesReady)
			{
				return;
			}
			foreach (TextState text2 in texts)
			{
				if ((Object)(object)text2.Text != (Object)null)
				{
					text2.Text.text = (off ? Localize(text2.Vanilla) : text2.Modded);
				}
			}
			foreach (WidthState width in widths)
			{
				if ((Object)(object)width.Layout != (Object)null)
				{
					width.Layout.preferredWidth = (off ? width.Vanilla : width.Modded);
				}
			}
			string[] addedByExtraSnaps = AddedByExtraSnaps;
			foreach (string text in addedByExtraSnaps)
			{
				Transform val = keyboard.Find(text);
				if ((Object)(object)val != (Object)null)
				{
					((Component)val).gameObject.SetActive(!off);
				}
			}
			Transform val2 = keyboard.Find("AltPlace");
			if ((Object)(object)val2 != (Object)null)
			{
				((Component)val2).gameObject.SetActive(off || ExtraSnaps.IsAutoMode);
			}
		}

		private static string Localize(string text)
		{
			if (text == null || text.IndexOf('$') < 0 || Localization.instance == null)
			{
				return text;
			}
			return Localization.instance.Localize(text);
		}
	}
	public sealed class ExtraSnapMarker : MonoBehaviour
	{
	}
	[BepInPlugin("qua8ion.valheim.extrasnapstoggle", "ExtraSnapsToggle", "1.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class ExtraSnapsTogglePlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "qua8ion.valheim.extrasnapstoggle";

		public const string PluginName = "ExtraSnapsToggle";

		public const string PluginVersion = "1.1.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<KeyboardShortcut> ToggleKey;

		internal static ConfigEntry<bool> ExtraSnapsOff;

		internal static ConfigEntry<bool> RememberState;

		internal static ConfigEntry<bool> RequireBuildTool;

		internal static ConfigEntry<bool> ShowMessages;

		internal static ConfigEntry<bool> ShowKeyHint;

		internal static bool Off;

		internal static bool Russian
		{
			get
			{
				if (Localization.instance != null)
				{
					return Localization.instance.GetSelectedLanguage() == "Russian";
				}
				return false;
			}
		}

		private void Awake()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Expected O, but got Unknown
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Expected O, but got Unknown
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Expected O, but got Unknown
			//IL_01c5: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "ToggleKey", new KeyboardShortcut((KeyCode)288, Array.Empty<KeyCode>()), "Switches Extra Snap Points Made Easy off and on: its extra snap points, its snap modes (Manual, Manual+, Grid) with their keys, and its key hints.");
			ExtraSnapsOff = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ExtraSnapsOff", false, "Current state, flipped by the toggle key. true: Extra Snap Points Made Easy is switched off completely and the game snaps exactly as without it.");
			RememberState = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RememberState", true, "Keep the state between game sessions. false: every session starts with Extra Snap Points Made Easy on.");
			RequireBuildTool = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RequireBuildTool", true, "The toggle key only works while a hammer or another building tool is in your hands.");
			ShowMessages = ((BaseUnityPlugin)this).Config.Bind<bool>("Interface", "ShowMessages", true, "Show a short message on screen when the state changes.");
			ShowKeyHint = ((BaseUnityPlugin)this).Config.Bind<bool>("Interface", "ShowKeyHint", true, "Add the key and the current state to the building key hints at the bottom of the screen.");
			if (!RememberState.Value && ExtraSnapsOff.Value)
			{
				ExtraSnapsOff.Value = false;
			}
			Off = ExtraSnapsOff.Value;
			ExtraSnapsOff.SettingChanged += delegate
			{
				Off = ExtraSnapsOff.Value;
				ExtraSnaps.ResetModes(Player.m_localPlayer);
				SnapFilter.ClearCache();
				BuildHint.Refresh();
			};
			ToggleKey.SettingChanged += delegate
			{
				BuildHint.Refresh();
			};
			ShowKeyHint.SettingChanged += delegate
			{
				BuildHint.Refresh();
			};
			Harmony val = new Harmony("qua8ion.valheim.extrasnapstoggle");
			Apply(val, typeof(Piece_GetSnapPoints_Patch));
			Apply(val, typeof(KeyHints_Awake_Before_Patch));
			Apply(val, typeof(KeyHints_Awake_After_Patch));
			ExtraSnaps.Hook(val);
		}

		private void Update()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			if (IsDown(ToggleKey.Value))
			{
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null) && InputAllowed(localPlayer) && (!RequireBuildTool.Value || ((Character)localPlayer).InPlaceMode()))
				{
					Toggle(localPlayer);
				}
			}
		}

		private static void Toggle(Player player)
		{
			if (!ExtraSnaps.Ready && !ExtraSnaps.ModesReady)
			{
				Message(player, Text("ExtraSnapsToggle: мод Extra Snap Points не распознан, см. лог BepInEx", "ExtraSnapsToggle: Extra Snap Points Made Easy was not recognised, see the BepInEx log"));
				return;
			}
			int num = ExtraSnaps.MarkAll();
			if (num > 0)
			{
				Log.LogWarning((object)(num + " extra snap points had no mark until now. Pieces placed or loaded before this moment keep them until they are reloaded."));
			}
			bool flag = !ExtraSnapsOff.Value;
			ExtraSnapsOff.Value = flag;
			Message(player, flag ? Text("Мод привязок выключен: привязка как в обычной игре", "Extra Snap Points off: the game's own snapping") : Text("Мод привязок включён", "Extra Snap Points on"));
			Log.LogInfo((object)("Extra Snap Points switched " + (flag ? "off" : "on")));
		}

		private static bool IsDown(KeyboardShortcut shortcut)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: 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_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			if ((int)((KeyboardShortcut)(ref shortcut)).MainKey == 0 || !UnityInput.Current.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey))
			{
				return false;
			}
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers)
			{
				if (!UnityInput.Current.GetKey(modifier))
				{
					return false;
				}
			}
			return true;
		}

		private static bool InputAllowed(Player player)
		{
			if (((Object)(object)Chat.instance == (Object)null || !Chat.instance.HasFocus()) && !Console.IsVisible() && !TextInput.IsVisible() && !Menu.IsVisible() && !InventoryGui.IsVisible() && !Minimap.IsOpen())
			{
				return !((Character)player).InCutscene();
			}
			return false;
		}

		private static void Message(Player player, string text)
		{
			if (ShowMessages.Value)
			{
				((Character)player).Message((MessageType)2, text, 0, (Sprite)null, false);
			}
		}

		private static void Apply(Harmony harmony, Type patch)
		{
			try
			{
				harmony.CreateClassProcessor(patch).Patch();
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Could not apply " + patch.Name + ", this part of the mod is off: " + ex));
			}
		}

		internal static string Text(string russian, string english)
		{
			if (!Russian)
			{
				return english;
			}
			return russian;
		}
	}
	internal static class ExtraSnaps
	{
		internal const string Guid = "Searica.Valheim.ExtraSnapPointsMadeEasy";

		private const string ManagerType = "ExtraSnapsMadeEasy.ExtraSnapPoints.SnapPointManager";

		private const string AdderType = "ExtraSnapsMadeEasy.ExtraSnapPoints.ExtraSnapsAdder";

		private const string ModesType = "ExtraSnapsMadeEasy.Patches.SnapModeManager";

		private const string VanillaSnapType = "ExtraSnapsMadeEasy.Patches.DisableVanillaManualSnapPatches";

		private static FieldInfo managerInstance;

		private static FieldInfo addedSnapPoints;

		private static FieldInfo snapMode;

		private static object autoMode;

		private static MethodInfo snapModeChanged;

		private static FieldRef<Player, int> manualSnapPoint;

		private static bool resetFailed;

		internal static bool Ready { get; private set; }

		internal static bool ModesReady { get; private set; }

		internal static bool IsAutoMode
		{
			get
			{
				if (ModesReady)
				{
					return object.Equals(snapMode.GetValue(null), autoMode);
				}
				return true;
			}
		}

		internal static void Hook(Harmony harmony)
		{
			try
			{
				manualSnapPoint = AccessTools.FieldRefAccess<Player, int>("m_manualSnapPoint");
			}
			catch (Exception ex)
			{
				ExtraSnapsTogglePlugin.Log.LogWarning((object)("Player.m_manualSnapPoint not found, the game's manual snap point is not reset by the key: " + ex.Message));
			}
			if (!Chainloader.PluginInfos.TryGetValue("Searica.Valheim.ExtraSnapPointsMadeEasy", out var value) || (Object)(object)value.Instance == (Object)null)
			{
				ExtraSnapsTogglePlugin.Log.LogError((object)"Extra Snap Points Made Easy is not loaded, the toggle key is off");
				return;
			}
			Assembly assembly = ((object)value.Instance).GetType().Assembly;
			string text = value.Metadata.Version.ToString();
			HookSnapPoints(harmony, assembly, text);
			HookModes(harmony, assembly, text);
			if (Ready || ModesReady)
			{
				ExtraSnapsTogglePlugin.Log.LogInfo((object)("Hooked Extra Snap Points Made Easy " + text + (Ready ? "" : " (without its extra snap points)") + (ModesReady ? "" : " (without its snap modes)")));
			}
		}

		private static void HookSnapPoints(Harmony harmony, Assembly assembly, string version)
		{
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Expected O, but got Unknown
			try
			{
				Type type = assembly.GetType("ExtraSnapsMadeEasy.ExtraSnapPoints.SnapPointManager");
				Type type2 = assembly.GetType("ExtraSnapsMadeEasy.ExtraSnapPoints.ExtraSnapsAdder");
				managerInstance = ((type == null) ? null : AccessTools.Field(type, "Instance"));
				addedSnapPoints = ((type == null) ? null : AccessTools.Field(type, "AddedSnapPoints"));
				MethodInfo methodInfo = ((type2 == null) ? null : AccessTools.GetDeclaredMethods(type2).FirstOrDefault((MethodInfo m) => m.Name == "AddExtraSnapPoints"));
				if (managerInstance == null || !managerInstance.IsStatic || addedSnapPoints == null || !typeof(List<GameObject>).IsAssignableFrom(addedSnapPoints.FieldType) || methodInfo == null)
				{
					ExtraSnapsTogglePlugin.Log.LogError((object)("Extra Snap Points Made Easy " + version + " keeps its extra snap points differently from the version this mod knows (2.1.0), they stay on"));
					return;
				}
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(ExtraSnaps), "AfterAdd", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				Ready = true;
			}
			catch (Exception ex)
			{
				ExtraSnapsTogglePlugin.Log.LogError((object)("Could not hook the extra snap points of Extra Snap Points Made Easy, they stay on: " + ex));
			}
		}

		private static void HookModes(Harmony harmony, Assembly assembly, string version)
		{
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Expected O, but got Unknown
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Expected O, but got Unknown
			try
			{
				Type type = assembly.GetType("ExtraSnapsMadeEasy.Patches.SnapModeManager");
				Type type2 = assembly.GetType("ExtraSnapsMadeEasy.Patches.DisableVanillaManualSnapPatches");
				MethodInfo methodInfo = ((type == null) ? null : AccessTools.DeclaredMethod(type, "UpdatePlacementGhostPostfix", (Type[])null, (Type[])null));
				MethodInfo methodInfo2 = ((type2 == null) ? null : AccessTools.DeclaredMethod(type2, "ResetManualSnapPointToAuto", (Type[])null, (Type[])null));
				snapMode = ((type == null) ? null : AccessTools.DeclaredField(type, "CurrentSnapMode"));
				snapModeChanged = ((type == null) ? null : AccessTools.DeclaredMethod(type, "InvokeOnSnapModeChanged", (Type[])null, (Type[])null));
				if (methodInfo == null || methodInfo2 == null || snapMode == null || !snapMode.IsStatic || !snapMode.FieldType.IsEnum || snapModeChanged == null || snapModeChanged.GetParameters().Length != 0)
				{
					ExtraSnapsTogglePlugin.Log.LogError((object)("Extra Snap Points Made Easy " + version + " handles its snap modes differently from the version this mod knows (2.1.0), they stay on"));
					return;
				}
				autoMode = Enum.Parse(snapMode.FieldType, "Auto");
				harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(ExtraSnaps), "SkipWhenOff", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(ExtraSnaps), "SkipWhenOff", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				ModesReady = true;
			}
			catch (Exception ex)
			{
				ExtraSnapsTogglePlugin.Log.LogError((object)("Could not hook the snap modes of Extra Snap Points Made Easy, they stay on: " + ex));
			}
		}

		private static bool SkipWhenOff()
		{
			return !ExtraSnapsTogglePlugin.Off;
		}

		private static void AfterAdd()
		{
			try
			{
				SnapFilter.ClearCache();
				int num = MarkAll();
				if (num > 0)
				{
					ExtraSnapsTogglePlugin.Log.LogInfo((object)("Marked " + num + " extra snap points"));
				}
			}
			catch (Exception ex)
			{
				ExtraSnapsTogglePlugin.Log.LogError((object)("Could not mark extra snap points: " + ex));
			}
		}

		internal static int MarkAll()
		{
			if (managerInstance == null || addedSnapPoints == null)
			{
				return 0;
			}
			object value = managerInstance.GetValue(null);
			if (value != null)
			{
				return SnapFilter.Mark(addedSnapPoints.GetValue(value) as List<GameObject>);
			}
			return 0;
		}

		internal static void ResetModes(Player player)
		{
			try
			{
				if (ModesReady && !object.Equals(snapMode.GetValue(null), autoMode))
				{
					snapMode.SetValue(null, autoMode);
					snapModeChanged.Invoke(null, null);
				}
				if ((Object)(object)player != (Object)null && manualSnapPoint != null)
				{
					manualSnapPoint.Invoke(player) = -1;
				}
			}
			catch (Exception ex)
			{
				if (!resetFailed)
				{
					resetFailed = true;
					ExtraSnapsTogglePlugin.Log.LogError((object)("Resetting the snap modes failed: " + ex));
				}
			}
		}
	}
	[HarmonyPatch(typeof(Piece), "GetSnapPoints", new Type[] { typeof(List<Transform>) })]
	internal static class Piece_GetSnapPoints_Patch
	{
		private static bool failed;

		private static void Prefix(List<Transform> points, out int __state)
		{
			__state = points?.Count ?? 0;
		}

		private static void Postfix(Piece __instance, List<Transform> points, int __state)
		{
			if (!ExtraSnapsTogglePlugin.Off || points == null)
			{
				return;
			}
			try
			{
				SnapFilter.RemoveExtras(points, __state, __instance);
			}
			catch (Exception ex)
			{
				if (!failed)
				{
					failed = true;
					ExtraSnapsTogglePlugin.Log.LogError((object)("Filtering snap points failed: " + ex));
				}
			}
		}
	}
	[HarmonyPatch(typeof(KeyHints), "Awake")]
	internal static class KeyHints_Awake_Before_Patch
	{
		[HarmonyBefore(new string[] { "Searica.Valheim.ExtraSnapPointsMadeEasy" })]
		private static void Postfix(KeyHints __instance)
		{
			try
			{
				BuildHint.BeforeExtraSnaps(__instance);
			}
			catch (Exception ex)
			{
				ExtraSnapsTogglePlugin.Log.LogError((object)("Could not add the key hint: " + ex));
			}
		}
	}
	[HarmonyPatch(typeof(KeyHints), "Awake")]
	internal static class KeyHints_Awake_After_Patch
	{
		[HarmonyAfter(new string[] { "Searica.Valheim.ExtraSnapPointsMadeEasy" })]
		private static void Postfix()
		{
			try
			{
				BuildHint.AfterExtraSnaps();
			}
			catch (Exception ex)
			{
				ExtraSnapsTogglePlugin.Log.LogError((object)("Could not set up the key hints: " + ex));
			}
		}
	}
	public static class SnapFilter
	{
		private struct Known
		{
			public int Total;

			public int Keep;
		}

		private sealed class ByReference : IEqualityComparer<object>
		{
			bool IEqualityComparer<object>.Equals(object a, object b)
			{
				return a == b;
			}

			int IEqualityComparer<object>.GetHashCode(object o)
			{
				return RuntimeHelpers.GetHashCode(o);
			}
		}

		private const int Mixed = -1;

		private const int CacheLimit = 20000;

		private static readonly Dictionary<object, Known> cache = new Dictionary<object, Known>(new ByReference());

		public static int CacheSize => cache.Count;

		public static void ClearCache()
		{
			cache.Clear();
		}

		public static int Mark(List<GameObject> extraPoints)
		{
			int num = 0;
			if (extraPoints == null)
			{
				return num;
			}
			foreach (GameObject extraPoint in extraPoints)
			{
				if ((Object)(object)extraPoint != (Object)null && (Object)(object)extraPoint.GetComponent<ExtraSnapMarker>() == (Object)null)
				{
					extraPoint.AddComponent<ExtraSnapMarker>();
					num++;
				}
			}
			return num;
		}

		public static void RemoveExtras(List<Transform> points, int from, object piece)
		{
			int num = points.Count - from;
			if (num <= 0)
			{
				return;
			}
			if (!cache.TryGetValue(piece, out var value) || value.Total != num)
			{
				value.Total = num;
				value.Keep = CountLeading(points, from);
				if (cache.Count >= 20000)
				{
					cache.Clear();
				}
				cache[piece] = value;
			}
			if (value.Keep == -1)
			{
				RemoveMarked(points, from);
			}
			else if (value.Keep < num)
			{
				points.RemoveRange(from + value.Keep, num - value.Keep);
			}
		}

		private static int CountLeading(List<Transform> points, int from)
		{
			int num = -1;
			for (int i = from; i < points.Count; i++)
			{
				if (IsExtra(points[i]))
				{
					if (num < 0)
					{
						num = i - from;
					}
				}
				else if (num >= 0)
				{
					return -1;
				}
			}
			if (num >= 0)
			{
				return num;
			}
			return points.Count - from;
		}

		private static void RemoveMarked(List<Transform> points, int from)
		{
			for (int num = points.Count - 1; num >= from; num--)
			{
				if (IsExtra(points[num]))
				{
					points.RemoveAt(num);
				}
			}
		}

		private static bool IsExtra(Transform point)
		{
			ExtraSnapMarker extraSnapMarker = default(ExtraSnapMarker);
			if ((Object)(object)point != (Object)null)
			{
				return ((Component)point).TryGetComponent<ExtraSnapMarker>(ref extraSnapMarker);
			}
			return false;
		}
	}
}