Decompiled source of LetMeBuild v1.1.0

plugins/LetMeBuild/LetMeBuild.dll

Decompiled 4 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 HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[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("LetMeBuild")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0+3cd869b4c525be8c671029286b5a13cd9dd28e9d")]
[assembly: AssemblyProduct("LetMeBuild")]
[assembly: AssemblyTitle("LetMeBuild")]
[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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 Ainzworth.LetMeBuild
{
	[BepInPlugin("uk.ainzworth.valheim.letmebuild", "LetMeBuild", "1.1.0")]
	public sealed class LetMeBuildPlugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(Player), "CheckCanRemovePiece", new Type[] { typeof(Piece) })]
		private static class PieceStationPatch
		{
			private sealed class StationCheckState
			{
				internal Piece Piece;

				internal CraftingStation? Station;
			}

			private static readonly Func<Humanoid, ItemData> GetRightItem = (Func<Humanoid, ItemData>)Delegate.CreateDelegate(typeof(Func<Humanoid, ItemData>), AccessTools.Method(typeof(Humanoid), "GetRightItem", (Type[])null, (Type[])null));

			private static void Prefix(Player __instance, Piece __0, out StationCheckState? __state)
			{
				__state = null;
				LetMeBuildPlugin instance = Instance;
				if (!((Object)(object)instance == (Object)null) && instance._enabled.Value && !((Object)(object)__0 == (Object)null) && IsTool(GetRightItem((Humanoid)(object)__instance)))
				{
					if (!((Object)(object)__0 == (Object)null) && !((Object)(object)__0.m_craftingStation == (Object)null))
					{
						__state = new StationCheckState
						{
							Piece = __0,
							Station = __0.m_craftingStation
						};
						__0.m_craftingStation = null;
					}
				}
			}

			private static void Finalizer(StationCheckState? __state)
			{
				if (__state != null && (Object)(object)__state.Piece != (Object)null)
				{
					__state.Piece.m_craftingStation = __state.Station;
				}
			}
		}

		[HarmonyPatch(typeof(Humanoid), "EquipItem")]
		private static class EquipToolPatch
		{
			private static void Prefix(ItemData item)
			{
				if (EnabledTool(item))
				{
					Instance.ApplyTool(item);
				}
			}
		}

		[HarmonyPatch(typeof(Player), "GetBuildStamina")]
		private static class BuildStaminaPatch
		{
			private static void Postfix(Player __instance, ref float __result)
			{
				if (EnabledTool(RightItem((Humanoid)(object)__instance)))
				{
					__result = 0f;
				}
			}
		}

		[HarmonyPatch(typeof(Attack), "GetAttackStamina")]
		private static class ToolAttackStaminaPatch
		{
			private static void Postfix(ItemData ___m_weapon, ref float __result)
			{
				if (EnabledTool(___m_weapon))
				{
					__result = 0f;
				}
			}
		}

		public const string PluginGuid = "uk.ainzworth.valheim.letmebuild";

		public const string PluginName = "LetMeBuild";

		public const string PluginVersion = "1.1.0";

		private readonly Dictionary<Piece, CraftingStation?> _originalStations = new Dictionary<Piece, CraftingStation>();

		private ConfigEntry<bool> _enabled;

		private ConfigEntry<float> _scanInterval;

		private ConfigEntry<bool> _logChanges;

		private static LetMeBuildPlugin? Instance;

		private Harmony? _harmony;

		private float _nextScanTime;

		private bool _lastEnabledState;

		private PieceTable? _lastHammerTable;

		private readonly Dictionary<SharedData, bool> _toolDurability = new Dictionary<SharedData, bool>();

		private static readonly Func<Humanoid, ItemData> RightItem = (Func<Humanoid, ItemData>)Delegate.CreateDelegate(typeof(Func<Humanoid, ItemData>), AccessTools.Method(typeof(Humanoid), "GetRightItem", (Type[])null, (Type[])null));

		private void Awake()
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Expected O, but got Unknown
			_enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable station-free, stamina-free and durability-free building and farming tools. Material costs remain unchanged.");
			_scanInterval = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Scan Interval Seconds", 1f, "How often tool items and build tables are rescanned. This allows pieces added by other mods after startup to be picked up automatically.");
			_logChanges = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Log Changes", false, "Log every Hammer piece whose crafting-station requirement is removed.");
			_lastEnabledState = _enabled.Value;
			_enabled.SettingChanged += OnEnabledChanged;
			Instance = this;
			_harmony = new Harmony("uk.ainzworth.valheim.letmebuild");
			_harmony.PatchAll(typeof(LetMeBuildPlugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"LetMeBuild 1.1.0 loaded.");
		}

		private void Update()
		{
			if (_lastEnabledState != _enabled.Value)
			{
				HandleEnabledStateChanged();
			}
			if (_enabled.Value)
			{
				float num = Mathf.Max(0.25f, _scanInterval.Value);
				if (!(Time.unscaledTime < _nextScanTime))
				{
					_nextScanTime = Time.unscaledTime + num;
					ApplyToTools();
				}
			}
		}

		private void OnDestroy()
		{
			if (_enabled != null)
			{
				_enabled.SettingChanged -= OnEnabledChanged;
			}
			RestoreAll();
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			Instance = null;
		}

		private void OnEnabledChanged(object sender, EventArgs args)
		{
			HandleEnabledStateChanged();
		}

		private void HandleEnabledStateChanged()
		{
			_lastEnabledState = _enabled.Value;
			if (_enabled.Value)
			{
				_nextScanTime = 0f;
				ApplyToTools();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Station bypass enabled.");
			}
			else
			{
				RestoreAll();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Station bypass disabled; original tool values and station requirements restored.");
			}
		}

		private void ApplyToHammerPieces(PieceTable hammerTable)
		{
			if ((Object)(object)_lastHammerTable != (Object)(object)hammerTable)
			{
				_lastHammerTable = hammerTable;
				((BaseUnityPlugin)this).Logger.LogDebug((object)("Hammer PieceTable resolved: " + ((Object)hammerTable).name));
			}
			int num = 0;
			int num2 = 0;
			foreach (GameObject piece in hammerTable.m_pieces)
			{
				if (!Object.op_Implicit((Object)(object)piece))
				{
					continue;
				}
				Piece component = piece.GetComponent<Piece>();
				if (!Object.op_Implicit((Object)(object)component))
				{
					continue;
				}
				if (!_originalStations.ContainsKey(component))
				{
					_originalStations.Add(component, component.m_craftingStation);
					num2++;
				}
				if (!((Object)(object)component.m_craftingStation == (Object)null))
				{
					string name = ((Object)component.m_craftingStation).name;
					component.m_craftingStation = null;
					num++;
					if (_logChanges.Value)
					{
						((BaseUnityPlugin)this).Logger.LogInfo((object)("Removed station requirement from '" + ((Object)piece).name + "' (was '" + name + "')."));
					}
				}
			}
			if (num > 0 || num2 > 0)
			{
				((BaseUnityPlugin)this).Logger.LogDebug((object)$"Hammer scan: tracked {num2} new piece(s), removed {num} station requirement(s), {_originalStations.Count} piece(s) known total.");
			}
		}

		private PieceTable? TryGetHammerPieceTable()
		{
			ObjectDB instance = ObjectDB.instance;
			if (!Object.op_Implicit((Object)(object)instance))
			{
				return null;
			}
			GameObject itemPrefab = instance.GetItemPrefab("Hammer");
			if (!Object.op_Implicit((Object)(object)itemPrefab))
			{
				return null;
			}
			ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
			if (!Object.op_Implicit((Object)(object)component))
			{
				return null;
			}
			return component.m_itemData.m_shared.m_buildPieces;
		}

		private void RestoreAll()
		{
			foreach (KeyValuePair<Piece, CraftingStation> originalStation in _originalStations)
			{
				Piece key = originalStation.Key;
				if (Object.op_Implicit((Object)(object)key))
				{
					key.m_craftingStation = originalStation.Value;
				}
			}
			RestoreTools();
			_originalStations.Clear();
			_lastHammerTable = null;
		}

		private static bool IsTool(ItemData? item)
		{
			if (item == null)
			{
				return false;
			}
			if (!((Object)(object)item.m_shared.m_buildPieces != (Object)null) && (!((Object)(object)item.m_dropPrefab != (Object)null) || ((Object)item.m_dropPrefab).name.IndexOf("scythe", StringComparison.OrdinalIgnoreCase) < 0))
			{
				return item.m_shared.m_name.IndexOf("scythe", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return true;
		}

		private static bool EnabledTool(ItemData? item)
		{
			if ((Object)(object)Instance != (Object)null && Instance._enabled.Value)
			{
				return IsTool(item);
			}
			return false;
		}

		private void ApplyTool(ItemData item, HashSet<PieceTable>? tables = null)
		{
			if (IsTool(item))
			{
				SharedData shared = item.m_shared;
				if (!_toolDurability.ContainsKey(shared))
				{
					_toolDurability.Add(shared, shared.m_useDurability);
				}
				shared.m_useDurability = false;
				if ((Object)(object)shared.m_buildPieces != (Object)null && (tables == null || tables.Add(shared.m_buildPieces)))
				{
					ApplyToHammerPieces(shared.m_buildPieces);
				}
			}
		}

		private void ApplyToTools()
		{
			HashSet<PieceTable> tables = new HashSet<PieceTable>();
			if ((Object)(object)ObjectDB.instance != (Object)null)
			{
				foreach (GameObject item in ObjectDB.instance.m_items)
				{
					if (Object.op_Implicit((Object)(object)item))
					{
						ItemDrop component = item.GetComponent<ItemDrop>();
						if ((Object)(object)component != (Object)null)
						{
							ApplyTool(component.m_itemData, tables);
						}
					}
				}
			}
			if (!((Object)(object)Player.m_localPlayer != (Object)null))
			{
				return;
			}
			foreach (ItemData allItem in ((Humanoid)Player.m_localPlayer).GetInventory().GetAllItems())
			{
				ApplyTool(allItem, tables);
			}
		}

		private void RestoreTools()
		{
			foreach (KeyValuePair<SharedData, bool> item in _toolDurability)
			{
				item.Key.m_useDurability = item.Value;
			}
			_toolDurability.Clear();
		}
	}
}