Decompiled source of HammerHotkeys v1.0.0

HammerHotkeys.dll

Decompiled 5 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 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("HammerHotkeys")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("HammerHotkeys")]
[assembly: AssemblyTitle("HammerHotkeys")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace HammerHotkeys;

[BepInPlugin("DMT.HammerHotkeys", "HammerHotkeys", "1.0.0")]
public class HammerHotkeysPlugin : BaseUnityPlugin
{
	private struct Bind
	{
		public KeyCode Key;

		public string Piece;
	}

	internal const string PluginGUID = "DMT.HammerHotkeys";

	internal const string PluginName = "HammerHotkeys";

	internal const string PluginVersion = "1.0.0";

	private const int MaxPendingAttempts = 30;

	private static ConfigEntry<string> BindsEntry;

	private static ConfigEntry<bool> AutoEquipEntry;

	private static ConfigEntry<bool> RequireAvailableEntry;

	private static ConfigEntry<bool> PlaySoundEntry;

	private static ConfigEntry<bool> ShowMessagesEntry;

	private static ConfigEntry<bool> OpenMenuEntry;

	private readonly List<Bind> _binds = new List<Bind>();

	private readonly HashSet<string> _warnedNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

	private Piece _pending;

	private int _pendingAttempts;

	private void Awake()
	{
		BindsEntry = ((BaseUnityPlugin)this).Config.Bind<string>("1 - General", "Binds", "F6=Workbench;F7=Portal;F8=Stonecutter", "Key=Piece pairs separated by ';'. The piece name is matched against the prefab name, the $piece_... localization key, and the English display name.");
		AutoEquipEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Auto Equip Hammer", true, "Equip the tool that contains the piece automatically if it is not already held.");
		RequireAvailableEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Require Available", true, "Only select pieces that are currently available/unlocked (same rule as the vanilla build menu).");
		PlaySoundEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Play Sound", true, "Play the vanilla selection sound when a piece is selected.");
		ShowMessagesEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Show Messages", true, "Show a center screen message when a bind fires or fails.");
		OpenMenuEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Open Build Menu On Select", false, "Open the build menu after selecting the piece instead of keeping it closed.");
		ParseBinds();
		BindsEntry.SettingChanged += OnBindsSettingChanged;
		((BaseUnityPlugin)this).Logger.LogInfo((object)string.Format("{0} {1} loaded with {2} bind(s)", "HammerHotkeys", "1.0.0", _binds.Count));
	}

	private void OnBindsSettingChanged(object sender, EventArgs e)
	{
		ParseBinds();
	}

	private void ParseBinds()
	{
		//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		_binds.Clear();
		string[] array = (BindsEntry.Value ?? string.Empty).Split(new char[1] { ';' });
		for (int i = 0; i < array.Length; i++)
		{
			string text = array[i].Trim();
			if (text.Length == 0)
			{
				continue;
			}
			int num = text.IndexOf('=');
			if (num <= 0 || num >= text.Length - 1)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Invalid bind '" + text + "', expected format Key=Piece"));
				continue;
			}
			string text2 = text.Substring(0, num).Trim();
			string piece = text.Substring(num + 1).Trim();
			if (!Enum.TryParse<KeyCode>(text2, ignoreCase: true, out KeyCode result))
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Invalid key '" + text2 + "' in bind '" + text + "'"));
			}
			else
			{
				_binds.Add(new Bind
				{
					Key = result,
					Piece = piece
				});
			}
		}
		((BaseUnityPlugin)this).Logger.LogInfo((object)$"Loaded {_binds.Count} bind(s): {DescribeBinds()}");
	}

	private string DescribeBinds()
	{
		//IL_0041: Unknown result type (might be due to invalid IL or missing references)
		if (_binds.Count == 0)
		{
			return "none";
		}
		List<string> list = new List<string>(_binds.Count);
		foreach (Bind bind in _binds)
		{
			list.Add($"{bind.Key}={bind.Piece}");
		}
		return string.Join(", ", list);
	}

	private void Update()
	{
		//IL_0052: Unknown result type (might be due to invalid IL or missing references)
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null || IsBlocked(localPlayer))
		{
			return;
		}
		if ((Object)(object)_pending != (Object)null)
		{
			AttemptPending(localPlayer);
		}
		if (_binds.Count == 0)
		{
			return;
		}
		foreach (Bind bind in _binds)
		{
			if (Input.GetKeyDown(bind.Key))
			{
				HandleBind(localPlayer, bind);
				break;
			}
		}
	}

	private static bool IsBlocked(Player player)
	{
		if (!((Character)player).IsDead() && !Console.IsVisible() && !TextInput.IsVisible() && !InventoryGui.IsVisible())
		{
			return Menu.IsVisible();
		}
		return true;
	}

	private void HandleBind(Player player, Bind bind)
	{
		if (!TryResolve(player, bind.Piece, out var tool, out var piece))
		{
			WarnUnknownPiece(player, bind.Piece);
			return;
		}
		if (((Humanoid)player).RightItem != tool)
		{
			if (!AutoEquipEntry.Value)
			{
				ShowMessage(player, "Hold " + DescribeTool(tool) + " first");
				return;
			}
			if (!((Humanoid)player).EquipItem(tool, true))
			{
				ShowMessage(player, "Can't equip " + DescribeTool(tool));
				return;
			}
		}
		if (RequireAvailableEntry.Value && !player.IsPieceAvailable(piece))
		{
			ShowMessage(player, DescribePiece(piece) + " is not available yet");
			return;
		}
		_pending = piece;
		_pendingAttempts = 30;
		AttemptPending(player);
	}

	private void AttemptPending(Player player)
	{
		Piece pending = _pending;
		if (!((Object)(object)pending == (Object)null))
		{
			if (player.SetSelectedPiece(pending) || (Object)(object)player.GetSelectedPiece() == (Object)(object)pending)
			{
				_pending = null;
				OnSelected(player, pending);
			}
			else if (--_pendingAttempts <= 0)
			{
				_pending = null;
				ShowMessage(player, "Couldn't select " + DescribePiece(pending));
				((BaseUnityPlugin)this).Logger.LogWarning((object)("SetSelectedPiece failed for '" + ((Object)pending).name + "' (place mode not ready?)"));
			}
		}
	}

	private void OnSelected(Player player, Piece piece)
	{
		Hud instance = Hud.instance;
		BuildUi val = (((Object)(object)instance != (Object)null) ? instance.m_buildUi : null);
		bool flag = (Object)(object)val != (Object)null && ((Component)val).gameObject.activeInHierarchy;
		if (OpenMenuEntry.Value)
		{
			if ((Object)(object)val != (Object)null && !flag)
			{
				val.OpenBuildMenu();
			}
		}
		else if (flag)
		{
			val.Close();
		}
		if (PlaySoundEntry.Value)
		{
			player.PlayButtonSound();
		}
		ShowMessage(player, DescribePiece(piece) + " ready");
	}

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

	private void WarnUnknownPiece(Player player, string name)
	{
		if (_warnedNames.Add(name))
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("No piece named '" + name + "' found in your build tools. Use the prefab name, the $piece_... localization key, or the English display name."));
		}
		ShowMessage(player, "Unknown piece '" + name + "'");
	}

	private static bool TryResolve(Player player, string name, out ItemData tool, out Piece piece)
	{
		tool = null;
		piece = null;
		Inventory inventory = ((Humanoid)player).GetInventory();
		if (inventory == null)
		{
			return false;
		}
		List<ItemData> allItems = inventory.GetAllItems();
		if (allItems == null)
		{
			return false;
		}
		ItemData val = null;
		Piece val2 = null;
		foreach (ItemData item in allItems)
		{
			if (item == null || item.m_shared == null)
			{
				continue;
			}
			PieceTable buildPieces = item.m_shared.m_buildPieces;
			if ((Object)(object)buildPieces == (Object)null || buildPieces.m_pieces == null)
			{
				continue;
			}
			Piece val3 = FindPiece(buildPieces, name);
			if (!((Object)(object)val3 == (Object)null))
			{
				if (IsBuildTool(item))
				{
					tool = item;
					piece = val3;
					return true;
				}
				if (val == null)
				{
					val = item;
					val2 = val3;
				}
			}
		}
		tool = val;
		piece = val2;
		return (Object)(object)piece != (Object)null;
	}

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

	private static Piece FindPiece(PieceTable table, string name)
	{
		foreach (GameObject piece in table.m_pieces)
		{
			if (!((Object)(object)piece == (Object)null))
			{
				Piece component = piece.GetComponent<Piece>();
				if ((Object)(object)component != (Object)null && Matches(component, piece, name))
				{
					return component;
				}
			}
		}
		return null;
	}

	private static bool Matches(Piece piece, GameObject go, string name)
	{
		if (string.Equals(((Object)go).name, name, StringComparison.OrdinalIgnoreCase))
		{
			return true;
		}
		string name2 = piece.m_name;
		if (string.IsNullOrEmpty(name2))
		{
			return false;
		}
		if (string.Equals(name2, name, StringComparison.OrdinalIgnoreCase))
		{
			return true;
		}
		if (string.Equals(name2.TrimStart(new char[1] { '$' }), name, StringComparison.OrdinalIgnoreCase))
		{
			return true;
		}
		if (string.Equals(name2, "$" + name, StringComparison.OrdinalIgnoreCase))
		{
			return true;
		}
		Localization instance = Localization.instance;
		if (instance == null)
		{
			return false;
		}
		string a = instance.Localize(name2);
		if (string.Equals(a, name, StringComparison.OrdinalIgnoreCase))
		{
			return true;
		}
		if (!string.Equals(a, name2, StringComparison.Ordinal))
		{
			return false;
		}
		string text = name2.TrimStart(new char[1] { '$' });
		a = instance.Localize(text);
		return string.Equals(a, name, StringComparison.OrdinalIgnoreCase);
	}

	private static string DescribePiece(Piece piece)
	{
		if ((Object)(object)piece == (Object)null)
		{
			return string.Empty;
		}
		string name = piece.m_name;
		Localization instance = Localization.instance;
		if (!string.IsNullOrEmpty(name) && instance != null)
		{
			string text = instance.Localize(name);
			if (string.Equals(text, name, StringComparison.Ordinal))
			{
				text = instance.Localize(name.TrimStart(new char[1] { '$' }));
			}
			if (!string.IsNullOrEmpty(text) && !string.Equals(text, name, StringComparison.Ordinal))
			{
				return text;
			}
		}
		return ((Object)piece).name;
	}

	private static string DescribeTool(ItemData item)
	{
		if (item == null)
		{
			return "the tool";
		}
		if ((Object)(object)item.m_dropPrefab != (Object)null)
		{
			return ((Object)item.m_dropPrefab).name;
		}
		if (!string.IsNullOrEmpty(item.m_shared?.m_name))
		{
			return item.m_shared.m_name;
		}
		return "the tool";
	}
}