Decompiled source of MeasureTwice v0.1.0

MeasureTwice.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.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Configs;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Extensions;
using Jotunn.Managers;
using Jotunn.Utils;
using Logging;
using MeasureTwice.Patches;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("MeasureTwice")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("MeasureTwice")]
[assembly: AssemblyCopyright("Copyright ©  2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("08a6f7d7-cf93-4931-aecd-abf2ce6ed34c")]
[assembly: AssemblyFileVersion("0.1.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 MeasureTwice
{
	[BepInPlugin("Searica.Valheim.MeasureTwice", "MeasureTwice", "0.1.0")]
	[BepInDependency("com.jotunn.jotunn", "2.23.2")]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	[SynchronizationMode(/*Could not decode attribute arguments.*/)]
	internal sealed class MeasureTwice : BaseUnityPlugin
	{
		public const string PluginName = "MeasureTwice";

		internal const string Author = "Searica";

		public const string PluginGUID = "Searica.Valheim.MeasureTwice";

		public const string PluginVersion = "0.1.0";

		internal static MeasureTwice Instance;

		internal static ConfigFile ConfigFile;

		internal static ConfigFileWatcher ConfigFileWatcher;

		internal CustomPiece SpacerBlockPiece;

		internal const string SpacerBlockName = "spacer_block";

		internal const string SpacerBlockPiecceName = "Ruler";

		internal const string GlobalSection = "Global";

		public ConfigEntry<int> TimedDestruction;

		public ConfigEntry<float> ScrollSpeed;

		public ConfigEntry<KeyCode> LengthModifierKey;

		public void Awake()
		{
			Instance = this;
			ConfigFile = ((BaseUnityPlugin)this).Config;
			Log.Init(((BaseUnityPlugin)this).Logger);
			((BaseUnityPlugin)this).Config.DisableSaveOnConfigSet();
			SetUpConfigEntries();
			((BaseUnityPlugin)this).Config.Save();
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = true;
			Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "Searica.Valheim.MeasureTwice");
			Game.isModded = true;
			PrefabManager.OnVanillaPrefabsAvailable += AddCustomPieces;
			ConfigFileWatcher = new ConfigFileWatcher(((BaseUnityPlugin)this).Config);
		}

		internal void SetUpConfigEntries()
		{
			Log.Verbosity = ConfigFileExtensions.BindConfigInOrder<Log.InfoLevel>(((BaseUnityPlugin)this).Config, "Global", "Verbosity", Log.InfoLevel.Low, "Logging level.", true, true, true, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			LengthModifierKey = ConfigFileExtensions.BindConfigInOrder<KeyCode>(((BaseUnityPlugin)this).Config, "Global", "Length Modifier Key", (KeyCode)307, "Hold this key to scroll and adjust length of the spacer block", false, true, true, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			ScrollSpeed = ConfigFileExtensions.BindConfigInOrder<float>(((BaseUnityPlugin)this).Config, "Global", "Scroll Speed", 0.05f, "Chnage in length for each tick of a the scroll wheel.", false, true, true, (AcceptableValueBase)(object)new AcceptableValueRange<float>(-1f, 1f), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			TimedDestruction = ConfigFileExtensions.BindConfigInOrder<int>(((BaseUnityPlugin)this).Config, "Global", "Timed Destroy", 20, "Number of seconds before spacer block self destructs.", false, true, true, (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 30), (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
		}

		public void OnDestroy()
		{
			((BaseUnityPlugin)this).Config.Save();
		}

		private void AddCustomPieces()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Expected O, but got Unknown
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Expected O, but got Unknown
			GameObject val = PrefabManager.Instance.CreateClonedPrefab("spacer_block", "wood_beam_1");
			val.AddComponent<CustomRuler>();
			val.GetComponent<ZNetView>().m_persistent = false;
			PieceConfig val2 = new PieceConfig();
			val2.Name = "Ruler";
			val2.Category = "Ruler";
			val2.Requirements = (RequirementConfig[])(object)new RequirementConfig[1]
			{
				new RequirementConfig("Wood", 0, 0, false)
			};
			val2.CraftingStation = CraftingStations.None;
			val2.PieceTable = PieceTables.Hammer;
			PieceConfig val3 = val2;
			SpacerBlockPiece = new CustomPiece(val, true, val3);
			PieceManager.Instance.AddPiece(SpacerBlockPiece);
			PrefabManager.OnVanillaPrefabsAvailable -= AddCustomPieces;
		}
	}
}
namespace MeasureTwice.Patches
{
	[HarmonyPatch]
	internal class CustomRuler : MonoBehaviour
	{
		public float m_timeout = 1f;

		private ZNetView m_nview;

		private static bool m_triggerOnPlaced;

		public void Awake()
		{
			m_nview = ((Component)this).GetComponent<ZNetView>();
			m_timeout = MeasureTwice.Instance.TimedDestruction.Value;
			if (m_triggerOnPlaced)
			{
				ApplyScale();
				((MonoBehaviour)this).InvokeRepeating("DestroyNow", m_timeout, 1f);
			}
		}

		public static void SetTriggerOnPlaced(bool trigger)
		{
			m_triggerOnPlaced = trigger;
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "PlacePiece")]
		private static void PlacePiecePrefix()
		{
			SetTriggerOnPlaced(trigger: true);
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(Player), "PlacePiece")]
		private static void PlacePiecePostfix()
		{
			SetTriggerOnPlaced(trigger: false);
		}

		public void ApplyScale()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			((Component)this).transform.localScale = ScaleManager.ScaleOnPlaced;
		}

		public void DestroyNow()
		{
			if (Object.op_Implicit((Object)(object)m_nview))
			{
				if (m_nview.IsValid())
				{
					if (!m_nview.HasOwner())
					{
						m_nview.ClaimOwnership();
					}
					if (m_nview.IsOwner())
					{
						ZNetScene.instance.Destroy(((Component)this).gameObject);
					}
				}
			}
			else
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
			}
		}
	}
	[HarmonyPatch]
	internal static class ScaleManager
	{
		private const float MinLength = 0.1f;

		private const float MaxLength = 2f;

		private const float Tolerance = 0.01f;

		private static bool SpacerBlockIsInUse = false;

		private static float LastOriginalLength = 0f;

		private static float LastTotalDelta = 0f;

		private static Vector3 LastGhostScale = Vector3.one;

		private static bool DisabledScroll = false;

		public static Vector3 ScaleOnPlaced => LastGhostScale;

		[HarmonyPrefix]
		[HarmonyPatch(typeof(Player), "UpdatePlacement")]
		private static void UpdatePlacementPrefix(Player __instance)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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)
			if (!Object.op_Implicit((Object)(object)__instance) || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			if (!((Character)__instance).InPlaceMode() || Hud.IsPieceSelectionVisible())
			{
				if (SpacerBlockIsInUse)
				{
					SpacerBlockIsInUse = false;
					LastOriginalLength = 0f;
					LastTotalDelta = 0f;
					LastGhostScale = Vector3.zero;
				}
			}
			else
			{
				if (!IsValidSelectedPiece(__instance, out var spacerBlock))
				{
					return;
				}
				if (ShouldModifyLength())
				{
					DisabledScroll = true;
					ZInput instance = ZInput.instance;
					if (instance != null)
					{
						instance.m_mouseScrollDeltaAction.Disable();
					}
					SetLength(__instance, spacerBlock, Input.mouseScrollDelta.y * MeasureTwice.Instance.ScrollSpeed.Value);
				}
				RefreshGhostScale(__instance);
			}
		}

		[HarmonyPostfix]
		[HarmonyPriority(0)]
		[HarmonyPatch(typeof(Player), "UpdatePlacement")]
		private static void UpdatePlacementPostfix(Player __instance, ref int __state)
		{
			if (DisabledScroll)
			{
				DisabledScroll = false;
				ZInput instance = ZInput.instance;
				if (instance != null)
				{
					instance.m_mouseScrollDeltaAction.Enable();
				}
			}
		}

		internal static bool IsValidSelectedPiece(Player player, out CustomRuler spacerBlock)
		{
			Piece selectedPiece = player.GetSelectedPiece();
			if (!Object.op_Implicit((Object)(object)selectedPiece) || !((Component)selectedPiece).TryGetComponent<CustomRuler>(ref spacerBlock))
			{
				spacerBlock = null;
				return false;
			}
			return Object.op_Implicit((Object)(object)spacerBlock);
		}

		internal static bool ShouldModifyLength()
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if (Input.GetKey(MeasureTwice.Instance.LengthModifierKey.Value))
			{
				return Input.mouseScrollDelta.y != 0f;
			}
			return false;
		}

		public static float ModifyLength(float length, float delta)
		{
			return Mathf.Clamp(length + delta, 0.1f, 2f);
		}

		private static void SetLength(Player player, CustomRuler spacerBlock, float delta)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//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)
			if (!SpacerBlockIsInUse && Object.op_Implicit((Object)(object)spacerBlock))
			{
				SpacerBlockIsInUse = true;
				LastOriginalLength = ((Component)spacerBlock).transform.localScale.x;
				LastGhostScale = ((Component)spacerBlock).transform.localScale;
			}
			LastTotalDelta = Mathf.Clamp(LastTotalDelta + delta, 0.1f - LastOriginalLength, 2f - LastOriginalLength);
			LastGhostScale.x = ModifyLength(LastOriginalLength, LastTotalDelta);
			((Character)player).Message((MessageType)2, $"Spacer Length: {LastGhostScale.x:#,0.000}", 0, (Sprite)null);
		}

		private static void RefreshGhostScale(Player player)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: 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)
			if (SpacerBlockIsInUse && Object.op_Implicit((Object)(object)player.m_placementGhost) && LastOriginalLength != 0f && Vector3.Distance(player.m_placementGhost.transform.localScale, LastGhostScale) > 0.01f)
			{
				player.m_placementGhost.transform.localScale = LastGhostScale;
			}
		}
	}
}
namespace Logging
{
	internal static class Log
	{
		internal enum InfoLevel
		{
			Low,
			Medium,
			High
		}

