Decompiled source of BetterHammer v1.0.1

BetterHammer.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BetterHammer.Core;
using BetterHammer.Grid;
using BetterHammer.Materials;
using BetterHammer.Structures;
using HarmonyLib;
using Jotunn.Configs;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("BetterHammer")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Open the build menu without a hammer, build with nearby materials, snap to a build grid, and copy and move structures.")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1+9ebcc11310090566bef46a7bd35a2e1c4f7e2898")]
[assembly: AssemblyProduct("BetterHammer")]
[assembly: AssemblyTitle("BetterHammer")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.1.0")]
[module: UnverifiableCode]
[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 BetterHammer
{
	[BepInPlugin("javidahmed64592.betterhammer", "Better Hammer", "1.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class BetterHammerPlugin : BaseUnityPlugin
	{
		public const string PluginGUID = "javidahmed64592.betterhammer";

		public const string PluginName = "Better Hammer";

		public const string PluginVersion = "1.0.1";

		private const string HammerPrefabName = "Hammer";

		private const string ButtonName = "BetterHammer_Toggle";

		private const string ButtonQueryName = "BetterHammer_Toggle!javidahmed64592.betterhammer";

		private static readonly float[] GridSizes = new float[5] { 0.25f, 0.5f, 1f, 2f, 4f };

		internal static ItemData _phantomHammer;

		private static ConfigEntry<bool> _gridEnabled;

		internal static ConfigEntry<float> _gridSize;

		private static readonly GridOverlay Overlay = new GridOverlay();

		internal static int _aimFrame = -10;

		internal static Vector3 _aimPoint;

		internal static GridPlane _aimPlane;

		internal static float _aimSign;

		private ConfigEntry<KeyCode> _keybind;

		private Harmony _harmony;

		private bool _knownRecipesRefreshed;

		private Piece _lastBuildPiece;

		internal static bool GridEnabled => _gridEnabled.Value;

		private void Awake()
		{
			//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_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Expected O, but got Unknown
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Expected O, but got Unknown
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Expected O, but got Unknown
			_keybind = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Keybinds", "Open Build Menu", (KeyCode)98, "Equips a virtual hammer and opens the build menu, without needing a real hammer in your inventory. Rebindable from the in-game controls menu.");
			InputManager.Instance.AddButton("javidahmed64592.betterhammer", new ButtonConfig
			{
				Name = "BetterHammer_Toggle",
				Config = _keybind
			});
			_gridEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Grid", "Enabled", true, "Show a world grid while building and snap pieces to its vertices.");
			_gridSize = ((BaseUnityPlugin)this).Config.Bind<float>("Grid", "Snap Distance", GridSizes[1], new ConfigDescription("Distance in metres between grid vertices (0.25, 0.5, 1, 2 or 4). While building, hold Ctrl and scroll to double or halve it.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(GridSizes[0], GridSizes[GridSizes.Length - 1]), Array.Empty<object>()));
			GridOverlay.BindConfig(((BaseUnityPlugin)this).Config);
			ChestMaterials.BindConfig(((BaseUnityPlugin)this).Config);
			CopyLibrary.BindConfig(((BaseUnityPlugin)this).Config);
			MultiCopy.BindConfig(((BaseUnityPlugin)this).Config);
			Translations.Load();
			if (Array.IndexOf(GridSizes, _gridSize.Value) < 0)
			{
				_gridSize.Value = GridSizes[1];
			}
			_harmony = new Harmony("javidahmed64592.betterhammer");
			_harmony.PatchAll();
		}

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

		private void Update()
		{
			if (_phantomHammer != null)
			{
				_phantomHammer.m_durability = _phantomHammer.m_shared.m_maxDurability;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				_phantomHammer = null;
				_knownRecipesRefreshed = false;
				_lastBuildPiece = null;
				PieceMover.Reset();
				MultiCopy.Reset();
				Overlay.Hide();
				return;
			}
			EnsurePhantomHammer();
			CopyLibrary.EnsureLoaded(localPlayer, _phantomHammer?.m_shared.m_buildPieces);
			if (!_knownRecipesRefreshed && _phantomHammer != null)
			{
				_knownRecipesRefreshed = true;
				localPlayer.UpdateKnownRecipesList();
			}
			if (Menu.IsVisible() || InventoryGui.IsVisible() || ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus()))
			{
				Overlay.Hide();
				return;
			}
			CopyLibrary.UpdateMenuInput(localPlayer);
			MultiCopy.UpdateSelectionKeys(localPlayer);
			if (ZInput.GetButtonDown("BetterHammer_Toggle!javidahmed64592.betterhammer"))
			{
				ToggleBuildMenu(localPlayer);
			}
			if (((Character)localPlayer).InPlaceMode() && Input.GetMouseButtonDown(1) && !PieceMover.RightClickConsumed && !MultiCopy.RightClickConsumed)
			{
				if (ShiftHeld())
				{
					ToggleRepairMode(localPlayer);
				}
				else if (CtrlHeld())
				{
					ToggleGrid(localPlayer);
				}
			}
			UpdateGrid(localPlayer);
		}

		private void LateUpdate()
		{
			MultiCopy.UpdateHighlight();
			PieceMover.UpdateHighlight();
		}

		private static void ToggleGrid(Player player)
		{
			_gridEnabled.Value = !_gridEnabled.Value;
			((Character)player).Message((MessageType)1, _gridEnabled.Value ? "$betterhammer_grid_on" : "$betterhammer_grid_off", 0, (Sprite)null, false);
		}

		private static void UpdateGrid(Player player)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			if (!GridActive(player) || Time.frameCount - _aimFrame > 2 || _aimPlane == GridPlane.None)
			{
				Overlay.Hide();
				return;
			}
			HandleGridScroll(player);
			Overlay.Show(_aimPoint, _gridSize.Value, _aimPlane, _aimSign);
		}

		internal static bool GridActive(Player player)
		{
			if (_gridEnabled.Value && ((Character)player).InPlaceMode() && !player.InRepairMode() && (Object)(object)player.m_placementGhost != (Object)null)
			{
				return IsHammerEquipped(player);
			}
			return false;
		}

		internal static bool IsHammerEquipped(Player player)
		{
			ItemData rightItem = ((Humanoid)player).GetRightItem();
			if (rightItem == null)
			{
				return false;
			}
			if (rightItem == _phantomHammer)
			{
				return true;
			}
			PieceTable val = rightItem.m_shared?.m_buildPieces;
			if ((Object)(object)val != (Object)null)
			{
				if (!ContainsHammer(rightItem.m_shared.m_name) && !ContainsHammer(((Object)(object)rightItem.m_dropPrefab != (Object)null) ? ((Object)rightItem.m_dropPrefab).name : null))
				{
					return ContainsHammer(((Object)val).name);
				}
				return true;
			}
			return false;
		}

		private static bool ContainsHammer(string name)
		{
			if (name != null)
			{
				return name.IndexOf("hammer", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return false;
		}

		internal static bool ShiftHeld()
		{
			if (!Input.GetKey((KeyCode)304))
			{
				return Input.GetKey((KeyCode)303);
			}
			return true;
		}

		internal static bool CtrlHeld()
		{
			if (!Input.GetKey((KeyCode)306))
			{
				return Input.GetKey((KeyCode)305);
			}
			return true;
		}

		internal static bool AltHeld()
		{
			if (!Input.GetKey((KeyCode)308))
			{
				return Input.GetKey((KeyCode)307);
			}
			return true;
		}

		internal static bool AltZoomActive(Player player)
		{
			if ((Object)(object)player == (Object)(object)Player.m_localPlayer && AltHeld() && ((Character)player).InPlaceMode())
			{
				return IsHammerEquipped(player);
			}
			return false;
		}

		private static void HandleGridScroll(Player player)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			float y = Input.mouseScrollDelta.y;
			if (y != 0f && CtrlHeld())
			{
				float num = ((y > 0f) ? (_gridSize.Value * 2f) : (_gridSize.Value / 2f));
				num = Mathf.Clamp(num, GridSizes[0], GridSizes[GridSizes.Length - 1]);
				if (!Mathf.Approximately(num, _gridSize.Value))
				{
					_gridSize.Value = num;
					((Character)player).Message((MessageType)1, Localization.instance.Localize("$betterhammer_grid_distance", new string[1] { num.ToString("0.###", CultureInfo.InvariantCulture) }), 0, (Sprite)null, false);
				}
			}
		}

		private void ToggleRepairMode(Player player)
		{
			if (player.InRepairMode())
			{
				if ((Object)(object)_lastBuildPiece != (Object)null)
				{
					player.SetSelectedPiece(_lastBuildPiece);
				}
				return;
			}
			_lastBuildPiece = player.GetSelectedPiece();
			Piece val = player.GetBuildPieces()?.FirstOrDefault((Func<Piece, bool>)((Piece p) => p.m_repairPiece));
			if ((Object)(object)val != (Object)null)
			{
				player.SetSelectedPiece(val);
			}
		}

		private static void ToggleBuildMenu(Player player)
		{
			EnsurePhantomHammer();
			if (_phantomHammer != null)
			{
				if (((Humanoid)player).GetRightItem() != _phantomHammer)
				{
					((Humanoid)player).EquipItem(_phantomHammer, true);
				}
				else
				{
					((Humanoid)player).UnequipItem(_phantomHammer, true);
				}
			}
		}

		private static void EnsurePhantomHammer()
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: 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_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: 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)
			//IL_008e: Expected O, but got Unknown
			if (_phantomHammer == null && !((Object)(object)ObjectDB.instance == (Object)null))
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("Hammer");
				if (!((Object)(object)itemPrefab == (Object)null))
				{
					ItemDrop component = itemPrefab.GetComponent<ItemDrop>();
					_phantomHammer = new ItemData
					{
						m_shared = component.m_itemData.m_shared,
						m_dropPrefab = itemPrefab,
						m_stack = 1,
						m_quality = 1,
						m_variant = 0,
						m_durability = component.m_itemData.m_shared.m_maxDurability,
						m_customData = new Dictionary<string, string>()
					};
				}
			}
		}
	}
}
namespace BetterHammer.UI
{
	internal static class KeyHintUI
	{
		private enum HintVisibility
		{
			Always,
			GridOnly,
			BuildOnly,
			SelectionOnly,
			CopyOnly
		}

		private sealed class Hint
		{
			public string Label;

			public int Column;

			public string[] Keys;

			public HintVisibility Visibility;

			public GameObject Item;

			public CanvasGroup Group;
		}

		[HarmonyPatch(typeof(KeyHints), "UpdateHints")]
		private static class KeyHints_UpdateHints_Patch
		{
			[HarmonyPostfix]
			private static void Postfix(KeyHints __instance)
			{
				if (_container != null && (Object)(object)_container == (Object)null)
				{
					Reset();
				}
				Update(__instance, Player.m_localPlayer);
			}
		}

		private const string ContainerName = "BetterHammer_KeyHints";

		private const string ScrollIcon = "@scroll";

		private const float LabelFontSize = 16f;

		private const float IconHeight = 32f;

		private const float IconScale = 1.8f;

		private const float ColumnSpacing = 12f;

		private const float RowSpacing = 16f;

		private const string Or = "/";

		private const string DeleteKey = "@delete";

		private const string ClearKey = "@clear";

		private static readonly List<Hint> Hints = new List<Hint>(11)
		{
			new Hint
			{
				Label = "$betterhammer_hint_copy_selection",
				Column = 0,
				Keys = new string[2] { "Left Alt", "$button_mouse0" },
				Visibility = HintVisibility.SelectionOnly
			},
			new Hint
			{
				Label = "$betterhammer_hint_deselect",
				Column = 0,
				Keys = new string[2] { "Left Alt", "$button_mouse1" },
				Visibility = HintVisibility.SelectionOnly
			},
			new Hint
			{
				Label = "$betterhammer_hint_select",
				Column = 0,
				Keys = new string[2] { "Left Alt", "$button_mouse2" },
				Visibility = HintVisibility.Always
			},
			new Hint
			{
				Label = "$betterhammer_hint_move",
				Column = 0,
				Keys = new string[2] { "Left Ctrl", "$button_mouse2" },
				Visibility = HintVisibility.Always
			},
			new Hint
			{
				Label = "$betterhammer_hint_grid",
				Column = 0,
				Keys = new string[2] { "Left Ctrl", "$button_mouse1" },
				Visibility = HintVisibility.BuildOnly
			},
			new Hint
			{
				Label = "$betterhammer_hint_repair",
				Column = 0,
				Keys = new string[2] { "Left Shift", "$button_mouse1" },
				Visibility = HintVisibility.Always
			},
			new Hint
			{
				Label = "$betterhammer_hint_copy_piece",
				Column = 1,
				Keys = new string[4] { "Left Shift", "$KEY_TabLeft", "/", "$KEY_TabRight" },
				Visibility = HintVisibility.CopyOnly
			},
			new Hint
			{
				Label = "$betterhammer_hint_delete_selection",
				Column = 1,
				Keys = new string[1] { "@delete" },
				Visibility = HintVisibility.SelectionOnly
			},
			new Hint
			{
				Label = "$betterhammer_hint_clear_selection",
				Column = 1,
				Keys = new string[1] { "@clear" },
				Visibility = HintVisibility.SelectionOnly
			},
			new Hint
			{
				Label = "$betterhammer_hint_grid_distance",
				Column = 1,
				Keys = new string[2] { "Left Ctrl", "@scroll" },
				Visibility = HintVisibility.GridOnly
			},
			new Hint
			{
				Label = "$betterhammer_hint_zoom",
				Column = 1,
				Keys = new string[2] { "Left Alt", "@scroll" },
				Visibility = HintVisibility.Always
			}
		};

		private static GameObject _container;

		private static RectTransform _rotateAnchor;

		private static RectTransform _rotateIcon;

		private static Image _rotateIconImage;

		private static bool _createFailed;

		private static bool _layoutDirty;

		private static TextMeshProUGUI _buildMenuLabel;

		private static string _buildMenuText;

		public static void Update(KeyHints keyHints, Player player)
		{
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Expected O, but got Unknown
			UpdateAbortHint(keyHints);
			if (!((Object)(object)keyHints.m_buildHints != (Object)null) || !keyHints.m_buildHints.activeInHierarchy || !((Object)(object)player != (Object)null) || !((Character)player).InPlaceMode() || ZInput.IsGamepadActive() || !BetterHammerPlugin.IsHammerEquipped(player))
			{
				if ((Object)(object)_container != (Object)null && _container.activeSelf)
				{
					_container.SetActive(false);
				}
			}
			else
			{
				if ((Object)(object)_container == (Object)null && (_createFailed || !Create(keyHints)))
				{
					return;
				}
				bool flag = player.InRepairMode();
				bool gridEnabled = BetterHammerPlugin.GridEnabled;
				foreach (Hint hint in Hints)
				{
					bool flag2 = true;
					bool flag3 = false;
					switch (hint.Visibility)
					{
					case HintVisibility.BuildOnly:
						flag2 = !flag;
						break;
					case HintVisibility.GridOnly:
						flag2 = !flag;
						flag3 = !gridEnabled;
						break;
					case HintVisibility.SelectionOnly:
						flag3 = !MultiCopy.HasSelection;
						break;
					case HintVisibility.CopyOnly:
						flag2 = GhostGroup.Active;
						break;
					}
					if (hint.Item.activeSelf != flag2)
					{
						hint.Item.SetActive(flag2);
						_layoutDirty = true;
					}
					hint.Group.alpha = (flag3 ? 0f : 1f);
				}
				if (!_container.activeSelf)
				{
					_container.SetActive(true);
					_layoutDirty = true;
				}
				if (_layoutDirty)
				{
					LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform)_container.transform);
					_layoutDirty = false;
				}
				AlignToRotateHint();
			}
		}

		private static void UpdateAbortHint(KeyHints keyHints)
		{
			if ((Object)(object)_buildMenuLabel == (Object)null && (Object)(object)keyHints.m_buildHints != (Object)null)
			{
				Transform val = keyHints.m_buildHints.transform.Find("Keyboard/BuildMenu/Text");
				_buildMenuLabel = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<TextMeshProUGUI>() : null);
				_buildMenuText = null;
			}
			if ((Object)(object)_buildMenuLabel == (Object)null)
			{
				return;
			}
			if (PieceMover.Moving)
			{
				if (_buildMenuText == null)
				{
					_buildMenuText = ((TMP_Text)_buildMenuLabel).text;
				}
				((TMP_Text)_buildMenuLabel).text = Localization.instance.Localize("$betterhammer_hint_abort");
			}
			else if (_buildMenuText != null)
			{
				((TMP_Text)_buildMenuLabel).text = _buildMenuText;
				_buildMenuText = null;
			}
		}

		private static void AlignToRotateHint()
		{
			//IL_0017: 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)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//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_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			Vector3[] array = (Vector3[])(object)new Vector3[4];
			_rotateAnchor.GetWorldCorners(array);
			Rect rect = _rotateIcon.rect;
			float num = Mathf.Min(((Rect)(ref rect)).width, ((Rect)(ref rect)).height * SpriteAspect(_rotateIconImage));
			float num2 = ((Transform)_rotateIcon).TransformPoint(Vector2.op_Implicit(((Rect)(ref rect)).center)).x + num / 2f * ((Transform)_rotateIcon).lossyScale.x;
			_container.transform.position = new Vector3(num2, array[2].y, array[2].z);
		}

		private static bool Create(KeyHints keyHints)
		{
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Expected O, but got Unknown
			//IL_0516: Unknown result type (might be due to invalid IL or missing references)
			//IL_0520: Expected O, but got Unknown
			//IL_0522: Unknown result type (might be due to invalid IL or missing references)
			//IL_052c: Expected O, but got Unknown
			//IL_0462: Unknown result type (might be due to invalid IL or missing references)
			Transform val = keyHints.m_buildHints.transform.Find("Keyboard");
			Transform val2 = (((Object)(object)val != (Object)null) ? val.Find("Copy") : null);
			Transform val3 = (((Object)(object)val != (Object)null) ? val.Find("rotate") : null);
			Transform val4 = (((Object)(object)val2 != (Object)null) ? val2.Find("Text") : null);
			Transform val5 = (((Object)(object)val2 != (Object)null) ? val2.Find("Text (1)") : null);
			Transform val6 = (((Object)(object)val2 != (Object)null) ? val2.Find("key_bkg") : null);
			Transform val7 = (((Object)(object)val3 != (Object)null) ? val3.Find("mousew_icon") : null);
			HorizontalLayoutGroup val8 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<HorizontalLayoutGroup>() : null);
			if ((Object)(object)val4 == (Object)null || (Object)(object)val5 == (Object)null || (Object)(object)val6 == (Object)null || (Object)(object)val7 == (Object)null || (Object)(object)val8 == (Object)null)
			{
				_createFailed = true;
				Debug.LogWarning((object)"BetterHammer: vanilla build key hints layout not as expected, not adding key hints.");
				return false;
			}
			RectTransform component = new GameObject("BetterHammer_KeyHints", new Type[1] { typeof(RectTransform) }).GetComponent<RectTransform>();
			((Transform)component).SetParent(keyHints.m_buildHints.transform, false);
			component.pivot = new Vector2(1f, 0f);
			HorizontalLayoutGroup obj = ((Component)component).gameObject.AddComponent<HorizontalLayoutGroup>();
			((HorizontalOrVerticalLayoutGroup)obj).spacing = 12f;
			((LayoutGroup)obj).childAlignment = (TextAnchor)8;
			((HorizontalOrVerticalLayoutGroup)obj).childControlWidth = true;
			((HorizontalOrVerticalLayoutGroup)obj).childControlHeight = true;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandWidth = false;
			((HorizontalOrVerticalLayoutGroup)obj).childForceExpandHeight = false;
			ContentSizeFitter obj2 = ((Component)component).gameObject.AddComponent<ContentSizeFitter>();
			obj2.horizontalFit = (FitMode)2;
			obj2.verticalFit = (FitMode)2;
			int num = 0;
			foreach (Hint hint in Hints)
			{
				num = Mathf.Max(num, hint.Column + 1);
			}
			Transform[] array = (Transform[])(object)new Transform[num];
			for (int i = 0; i < num; i++)
			{
				GameObject val9 = new GameObject("BetterHammer_KeyHints_Column" + i, new Type[1] { typeof(RectTransform) });
				val9.transform.SetParent((Transform)(object)component, false);
				VerticalLayoutGroup obj3 = val9.AddComponent<VerticalLayoutGroup>();
				((HorizontalOrVerticalLayoutGroup)obj3).spacing = 16f;
				((LayoutGroup)obj3).childAlignment = (TextAnchor)((i == num - 1) ? 8 : 6);
				((HorizontalOrVerticalLayoutGroup)obj3).childControlWidth = true;
				((HorizontalOrVerticalLayoutGroup)obj3).childControlHeight = true;
				((HorizontalOrVerticalLayoutGroup)obj3).childForceExpandWidth = false;
				((HorizontalOrVerticalLayoutGroup)obj3).childForceExpandHeight = false;
				array[i] = val9.transform;
			}
			foreach (Hint hint2 in Hints)
			{
				GameObject val10 = Object.Instantiate<GameObject>(((Component)val2).gameObject, array[hint2.Column], false);
				((Object)val10).name = "BetterHammer_Hint_" + hint2.Label.TrimStart(new char[1] { '$' });
				val10.SetActive(true);
				for (int num2 = val10.transform.childCount - 1; num2 >= 0; num2--)
				{
					Object.DestroyImmediate((Object)(object)((Component)val10.transform.GetChild(num2)).gameObject);
				}
				AddText(val4, val10.transform, Localization.instance.Localize(hint2.Label));
				for (int j = 0; j < hint2.Keys.Length; j++)
				{
					if (hint2.Keys[j] == "/")
					{
						AddText(val5, val10.transform, "/");
						continue;
					}
					if (j > 0 && hint2.Keys[j - 1] != "/")
					{
						AddText(val5, val10.transform, "+");
					}
					if (hint2.Keys[j] == "@scroll")
					{
						GameObject val11 = Object.Instantiate<GameObject>(((Component)val7).gameObject, val10.transform, false);
						val11.SetActive(true);
						Image component2 = val11.GetComponent<Image>();
						component2.preserveAspect = true;
						float num3 = SpriteAspect(component2);
						LayoutElement obj4 = val11.GetComponent<LayoutElement>() ?? val11.AddComponent<LayoutElement>();
						float minWidth = (obj4.preferredWidth = 32f * num3 * 1.8f);
						obj4.minWidth = minWidth;
						minWidth = (obj4.preferredHeight = 32f);
						obj4.minHeight = minWidth;
						minWidth = (obj4.flexibleHeight = 0f);
						obj4.flexibleWidth = minWidth;
						val11.transform.localScale = new Vector3(1.8f, 1.8f, 1f);
					}
					else
					{
						GameObject obj5 = Object.Instantiate<GameObject>(((Component)val6).gameObject, val10.transform, false);
						obj5.SetActive(true);
						((TMP_Text)obj5.GetComponentInChildren<TextMeshProUGUI>()).text = KeyText(hint2.Keys[j]);
					}
				}
				hint2.Item = val10;
				hint2.Group = val10.GetComponent<CanvasGroup>() ?? val10.AddComponent<CanvasGroup>();
			}
			LayoutRebuilder.ForceRebuildLayoutImmediate(component);
			for (int k = 0; k < num; k++)
			{
				EqualiseColumnWidths(k);
			}
			_rotateAnchor = (RectTransform)val3;
			_rotateIcon = (RectTransform)val7;
			_rotateIconImage = ((Component)val7).GetComponent<Image>();
			_container = ((Component)component).gameObject;
			_layoutDirty = true;
			return true;
		}

		private static void EqualiseColumnWidths(int column)
		{
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			List<Transform> list = new List<Transform>();
			foreach (Hint hint in Hints)
			{
				if (hint.Column == column)
				{
					list.Add(hint.Item.transform);
				}
			}
			int num = int.MaxValue;
			foreach (Transform item in list)
			{
				num = Mathf.Min(num, item.childCount);
			}
			for (int i = 0; i < num; i++)
			{
				float num2 = 0f;
				foreach (Transform item2 in list)
				{
					float num3 = num2;
					Rect rect = ((RectTransform)item2.GetChild(i)).rect;
					num2 = Mathf.Max(num3, ((Rect)(ref rect)).width);
				}
				foreach (Transform item3 in list)
				{
					GameObject gameObject = ((Component)item3.GetChild(i)).gameObject;
					(gameObject.GetComponent<LayoutElement>() ?? gameObject.AddComponent<LayoutElement>()).minWidth = num2;
				}
			}
		}

		private static string KeyText(string key)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: 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)
			if (!(key == "@delete"))
			{
				if (key == "@clear")
				{
					return ((object)MultiCopy.ClearKey/*cast due to .constrained prefix*/).ToString();
				}
				return Localization.instance.Localize(key);
			}
			return ((object)CopyLibrary.DeleteKey/*cast due to .constrained prefix*/).ToString();
		}

		private static float SpriteAspect(Image image)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)image.sprite != (Object)null))
			{
				return 0.6f;
			}
			Rect rect = image.sprite.rect;
			float width = ((Rect)(ref rect)).width;
			rect = image.sprite.rect;
			return width / ((Rect)(ref rect)).height;
		}

		private static void AddText(Transform template, Transform parent, string text)
		{
			GameObject obj = Object.Instantiate<GameObject>(((Component)template).gameObject, parent, false);
			obj.SetActive(true);
			LayoutElement component = obj.GetComponent<LayoutElement>();
			if ((Object)(object)component != (Object)null)
			{
				Object.DestroyImmediate((Object)(object)component);
			}
			TextMeshProUGUI component2 = obj.GetComponent<TextMeshProUGUI>();
			((TMP_Text)component2).enableAutoSizing = false;
			((TMP_Text)component2).fontSize = 16f;
			((TMP_Text)component2).textWrappingMode = (TextWrappingModes)0;
			((TMP_Text)component2).text = text;
		}

		public static void Reset()
		{
			_container = null;
			_rotateAnchor = null;
			_rotateIcon = null;
			_rotateIconImage = null;
			_createFailed = false;
			_buildMenuLabel = null;
			_buildMenuText = null;
			foreach (Hint hint in Hints)
			{
				hint.Item = null;
				hint.Group = null;
			}
		}
	}
}
namespace BetterHammer.Structures
{
	internal static class CopyLibrary
	{
		private sealed class LibraryFile
		{
			public int NextNumber = 1;

