Decompiled source of Classic Snap v1.0.0

ClassicSnap.dll

Decompiled 3 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
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("ClassicSnap")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ClassicSnap")]
[assembly: AssemblyTitle("ClassicSnap")]
[assembly: AssemblyVersion("1.0.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 TheShack.ClassicSnap
{
	[BepInPlugin("theshack.classicsnap", "Classic Snap", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(Piece), "GetSnapPoints", new Type[] { typeof(List<Transform>) })]
		private static class PieceGetSnapPointsPatch
		{
			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 (!classicSnap.Value || points == null || points.Count <= __state)
				{
					return;
				}
				int num = FirstExtraIndex(__instance);
				if (num < 0)
				{
					return;
				}
				Transform transform = ((Component)__instance).transform;
				for (int num2 = points.Count - 1; num2 >= __state; num2--)
				{
					Transform val = points[num2];
					if ((Object)(object)val != (Object)null && (Object)(object)val.parent == (Object)(object)transform && val.GetSiblingIndex() >= num)
					{
						points.RemoveAt(num2);
					}
				}
			}
		}

		public const string PluginGuid = "theshack.classicsnap";

		public const string PluginName = "Classic Snap";

		public const string PluginVersion = "1.0.0";

		private const string EspGuid = "Searica.Valheim.ExtraSnapPointsMadeEasy";

		private const string ClassicName = "Classic";

		private static ManualLogSource log;

		private static ConfigEntry<bool> classicSnap;

		private static object espPlugin;

		private static PropertyInfo espToggleManualKey;

		private static PropertyInfo espNotificationType;

		private static FieldInfo espModeField;

		private static object espModeAuto;

		private static object espModeManual;

		private static MethodInfo espModeChanged;

		private static object espSnapPointManager;

		private static FieldInfo espAddedSnapPoints;

		private static readonly FieldRef<Player, int> manualSnapPoint = AccessTools.FieldRefAccess<Player, int>("m_manualSnapPoint");

		private static readonly Dictionary<string, int> firstExtraIndex = new Dictionary<string, int>();

		private static readonly Dictionary<int, int> firstExtraIndexByInstance = new Dictionary<int, int>();

		private static bool indexDirty = true;

		private void Awake()
		{
			//IL_0048: 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_0067: Expected O, but got Unknown
			log = ((BaseUnityPlugin)this).Logger;
			classicSnap = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Classic", true, "Whether Classic mode is on: only the game's original snap points, and Q/E picks the snap point as in the base game. Switched in game with Extra Snap Points' Toggle Manual Snap Mode key, which cycles Classic -> Auto -> Manual. Remembered between sessions.");
			try
			{
				if (!Resolve())
				{
					log.LogWarning((object)"Extra Snap Points Made Easy internals not found (renamed in an update?). Classic Snap is off.");
					return;
				}
				Harmony val = new Harmony("theshack.classicsnap");
				val.PatchAll(typeof(Plugin).Assembly);
				PatchEsp(val);
				log.LogInfo((object)("ready, " + (classicSnap.Value ? "Classic" : "ESP snapping") + " at start"));
			}
			catch (Exception ex)
			{
				log.LogWarning((object)("could not hook Extra Snap Points Made Easy, Classic Snap is off: " + ex));
			}
		}

		private static bool Resolve()
		{
			Type type = AccessTools.TypeByName("ExtraSnapsMadeEasy.ExtraSnapsPlugin");
			Type type2 = AccessTools.TypeByName("ExtraSnapsMadeEasy.Patches.SnapModeManager");
			Type type3 = AccessTools.TypeByName("ExtraSnapsMadeEasy.ExtraSnapPoints.SnapPointManager");
			if (type == null || type2 == null || type3 == null)
			{
				return false;
			}
			espPlugin = AccessTools.Field(type, "Instance")?.GetValue(null);
			espToggleManualKey = AccessTools.Property(type, "ToggleManualSnap");
			espNotificationType = AccessTools.Property(type, "NotificationType");
			espModeField = AccessTools.Field(type2, "CurrentSnapMode");
			espModeChanged = AccessTools.Method(type2, "InvokeOnSnapModeChanged", (Type[])null, (Type[])null);
			espSnapPointManager = AccessTools.Field(type3, "Instance")?.GetValue(null);
			espAddedSnapPoints = AccessTools.Field(type3, "AddedSnapPoints");
			if (espPlugin == null || espToggleManualKey == null || espNotificationType == null || espModeField == null || espSnapPointManager == null || espAddedSnapPoints == null)
			{
				return false;
			}
			espModeAuto = Enum.Parse(espModeField.FieldType, "Auto");
			espModeManual = Enum.Parse(espModeField.FieldType, "Manual");
			return true;
		}

		private static void PatchEsp(Harmony harmony)
		{
			Type declaringType = espModeField.DeclaringType;
			Type type = AccessTools.TypeByName("ExtraSnapsMadeEasy.Patches.DisableVanillaManualSnapPatches");
			Type type2 = AccessTools.TypeByName("ExtraSnapsMadeEasy.ExtraSnapPoints.ExtraSnapsAdder");
			Patch(harmony, AccessTools.Method(declaringType, "UpdatePlacementGhostPostfix", (Type[])null, (Type[])null), "ModeKey_Prefix", "ModeKey_Postfix");
			Patch(harmony, AccessTools.Method(type, "UpdatePlacementGhost_Postfix", (Type[])null, (Type[])null), "SkipInClassic", null);
			Patch(harmony, AccessTools.Method(type, "ResetManualSnapPointToAuto", (Type[])null, (Type[])null), "SkipInClassic", null);
			Patch(harmony, AccessTools.Method(type2, "AddExtraSnapPoints", (Type[])null, (Type[])null), null, "MarkIndexDirty");
		}

		private static void Patch(Harmony harmony, MethodInfo target, string prefix, string postfix)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			if (target == null)
			{
				throw new MissingMethodException("an Extra Snap Points Made Easy method for " + (prefix ?? postfix));
			}
			harmony.Patch((MethodBase)target, (prefix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(Plugin), prefix, (Type[])null), (postfix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(Plugin), postfix, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		private static bool ModeKey_Prefix(Player __0)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__0 == (Object)null || (Object)(object)__0 != (Object)(object)Player.m_localPlayer || !((Character)__0).InPlaceMode() || ((Character)__0).IsDead())
			{
				return true;
			}
			if (!Input.GetKeyDown(((ConfigEntry<KeyCode>)espToggleManualKey.GetValue(espPlugin)).Value))
			{
				return true;
			}
			if (classicSnap.Value)
			{
				SetClassic(on: false, __0);
				SetEspMode(espModeAuto);
				Notify(__0, "Snap Mode: Auto");
				return false;
			}
			if (espModeField.GetValue(null).Equals(espModeManual))
			{
				SetEspMode(espModeAuto);
				SetClassic(on: true, __0);
				Notify(__0, "Snap Mode: Classic");
				return false;
			}
			return true;
		}

		private static void ModeKey_Postfix(Player __0)
		{
			if (classicSnap.Value && !espModeField.GetValue(null).Equals(espModeAuto))
			{
				SetClassic(on: false, __0);
			}
		}

		private static bool SkipInClassic()
		{
			return !classicSnap.Value;
		}

		private static void SetClassic(bool on, Player player)
		{
			if (classicSnap.Value != on)
			{
				log.LogInfo((object)(on ? "switched to Classic" : "left Classic"));
			}
			classicSnap.Value = on;
			if ((Object)(object)player != (Object)null)
			{
				manualSnapPoint.Invoke(player) = -1;
			}
		}

		private static void SetEspMode(object mode)
		{
			espModeField.SetValue(null, mode);
			espModeChanged?.Invoke(null, null);
		}

		private static void Notify(Player player, string text)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			object boxedValue = ((ConfigEntryBase)espNotificationType.GetValue(espPlugin)).BoxedValue;
			((Character)player).Message((MessageType)boxedValue, text, 0, (Sprite)null, false);
		}

		private static void MarkIndexDirty()
		{
			indexDirty = true;
		}

		private static int FirstExtraIndex(Piece piece)
		{
			if (indexDirty)
			{
				RebuildIndex();
			}
			int instanceID = ((Object)piece).GetInstanceID();
			if (firstExtraIndexByInstance.TryGetValue(instanceID, out var value))
			{
				return value;
			}
			if (!firstExtraIndex.TryGetValue(Utils.GetPrefabName(((Component)piece).gameObject), out value))
			{
				value = -1;
			}
			if (firstExtraIndexByInstance.Count > 100000)
			{
				firstExtraIndexByInstance.Clear();
			}
			firstExtraIndexByInstance[instanceID] = value;
			return value;
		}

		private static void RebuildIndex()
		{
			indexDirty = false;
			if (!(espAddedSnapPoints.GetValue(espSnapPointManager) is List<GameObject> list))
			{
				return;
			}
			foreach (GameObject item in list)
			{
				Transform val = (((Object)(object)item == (Object)null) ? null : item.transform.parent);
				if (!((Object)(object)val == (Object)null))
				{
					int siblingIndex = item.transform.GetSiblingIndex();
					if (!firstExtraIndex.TryGetValue(((Object)val).name, out var value) || siblingIndex < value)
					{
						firstExtraIndex[((Object)val).name] = siblingIndex;
					}
				}
			}
			firstExtraIndexByInstance.Clear();
			log.LogInfo((object)$"indexed extra snap points on {firstExtraIndex.Count} piece prefabs");
		}
	}
}