		private static ManualLogSource logSource;

		internal static ConfigEntry<InfoLevel> Verbosity { get; set; }

		internal static InfoLevel VerbosityLevel => Verbosity.Value;

		internal static bool IsVerbosityLow => Verbosity.Value >= InfoLevel.Low;

		internal static bool IsVerbosityMedium => Verbosity.Value >= InfoLevel.Medium;

		internal static bool IsVerbosityHigh => Verbosity.Value >= InfoLevel.High;

		internal static void Init(ManualLogSource logSource)
		{
			Log.logSource = logSource;
		}

		internal static void LogDebug(object data)
		{
			logSource.LogDebug(data);
		}

		internal static void LogError(object data)
		{
			logSource.LogError(data);
		}

		internal static void LogFatal(object data)
		{
			logSource.LogFatal(data);
		}

		internal static void LogMessage(object data)
		{
			logSource.LogMessage(data);
		}

		internal static void LogWarning(object data)
		{
			logSource.LogWarning(data);
		}

		internal static void LogInfo(object data, InfoLevel level = InfoLevel.Low)
		{
			if (Verbosity == null || VerbosityLevel >= level)
			{
				logSource.LogInfo(data);
			}
		}

		internal static void LogGameObject(GameObject prefab, bool includeChildren = false)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			LogInfo("***** " + ((Object)prefab).name + " *****");
			Component[] components = prefab.GetComponents<Component>();
			for (int i = 0; i < components.Length; i++)
			{
				LogComponent(components[i]);
			}
			if (!includeChildren)
			{
				return;
			}
			LogInfo("***** " + ((Object)prefab).name + " (children) *****");
			foreach (Transform item in prefab.transform)
			{
				Transform val = item;
				if (Object.op_Implicit((Object)(object)val))
				{
					LogInfo(" - " + ((Object)val).name);
					components = ((Component)val).GetComponents<Component>();
					for (int i = 0; i < components.Length; i++)
					{
						LogComponent(components[i]);
					}
				}
			}
		}