			public List<SavedCopy> Copies = new List<SavedCopy>();
		}

		internal sealed class SavedCopy
		{
			public int Number;

			public string Name;

			public List<SavedPiece> Pieces = new List<SavedPiece>();
		}

		internal sealed class SavedPiece
		{
			public string Prefab;

			public float[] Position;

			public float[] Rotation;
		}

		internal sealed class Part
		{
			public Piece Prefab;

			public Vector3 Position;

			public Quaternion Rotation;

			public int SnapCount;
		}

		internal sealed class Copy
		{
			public string Name;

			public Piece Piece;

			public readonly List<Part> Parts = new List<Part>();

			public readonly List<Piece> Prefabs = new List<Piece>();

			public List<Piece> StationPieces = new List<Piece>();

			public string Description;

			public SavedCopy Saved;
		}

		private sealed class NameReceiver(string initial, Action<string> onEntered) : TextReceiver
		{
			public string GetText()
			{
				return initial;
			}

			public void SetText(string text)
			{
				onEntered(text);
			}
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static PopupButtonCallback <0>__Pop;
		}

		private const string CategoryName = "Copies";

		private static readonly List<Copy> Copies = new List<Copy>();

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

		private static readonly List<Transform> SnapPoints = new List<Transform>();

		private static LibraryFile _file;

