Decompiled source of HammerCostCap v1.3.0

HammerCostCap.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("HammerCostCap")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+8e98c8e052d6fcb45fe4e8b236a4f39a4d16ef36")]
[assembly: AssemblyProduct("HammerCostCap")]
[assembly: AssemblyTitle("HammerCostCap")]
[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 HammerCostCap
{
	public enum CostAction
	{
		UpToDate,
		Recap,
		Capture
	}
	public sealed class CostState
	{
		public object Original { get; private set; }

		public object Capped { get; private set; }

		public CostAction Observe(object current)
		{
			if (current == null)
			{
				return CostAction.UpToDate;
			}
			if (Capped != null && current == Capped)
			{
				return CostAction.UpToDate;
			}
			if (Original != null && current == Original)
			{
				return CostAction.Recap;
			}
			return CostAction.Capture;
		}

		public void Capture(object original, object capped)
		{
			Original = original;
			Capped = capped;
		}
	}
	public enum CostMode
	{
		Full,
		Capped,
		Free
	}
	public static class CapLogic
	{
		public const int Cap = 1;

		public const CostMode DefaultMode = CostMode.Capped;

		public const float DeconstructWindow = 3f;

		public const string HintLabel = "Cost mode";

		public static int CapAmount(CostMode mode, int amount)
		{
			switch (mode)
			{
			case CostMode.Free:
				return 0;
			case CostMode.Capped:
				if (amount <= 1)
				{
					return amount;
				}
				return 1;
			default:
				return amount;
			}
		}

		public static bool NeedsCap(CostMode mode, IReadOnlyCollection<int> amounts)
		{
			switch (mode)
			{
			case CostMode.Free:
				return amounts.Count > 0;
			case CostMode.Capped:
				foreach (int amount in amounts)
				{
					if (amount > 1)
					{
						return true;
					}
				}
				return false;
			default:
				return false;
			}
		}

		public static bool ShouldCap(CostMode mode, bool inHammer, bool excluded)
		{
			if (mode != CostMode.Full && inHammer)
			{
				return !excluded;
			}
			return false;
		}

		public static CostMode RefundMode(CostMode mode, bool localDeconstruct)
		{
			if (!localDeconstruct)
			{
				return CostMode.Full;
			}
			return mode;
		}

		public static bool IsLocalDeconstruct(bool insideRemoveCall, bool targetsRemovedPiece, float secondsSinceRemove)
		{
			if (!insideRemoveCall)
			{
				if (targetsRemovedPiece && secondsSinceRemove >= 0f)
				{
					return secondsSinceRemove <= 3f;
				}
				return false;
			}
			return true;
		}

		public static CostMode NextMode(CostMode mode)
		{
			return mode switch
			{
				CostMode.Capped => CostMode.Free, 
				CostMode.Free => CostMode.Full, 
				_ => CostMode.Capped, 
			};
		}

		public static string CycleMessage(CostMode mode)
		{
			return "Hammer cost: " + mode;
		}

		public static bool ShouldCycle(bool hammerInHand, bool inWorld, bool textInputOpen)
		{
			if (hammerInHand && inWorld)
			{
				return !textInputOpen;
			}
			return false;
		}

		public static CostMode ParseMode(string text)
		{
			if (!Enum.TryParse<CostMode>(text?.Trim(), ignoreCase: true, out var result))
			{
				return CostMode.Capped;
			}
			return result;
		}

		public static HashSet<string> ParseExclusions(string text)
		{
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			if (string.IsNullOrEmpty(text))
			{
				return hashSet;
			}
			string[] array = text.Split(new char[1] { ',' });
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (text2.Length > 0)
				{
					hashSet.Add(text2);
				}
			}
			return hashSet;
		}

		public static string PrefabName(string objectName)
		{
			if (objectName == null)
			{
				return null;
			}
			int num = objectName.IndexOf("(Clone)", StringComparison.Ordinal);
			if (num >= 0)
			{
				return objectName.Substring(0, num);
			}
			return objectName;
		}
	}
	[BepInPlugin("lily.hammercostcap", "Hammer Cost Cap", "1.3.0")]
	public class HammerCostCapPlugin : BaseUnityPlugin
	{
		private static class Patches
		{
			[HarmonyPatch(typeof(PieceTable), "UpdateAvailable")]
			[HarmonyPrefix]
			private static void UpdateAvailable(PieceTable __instance)
			{
				Guarded("UpdateAvailable", delegate
				{
					if (!IsHammer(__instance))
					{
						return;
					}
					_hammerTable = __instance;
					RefreshHammer();
					foreach (GameObject piece in __instance.m_pieces)
					{
						Piece val = (((Object)(object)piece != (Object)null) ? piece.GetComponent<Piece>() : null);
						if ((Object)(object)val != (Object)null)
						{
							Apply(val, ((Object)piece).name);
						}
					}
				});
			}

			[HarmonyPatch(typeof(Player), "HaveRequirements", new Type[]
			{
				typeof(Piece),
				typeof(RequirementMode)
			})]
			[HarmonyPrefix]
			private static void HaveRequirements(Piece piece)
			{
				Guarded("HaveRequirements", delegate
				{
					if ((Object)(object)piece != (Object)null)
					{
						Apply(piece, CapLogic.PrefabName(((Object)((Component)piece).gameObject).name));
					}
				});
			}

			[HarmonyPatch(typeof(Hud), "SetupPieceInfo")]
			[HarmonyPrefix]
			private static void SetupPieceInfo(Piece piece)
			{
				Guarded("SetupPieceInfo", delegate
				{
					if ((Object)(object)piece != (Object)null)
					{
						Apply(piece, CapLogic.PrefabName(((Object)((Component)piece).gameObject).name));
					}
				});
			}

			[HarmonyPatch(typeof(Piece), "DropResources")]
			[HarmonyPrefix]
			private static void DropResources(Piece __instance)
			{
				Guarded("DropResources", delegate
				{
					if ((Object)(object)__instance != (Object)null)
					{
						CapPlaced(__instance);
					}
				});
			}

			[HarmonyPatch(typeof(Player), "RemovePiece")]
			[HarmonyPrefix]
			private static void RemovePiecePrefix(Player __instance)
			{
				Guarded("RemovePiece", delegate
				{
					NoteRemove(__instance);
				});
			}

			[HarmonyPatch(typeof(Player), "RemovePiece")]
			[HarmonyPostfix]
			private static void RemovePiecePostfix()
			{
				_insideRemove = false;
			}

			[HarmonyPatch(typeof(WearNTear), "Remove")]
			[HarmonyPrefix]
			private static void WearNTearRemove(WearNTear __instance)
			{
				Guarded("WearNTear.Remove", delegate
				{
					if (_insideRemove)
					{
						NoteRemoved((Component)(object)__instance);
					}
				});
			}
		}

		public const string Guid = "lily.hammercostcap";

		public const string Version = "1.3.0";

		private const string HammerItem = "Hammer";

		private const string HammerTableName = "_HammerPieceTable";

		private static HammerCostCapPlugin _instance;

		private static ConfigEntry<CostMode> _mode;

		private static ConfigEntry<string> _exclude;

		private static ConfigEntry<bool> _debugLog;

		private static ConfigEntry<KeyboardShortcut> _cycleKey;

		private static HashSet<string> _excluded = new HashSet<string>(StringComparer.Ordinal);

		private static readonly Dictionary<Piece, CostState> _states = new Dictionary<Piece, CostState>();

		private static readonly HashSet<string> _warned = new HashSet<string>();

		private static HashSet<string> _hammerNames = new HashSet<string>(StringComparer.Ordinal);

		private static PieceTable _hammerTable;

		private static int _hammerCount = -1;

		private Harmony _harmony;

		private static readonly MethodInfo _getRightItem = AccessTools.Method(typeof(Humanoid), "GetRightItem", (Type[])null, (Type[])null);

		private static GameObject _hint;

		private static TMP_Text _hintKey;

		private static bool _hintDirty = true;

		private static bool _hintGaveUp;

		private static bool _insideRemove;

		private static ZDOID _removedId = ZDOID.None;

		private static float _removedAt = -1000f;

		private void Awake()
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Expected O, but got Unknown
			_instance = this;
			_mode = ((BaseUnityPlugin)this).Config.Bind<CostMode>("General", "Mode", CostMode.Capped, "What every Hammer piece costs: Capped = at most 1 of each item it needs, Free = nothing, Full = the original cost. Applies at once (BEH-1-1, 3-1).");
			_exclude = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Exclude", "", "Comma-separated prefab names that keep their original cost, e.g. portal_wood, piece_chest_wood (BEH-1-4).");
			_cycleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "CycleKey", new KeyboardShortcut((KeyCode)287, Array.Empty<KeyCode>()), "Cycles Mode (Capped -> Free -> Full) while the Hammer is equipped; written to this file (BEH-3-7).");
			_cycleKey.SettingChanged += delegate
			{
				_hintDirty = true;
			};
			_debugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugLog", false, "Log each piece the first time it is capped, and every restore.");
			_excluded = CapLogic.ParseExclusions(_exclude.Value);
			_mode.SettingChanged += delegate
			{
				Reapply();
			};
			_exclude.SettingChanged += delegate
			{
				_excluded = CapLogic.ParseExclusions(_exclude.Value);
				Reapply();
			};
			try
			{
				_harmony = new Harmony("lily.hammercostcap");
				_harmony.PatchAll(typeof(Patches));
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("HammerCostCap disabled: " + ex));
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			if ((Object)(object)_hint != (Object)null)
			{
				Object.Destroy((Object)(object)_hint);
			}
		}

		private void Update()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				KeyboardShortcut value = _cycleKey.Value;
				if (((KeyboardShortcut)(ref value)).IsDown())
				{
					CycleMode();
				}
				UpdateHint();
			}
			catch (Exception ex)
			{
				WarnOnce("update", "HammerCostCap hotkey failed: " + ex);
			}
		}

		private static bool HammerInHand()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || _getRightItem == null)
			{
				return false;
			}
			object? obj = _getRightItem.Invoke(localPlayer, null);
			ItemData val = (ItemData)((obj is ItemData) ? obj : null);
			if (val != null)
			{
				return IsHammer(val.m_shared?.m_buildPieces);
			}
			return false;
		}

		private static bool TextInputOpen()
		{
			if (!TextInput.IsVisible() && !Console.IsVisible())
			{
				if ((Object)(object)Chat.instance != (Object)null)
				{
					return Chat.instance.HasFocus();
				}
				return false;
			}
			return true;
		}

		private static void CycleMode()
		{
			if (CapLogic.ShouldCycle(HammerInHand(), (Object)(object)Player.m_localPlayer != (Object)null, TextInputOpen()))
			{
				_mode.Value = CapLogic.NextMode(_mode.Value);
				((BaseUnityPlugin)_instance).Config.Save();
				MessageHud instance = MessageHud.instance;
				if (instance != null)
				{
					instance.ShowMessage((MessageType)2, CapLogic.CycleMessage(_mode.Value), 0, (Sprite)null, false, true);
				}
			}
		}

		private static void UpdateHint()
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			KeyHints instance = KeyHints.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.m_buildHints == (Object)null)
			{
				_hint = null;
				return;
			}
			if ((Object)(object)_hint == (Object)null)
			{
				if (_hintGaveUp)
				{
					return;
				}
				if (!BuildHint(instance.m_buildHints))
				{
					_hintGaveUp = true;
					return;
				}
				_hintDirty = true;
			}
			if (_hintDirty && (Object)(object)_hintKey != (Object)null)
			{
				TMP_Text hintKey = _hintKey;
				KeyboardShortcut value = _cycleKey.Value;
				hintKey.text = ((object)((KeyboardShortcut)(ref value)).MainKey/*cast due to .constrained prefix*/).ToString();
				_hintDirty = false;
			}
		}

		private static bool BuildHint(GameObject bar)
		{
			Transform val = null;
			TMP_Text[] componentsInChildren = bar.GetComponentsInChildren<TMP_Text>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Transform val2 = HintRoot(componentsInChildren[i].transform, bar.transform);
				if ((Object)(object)val2 != (Object)null && ((Component)val2).GetComponentsInChildren<TMP_Text>(true).Length == 2)
				{
					val = val2;
					break;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				WarnOnce("hint", "build hint bar layout not recognised; the Cost mode hint is skipped. Tree: " + Tree(bar.transform, 0));
				return false;
			}
			GameObject obj = Object.Instantiate<GameObject>(((Component)val).gameObject, val.parent);
			((Object)obj).name = "HammerCostCapHint";
			obj.transform.SetAsLastSibling();
			TMP_Text[] componentsInChildren2 = obj.GetComponentsInChildren<TMP_Text>(true);
			TMP_Text obj2 = ((componentsInChildren2[0].text.Length <= componentsInChildren2[1].text.Length) ? componentsInChildren2[0] : componentsInChildren2[1]);
			((obj2 == componentsInChildren2[0]) ? componentsInChildren2[1] : componentsInChildren2[0]).text = "Cost mode";
			_hintKey = obj2;
			_hint = obj;
			Log("Cost mode hint added, cloned from " + ((Object)val).name);
			return true;
		}

		private static Transform HintRoot(Transform t, Transform bar)
		{
			while ((Object)(object)t != (Object)null && (Object)(object)t.parent != (Object)null && (Object)(object)t.parent != (Object)(object)bar)
			{
				if (t.parent.childCount >= 3)
				{
					return t;
				}
				t = t.parent;
			}
			if (!((Object)(object)t != (Object)null) || !((Object)(object)t.parent == (Object)(object)bar))
			{
				return null;
			}
			return t;
		}

		private static string Tree(Transform t, int depth)
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append('\n').Append(' ', depth * 2).Append(((Object)t).name);
			TMP_Text[] components = ((Component)t).GetComponents<TMP_Text>();
			foreach (TMP_Text val in components)
			{
				stringBuilder.Append(" \"").Append(val.text).Append('"');
			}
			foreach (Transform item in t)
			{
				Transform t2 = item;
				stringBuilder.Append(Tree(t2, depth + 1));
			}
			return stringBuilder.ToString();
		}

		private static void Reapply()
		{
			try
			{
				foreach (KeyValuePair<Piece, CostState> state in _states)
				{
					if ((Object)(object)state.Key != (Object)null)
					{
						Restore(state.Key);
					}
				}
				_states.Clear();
				RefreshHammer(force: true);
				foreach (string hammerName in _hammerNames)
				{
					ZNetScene instance = ZNetScene.instance;
					GameObject obj = ((instance != null) ? instance.GetPrefab(hammerName) : null);
					Piece val = ((obj != null) ? obj.GetComponent<Piece>() : null);
					if ((Object)(object)val != (Object)null)
					{
						Apply(val, hammerName);
					}
				}
				Log("Mode " + _mode.Value.ToString() + ", " + _excluded.Count + " excluded; costs reapplied to " + _hammerNames.Count + " Hammer pieces");
			}
			catch (Exception ex)
			{
				WarnOnce("reapply", "failed to reapply costs: " + ex);
			}
		}

		private static void RefreshHammer(bool force = false)
		{
			PieceTable val = _hammerTable;
			if ((Object)(object)val == (Object)null)
			{
				ObjectDB instance = ObjectDB.instance;
				object obj;
				if (instance == null)
				{
					obj = null;
				}
				else
				{
					GameObject itemPrefab = instance.GetItemPrefab("Hammer");
					obj = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null);
				}
				val = ((ItemDrop)(obj?)).m_itemData?.m_shared?.m_buildPieces;
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				_hammerTable = val;
			}
			if (!force && val.m_pieces.Count == _hammerCount)
			{
				return;
			}
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			foreach (GameObject piece in val.m_pieces)
			{
				if ((Object)(object)piece != (Object)null)
				{
					hashSet.Add(((Object)piece).name);
				}
			}
			_hammerNames = hashSet;
			_hammerCount = val.m_pieces.Count;
		}

		private static bool IsHammer(PieceTable table)
		{
			if ((Object)(object)table != (Object)null)
			{
				if (table != _hammerTable)
				{
					return ((Object)((Component)table).gameObject).name == "_HammerPieceTable";
				}
				return true;
			}
			return false;
		}

		private static bool InHammer(string prefab)
		{
			if (_hammerNames.Count == 0)
			{
				RefreshHammer();
			}
			return _hammerNames.Contains(prefab);
		}

		private static void Apply(Piece piece, string prefab)
		{
			if ((Object)(object)piece == (Object)null)
			{
				return;
			}
			if (!CapLogic.ShouldCap(_mode.Value, InHammer(prefab), _excluded.Contains(prefab)))
			{
				Restore(piece);
				return;
			}
			Requirement[] resources = piece.m_resources;
			if (resources == null)
			{
				return;
			}
			if (!_states.TryGetValue(piece, out var value))
			{
				value = new CostState();
				_states[piece] = value;
			}
			switch (value.Observe(resources))
			{
			case CostAction.UpToDate:
				break;
			case CostAction.Recap:
				piece.m_resources = (Requirement[])value.Capped;
				break;
			case CostAction.Capture:
			{
				Requirement[] array = CapCopy(resources);
				value.Capture(resources, array);
				piece.m_resources = array;
				if (array != resources)
				{
					Log("capped " + prefab + ": " + Describe(resources) + " -> " + Describe(array));
				}
				break;
			}
			}
		}

		private static void Restore(Piece piece)
		{
			if (_states.TryGetValue(piece, out var value))
			{
				Requirement[] array = (Requirement[])value.Original;
				if (array != null && piece.m_resources != array && piece.m_resources == value.Capped)
				{
					piece.m_resources = array;
					Log("restored " + ((Object)((Component)piece).gameObject).name + ": " + Describe(array));
				}
			}
		}

		private static Requirement[] CapCopy(Requirement[] reqs)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Expected O, but got Unknown
			CostMode value = _mode.Value;
			int[] array = new int[reqs.Length];
			for (int i = 0; i < reqs.Length; i++)
			{
				array[i] = ((reqs[i] != null) ? reqs[i].m_amount : 0);
			}
			if (!CapLogic.NeedsCap(value, (IReadOnlyCollection<int>)(object)array))
			{
				return reqs;
			}
			if (value == CostMode.Free)
			{
				return (Requirement[])(object)new Requirement[0];
			}
			Requirement[] array2 = (Requirement[])(object)new Requirement[reqs.Length];
			for (int j = 0; j < reqs.Length; j++)
			{
				Requirement val = reqs[j];
				if (val != null)
				{
					array2[j] = new Requirement
					{
						m_resItem = val.m_resItem,
						m_amount = CapLogic.CapAmount(value, val.m_amount),
						m_extraAmountOnlyOneIngredient = val.m_extraAmountOnlyOneIngredient,
						m_amountPerLevel = val.m_amountPerLevel,
						m_recover = val.m_recover
					};
				}
			}
			return array2;
		}

		private static void NoteRemove(Player player)
		{
			_insideRemove = true;
			NoteRemoved((Component)(object)player.GetHoveringPiece());
		}

		private static void NoteRemoved(Component target)
		{
			//IL_0023: 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)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			ZNetView val = (Object.op_Implicit((Object)(object)target) ? target.GetComponent<ZNetView>() : null);
			ZDOID val2 = (((Object)(object)val != (Object)null && val.GetZDO() != null) ? val.GetZDO().m_uid : ZDOID.None);
			if (val2 != ZDOID.None)
			{
				_removedId = val2;
				_removedAt = Time.time;
			}
		}

		private static void CapPlaced(Piece piece)
		{
			//IL_0035: 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)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Expected O, but got Unknown
			string text = CapLogic.PrefabName(((Object)((Component)piece).gameObject).name);
			Requirement[] array = OriginalCost(text, piece);
			if (array == null)
			{
				return;
			}
			ZNetView component = ((Component)piece).GetComponent<ZNetView>();
			ZDOID val = (((Object)(object)component != (Object)null && component.GetZDO() != null) ? component.GetZDO().m_uid : ZDOID.None);
			bool flag = CapLogic.IsLocalDeconstruct(_insideRemove, val != ZDOID.None && val == _removedId, Time.time - _removedAt);
			CostMode mode = CapLogic.RefundMode(_mode.Value, flag);
			if (!CapLogic.ShouldCap(mode, InHammer(text), _excluded.Contains(text)))
			{
				mode = CostMode.Full;
			}
			Requirement[] array2 = (Requirement[])(object)new Requirement[array.Length];
			for (int i = 0; i < array.Length; i++)
			{
				Requirement val2 = array[i];
				if (val2 != null)
				{
					array2[i] = new Requirement
					{
						m_resItem = val2.m_resItem,
						m_amount = CapLogic.CapAmount(mode, val2.m_amount),
						m_extraAmountOnlyOneIngredient = val2.m_extraAmountOnlyOneIngredient,
						m_amountPerLevel = val2.m_amountPerLevel,
						m_recover = val2.m_recover
					};
				}
			}
			piece.m_resources = array2;
			Log("refund " + text + " as " + mode.ToString() + (flag ? " (own deconstruction)" : " (not ours)") + ": " + Describe(array2));
		}

		private static Requirement[] OriginalCost(string prefab, Piece placed)
		{
			ZNetScene instance = ZNetScene.instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				GameObject prefab2 = instance.GetPrefab(prefab);
				obj = ((prefab2 != null) ? prefab2.GetComponent<Piece>() : null);
			}
			Piece val = (Piece)obj;
			if ((Object)(object)val == (Object)null)
			{
				return placed.m_resources;
			}
			if (_states.TryGetValue(val, out var value) && value.Original is Requirement[] array && (val.m_resources == value.Capped || val.m_resources == array))
			{
				return array;
			}
			return val.m_resources;
		}

		private static string Describe(Requirement[] reqs)
		{
			StringBuilder stringBuilder = new StringBuilder("[");
			foreach (Requirement val in reqs)
			{
				if (stringBuilder.Length > 1)
				{
					stringBuilder.Append(", ");
				}
				stringBuilder.Append((val == null) ? "?" : (val.m_amount + " " + (Object.op_Implicit((Object)(object)val.m_resItem) ? ((Object)val.m_resItem).name : "?")));
			}
			return stringBuilder.Append(']').ToString();
		}

		private static void Log(string message)
		{
			if (_debugLog.Value)
			{
				((BaseUnityPlugin)_instance).Logger.LogInfo((object)message);
			}
		}

		private static void WarnOnce(string key, string message)
		{
			if (_warned.Add(key))
			{
				((BaseUnityPlugin)_instance).Logger.LogWarning((object)message);
			}
		}

		private static void Guarded(string key, Action action)
		{
			try
			{
				action();
			}
			catch (Exception ex)
			{
				WarnOnce(key, "HammerCostCap " + key + " failed: " + ex);
			}
		}
	}
}