		internal static void LogComponent(Component compo)
		{
			if (!Object.op_Implicit((Object)(object)compo))
			{
				return;
			}
			try
			{
				LogInfo("--- " + ((object)compo).GetType().Name + ": " + ((Object)compo).name + " ---");
			}
			catch (Exception ex)
			{
				LogError(ex.ToString());
				LogWarning("Could not get type name for component!");
				return;
			}
			try
			{
				foreach (PropertyInfo declaredProperty in AccessTools.GetDeclaredProperties(((object)compo).GetType()))
				{
					try
					{
						LogInfo($" - {declaredProperty.Name} = {declaredProperty.GetValue(compo)}");
					}
					catch (Exception ex2)
					{
						LogError(ex2.ToString());
						LogWarning("Could not get property: " + declaredProperty.Name + " for component!");
					}
				}
			}
			catch (Exception ex3)
			{
				LogError(ex3.ToString());
				LogWarning("Could not get properties for component!");
			}
			try
			{
				foreach (FieldInfo declaredField in AccessTools.GetDeclaredFields(((object)compo).GetType()))
				{
					try
					{
						LogInfo($" - {declaredField.Name} = {declaredField.GetValue(compo)}");
					}
					catch (Exception ex4)
					{
						LogError(ex4.ToString());
						LogWarning("Could not get field: " + declaredField.Name + " for component!");
					}
				}
			}
			catch (Exception ex5)
			{
				LogError(ex5.ToString());
				LogWarning("Could not get fields for component!");
			}
		}
	}
}
namespace Configs
{
	public static class ConfigFileExtensions
	{
		public static bool DisableSaveOnConfigSet(this ConfigFile configFile)
		{
			bool saveOnConfigSet = configFile.SaveOnConfigSet;
			configFile.SaveOnConfigSet = false;
			return saveOnConfigSet;
		}
	}
	internal sealed class ConfigFileWatcher
	{
		private const long RELOAD_DELAY = 10000000L;