		private static PieceTable _table;

		private static GameObject _container;

		private static PieceCategory _category;

		private const int NameCharacterLimit = 40;

		private static ConfigEntry<KeyCode> _deleteKey;

		private static ConfigEntry<KeyCode> _renameKey;

		private static string FilePath => Path.Combine(Paths.ConfigPath, "BetterHammer", "copies.json");

		internal static KeyCode DeleteKey
		{
			get
			{
				//IL_000f: Unknown result type (might be due to invalid IL or missing references)
				if (_deleteKey == null)
				{
					return (KeyCode)127;
				}
				return _deleteKey.Value;
			}
		}

		internal static IEnumerable<string> AllNames => Names;

		public static void BindConfig(ConfigFile config)
		{
			_deleteKey = config.Bind<KeyCode>("Keybinds", "Delete", (KeyCode)127, "With the build menu open, hover a saved copy in the Copies tab and press this to delete it. With the build menu closed, press it to remove every piece selected for copying.");
			_renameKey = config.Bind<KeyCode>("Keybinds", "Rename Copy", (KeyCode)277, "With the build menu open, hover a saved copy in the Copies tab and press this to rename it.");
		}

		internal static void AskForName(string topic, string current, Action<string> onEntered)
		{
			if ((Object)(object)TextInput.instance == (Object)null)
			{
				onEntered(current);
			}
			else
			{
				TextInput.instance.RequestText((TextReceiver)(object)new NameReceiver(current, onEntered), topic, 40);
			}
		}

		internal static string NextDefaultName()
		{
			return DefaultName((_file == null) ? 1 : _file.NextNumber);
		}

		private static string DefaultName(int number)
		{
			return Localization.instance.Localize("$betterhammer_copy_name", new string[1] { number.ToString(CultureInfo.InvariantCulture) });
		}

		private static string CleanName(string name, int number)
		{
			name = name?.Trim();
			if (!string.IsNullOrEmpty(name) && !(name == DefaultName(number)))
			{
				return name;
			}
			return null;
		}

		private static void RefreshNames()
		{
			Names.Clear();
			foreach (Copy copy in Copies)
			{
				Names.Add(copy.Name);
			}
		}

		internal static void EnsureLoaded(Player player, PieceTable table)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Expected O, but got Unknown
			if (_file != null || (Object)(object)table == (Object)null || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return;
			}
			_table = table;
			_category = PieceManager.Instance.AddPieceCategory("Copies");
			_container = new GameObject("BetterHammer_Copies");
			_container.SetActive(false);
			Object.DontDestroyOnLoad((Object)(object)_container);
			_file = Read();
			foreach (SavedCopy copy in _file.Copies)
			{
				Register(copy);
			}
			player.UpdateAvailablePiecesList();
		}

		internal static Copy Find(Piece piece)
		{
			if ((Object)(object)piece == (Object)null)
			{
				return null;
			}
			foreach (Copy copy in Copies)
			{
				if ((Object)(object)copy.Piece == (Object)(object)piece)
				{
					return copy;
				}
			}
			return null;
		}

		internal static bool IsCopyName(string name)
		{
			return Names.Contains(name);
		}

		internal static Copy Add(Player player, IList<(Piece Prefab, Vector3 Position, Quaternion Rotation)> pieces, string name)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			if (_file == null || pieces.Count == 0)
			{
				return null;
			}
			Vector3 item = pieces[0].Position;
			SavedCopy savedCopy = new SavedCopy
			{
				Number = _file.NextNumber++
			};
			savedCopy.Name = CleanName(name, savedCopy.Number);
			foreach (var piece in pieces)
			{
				Piece item2 = piece.Prefab;
				Vector3 item3 = piece.Position;
				Quaternion item4 = piece.Rotation;
				Vector3 val = item3 - item;
				savedCopy.Pieces.Add(new SavedPiece
				{
					Prefab = ((Object)item2).name,
					Position = new float[3] { val.x, val.y, val.z },
					Rotation = new float[4] { item4.x, item4.y, item4.z, item4.w }
				});
			}
			_file.Copies.Add(savedCopy);
			Save();
			Copy result = Register(savedCopy);
			player.UpdateAvailablePiecesList();
			return result;
		}

		internal static void UpdateMenuInput(Player player)
		{
			//IL_002f: 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_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Expected O, but got Unknown
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Expected O, but got Unknown
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Expected O, but got Unknown
			if (_deleteKey == null || !Hud.IsPieceSelectionVisible() || UnifiedPopup.IsVisible() || TypingInTextField())
			{
				return;
			}
			bool keyDown = Input.GetKeyDown(_deleteKey.Value);
			bool flag = !keyDown && Input.GetKeyDown(_renameKey.Value);
			Copy copy = ((keyDown || flag) ? Find(Hud.instance.m_hoveredPiece) : null);
			if (copy == null)
			{
				return;
			}
			if (flag)
			{
				AskForName("$betterhammer_copy_rename_title", copy.Name, delegate(string name)
				{
					Rename(player, copy, name);
				});
				return;
			}
			string text = Localization.instance.Localize("$betterhammer_copy_delete_text", new string[1] { copy.Name });
			PopupButtonCallback val = delegate
			{
				UnifiedPopup.Pop();
				Delete(player, copy);
			};
			object obj = <>O.<0>__Pop;
			if (obj == null)
			{
				PopupButtonCallback val2 = UnifiedPopup.Pop;
				<>O.<0>__Pop = val2;
				obj = (object)val2;
			}
			UnifiedPopup.Push((PopupBase)new YesNoPopup("$betterhammer_copy_delete_title", text, val, (PopupButtonCallback)obj, true, false));
		}

		internal static bool TypingInTextField()
		{
			if (Console.IsVisible() || TextInput.IsVisible())
			{
				return true;
			}
			GameObject val = (((Object)(object)EventSystem.current != (Object)null) ? EventSystem.current.currentSelectedGameObject : null);
			TMP_InputField val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<TMP_InputField>() : null);
			if ((Object)(object)val2 != (Object)null)
			{
				return val2.isFocused;
			}
			return false;
		}

		internal static string MenuHint()
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: 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)
			if (_deleteKey == null)
			{
				return "";
			}
			return Localization.instance.Localize("$betterhammer_copy_menu_hint", new string[2]
			{
				((object)_renameKey.Value/*cast due to .constrained prefix*/).ToString(),
				((object)_deleteKey.Value/*cast due to .constrained prefix*/).ToString()
			});
		}

		private static void Rename(Player player, Copy copy, string name)
		{
			if (!Copies.Contains(copy))
			{
				return;
			}
			string name2 = copy.Name;
			copy.Saved.Name = CleanName(name, copy.Saved.Number);
			copy.Name = copy.Saved.Name ?? DefaultName(copy.Saved.Number);
			copy.Piece.m_name = copy.Name;
			Save();
			RefreshNames();
			if ((Object)(object)player != (Object)null)
			{
				player.UpdateAvailablePiecesList();
				if (Hud.IsPieceSelectionVisible())
				{
					Hud.instance.m_buildUi.OpenBuildMenu();
				}
				((Character)player).Message((MessageType)1, Localization.instance.Localize("$betterhammer_copy_renamed", new string[2] { name2, copy.Name }), 0, (Sprite)null, false);
			}
		}

		private static void Delete(Player player, Copy copy)
		{
			_table.m_pieces.Remove(((Component)copy.Piece).gameObject);
			Copies.Remove(copy);
			RefreshNames();
			_file.Copies.Remove(copy.Saved);
			Save();
			if ((Object)(object)player != (Object)null)
			{
				player.UpdateAvailablePiecesList();
				if (Hud.IsPieceSelectionVisible())
				{
					Hud.instance.m_buildUi.OpenBuildMenu();
				}
				((Character)player).Message((MessageType)1, Localization.instance.Localize("$betterhammer_copy_deleted", new string[1] { copy.Name }), 0, (Sprite)null, false);
			}
		}

		internal static Part MakePart(Piece prefab, Vector3 position, Quaternion rotation)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			SnapPoints.Clear();
			prefab.GetSnapPoints(SnapPoints);
			int count = SnapPoints.Count;
			SnapPoints.Clear();
			return new Part
			{
				Prefab = prefab,
				Position = position,
				Rotation = rotation,
				SnapCount = count
			};
		}

		private static Copy Register(SavedCopy saved)
		{
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c6: Expected O, but got Unknown
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			Copy copy = new Copy
			{
				Name = (CleanName(saved.Name, saved.Number) ?? DefaultName(saved.Number)),
				Saved = saved
			};
			foreach (SavedPiece piece in saved.Pieces)
			{
				GameObject prefab = ZNetScene.instance.GetPrefab(piece.Prefab);
				Piece val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<Piece>() : null);
				if ((Object)(object)val == (Object)null)
				{
					Debug.LogWarning((object)("BetterHammer: copy " + saved.Number + " uses missing piece " + piece.Prefab + ", not adding it."));
					return null;
				}
				SnapPoints.Clear();
				val.GetSnapPoints(SnapPoints);
				List<Part> parts = copy.Parts;
				Part obj = new Part
				{
					Prefab = val,
					Position = new Vector3(piece.Position[0], piece.Position[1], piece.Position[2])
				};
				Quaternion val2 = new Quaternion(piece.Rotation[0], piece.Rotation[1], piece.Rotation[2], piece.Rotation[3]);
				obj.Rotation = ((Quaternion)(ref val2)).normalized;
				obj.SnapCount = SnapPoints.Count;
				parts.Add(obj);
				copy.Prefabs.Add(val);
			}
			SnapPoints.Clear();
			if (copy.Parts.Count == 0)
			{
				return null;
			}
			GameObject val3 = new GameObject("BetterHammer_Copy_" + saved.Number.ToString(CultureInfo.InvariantCulture));
			val3.transform.SetParent(_container.transform, false);
			Piece val4 = val3.AddComponent<Piece>();
			val4.m_name = copy.Name;
			val4.m_category = _category;
			val4.m_resources = CombineRequirements(copy.Prefabs, out copy.StationPieces).ToArray();
			val4.m_craftingStation = ((copy.StationPieces.Count > 0) ? copy.StationPieces[0].m_craftingStation : null);
			copy.Description = DescribePieces(copy.Prefabs);
			val4.m_description = copy.Description;
			val4.m_icon = RenderIcon(copy) ?? copy.Prefabs[0].m_icon;
			copy.Piece = val4;
			_table.m_pieces.Add(val3);
			Copies.Add(copy);
			RefreshNames();
			return copy;
		}

		internal static List<Requirement> CombineRequirements(IEnumerable<Piece> pieces, out List<Piece> stationPieces)
		{
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Expected O, but got Unknown
			List<Requirement> list = new List<Requirement>();
			Dictionary<string, Requirement> dictionary = new Dictionary<string, Requirement>();
			HashSet<string> hashSet = new HashSet<string>();
			stationPieces = new List<Piece>();
			foreach (Piece piece in pieces)
			{
				Requirement[] resources = piece.m_resources;
				foreach (Requirement val in resources)
				{
					if (!((Object)(object)val.m_resItem == (Object)null) && val.m_amount > 0)
					{
						string name = val.m_resItem.m_itemData.m_shared.m_name;
						if (dictionary.TryGetValue(name, out var value))
						{
							Requirement obj = value;
							obj.m_amount += val.m_amount;
							continue;
						}
						value = (dictionary[name] = new Requirement
						{
							m_resItem = val.m_resItem,
							m_amount = val.m_amount,
							m_recover = val.m_recover
						});
						list.Add(value);
					}
				}
				if ((Object)(object)piece.m_craftingStation != (Object)null && hashSet.Add(piece.m_craftingStation.m_name))
				{
					stationPieces.Add(piece);
				}
			}
			return list;
		}

		internal static string DescribePieces(IEnumerable<Piece> pieces)
		{
			return string.Join(", ", from piece in pieces
				group piece by piece.m_name into same
				select same.Count().ToString(CultureInfo.InvariantCulture) + "× " + Localization.instance.Localize(same.Key));
		}

		private static Sprite RenderIcon(Copy copy)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: 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_00d7: Expected O, but got Unknown
			GameObject val = new GameObject("BetterHammer_CopyPreview");
			val.transform.position = new Vector3(0f, -5000f, 0f);
			ZNetView.m_forceDisableInit = true;
			TerrainOp.m_forceDisableTerrainOps = true;
			try
			{
				foreach (Part part in copy.Parts)
				{
					Object.Instantiate<GameObject>(((Component)part.Prefab).gameObject, val.transform.position + part.Position, part.Rotation, val.transform);
				}
			}
			finally
			{
				ZNetView.m_forceDisableInit = false;
				TerrainOp.m_forceDisableTerrainOps = false;
			}
			try
			{
				return RenderManager.Instance.Render(new RenderRequest(val)
				{
					Rotation = RenderManager.IsometricRotation,
					Width = 128,
					Height = 128
				});
			}
			catch (Exception ex)
			{
				Debug.LogWarning((object)("BetterHammer: couldn't render an icon for " + copy.Name + ": " + ex.Message));
				return null;
			}
			finally
			{
				Object.DestroyImmediate((Object)(object)val);
			}
		}

		private static LibraryFile Read()
		{
			LibraryFile libraryFile = null;
			string filePath = FilePath;
			if (File.Exists(filePath))
			{
				try
				{
					libraryFile = JsonConvert.DeserializeObject<LibraryFile>(File.ReadAllText(filePath));
				}
				catch (Exception ex)
				{
					string text = filePath + ".unreadable-" + DateTime.Now.ToString("yyyyMMdd-HHmmss", CultureInfo.InvariantCulture);
					Debug.LogError((object)("BetterHammer: couldn't read " + filePath + " (" + ex.Message + "), moved it to " + text));
					try
					{
						File.Move(filePath, text);
					}
					catch (Exception ex2)
					{
						Debug.LogError((object)("BetterHammer: couldn't move it either: " + ex2.Message));
					}
				}
			}
			if (libraryFile == null)
			{
				libraryFile = new LibraryFile();
			}
			LibraryFile libraryFile2 = libraryFile;
			if (libraryFile2.Copies == null)
			{
				libraryFile2.Copies = new List<SavedCopy>();
			}
			foreach (SavedCopy copy in libraryFile.Copies)
			{
				copy?.Pieces?.RemoveAll(delegate(SavedPiece piece)
				{
					if (piece != null && piece.Prefab != null)
					{
						float[] position = piece.Position;
						if (position != null && position.Length == 3)
						{
							position = piece.Rotation;
							return position == null || position.Length != 4;
						}
					}
					return true;
				});
			}
			libraryFile.Copies.RemoveAll((SavedCopy copy) => copy?.Pieces == null || copy.Pieces.Count == 0);
			int num = ((libraryFile.Copies.Count > 0) ? libraryFile.Copies.Max((SavedCopy copy) => copy.Number) : 0);
			libraryFile.NextNumber = Mathf.Max(libraryFile.NextNumber, num + 1);
			return libraryFile;
		}

		private static void Save()
		{
			try
			{
				string filePath = FilePath;
				Directory.CreateDirectory(Path.GetDirectoryName(filePath));
				File.WriteAllText(filePath, JsonConvert.SerializeObject((object)_file, (Formatting)1));
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("BetterHammer: couldn't save copies to " + FilePath + ": " + ex.Message));
			}
		}
	}
	internal static class GhostGroup
	{
		internal enum Owner
		{
			None,
			Copy,
			Move
		}

		private sealed class Member
		{
			public CopyLibrary.Part Part;

			public GameObject Ghost;
		}

		private static readonly List<Member> Members = new List<Member>();

		private static int _snapFrame = -10;

		internal static Owner ActiveOwner { get; private set; }

		internal static bool Active => Members.Count > 0;

		internal static int Count => Members.Count;

		internal static bool CreatingGhosts { get; private set; }

		internal static GameObject PrefabOverride { get; private set; }

		internal static int Reference { get; private set; }

		internal static void Begin(Player player, IList<CopyLibrary.Part> parts, Owner owner, int reference = 0, int snapPoint = -1)
		{
			End();
			if ((Object)(object)player.m_placementGhost != (Object)null)
			{
				Object.Destroy((Object)(object)player.m_placementGhost);
				player.m_placementGhost = null;
			}
			int placeRotation = player.m_placeRotation;
			CreatingGhosts = true;
			try
			{
				foreach (CopyLibrary.Part part in parts)
				{
					Members.Add(new Member
					{
						Part = part,
						Ghost = CreateGhost(player, part.Prefab)
					});
				}
			}
			finally
			{
				CreatingGhosts = false;
				PrefabOverride = null;
			}
			player.m_placeRotation = placeRotation;
			ActiveOwner = owner;
			if (reference < 0 || reference >= Members.Count)
			{
				reference = 0;
				snapPoint = -1;
			}
			UseAsReference(player, reference);
			player.m_manualSnapPoint = snapPoint;
		}

		internal static void End()
		{
			foreach (Member member in Members)
			{
				if ((Object)(object)member.Ghost != (Object)null)
				{
					Object.Destroy((Object)(object)member.Ghost);
				}
			}
			Members.Clear();
			ActiveOwner = Owner.None;
		}

		internal static List<(Vector3 Position, Quaternion Rotation)> Poses(Player player)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			List<(Vector3, Quaternion)> list = new List<(Vector3, Quaternion)>();
			foreach (Member member in Members)
			{
				Transform val = (((Object)(object)member.Ghost != (Object)null) ? member.Ghost.transform : player.m_placementGhost.transform);
				list.Add((val.position, val.rotation));
			}
			return list;
		}

		internal static int RotationSteps(Player player, Quaternion rotation)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			return Mathf.RoundToInt(((Quaternion)(ref rotation)).eulerAngles.y / player.m_placeRotationDegrees);
		}

		private static GameObject CreateGhost(Player player, Piece prefab)
		{
			PrefabOverride = ((Component)prefab).gameObject;
			player.SetupPlacementGhost();
			PrefabOverride = null;
			GameObject placementGhost = player.m_placementGhost;
			player.m_placementGhost = null;
			if ((Object)(object)placementGhost != (Object)null)
			{
				placementGhost.SetActive(false);
			}
			return placementGhost;
		}

		private static void UseAsReference(Player player, int index)
		{
			Member member = Members[index];
			player.m_placementGhost = member.Ghost;
			if ((Object)(object)player.m_placementGhost != (Object)null)
			{
				player.m_placementGhost.SetActive(true);
			}
			member.Ghost = null;
			Reference = index;
		}

		private static void SwitchReference(Player player, int index)
		{
			//IL_001d: 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_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			GameObject placementGhost = player.m_placementGhost;
			Quaternion val = (((Object)(object)placementGhost != (Object)null) ? (placementGhost.transform.rotation * Quaternion.Inverse(Members[Reference].Part.Rotation)) : Quaternion.identity);
			Members[Reference].Ghost = placementGhost;
			if ((Object)(object)placementGhost != (Object)null)
			{
				placementGhost.SetActive(false);
			}
			player.m_placementGhost = null;
			UseAsReference(player, index);
			player.m_placeRotation = RotationSteps(player, val * Members[index].Part.Rotation);
		}

		internal static void BeforeUpdatePlacementGhost(Player player)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Invalid comparison between Unknown and I4
			if (!Active || (Object)(object)player.m_placementGhost == (Object)null || _snapFrame == Time.frameCount || ZInput.GetButton("JoyAltKeys") || Hud.IsPieceSelectionVisible() || ((Object)(object)Minimap.instance != (Object)null && (int)Minimap.instance.m_mode == 2) || Console.IsVisible() || ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus()))
			{
				return;
			}
			int num = 0;
			if (ZInput.GetButtonDown("TabRight"))
			{
				num = 1;
			}
			else if (ZInput.GetButtonDown("TabLeft"))
			{
				num = -1;
			}
			if (num != 0)
			{
				_snapFrame = Time.frameCount;
				int piece = Reference;
				int point = player.m_manualSnapPoint;
				if (BetterHammerPlugin.ShiftHeld())
				{
					piece = (piece + num + Members.Count) % Members.Count;
					point = ((Members[piece].Part.SnapCount <= 0) ? (-1) : 0);
				}
				else
				{
					NextSnapPoint(ref piece, ref point, num);
				}
				if (piece != Reference)
				{
					SwitchReference(player, piece);
				}
				player.m_manualSnapPoint = point - num;
				((Character)player).Message((MessageType)1, Localization.instance.Localize("$betterhammer_copyReference", new string[3]
				{
					Localization.instance.Localize(Members[piece].Part.Prefab.m_name),
					(piece + 1).ToString(CultureInfo.InvariantCulture),
					Members.Count.ToString(CultureInfo.InvariantCulture)
				}), 0, (Sprite)null, false);
			}
		}

		private static void NextSnapPoint(ref int piece, ref int point, int step)
		{
			List<(int, int)> list = new List<(int, int)>(1) { (-1, -1) };
			for (int i = 0; i < Members.Count; i++)
			{
				for (int j = 0; j < Members[i].Part.SnapCount; j++)
				{
					list.Add((i, j));
				}
			}
			int num = ((point >= 0) ? list.IndexOf((piece, point)) : 0);
			if (num < 0)
			{
				num = 0;
			}
			var (num2, num3) = list[(num + step + list.Count) % list.Count];
			if (num2 >= 0)
			{
				piece = num2;
			}
			point = num3;
		}

		internal static void AfterUpdatePlacementGhost(Player player, bool flashGuardStone)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: 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_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//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)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Invalid comparison between Unknown and I4
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			if (!Active)
			{
				return;
			}
			GameObject placementGhost = player.m_placementGhost;
			bool flag = (Object)(object)placementGhost != (Object)null && placementGhost.activeSelf;
			PlacementStatus val = player.m_placementStatus;
			Quaternion val2 = (((Object)(object)placementGhost != (Object)null) ? (placementGhost.transform.rotation * Quaternion.Inverse(Members[Reference].Part.Rotation)) : Quaternion.identity);
			Vector3 position = Members[Reference].Part.Position;
			foreach (Member member in Members)
			{
				if ((Object)(object)member.Ghost == (Object)null)
				{
					continue;
				}
				member.Ghost.SetActive(flag);
				if (!flag)
				{
					continue;
				}
				Vector3 val3 = placementGhost.transform.position + val2 * (member.Part.Position - position);
				member.Ghost.transform.SetPositionAndRotation(val3, val2 * member.Part.Rotation);
				if ((int)val == 0)
				{
					if (Location.IsInsideNoBuildLocation(val3))
					{
						val = (PlacementStatus)3;
					}
					else if (!PrivateArea.CheckAccess(val3, 0f, flashGuardStone, false))
					{
						val = (PlacementStatus)4;
					}
				}
			}
			if (!flag)
			{
				return;
			}
			if (val != player.m_placementStatus)
			{
				player.m_placementStatus = val;
				player.SetPlacementGhostValid(false);
			}
			bool flag2 = (int)val == 0;
			foreach (Member member2 in Members)
			{
				Piece val4 = (((Object)(object)member2.Ghost != (Object)null) ? member2.Ghost.GetComponent<Piece>() : null);
				if ((Object)(object)val4 != (Object)null)
				{
					val4.SetInvalidPlacementHeightlight(!flag2);
				}
			}
		}
	}
	internal static class MultiCopy
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static PopupButtonCallback <0>__Pop;
		}

		private const string RemoveButton = "Remove";

		private const string PlaceButton = "Attack";

		private const float MaterialPageSeconds = 2.5f;

		private static readonly Color HighlightColor = new Color(0.25f, 0.9f, 0.75f);

		private static readonly int EmissionColor = Shader.PropertyToID("_EmissionColor");

		private static readonly List<Piece> Selected = new List<Piece>();

		private static CopyLibrary.Copy _active;

		private static (CopyLibrary.Copy Copy, int Reference, int SnapPoint) _kept;

		private static int _rightClickFrame = -10;

		private static bool _lit;

		private static Piece _summary;

		private static bool _selectionDirty = true;

		private static List<Requirement> _selectionRequirements = new List<Requirement>();

		private static List<Piece> _selectionStations = new List<Piece>();

		private static string _selectionDescription = "";

		private static ConfigEntry<KeyCode> _clearKey;

		internal static KeyCode ClearKey
		{
			get
			{
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				if (_clearKey == null)
				{
					return (KeyCode)8;
				}
				return _clearKey.Value;
			}
		}

		internal static bool Placing
		{
			get
			{
				if (_active != null)
				{
					return GhostGroup.ActiveOwner == GhostGroup.Owner.Copy;
				}
				return false;
			}
		}

		internal static bool HasSelection => Selected.Count > 0;

		internal static bool RightClickConsumed => _rightClickFrame == Time.frameCount;

		internal static bool BeforeUpdatePlacement(Player player, bool takeInput)
		{
			Prune();
			if (Placing && (!((Character)player).InPlaceMode() || (Object)(object)player.m_placementGhost == (Object)null || CopyLibrary.Find(player.GetSelectedPiece()) != _active))
			{
				Keep(player);
				Deactivate();
			}
			bool placing = Placing;
			if (!takeInput || !((Character)player).InPlaceMode() || ((Character)player).IsDead() || Hud.IsPieceSelectionVisible() || Hud.InRadial() || ZInput.IsGamepadActive() || !BetterHammerPlugin.IsHammerEquipped(player))
			{
				return placing;
			}
			bool flag = BetterHammerPlugin.AltHeld();
			bool buttonDown = ZInput.GetButtonDown("Attack");
			bool flag2 = placing;
			if (flag && ZInput.GetButtonDown("Remove"))
			{
				PieceMover.BlockRemoveUntilReleased(player);
				Select(player);
			}
			else if (flag && Input.GetMouseButtonDown(1))
			{
				_rightClickFrame = Time.frameCount;
				Deselect(player);
			}
			else if (flag && buttonDown)
			{
				player.m_lastToolUseTime = Time.time;
				flag2 = true;
				Confirm(player);
			}
			else if (Placing && buttonDown && Time.time - player.m_lastToolUseTime > player.m_placeDelay)
			{
				Place(player);
			}
			if (!flag2)
			{
				return Placing;
			}
			return true;
		}

		public static void BindConfig(ConfigFile config)
		{
			_clearKey = config.Bind<KeyCode>("Keybinds", "Clear Selection", (KeyCode)8, "Deselects every piece selected for copying, without changing anything else.");
		}

		internal static void ReplaceSelected(Piece original, Piece replacement)
		{
			int num = Selected.IndexOf(original);
			if (num >= 0 && !((Object)(object)replacement == (Object)null))
			{
				ResetHighlight(original);
				Selected[num] = replacement;
				_selectionDirty = true;
			}
		}

		internal static void UpdateSelectionKeys(Player player)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Expected O, but got Unknown
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Expected O, but got Unknown
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Expected O, but got Unknown
			if (Selected.Count == 0 || Hud.IsPieceSelectionVisible() || UnifiedPopup.IsVisible() || !((Character)player).InPlaceMode() || !BetterHammerPlugin.IsHammerEquipped(player) || CopyLibrary.TypingInTextField())
			{
				return;
			}
			if (Input.GetKeyDown(ClearKey))
			{
				int count = Selected.Count;
				ClearHighlights();
				Selected.Clear();
				_selectionDirty = true;
				((Character)player).Message((MessageType)1, Localization.instance.Localize("$betterhammer_selection_cleared", new string[1] { Count(count) }), 0, (Sprite)null, false);
			}
			else if (Input.GetKeyDown(CopyLibrary.DeleteKey))
			{
				Prune();
				string text = Localization.instance.Localize("$betterhammer_selection_delete_text", new string[1] { Count(Selected.Count) });
				PopupButtonCallback val = delegate
				{
					UnifiedPopup.Pop();
					RemoveSelected(player);
				};
				object obj = <>O.<0>__Pop;
				if (obj == null)
				{
					PopupButtonCallback val2 = UnifiedPopup.Pop;
					<>O.<0>__Pop = val2;
					obj = (object)val2;
				}
				UnifiedPopup.Push((PopupBase)new YesNoPopup("$betterhammer_selection_delete_title", text, val, (PopupButtonCallback)obj, true, false));
			}
		}

		private static void RemoveSelected(Player player)
		{
			Prune();
			int count = Selected.Count;
			int num = 0;
			foreach (Piece item in Selected.ToList())
			{
				if (CanRemove(player, item))
				{
					ResetHighlight(item);
					Remove(player, item);
					Selected.Remove(item);
					num++;
				}
			}
			_selectionDirty = true;
			((Character)player).Message((MessageType)1, (num == count) ? Localization.instance.Localize("$betterhammer_selection_removed", new string[1] { Count(num) }) : Localization.instance.Localize("$betterhammer_selection_removed_some", new string[2]
			{
				Count(num),
				Count(count)
			}), 0, (Sprite)null, false);
		}

		private static bool CanRemove(Player player, Piece piece)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			ZNetView component = ((Component)piece).GetComponent<ZNetView>();
			Vector3 position = ((Component)piece).transform.position;
			bool flag = player.m_noPlacementCost || (Object)(object)piece.m_craftingStation == (Object)null || ZoneSystem.instance.GetGlobalKey((GlobalKeys)27) || (Object)(object)CraftingStation.HaveBuildStationInRange(piece.m_craftingStation.m_name, ((Component)player).transform.position) != (Object)null;
			if ((Object)(object)component != (Object)null && component.IsValid() && piece.m_canBeRemoved && flag && !Location.IsInsideNoBuildLocation(position) && PrivateArea.CheckAccess(position, 0f, false, false))
			{
				return piece.CanBeRemoved();
			}
			return false;
		}

		private static void Remove(Player player, Piece piece)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Expected O, but got Unknown
			IRemoved component = ((Component)piece).GetComponent<IRemoved>();
			if (component != null)
			{
				component.OnRemoved();
			}
			WearNTear component2 = ((Component)piece).GetComponent<WearNTear>();
			if ((Object)(object)component2 != (Object)null)
			{
				component2.Remove(false);
				return;
			}
			Character component3 = ((Component)piece).GetComponent<Character>();
			if ((Object)(object)component3 != (Object)null)
			{
				component3.Damage(new HitData(1E+10f));
				return;
			}
			((Component)piece).GetComponent<ZNetView>().ClaimOwnership();
			piece.DropResources((HitData)null);
			piece.m_placeEffect.Create(((Component)piece).transform.position, ((Component)piece).transform.rotation, ((Component)piece).transform, 1f, -1, ((Character)player).GetZDOID());
			player.m_removeEffects.Create(((Component)piece).transform.position, Quaternion.identity, (Transform)null, 1f, -1, ((Character)player).GetZDOID());
			ZNetScene.instance.Destroy(((Component)piece).gameObject);
		}

		internal static void Reset()
		{
			ClearHighlights();
			Selected.Clear();
			Deactivate();
			_kept = default((CopyLibrary.Copy, int, int));
			_selectionDirty = true;
		}

		private static void Select(Player player)
		{
			Piece hoveringPiece = player.GetHoveringPiece();
			if ((Object)(object)hoveringPiece == (Object)null)
			{
				return;
			}
			string text = Localization.instance.Localize(hoveringPiece.m_name);
			if (Selected.Contains(hoveringPiece))
			{
				((Character)player).Message((MessageType)1, Localization.instance.Localize("$betterhammer_copy_already", new string[1] { text }), 0, (Sprite)null, false);
				return;
			}
			ZNetView component = ((Component)hoveringPiece).GetComponent<ZNetView>();
			Vector2Int val = default(Vector2Int);
			PieceCategory val2 = default(PieceCategory);
			if ((Object)(object)component == (Object)null || !component.IsValid() || !player.m_buildPieces.GetPieceIndex(hoveringPiece, ref val, ref val2))
			{
				((Character)player).Message((MessageType)2, "$msg_missingrequirement", 0, (Sprite)null, false);
				return;
			}
			Selected.Add(hoveringPiece);
			_selectionDirty = true;
			((Character)player).Message((MessageType)1, Localization.instance.Localize("$betterhammer_copy_selected", new string[2]
			{
				text,
				Count(Selected.Count)
			}), 0, (Sprite)null, false);
		}

		private static void Deselect(Player player)
		{
			Piece hoveringPiece = player.GetHoveringPiece();
			int num = (((Object)(object)hoveringPiece != (Object)null) ? Selected.IndexOf(hoveringPiece) : (-1));
			if (num >= 0)
			{
				ResetHighlight(hoveringPiece);
				Selected.RemoveAt(num);
				_selectionDirty = true;
				((Character)player).Message((MessageType)1, Localization.instance.Localize("$betterhammer_copy_deselected", new string[2]
				{
					Localization.instance.Localize(hoveringPiece.m_name),
					Count(Selected.Count)
				}), 0, (Sprite)null, false);
			}
		}

		private static void Confirm(Player player)
		{
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			Prune();
			if (Selected.Count == 0)
			{
				((Character)player).Message((MessageType)2, "$betterhammer_copy_nothing", 0, (Sprite)null, false);
				return;
			}
			List<(Piece Prefab, Vector3 Position, Quaternion Rotation)> pieces = new List<(Piece, Vector3, Quaternion)>();
			Vector2Int val2 = default(Vector2Int);
			PieceCategory val3 = default(PieceCategory);
			foreach (Piece item in Selected)
			{
				GameObject prefab = ZNetScene.instance.GetPrefab(Utils.GetPrefabName(((Component)item).gameObject));
				Piece val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<Piece>() : null);
				if ((Object)(object)val == (Object)null || !player.m_buildPieces.GetPieceIndex(val, ref val2, ref val3))
				{
					((Character)player).Message((MessageType)2, Localization.instance.Localize("$betterhammer_copy_unavailable", new string[1] { Localization.instance.Localize(item.m_name) }), 0, (Sprite)null, false);
					return;
				}
				pieces.Add((val, ((Component)item).transform.position, ((Component)item).transform.rotation));
			}
			CopyLibrary.AskForName("$betterhammer_copy_name_title", CopyLibrary.NextDefaultName(), delegate(string name)
			{
				Save(player, pieces, name);
			});
		}

		private static void Save(Player player, List<(Piece Prefab, Vector3 Position, Quaternion Rotation)> pieces, string name)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			PieceMover.Abort(player);
			CopyLibrary.Copy copy = CopyLibrary.Add(player, pieces, name);
			if (copy == null)
			{
				((Character)player).Message((MessageType)2, "$betterhammer_copy_failed", 0, (Sprite)null, false);
				return;
			}
			ClearHighlights();
			Selected.Clear();
			_selectionDirty = true;
			if (player.SetSelectedPiece(copy.Piece))
			{
				player.m_placeRotation = GhostGroup.RotationSteps(player, copy.Parts[0].Rotation);
			}
			((Character)player).Message((MessageType)1, Localization.instance.Localize("$betterhammer_copy_saved", new string[1] { copy.Name }), 0, (Sprite)null, false);
		}

		internal static void BeforeSetupPlacementGhost(Player player)
		{
			if (!GhostGroup.CreatingGhosts)
			{
				Keep(player);
			}
		}

		private static void Keep(Player player)
		{
			if (Placing)
			{
				_kept = (Copy: _active, Reference: GhostGroup.Reference, SnapPoint: player.m_manualSnapPoint);
			}
		}

		internal static void AfterSetupPlacementGhost(Player player)
		{
			if (GhostGroup.CreatingGhosts)
			{
				return;
			}
			GhostGroup.End();
			_active = null;
			if (!((Character)player).InPlaceMode() || ((Character)player).IsDead())
			{
				return;
			}
			(CopyLibrary.Copy Copy, int Reference, int SnapPoint) kept = _kept;
			CopyLibrary.Copy item = kept.Copy;
			int item2 = kept.Reference;
			int item3 = kept.SnapPoint;
			_kept = default((CopyLibrary.Copy, int, int));
			CopyLibrary.Copy copy = CopyLibrary.Find(player.GetSelectedPiece());
			if (copy != null)
			{
				if (copy == item)
				{
					GhostGroup.Begin(player, copy.Parts, GhostGroup.Owner.Copy, item2, item3);
				}
				else
				{
					GhostGroup.Begin(player, copy.Parts, GhostGroup.Owner.Copy);
				}
				_active = copy;
			}
		}

		private static void Deactivate()
		{
			if (GhostGroup.ActiveOwner == GhostGroup.Owner.Copy)
			{
				GhostGroup.End();
			}
			_active = null;
		}

		internal static List<Piece> SelectionStartingWith(Piece piece)
		{
			Prune();
			if ((Object)(object)piece == (Object)null || Selected.Count < 2 || !Selected.Contains(piece))
			{
				return null;
			}
			List<Piece> list = new List<Piece>(1);
			list.Add(piece);
			list.AddRange(Selected.Where((Piece other) => (Object)(object)other != (Object)(object)piece));
			return list;
		}

		internal static bool IsSelected(Piece piece)
		{
			if ((Object)(object)piece != (Object)null)
			{
				return Selected.Contains(piece);
			}
			return false;
		}

		private static void Place(Player player)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
			player.m_lastToolUseTime = Time.time;
			ItemData rightItem = ((Humanoid)player).GetRightItem();
			if (!((Character)player).HaveStamina(rightItem.m_shared.m_attack.m_attackStamina))
			{
				Hud.instance.StaminaBarEmptyFlash();
				return;
			}
			player.UpdatePlacementGhost(true);
			GameObject placementGhost = player.m_placementGhost;
			if ((int)player.m_placementStatus != 0 || (Object)(object)placementGhost == (Object)null)
			{
				((Character)player).Message((MessageType)2, PieceMover.StatusMessages.TryGetValue(player.m_placementStatus, out var value) ? value : "$msg_invalidplacement", 0, (Sprite)null, false);
				return;
			}
			if (!HaveStations(player, _active.Prefabs))
			{
				((Character)player).Message((MessageType)2, "$msg_missingstation", 0, (Sprite)null, false);
				return;
			}
			if (!player.m_noPlacementCost && !player.HaveRequirements(_active.Piece, (RequirementMode)0))
			{
				((Character)player).Message((MessageType)2, "$msg_missingrequirement", 0, (Sprite)null, false);
				return;
			}
			int placeRotation = player.m_placeRotation;
			List<(Vector3, Quaternion)> list = GhostGroup.Poses(player);
			for (int i = 0; i < list.Count; i++)
			{
				player.PlacePiece(_active.Parts[i].Prefab, list[i].Item1, list[i].Item2, i == 0, false);
			}
			player.m_placeRotation = placeRotation;
			if (!player.m_noPlacementCost && !ZoneSystem.instance.GetGlobalKey((GlobalKeys)24))
			{
				player.ConsumeResources(_active.Piece.m_resources, 0, -1, 1);
			}
			((Character)player).UseStamina(player.GetBuildStamina());
			if (rightItem.m_shared.m_useDurability)
			{
				rightItem.m_durability -= player.GetPlaceDurability(rightItem) * Game.m_durabilityRate;
			}
			if ((int)player.m_buildPieces.m_skill != 0)
			{
				((Character)player).RaiseSkill(player.m_buildPieces.m_skill, 1f);
			}
			rightItem.m_shared.m_buildEffect.Create(((Component)player).transform.position, Quaternion.identity, (Transform)null, 1f, -1, ((Character)player).GetZDOID());
			((Character)player).Message((MessageType)1, Localization.instance.Localize("$betterhammer_copy_placed", new string[1] { Count(list.Count) }), 0, (Sprite)null, false);
		}

		private static bool HaveStations(Player player, List<Piece> pieces)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			if (player.m_noPlacementCost || ZoneSystem.instance.GetGlobalKey((GlobalKeys)27))
			{
				return true;
			}
			foreach (Piece piece in pieces)
			{
				if ((Object)(object)piece.m_craftingStation != (Object)null && (Object)(object)CraftingStation.HaveBuildStationInRange(piece.m_craftingStation.m_name, ((Component)player).transform.position) == (Object)null)
				{
					return false;
				}
			}
			return true;
		}

		internal static bool TryGetSummary(Piece piece, out Piece summary)
		{
			summary = null;
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return false;
			}
			bool flag = Hud.IsPieceSelectionVisible();
			Prune();
			if (!flag && Selected.Count > 0 && BetterHammerPlugin.AltHeld() && BetterHammerPlugin.IsHammerEquipped(localPlayer))
			{
				if (_selectionDirty)
				{
					_selectionDirty = false;
					_selectionRequirements = CopyLibrary.CombineRequirements(Selected, out _selectionStations);
					_selectionDescription = CopyLibrary.DescribePieces(Selected);
				}
				summary = Fill(localPlayer, Localization.instance.Localize("$betterhammer_copy_summary_selected", new string[1] { Count(Selected.Count) }), _selectionDescription, Selected[0].m_icon, _selectionRequirements, _selectionStations);
				return true;
			}
			CopyLibrary.Copy copy = CopyLibrary.Find(piece);
			if (copy == null)
			{
				return false;
			}
			string description = (flag ? (copy.Description + "\n" + CopyLibrary.MenuHint()) : copy.Description);
			summary = Fill(localPlayer, copy.Name, description, copy.Piece.m_icon, copy.Piece.m_resources, copy.StationPieces);
			return true;
		}

		private static Piece Fill(Player player, string name, string description, Sprite icon, IList<Requirement> requirements, List<Piece> stationPieces)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			if ((Object)(object)_summary == (Object)null)
			{
				GameObject val = new GameObject("BetterHammer_CopySummary");
				val.SetActive(false);
				Object.DontDestroyOnLoad((Object)val);
				_summary = val.AddComponent<Piece>();
			}
			int num = (((Object)(object)Hud.instance != (Object)null) ? Mathf.Max(1, Hud.instance.m_requirementItems.Length - 1) : Mathf.Max(1, requirements.Count));
			int num2 = Mathf.Max(1, Mathf.CeilToInt((float)requirements.Count / (float)num));
			int num3 = (int)(Time.time / 2.5f) % num2;
			if (num2 > 1)
			{
				description = description + "\n" + Localization.instance.Localize("$betterhammer_copy_materials_page", new string[2]
				{
					Count(num3 + 1),
					Count(num2)
				});
			}
			_summary.m_name = name;
			_summary.m_description = description;
			_summary.m_icon = icon;
			_summary.m_resources = requirements.Skip(num3 * num).Take(num).ToArray();
			_summary.m_craftingStation = StationToShow(player, stationPieces);
			return _summary;
		}

		private static CraftingStation StationToShow(Player player, List<Piece> stationPieces)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			CraftingStation val = null;
			foreach (Piece stationPiece in stationPieces)
			{
				CraftingStation craftingStation = stationPiece.m_craftingStation;
				if (val == null)
				{
					val = craftingStation;
				}
				if ((Object)(object)CraftingStation.HaveBuildStationInRange(craftingStation.m_name, ((Component)player).transform.position) == (Object)null)
				{
					return craftingStation;
				}
			}
			return val;
		}

		internal static void UpdateHighlight()
		{
			//IL_009f: 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)
			Player localPlayer = Player.m_localPlayer;
			if (Selected.Count <= 0 || !((Object)(object)MaterialMan.instance != (Object)null) || !((Object)(object)localPlayer != (Object)null) || !((Character)localPlayer).InPlaceMode() || !BetterHammerPlugin.IsHammerEquipped(localPlayer))
			{
				if (_lit)
				{
					ClearHighlights();
				}
				return;
			}
			Prune();
			float num = Mathf.Lerp(0.3f, 0.7f, (Mathf.Sin(Time.time * 5f) + 1f) * 0.5f);
			foreach (Piece item in Selected)
			{
				MaterialMan.instance.SetValue<Color>(((Component)item).gameObject, EmissionColor, HighlightColor * num, false);
			}
			_lit = true;
		}

		private static void ClearHighlights()
		{
			foreach (Piece item in Selected)
			{
				ResetHighlight(item);
			}
			_lit = false;
		}

		private static void ResetHighlight(Piece piece)
		{
			if ((Object)(object)piece != (Object)null && (Object)(object)MaterialMan.instance != (Object)null)
			{
				MaterialMan.instance.ResetValue(((Component)piece).gameObject, EmissionColor);
			}
		}

		private static void Prune()
		{
			if (Selected.RemoveAll(delegate(Piece piece)
			{
				if (!((Object)(object)piece == (Object)null))
				{
					ZNetView component = ((Component)piece).GetComponent<ZNetView>();
					if (component != null)
					{
						return !component.IsValid();
					}
				}
				return true;
			}) > 0)
			{
				_selectionDirty = true;
			}
		}

		private static string Count(int value)
		{
			return value.ToString(CultureInfo.InvariantCulture);
		}
	}
	internal static class PieceMover
	{
		private const string RemoveButton = "Remove";

		private const string PlaceButton = "Attack";

		private static readonly List<ZNetView> Sources = new List<ZNetView>();

		private static string _prefabName;

		private static Piece _previousPiece;

		private static int _previousRotation;

		private static bool _blockRemoveUntilReleased;

		private static int _rightClickFrame = -10;

		private static readonly Color HighlightColor = new Color(0.941f, 0.69f, 0.29f);

		private static readonly int EmissionColor = Shader.PropertyToID("_EmissionColor");

		private static readonly List<Collider> SourceColliders = new List<Collider>();

		private static readonly List<Collider> HiddenColliders = new List<Collider>();

		private static readonly List<StationExtension> HiddenExtensions = new List<StationExtension>();

		internal static readonly Dictionary<PlacementStatus, string> StatusMessages = new Dictionary<PlacementStatus, string>
		{
			[(PlacementStatus)3] = "$msg_nobuildzone",
			[(PlacementStatus)2] = "$msg_blocked",
			[(PlacementStatus)4] = "$msg_privatezone",
			[(PlacementStatus)5] = "$msg_needspace",
			[(PlacementStatus)6] = "$msg_noteleportarea",
			[(PlacementStatus)7] = "$msg_extensionmissingstation",
			[(PlacementStatus)8] = "$msg_wrongbiome",
			[(PlacementStatus)9] = "$msg_needcultivated",
			[(PlacementStatus)10] = "$msg_needdirt",
			[(PlacementStatus)11] = "$msg_notindungeon",
			[(PlacementStatus)13] = "$msg_snowtoodeep",
			[(PlacementStatus)14] = "$msg_nosnow"
		};

		internal static bool Moving => Sources.Count > 0;

		private static bool MovingGroup => Sources.Count > 1;

		internal static bool RightClickConsumed
		{
			get
			{
				if (!Moving)
				{
					return _rightClickFrame == Time.frameCount;
				}
				return true;
			}
		}

		internal static bool BeforeUpdatePlacement(Player player, bool takeInput)
		{
			if (_blockRemoveUntilReleased)
			{
				if (ZInput.GetButton("Remove") || ZInput.GetButtonUp("Remove"))
				{
					player.m_blockRemove = true;
				}
				else
				{
					_blockRemoveUntilReleased = false;
				}
			}
			string text = (Moving ? AbortReason(player) : null);
			if (text != null)
			{
				Stop(player);
				((Character)player).Message((MessageType)1, text, 0, (Sprite)null, false);
			}
			bool moving = Moving;
			if (!takeInput || !((Character)player).InPlaceMode() || ((Character)player).IsDead() || Hud.IsPieceSelectionVisible() || Hud.InRadial() || ZInput.IsGamepadActive() || !BetterHammerPlugin.IsHammerEquipped(player))
			{
				return moving;
			}
			if (BetterHammerPlugin.CtrlHeld() && ZInput.GetButtonDown("Remove"))
			{
				BlockRemoveUntilReleased(player);
				PickUp(player);
			}
			else if (Moving && ZInput.GetButtonDown("Remove") && IsSource(player.GetHoveringPiece()))
			{
				BlockRemoveUntilReleased(player);
				((Character)player).Message((MessageType)2, "$betterhammer_move_cant_remove", 0, (Sprite)null, false);
			}
			else if (Moving && Input.GetMouseButtonDown(1))
			{
				_rightClickFrame = Time.frameCount;
				Stop(player);
				((Character)player).Message((MessageType)1, "$betterhammer_move_aborted", 0, (Sprite)null, false);
			}
			else if (Moving && !BetterHammerPlugin.AltHeld() && ZInput.GetButtonDown("Attack") && Time.time - player.m_lastToolUseTime > player.m_placeDelay)
			{
				PutDown(player);
			}
			if (!moving)
			{
				return Moving;
			}
			return true;
		}

		internal static void BlockVanillaPlacing(Player player)
		{
			player.m_placePressedTime = -9999f;
		}

		internal static void BlockRemoveUntilReleased(Player player)
		{
			_blockRemoveUntilReleased = true;
			player.m_blockRemove = true;
		}

		internal static void Abort(Player player)
		{
			if (Moving)
			{
				Stop(player);
				((Character)player).Message((MessageType)1, "$betterhammer_move_aborted", 0, (Sprite)null, false);
			}
		}

		internal static void Reset()
		{
			ClearHighlight();
			Sources.Clear();
			_prefabName = null;
			_previousPiece = null;
			_blockRemoveUntilReleased = false;
		}

		private static void PickUp(Player player)
		{
			//IL_00c2: 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_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			Piece hoveringPiece = player.GetHoveringPiece();
			if ((Object)(object)hoveringPiece == (Object)null)
			{
				return;
			}
			List<Piece> list = MultiCopy.SelectionStartingWith(hoveringPiece) ?? new List<Piece>(1) { hoveringPiece };
			List<ZNetView> list2 = new List<ZNetView>();
			foreach (Piece item in list)
			{
				if (!CanMove(player, item, out var nview))
				{
					return;
				}
				list2.Add(nview);
			}
			if (!Moving)
			{
				_previousPiece = player.GetSelectedPiece();
				_previousRotation = player.m_placeRotation;
			}
			bool flag = GhostGroup.ActiveOwner == GhostGroup.Owner.Move;
			if (flag)
			{
				GhostGroup.End();
			}
			if (!player.SetSelectedPiece(hoveringPiece))
			{
				((Character)player).Message((MessageType)2, "$msg_missingrequirement", 0, (Sprite)null, false);
				return;
			}
			Quaternion rotation = ((Component)hoveringPiece).transform.rotation;
			player.m_placeRotation = (int)Math.Round(((Quaternion)(ref rotation)).eulerAngles.y / player.m_placeRotationDegrees);
			ClearHighlight();
			Sources.Clear();
			Sources.AddRange(list2);
			_prefabName = Utils.GetPrefabName(((Component)hoveringPiece).gameObject);
			if (!MovingGroup)
			{
				if (flag)
				{
					player.SetupPlacementGhost();
				}
				((Character)player).Message((MessageType)1, Localization.instance.Localize("$betterhammer_move_started", new string[1] { Localization.instance.Localize(hoveringPiece.m_name) }), 0, (Sprite)null, false);
				return;
			}
			List<CopyLibrary.Part> list3 = new List<CopyLibrary.Part>();
			foreach (Piece item2 in list)
			{
				list3.Add(CopyLibrary.MakePart(PrefabOf(item2), ((Component)item2).transform.position, ((Component)item2).transform.rotation));
			}
			GhostGroup.Begin(player, list3, GhostGroup.Owner.Move);
			((Character)player).Message((MessageType)1, Localization.instance.Localize("$betterhammer_move_started_group", new string[1] { Sources.Count.ToString(CultureInfo.InvariantCulture) }), 0, (Sprite)null, false);
		}

		private static Piece PrefabOf(Piece piece)
		{
			GameObject prefab = ZNetScene.instance.GetPrefab(Utils.GetPrefabName(((Component)piece).gameObject));
			if (!((Object)(object)prefab != (Object)null))
			{
				return piece;
			}
			return prefab.GetComponent<Piece>();
		}

		private static bool IsSource(Piece piece)
		{
			if ((Object)(object)piece == (Object)null)
			{
				return false;
			}
			foreach (ZNetView source in Sources)
			{
				if ((Object)(object)source != (Object)null && (Object)(object)((Component)source).GetComponent<Piece>() == (Object)(object)piece)
				{
					return true;
				}
			}
			return false;
		}

		private static void PutDown(Player player)
		{
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0249: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Unknown result type (might be due to invalid IL or missing references)
			//IL_028b: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			player.m_lastToolUseTime = Time.time;
			List<Piece> list = new List<Piece>();
			foreach (ZNetView source in Sources)
			{
				Piece component = ((Component)source).GetComponent<Piece>();
				if ((Object)(object)component == (Object)null || !CanMove(player, component, out var _))
				{
					return;
				}
				list.Add(component);
			}
			ItemData rightItem = ((Humanoid)player).GetRightItem();
			if (!((Character)player).HaveStamina(rightItem.m_shared.m_attack.m_attackStamina))
			{
				Hud.instance.StaminaBarEmptyFlash();
				return;
			}
			player.UpdatePlacementGhost(true);
			GameObject placementGhost = player.m_placementGhost;
			if ((int)player.m_placementStatus != 0 || (Object)(object)placementGhost == (Object)null)
			{
				((Character)player).Message((MessageType)2, StatusMessages.TryGetValue(player.m_placementStatus, out var value) ? value : "$msg_invalidplacement", 0, (Sprite)null, false);
				return;
			}
			List<(Vector3, Quaternion)> list2 = (List<(Vector3, Quaternion)>)(MovingGroup ? ((IList)GhostGroup.Poses(player)) : ((IList)new List<(Vector3, Quaternion)>(1) { (placementGhost.transform.position, placementGhost.transform.rotation) }));
			List<GameObject> list3 = new List<GameObject>();
			for (int i = 0; i < Sources.Count; i++)
			{
				GameObject val = Recreate(Sources[i], list2[i].Item1, list2[i].Item2);
				if ((Object)(object)val == (Object)null)
				{
					foreach (GameObject item in list3)
					{
						ZNetScene.instance.Destroy(item);
					}
					((Character)player).Message((MessageType)2, "$betterhammer_move_failed", 0, (Sprite)null, false);
					return;
				}
				list3.Add(val);
			}
			Vector3 position = ((Component)list[0]).transform.position;
			ClearHighlight();
			for (int j = 0; j < Sources.Count; j++)
			{
				MultiCopy.ReplaceSelected(list[j], list3[j].GetComponent<Piece>());
				Sources[j].ClaimOwnership();
				ZNetScene.instance.Destroy(((Component)Sources[j]).gameObject);
				list[j].m_placeEffect.Create(list2[j].Item1, list2[j].Item2, list3[j].transform, 1f, -1, ((Character)player).GetZDOID());
			}
			player.m_removeEffects.Create(position, Quaternion.identity, (Transform)null, 1f, -1, ((Character)player).GetZDOID());
			player.FaceLookDirection();
			((Character)player).m_zanim.SetTrigger(rightItem.m_shared.m_attack.m_attackAnimation);
			((Character)player).UseStamina(player.GetBuildStamina());
			if (rightItem.m_shared.m_useDurability)
			{
				rightItem.m_durability -= player.GetPlaceDurability(rightItem) * Game.m_durabilityRate;
			}
			int count = Sources.Count;
			Sources.Clear();
			Stop(player);
			((Character)player).Message((MessageType)1, (count > 1) ? Localization.instance.Localize("$betterhammer_moved_group", new string[1] { count.ToString(CultureInfo.InvariantCulture) }) : Localization.instance.Localize("$betterhammer_moved", new string[1] { Localization.instance.Localize(list[0].m_name) }), 0, (Sprite)null, false);
		}

		internal static void UpdateHighlight()
		{
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			if (!Moving || (Object)(object)MaterialMan.instance == (Object)null)
			{
				return;
			}
			float num = Mathf.Lerp(0.3f, 0.7f, (Mathf.Sin(Time.time * 5f) + 1f) * 0.5f);
			foreach (ZNetView source in Sources)
			{
				if ((Object)(object)source != (Object)null)
				{
					MaterialMan.instance.SetValue<Color>(((Component)source).gameObject, EmissionColor, HighlightColor * num, false);
				}
			}
		}

		private static void ClearHighlight()
		{
			if ((Object)(object)MaterialMan.instance == (Object)null)
			{
				return;
			}
			foreach (ZNetView source in Sources)
			{
				if ((Object)(object)source != (Object)null)
				{
					MaterialMan.instance.ResetValue(((Component)source).gameObject, EmissionColor);
				}
			}
		}

		internal static void HideFromPlacementChecks()
		{
			if (!Moving)
			{
				return;
			}
			foreach (ZNetView source in Sources)
			{
				if ((Object)(object)source == (Object)null)
				{
					continue;
				}
				((Component)source).GetComponentsInChildren<Collider>(SourceColliders);
				foreach (Collider sourceCollider in SourceColliders)
				{
					if (sourceCollider.enabled)
					{
						sourceCollider.enabled = false;
						HiddenColliders.Add(sourceCollider);
					}
				}
				SourceColliders.Clear();
				StationExtension componentInChildren = ((Component)source).GetComponentInChildren<StationExtension>();
				if ((Object)(object)componentInChildren != (Object)null && StationExtension.m_allExtensions.Remove(componentInChildren))
				{
					HiddenExtensions.Add(componentInChildren);
				}
			}
		}

		internal static void RestoreAfterPlacementChecks()
		{
			foreach (Collider hiddenCollider in HiddenColliders)
			{
				if ((Object)(object)hiddenCollider != (Object)null)
				{
					hiddenCollider.enabled = true;
				}
			}
			HiddenColliders.Clear();
			StationExtension.m_allExtensions.AddRange(HiddenExtensions);
			HiddenExtensions.Clear();
		}

		private static GameObject Recreate(ZNetView source, Vector3 position, Quaternion rotation)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: 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)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			ZDO zDO = source.GetZDO();
			int prefab = zDO.GetPrefab();
			GameObject prefab2 = ZNetScene.instance.GetPrefab(prefab);
			if ((Object)(object)prefab2 == (Object)null)
			{
				return null;
			}
			ZDO val = ZDOMan.instance.CreateNewZDO(position, prefab);
			val.Persistent = zDO.Persistent;
			val.Type = zDO.Type;
			val.Distant = zDO.Distant;
			val.SetPrefab(prefab);
			val.SetRotation(rotation);
			CopyData(zDO.m_uid, val);
			GameObject val2 = null;
			ZNetView.m_useInitZDO = true;
			ZNetView.m_initZDO = val;
			try
			{
				val2 = Object.Instantiate<GameObject>(prefab2, position, rotation);
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("BetterHammer: failed to move " + ((Object)prefab2).name + ": " + ex));
			}
			finally
			{
				bool flag = ZNetView.m_initZDO != null;
				ZNetView.m_initZDO = null;
				ZNetView.m_useInitZDO = false;
				if ((Object)(object)val2 == (Object)null || flag)
				{
					if ((Object)(object)val2 != (Object)null)
					{
						Object.Destroy((Object)(object)val2);
					}
					ZDOMan.instance.DestroyZDO(val);
					val2 = null;
				}
			}
			return val2;
		}

		private static void CopyData(ZDOID from, ZDO to)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			List<KeyValuePair<int, float>> list = default(List<KeyValuePair<int, float>>);
			List<KeyValuePair<int, Vector3>> list2 = default(List<KeyValuePair<int, Vector3>>);
			List<KeyValuePair<int, Quaternion>> list3 = default(List<KeyValuePair<int, Quaternion>>);
			List<KeyValuePair<int, int>> list4 = default(List<KeyValuePair<int, int>>);
			List<KeyValuePair<int, long>> list5 = default(List<KeyValuePair<int, long>>);
			List<KeyValuePair<int, string>> list6 = default(List<KeyValuePair<int, string>>);
			List<KeyValuePair<int, byte[]>> list7 = default(List<KeyValuePair<int, byte[]>>);
			ZDOConnection val = default(ZDOConnection);
			ZDOExtraData.GetData(from, ref list, ref list2, ref list3, ref list4, ref list5, ref list6, ref list7, ref val);
			foreach (KeyValuePair<int, float> item in list)
			{
				to.Set(item.Key, item.Value);
			}
			foreach (KeyValuePair<int, Vector3> item2 in list2)
			{
				to.Set(item2.Key, item2.Value);
			}
			foreach (KeyValuePair<int, Quaternion> item3 in list3)
			{
				to.Set(item3.Key, item3.Value);
			}
			foreach (KeyValuePair<int, int> item4 in list4)
			{
				to.Set(item4.Key, item4.Value, false);
			}
			foreach (KeyValuePair<int, long> item5 in list5)
			{
				to.Set(item5.Key, item5.Value);
			}
			foreach (KeyValuePair<int, string> item6 in list6)
			{
				to.Set(item6.Key, item6.Value);
			}
			foreach (KeyValuePair<int, byte[]> item7 in list7)
			{
				to.Set(item7.Key, (byte[])item7.Value.Clone());
			}
		}

		private static bool CanMove(Player player, Piece piece, out ZNetView nview)
		{
			//IL_0042: 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_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			nview = ((Component)piece).GetComponent<ZNetView>();
			if ((Object)(object)nview == (Object)null || !nview.IsValid() || !piece.m_canBeRemoved || !IsMovableKind(piece))
			{
				((Character)player).Message((MessageType)2, "$betterhammer_move_cant", 0, (Sprite)null, false);
				return false;
			}
			Vector3 position = ((Component)piece).transform.position;
			if (Location.IsInsideNoBuildLocation(position))
			{
				((Character)player).Message((MessageType)2, "$msg_nobuildzone", 0, (Sprite)null, false);
				retu