		private DateTime lastReadTime = DateTime.MinValue;

		private readonly ConfigFile configFile;

		private readonly string ConfigFileDir;

		private readonly string ConfigFileName;

		internal event Action OnConfigFileReloaded;

		internal ConfigFileWatcher(ConfigFile configFile)
		{
			this.configFile = configFile;
			ConfigFileDir = Directory.GetParent(configFile.ConfigFilePath).FullName;
			ConfigFileName = Path.GetFileName(configFile.ConfigFilePath);
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(ConfigFileDir, ConfigFileName);
			fileSystemWatcher.Changed += ReloadConfigFile;
			fileSystemWatcher.Created += ReloadConfigFile;
			fileSystemWatcher.Renamed += ReloadConfigFile;
			fileSystemWatcher.IncludeSubdirectories = true;
			fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher.EnableRaisingEvents = true;
		}

		private void InvokeOnConfigFileReloaded()
		{
			this.OnConfigFileReloaded?.SafeInvoke();
		}

		internal void ReloadConfigFile(object sender, FileSystemEventArgs eventArgs)
		{
			DateTime now = DateTime.Now;
			long num = now.Ticks - lastReadTime.Ticks;
			if (!File.Exists(configFile.ConfigFilePath) || num < 10000000)
			{
				return;
			}
			try
			{
				Log.LogInfo("Reloading " + configFile.ConfigFilePath);
				bool saveOnConfigSet = configFile.DisableSaveOnConfigSet();
				configFile.Reload();
				configFile.SaveOnConfigSet = saveOnConfigSet;
				lastReadTime = now;
				InvokeOnConfigFileReloaded();
			}
			catch
			{
				Log.LogError("There was an issue loading " + configFile.ConfigFilePath);
				Log.LogError("Please check your config entries for spelling and format!");
			}
		}
	}
	internal static class SafeInvokeEvent
	{
		internal static void SafeInvoke(this Action events)
		{
			if (events == null)
			{
				return;
			}
			Delegate[] invocationList = events.GetInvocationList();
			for (int i = 0; i < invocationList.Length; i++)
			{
				Action action = (Action)invocationList[i];
				try
				{
					action();
				}
				catch (Exception arg)
				{
					Log.LogWarning("Exception thrown at event " + new StackFrame(1).GetMethod().Name + $" in {action.Method.DeclaringType.Name}.{action.Method.Name}:\n{arg}");
				}
			}
		}
	}
}