Decompiled source of ChestSnapping v1.0.0

ChestSnapping.dll

Decompiled 5 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("ChestSnapping")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ChestSnapping")]
[assembly: AssemblyTitle("ChestSnapping")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ChestSnapping
{
	[BepInPlugin("com.kydldev.ChestSnapping", "Chest Snapping", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class ChestSnappingPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.kydldev.ChestSnapping";

		public const string PluginName = "Chest Snapping";

		public const string PluginVersion = "1.0.0";

		internal static readonly string[] DefaultPrefabs = new string[4] { "piece_chest_wood", "piece_chest", "piece_chest_private", "piece_chest_blackmetal" };

		internal static ManualLogSource Log;

		internal static ConfigEntry<string> ExtraPrefabs;

		internal static ConfigEntry<string> ExcludedPrefabs;

		internal static ConfigEntry<bool> AutoDetectContainers;

		internal static ConfigEntry<string> Adjustments;

		internal static HashSet<string> Included = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		internal static HashSet<string> ExtraSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		internal static HashSet<string> Excluded = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

		private Harmony _harmony;

		private volatile bool _refreshQueued;

		private void Awake()
		{
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ExtraPrefabs = ((BaseUnityPlugin)this).Config.Bind<string>("Prefabs", "ExtraPrefabs", "", "Comma-separated prefab names of additional chests/containers that should get snap points (modded chests, or vanilla chests added in a future update). Example: piece_chest_custom, MyMod_BigCrate. Run the console command 'chestsnap_list' to see candidate prefab names, or 'chestsnap_add <prefab>' to add one without editing this file.");
			ExcludedPrefabs = ((BaseUnityPlugin)this).Config.Bind<string>("Prefabs", "ExcludedPrefabs", "", "Comma-separated prefab names that should NOT get snap points, even if they are in the built-in list or matched by AutoDetectContainers.");
			AutoDetectContainers = ((BaseUnityPlugin)this).Config.Bind<bool>("Prefabs", "AutoDetectContainers", false, "If true, every buildable piece that has a Container component on its root object (and is not a ship or cart) automatically gets snap points. Handy for modded chests, but may also catch things you do not consider a chest - use ExcludedPrefabs to opt those out.");
			Adjustments = ((BaseUnityPlugin)this).Config.Bind<string>("Offsets", "PrefabAdjustments", "", "Per-prefab tweaks to where the snap points sit. Usually changed with the console commands chestsnap_shift / chestsnap_grow / chestsnap_point / chestsnap_reset (use chestsnap_show on to see the points), but you can also edit it by hand. Format: entries separated by ';', each 'prefab: shift=x,y,z grow=x,y,z p5=x,y,z'. Distances are in meters along the chest's own axes (+X right, +Y up, +Z front), '.' is always the decimal separator. shift moves all points together. grow is added to the half-size of the snap box per axis (0.05 = 10 cm bigger on that axis, negative = smaller). pN adds an offset to a single point, N = 1-14 in Q/E cycling order. Example: MyMod_Crate: shift=0,0.05,0 grow=-0.02,0,-0.02 p5=0,0.1,0");
			ExtraPrefabs.SettingChanged += delegate
			{
				_refreshQueued = true;
			};
			ExcludedPrefabs.SettingChanged += delegate
			{
				_refreshQueued = true;
			};
			AutoDetectContainers.SettingChanged += delegate
			{
				_refreshQueued = true;
			};
			Adjustments.SettingChanged += delegate
			{
				_refreshQueued = true;
			};
			RebuildSets();
			RegisterLocalization();
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new ListContainersCommand());
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new AddPrefabCommand());
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new RemovePrefabCommand());
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new ShiftCommand());
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new GrowCommand());
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new PointCommand());
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new ResetCommand());
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new InfoCommand());
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new ShowCommand());
			_harmony = new Harmony("com.kydldev.ChestSnapping");
			_harmony.PatchAll(typeof(ChestSnappingPlugin).Assembly);
		}

		private void Update()
		{
			if (_refreshQueued)
			{
				_refreshQueued = false;
				RebuildSets();
				ChestSnapPoints.RefreshAll();
			}
		}

		private void OnDestroy()
		{
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
		}

		internal static void RebuildSets()
		{
			ExtraSet = Parse(ExtraPrefabs.Value);
			Excluded = Parse(ExcludedPrefabs.Value);
			HashSet<string> hashSet = new HashSet<string>(DefaultPrefabs, StringComparer.OrdinalIgnoreCase);
			hashSet.UnionWith(ExtraSet);
			Included = hashSet;
			SnapAdjustments.Load(Adjustments.Value);
		}

		private static HashSet<string> Parse(string csv)
		{
			HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
			if (string.IsNullOrWhiteSpace(csv))
			{
				return hashSet;
			}
			string[] array = csv.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i].Trim();
				if (text.Length > 0)
				{
					hashSet.Add(text);
				}
			}
			return hashSet;
		}

		private static void RegisterLocalization()
		{
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			SnapDef[] points = SnapLayout.Points;
			for (int i = 0; i < points.Length; i++)
			{
				SnapDef snapDef = points[i];
				dictionary[snapDef.TokenKey] = snapDef.EnglishName;
			}
			CustomLocalization localization = LocalizationManager.Instance.GetLocalization();
			string text = "English";
			localization.AddTranslation(ref text, dictionary);
		}
	}
	[HarmonyPatch(typeof(Piece), "Awake")]
	internal static class PieceAwakePatch
	{
		private static void Postfix(Piece __instance)
		{
			ChestSnapPoints.Apply(__instance);
		}
	}
	internal struct SnapDef
	{
		public string TokenKey;

		public string EnglishName;

		public Vector3 Factor;

		public string ObjectName => "$" + TokenKey;
	}
	internal static class SnapLayout
	{
		public static readonly SnapDef[] Points = Build();

		private static SnapDef[] Build()
		{
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			List<SnapDef> list = new List<SnapDef>();
			float[] array = new float[2] { -1f, 1f };
			foreach (float num in array)
			{
				float[] array2 = new float[2] { 1f, -1f };
				foreach (float num2 in array2)
				{
					float[] array3 = new float[2] { -1f, 1f };
					foreach (float num3 in array3)
					{
						string text = ((num < 0f) ? "Bottom" : "Top");
						string text2 = ((num2 > 0f) ? "Front" : "Back");
						string text3 = ((num3 < 0f) ? "Left" : "Right");
						list.Add(Make(text + " " + text2 + " " + text3, new Vector3(num3, num, num2)));
					}
				}
			}
			list.Add(Make("Bottom Center", new Vector3(0f, -1f, 0f)));
			list.Add(Make("Top Center", new Vector3(0f, 1f, 0f)));
			list.Add(Make("Back Center", new Vector3(0f, 0f, -1f)));
			list.Add(Make("Front Center", new Vector3(0f, 0f, 1f)));
			list.Add(Make("Left Center", new Vector3(-1f, 0f, 0f)));
			list.Add(Make("Right Center", new Vector3(1f, 0f, 0f)));
			return list.ToArray();
		}

		private static SnapDef Make(string english, Vector3 factor)
		{
			//IL_0032: 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)
			return new SnapDef
			{
				EnglishName = english,
				TokenKey = "chestsnap_" + english.ToLowerInvariant().Replace(' ', '_'),
				Factor = factor
			};
		}

		public static int IndexOfObjectName(string objectName)
		{
			for (int i = 0; i < Points.Length; i++)
			{
				if (string.Equals(Points[i].ObjectName, objectName, StringComparison.Ordinal))
				{
					return i;
				}
			}
			return -1;
		}

		public static bool TryFindPoint(string key, out int index)
		{
			index = -1;
			if (string.IsNullOrWhiteSpace(key))
			{
				return false;
			}
			string text = key.Trim();
			if (int.TryParse((text.Length > 1 && (text[0] == 'p' || text[0] == 'P')) ? text.Substring(1) : text, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
			{
				if (result < 1 || result > Points.Length)
				{
					return false;
				}
				index = result - 1;
				return true;
			}
			string b = text.Replace(' ', '_').Replace('-', '_');
			for (int i = 0; i < Points.Length; i++)
			{
				if (string.Equals(Points[i].EnglishName.Replace(' ', '_'), b, StringComparison.OrdinalIgnoreCase))
				{
					index = i;
					return true;
				}
			}
			return false;
		}
	}
	internal static class ChestSnapPoints
	{
		private const string SnapTag = "snappoint";

		private const string NamePrefix = "$chestsnap_";

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

		internal static void Apply(Piece piece, bool refresh = false)
		{
			if ((Object)(object)piece == (Object)null)
			{
				return;
			}
			try
			{
				string prefabName = GetPrefabName(((Component)piece).gameObject);
				bool flag = Wants(((Component)piece).gameObject);
				bool flag2 = HasPoints(((Component)piece).transform);
				if (flag && !flag2)
				{
					AddPoints(((Component)piece).transform, prefabName);
				}
				else if (flag && refresh)
				{
					Reposition(((Component)piece).transform, prefabName);
				}
				else if (!flag && flag2)
				{
					RemovePoints(((Component)piece).transform);
				}
				if (flag && SnapMarkers.Enabled)
				{
					SnapMarkers.Sync(((Component)piece).transform);
				}
			}
			catch (Exception ex)
			{
				ChestSnappingPlugin.Log.LogWarning((object)("Could not update snap points on " + ((Object)piece).name + ": " + ex));
			}
		}

		internal static void RefreshAll()
		{
			Piece[] array = Object.FindObjectsByType<Piece>((FindObjectsSortMode)0);
			for (int i = 0; i < array.Length; i++)
			{
				Apply(array[i], refresh: true);
			}
		}

		internal static bool Wants(GameObject go)
		{
			return Source(go) != null;
		}

		internal static string Source(GameObject go)
		{
			string prefabName = GetPrefabName(go);
			if (ChestSnappingPlugin.Excluded.Contains(prefabName))
			{
				return null;
			}
			if (ChestSnappingPlugin.ExtraSet.Contains(prefabName))
			{
				return "extra";
			}
			if (ChestSnappingPlugin.Included.Contains(prefabName))
			{
				return "default";
			}
			if (ChestSnappingPlugin.AutoDetectContainers.Value && IsPlainContainer(go))
			{
				return "auto";
			}
			return null;
		}

		internal static bool IsPlainContainer(GameObject go)
		{
			if ((Object)(object)go.GetComponent<Container>() != (Object)null && (Object)(object)go.GetComponent<Ship>() == (Object)null)
			{
				return (Object)(object)go.GetComponent<Vagon>() == (Object)null;
			}
			return false;
		}

		internal static string GetPrefabName(GameObject go)
		{
			string name = ((Object)go).name;
			if (!name.EndsWith("(Clone)", StringComparison.Ordinal))
			{
				return name;
			}
			return name.Substring(0, name.Length - "(Clone)".Length);
		}

		internal static bool HasPoints(Transform root)
		{
			for (int i = 0; i < root.childCount; i++)
			{
				if (((Object)root.GetChild(i)).name.StartsWith("$chestsnap_", StringComparison.Ordinal))
				{
					return true;
				}
			}
			return false;
		}

		internal static int PointIndex(Transform t)
		{
			if (!((Object)t).name.StartsWith("$chestsnap_", StringComparison.Ordinal))
			{
				return -1;
			}
			return SnapLayout.IndexOfObjectName(((Object)t).name);
		}

		private static void AddPoints(Transform root, string prefabName)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: 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_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			if (TryComputePositions(root, prefabName, out var positions))
			{
				for (int i = 0; i < SnapLayout.Points.Length; i++)
				{
					Transform transform = new GameObject(SnapLayout.Points[i].ObjectName)
					{
						tag = "snappoint"
					}.transform;
					transform.SetParent(root, false);
					transform.localRotation = Quaternion.identity;
					transform.localScale = Vector3.one;
					transform.localPosition = positions[i];
				}
			}
		}

		private static void Reposition(Transform root, string prefabName)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			if (!TryComputePositions(root, prefabName, out var positions))
			{
				return;
			}
			for (int i = 0; i < root.childCount; i++)
			{
				Transform child = root.GetChild(i);
				int num = PointIndex(child);
				if (num >= 0)
				{
					child.localPosition = positions[num];
				}
			}
		}

		private static void RemovePoints(Transform root)
		{
			for (int num = root.childCount - 1; num >= 0; num--)
			{
				Transform child = root.GetChild(num);
				if (((Object)child).name.StartsWith("$chestsnap_", StringComparison.Ordinal))
				{
					((Component)child).gameObject.tag = "Untagged";
					Object.Destroy((Object)(object)((Component)child).gameObject);
				}
			}
		}

		private static bool TryComputePositions(Transform root, string prefabName, out Vector3[] positions)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			positions = null;
			if (!TryGetLocalBounds(root, out var bounds))
			{
				if (WarnedPrefabs.Add(prefabName))
				{
					ChestSnappingPlugin.Log.LogWarning((object)("No colliders or meshes found on '" + prefabName + "', cannot place snap points on it."));
				}
				return false;
			}
			positions = ComputePositions(bounds, SnapAdjustments.Get(prefabName));
			return true;
		}

		internal static Vector3[] ComputePositions(Bounds bounds, PrefabAdjust adj)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//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_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//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_0036: 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_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: 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_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: 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)
			Vector3 val = ((Bounds)(ref bounds)).center;
			Vector3 val2 = ((Bounds)(ref bounds)).extents;
			if (adj != null)
			{
				val += adj.Shift;
				val2 = Vector3.Max(val2 + adj.Grow, Vector3.zero);
			}
			Vector3[] array = (Vector3[])(object)new Vector3[SnapLayout.Points.Length];
			for (int i = 0; i < array.Length; i++)
			{
				Vector3 val3 = val + Vector3.Scale(val2, SnapLayout.Points[i].Factor);
				if (adj != null && adj.Points.TryGetValue(i, out var value))
				{
					val3 += value;
				}
				array[i] = val3;
			}
			return array;
		}

		internal static bool TryGetLocalBounds(Transform root, out Bounds bounds)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: 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)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: 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_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			bounds = default(Bounds);
			bool found = false;
			Matrix4x4 worldToLocalMatrix = root.worldToLocalMatrix;
			Collider[] componentsInChildren = ((Component)root).GetComponentsInChildren<Collider>(true);
			foreach (Collider val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && !val.isTrigger && TryGetColliderBox(val, out var center, out var size))
				{
					Encapsulate(ref bounds, ref found, worldToLocalMatrix * ((Component)val).transform.localToWorldMatrix, center, size);
				}
			}
			if (found)
			{
				return true;
			}
			MeshFilter[] componentsInChildren2 = ((Component)root).GetComponentsInChildren<MeshFilter>(true);
			foreach (MeshFilter val2 in componentsInChildren2)
			{
				if (!(((Object)((Component)val2).gameObject).name == "chestsnap_marker"))
				{
					Mesh sharedMesh = val2.sharedMesh;
					if (!((Object)(object)sharedMesh == (Object)null))
					{
						Matrix4x4 m = worldToLocalMatrix * ((Component)val2).transform.localToWorldMatrix;
						Bounds bounds2 = sharedMesh.bounds;
						Vector3 center2 = ((Bounds)(ref bounds2)).center;
						bounds2 = sharedMesh.bounds;
						Encapsulate(ref bounds, ref found, m, center2, ((Bounds)(ref bounds2)).size);
					}
				}
			}
			return found;
		}

		private static bool TryGetColliderBox(Collider col, out Vector3 center, out Vector3 size)
		{
			//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_0023: 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_0041: 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_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_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: 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_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: 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_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: 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_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			BoxCollider val = (BoxCollider)(object)((col is BoxCollider) ? col : null);
			if ((Object)(object)val != (Object)null)
			{
				center = val.center;
				size = val.size;
				return true;
			}
			SphereCollider val2 = (SphereCollider)(object)((col is SphereCollider) ? col : null);
			if ((Object)(object)val2 != (Object)null)
			{
				center = val2.center;
				size = Vector3.one * (val2.radius * 2f);
				return true;
			}
			CapsuleCollider val3 = (CapsuleCollider)(object)((col is CapsuleCollider) ? col : null);
			if ((Object)(object)val3 != (Object)null)
			{
				float num = val3.radius * 2f;
				float num2 = Mathf.Max(val3.height, num);
				center = val3.center;
				size = ((val3.direction == 0) ? new Vector3(num2, num, num) : ((val3.direction == 1) ? new Vector3(num, num2, num) : new Vector3(num, num, num2)));
				return true;
			}
			MeshCollider val4 = (MeshCollider)(object)((col is MeshCollider) ? col : null);
			if ((Object)(object)val4 != (Object)null && (Object)(object)val4.sharedMesh != (Object)null)
			{
				Bounds bounds = val4.sharedMesh.bounds;
				center = ((Bounds)(ref bounds)).center;
				bounds = val4.sharedMesh.bounds;
				size = ((Bounds)(ref bounds)).size;
				return true;
			}
			center = Vector3.zero;
			size = Vector3.zero;
			return false;
		}

		private static void Encapsulate(ref Bounds bounds, ref bool found, Matrix4x4 m, Vector3 center, Vector3 size)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_0017: 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_002b: 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_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: 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_005b: 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_0061: 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_0067: 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_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = size * 0.5f;
			for (int i = 0; i < 8; i++)
			{
				Vector3 val2 = center + new Vector3(((i & 1) == 0) ? (0f - val.x) : val.x, ((i & 2) == 0) ? (0f - val.y) : val.y, ((i & 4) == 0) ? (0f - val.z) : val.z);
				Vector3 val3 = ((Matrix4x4)(ref m)).MultiplyPoint3x4(val2);
				if (!found)
				{
					bounds = new Bounds(val3, Vector3.zero);
					found = true;
				}
				else
				{
					((Bounds)(ref bounds)).Encapsulate(val3);
				}
			}
		}
	}
	internal static class CommandUtil
	{
		internal static void Print(string text)
		{
			Console.instance.Print(text);
		}

		internal static bool TryParseFloat(string s, out float value)
		{
			return float.TryParse(s.Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out value);
		}

		internal static bool TryParseVector(string[] args, int start, out Vector3 v)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			v = Vector3.zero;
			if (args == null || args.Length < start + 3)
			{
				return false;
			}
			if (!TryParseFloat(args[start], out var value) || !TryParseFloat(args[start + 1], out var value2) || !TryParseFloat(args[start + 2], out var value3))
			{
				return false;
			}
			v = new Vector3(value, value2, value3);
			return true;
		}

		internal static string Fmt(Vector3 v)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: 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)
			return "(" + SnapAdjustments.Num(v.x) + ", " + SnapAdjustments.Num(v.y) + ", " + SnapAdjustments.Num(v.z) + ")";
		}

		internal static string ResolvePrefabName(string typed)
		{
			typed = typed.Trim();
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				foreach (GameObject prefab in ZNetScene.instance.m_prefabs)
				{
					if ((Object)(object)prefab != (Object)null && string.Equals(((Object)prefab).name, typed, StringComparison.OrdinalIgnoreCase))
					{
						return ((Object)prefab).name;
					}
				}
			}
			return typed;
		}

		internal static List<string> ContainerPrefabNames()
		{
			if ((Object)(object)ZNetScene.instance == (Object)null)
			{
				return new List<string>();
			}
			return (from p in ZNetScene.instance.m_prefabs
				where (Object)(object)p != (Object)null && (Object)(object)p.GetComponent<Piece>() != (Object)null && (Object)(object)p.GetComponent<Container>() != (Object)null
				select ((Object)p).name).OrderBy<string, string>((string n) => n, StringComparer.OrdinalIgnoreCase).ToList();
		}

		internal static void NoteIfInactive(string name)
		{
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				GameObject prefab = ZNetScene.instance.GetPrefab(name);
				if ((Object)(object)prefab == (Object)null)
				{
					Print("Note: no prefab named '" + name + "' is loaded right now - check the spelling.");
				}
				else if (ChestSnapPoints.Source(prefab) == null)
				{
					Print("Note: '" + name + "' has no snap points yet. Run: chestsnap_add " + name);
				}
			}
			else if (!ChestSnappingPlugin.Included.Contains(name))
			{
				Print("Note: '" + name + "' has no snap points yet. Run: chestsnap_add " + name);
			}
		}
	}
	internal class ListContainersCommand : ConsoleCommand
	{
		public override string Name => "chestsnap_list";

		public override string Help => "Lists buildable container prefabs and whether they have snap points. Usage: chestsnap_list [name filter]";

		public override void Run(string[] args)
		{
			if ((Object)(object)ZNetScene.instance == (Object)null)
			{
				CommandUtil.Print("Load into a world first (prefabs are not available in the main menu).");
				return;
			}
			string value = ((args != null && args.Length != 0) ? args[0] : null);
			List<string> list = new List<string>();
			foreach (GameObject prefab in ZNetScene.instance.m_prefabs)
			{
				if (!((Object)(object)prefab == (Object)null) && !((Object)(object)prefab.GetComponent<Piece>() == (Object)null) && !((Object)(object)prefab.GetComponent<Container>() == (Object)null) && (string.IsNullOrEmpty(value) || ((Object)prefab).name.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0))
				{
					string text = ChestSnapPoints.Source(prefab);
					string text2 = ((text != null) ? ("snap points (" + text + ")") : "-");
					string text3 = (ChestSnapPoints.IsPlainContainer(prefab) ? "" : "  [ship/cart]");
					string text4 = ((SnapAdjustments.Get(((Object)prefab).name) != null) ? "  [adjusted]" : "");
					list.Add(((Object)prefab).name.PadRight(32) + text2 + text3 + text4);
				}
			}
			list.Sort(StringComparer.OrdinalIgnoreCase);
			CommandUtil.Print("Buildable containers (" + list.Count + "):");
			foreach (string item in list)
			{
				CommandUtil.Print("  " + item);
			}
			CommandUtil.Print("Add one with: chestsnap_add <prefab_name>");
		}

		public override List<string> CommandOptionList()
		{
			return CommandUtil.ContainerPrefabNames();
		}
	}
	internal class AddPrefabCommand : ConsoleCommand
	{
		public override string Name => "chestsnap_add";

		public override string Help => "Adds a chest/container prefab to the snapping list (saved in the config). Usage: chestsnap_add <prefab_name>";

		public override void Run(string[] args)
		{
			if (args == null || args.Length < 1)
			{
				CommandUtil.Print("Usage: chestsnap_add <prefab_name>   (see chestsnap_list)");
				return;
			}
			string text = CommandUtil.ResolvePrefabName(args[0]);
			if (ChestSnappingPlugin.Included.Contains(text))
			{
				CommandUtil.Print("'" + text + "' already gets snap points.");
				return;
			}
			if ((Object)(object)ZNetScene.instance != (Object)null && (Object)(object)ZNetScene.instance.GetPrefab(text) == (Object)null)
			{
				CommandUtil.Print("Warning: no prefab named '" + text + "' is currently loaded. Adding it anyway (names are case-insensitive).");
			}
			string value = ChestSnappingPlugin.ExtraPrefabs.Value;
			ChestSnappingPlugin.ExtraPrefabs.Value = (string.IsNullOrWhiteSpace(value) ? text : (value.TrimEnd(',', ' ') + ", " + text));
			CommandUtil.Print("Added '" + text + "'. Existing chests update right away.");
			CommandUtil.Print("Tune where the points sit with chestsnap_show on / chestsnap_grow / chestsnap_shift / chestsnap_point.");
		}

		public override List<string> CommandOptionList()
		{
			return (from n in CommandUtil.ContainerPrefabNames()
				where !ChestSnappingPlugin.Included.Contains(n)
				select n).ToList();
		}
	}
	internal class RemovePrefabCommand : ConsoleCommand
	{
		public override string Name => "chestsnap_remove";

		public override string Help => "Removes a prefab you added with chestsnap_add (or typed into ExtraPrefabs). Usage: chestsnap_remove <prefab_name>";

		public override void Run(string[] args)
		{
			if (args == null || args.Length < 1)
			{
				CommandUtil.Print("Usage: chestsnap_remove <prefab_name>");
				return;
			}
			string text = CommandUtil.ResolvePrefabName(args[0]);
			if (!ChestSnappingPlugin.ExtraSet.Contains(text))
			{
				if (ChestSnappingPlugin.Included.Contains(text))
				{
					CommandUtil.Print("'" + text + "' is a built-in chest. To turn it off, put it in ExcludedPrefabs in the config.");
				}
				else
				{
					CommandUtil.Print("'" + text + "' is not on the extra list.");
				}
				return;
			}
			List<string> list = new List<string>();
			string[] array = ChestSnappingPlugin.ExtraPrefabs.Value.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries);
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = array[i].Trim();
				if (text2.Length > 0 && !string.Equals(text2, text, StringComparison.OrdinalIgnoreCase))
				{
					list.Add(text2);
				}
			}
			ChestSnappingPlugin.ExtraPrefabs.Value = string.Join(", ", list);
			CommandUtil.Print("Removed '" + text + "'. Existing chests update right away.");
			if (SnapAdjustments.Get(text) != null)
			{
				CommandUtil.Print("Its saved adjustments are kept; clear them with: chestsnap_reset " + text);
			}
		}

		public override List<string> CommandOptionList()
		{
			return ChestSnappingPlugin.ExtraSet.OrderBy<string, string>((string n) => n, StringComparer.OrdinalIgnoreCase).ToList();
		}
	}
	internal abstract class BoxAdjustCommand : ConsoleCommand
	{
		protected abstract string What { get; }

		protected abstract string Explanation { get; }

		public override string Help => Explanation + " Usage: " + ((ConsoleCommand)this).Name + " <prefab_name> <x> <y> <z>   (meters; 0 0 0 clears it)";

		protected abstract void Set(PrefabAdjust adj, Vector3 value);

		public override void Run(string[] args)
		{
			//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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: 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_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			Vector3 v = Vector3.zero;
			if (args == null || args.Length < 4 || !CommandUtil.TryParseVector(args, 1, out v))
			{
				CommandUtil.Print("Usage: " + ((ConsoleCommand)this).Name + " <prefab_name> <x> <y> <z>   (meters in the chest's own axes: +X right, +Y up, +Z front)");
				CommandUtil.Print(Explanation);
				return;
			}
			string text = CommandUtil.ResolvePrefabName(args[0]);
			Vector3 value = v;
			SnapAdjustments.Edit(text, delegate(PrefabAdjust a)
			{
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				Set(a, value);
			});
			CommandUtil.Print(text + ": " + What + ((value == Vector3.zero) ? " cleared." : (" = " + CommandUtil.Fmt(value) + ".")));
			CommandUtil.NoteIfInactive(text);
		}

		public override List<string> CommandOptionList()
		{
			return CommandUtil.ContainerPrefabNames();
		}
	}
	internal class ShiftCommand : BoxAdjustCommand
	{
		public override string Name => "chestsnap_shift";

		protected override string What => "shift";

		protected override string Explanation => "Moves all snap points of a chest together (use when the chest's box is off-center).";

		protected override void Set(PrefabAdjust adj, Vector3 value)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			adj.Shift = value;
		}
	}
	internal class GrowCommand : BoxAdjustCommand
	{
		public override string Name => "chestsnap_grow";

		protected override string What => "grow";

		protected override string Explanation => "Adds to the snap box's half-size per axis: 0.05 = 10 cm bigger on that axis, negative shrinks it (use when the collider is oversized).";

		protected override void Set(PrefabAdjust adj, Vector3 value)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			adj.Grow = value;
		}
	}
	internal class PointCommand : ConsoleCommand
	{
		public override string Name => "chestsnap_point";

		public override string Help => "Offsets one snap point of a chest. <point> is 1-14 (the Q/E order) or a name like top_front_left. Usage: chestsnap_point <prefab_name> <point> <x> <y> <z>   (meters; 0 0 0 clears it)";

		public override void Run(string[] args)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			if (args == null || args.Length < 5)
			{
				CommandUtil.Print("Usage: chestsnap_point <prefab_name> <point> <x> <y> <z>");
				CommandUtil.Print("<point> is 1-14 (Q/E order) or a name such as top_front_left. See: chestsnap_info <prefab_name>");
				return;
			}
			if (!SnapLayout.TryFindPoint(args[1], out var index))
			{
				CommandUtil.Print("Unknown point '" + args[1] + "'. Use 1-14 or a name such as top_front_left (see chestsnap_info).");
				return;
			}
			if (!CommandUtil.TryParseVector(args, 2, out var v))
			{
				CommandUtil.Print("Could not read x y z as numbers.");
				return;
			}
			string text = CommandUtil.ResolvePrefabName(args[0]);
			int idx = index;
			Vector3 offset = v;
			SnapAdjustments.Edit(text, delegate(PrefabAdjust a)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: 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 (offset == Vector3.zero)
				{
					a.Points.Remove(idx);
				}
				else
				{
					a.Points[idx] = offset;
				}
			});
			string text2 = idx + 1 + " (" + SnapLayout.Points[idx].EnglishName + ")";
			CommandUtil.Print(text + ": point " + text2 + ((offset == Vector3.zero) ? " offset cleared." : (" offset = " + CommandUtil.Fmt(offset) + ".")));
			CommandUtil.NoteIfInactive(text);
		}

		public override List<string> CommandOptionList()
		{
			return CommandUtil.ContainerPrefabNames();
		}
	}
	internal class ResetCommand : ConsoleCommand
	{
		public override string Name => "chestsnap_reset";

		public override string Help => "Clears the saved adjustments of a chest, or only those of one point. Usage: chestsnap_reset <prefab_name> [point]";

		public override void Run(string[] args)
		{
			if (args == null || args.Length < 1)
			{
				CommandUtil.Print("Usage: chestsnap_reset <prefab_name> [point]");
				return;
			}
			string text = CommandUtil.ResolvePrefabName(args[0]);
			if (SnapAdjustments.Get(text) == null)
			{
				CommandUtil.Print("'" + text + "' has no saved adjustments.");
			}
			else if (args.Length >= 2)
			{
				if (!SnapLayout.TryFindPoint(args[1], out var index))
				{
					CommandUtil.Print("Unknown point '" + args[1] + "'. Use 1-14 or a name such as top_front_left.");
					return;
				}
				int idx = index;
				SnapAdjustments.Edit(text, delegate(PrefabAdjust a)
				{
					a.Points.Remove(idx);
				});
				CommandUtil.Print(text + ": offset of point " + (idx + 1) + " (" + SnapLayout.Points[idx].EnglishName + ") cleared.");
			}
			else
			{
				SnapAdjustments.Edit(text, delegate(PrefabAdjust a)
				{
					//IL_0001: Unknown result type (might be due to invalid IL or missing references)
					//IL_0006: Unknown result type (might be due to invalid IL or missing references)
					//IL_000c: Unknown result type (might be due to invalid IL or missing references)
					//IL_0011: Unknown result type (might be due to invalid IL or missing references)
					a.Shift = Vector3.zero;
					a.Grow = Vector3.zero;
					a.Points.Clear();
				});
				CommandUtil.Print(text + ": all adjustments cleared.");
			}
		}

		public override List<string> CommandOptionList()
		{
			return CommandUtil.ContainerPrefabNames();
		}
	}
	internal class InfoCommand : ConsoleCommand
	{
		public override string Name => "chestsnap_info";

		public override string Help => "Shows a chest's measured snap box, its adjustments and the final position of each snap point. Usage: chestsnap_info <prefab_name>";

		public override void Run(string[] args)
		{
			//IL_00af: 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_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: 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_0193: Unknown result type (might be due to invalid IL or missing references)
			if (args == null || args.Length < 1)
			{
				CommandUtil.Print("Usage: chestsnap_info <prefab_name>");
				return;
			}
			if ((Object)(object)ZNetScene.instance == (Object)null)
			{
				CommandUtil.Print("Load into a world first (prefabs are not available in the main menu).");
				return;
			}
			string text = CommandUtil.ResolvePrefabName(args[0]);
			GameObject prefab = ZNetScene.instance.GetPrefab(text);
			if ((Object)(object)prefab == (Object)null)
			{
				CommandUtil.Print("No prefab named '" + text + "' is loaded. Try chestsnap_list.");
				return;
			}
			string name = ((Object)prefab).name;
			CommandUtil.Print(name + "  -  snap points: " + (ChestSnapPoints.Source(prefab) ?? "none (not on the list)"));
			if (!ChestSnapPoints.TryGetLocalBounds(prefab.transform, out var bounds))
			{
				CommandUtil.Print("  No colliders or meshes found, so no snap points can be placed.");
				return;
			}
			PrefabAdjust prefabAdjust = ChestSnapPoints_Adjust(name);
			CommandUtil.Print("  Measured box: center " + CommandUtil.Fmt(((Bounds)(ref bounds)).center) + "  size " + CommandUtil.Fmt(((Bounds)(ref bounds)).size));
			CommandUtil.Print("  shift " + CommandUtil.Fmt(prefabAdjust.Shift) + "   grow " + CommandUtil.Fmt(prefabAdjust.Grow));
			CommandUtil.Print("  Local positions (after adjustments):");
			Vector3[] array = ChestSnapPoints.ComputePositions(bounds, SnapAdjustments.Get(name));
			for (int i = 0; i < array.Length; i++)
			{
				string text2 = "  " + (i + 1) + "  " + SnapLayout.Points[i].EnglishName + "  " + CommandUtil.Fmt(array[i]);
				if (prefabAdjust.Points.TryGetValue(i, out var value))
				{
					text2 = text2 + "   [point offset " + CommandUtil.Fmt(value) + "]";
				}
				CommandUtil.Print(text2);
			}
		}

		private static PrefabAdjust ChestSnapPoints_Adjust(string name)
		{
			return SnapAdjustments.Get(name) ?? new PrefabAdjust();
		}

		public override List<string> CommandOptionList()
		{
			return CommandUtil.ContainerPrefabNames();
		}
	}
	internal class ShowCommand : ConsoleCommand
	{
		public override string Name => "chestsnap_show";

		public override string Help => "Shows/hides small spheres on all chest snap points (yellow = corners, cyan = face centers). Usage: chestsnap_show [on|off]";

		public override void Run(string[] args)
		{
			bool flag = !SnapMarkers.Enabled;
			if (args != null && args.Length != 0)
			{
				switch (args[0].Trim().ToLowerInvariant())
				{
				case "on":
				case "1":
				case "true":
					flag = true;
					break;
				case "off":
				case "0":
				case "false":
					flag = false;
					break;
				default:
					CommandUtil.Print("Usage: chestsnap_show [on|off]");
					return;
				}
			}
			SnapMarkers.SetEnabled(flag);
			CommandUtil.Print("Snap point markers " + (flag ? "on" : "off") + ".");
		}

		public override List<string> CommandOptionList()
		{
			return new List<string> { "on", "off" };
		}
	}
	internal sealed class PrefabAdjust
	{
		public Vector3 Shift;

		public Vector3 Grow;

		public readonly Dictionary<int, Vector3> Points = new Dictionary<int, Vector3>();

		public bool IsEmpty
		{
			get
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_0013: Unknown result type (might be due to invalid IL or missing references)
				//IL_0018: Unknown result type (might be due to invalid IL or missing references)
				if (Shift == Vector3.zero && Grow == Vector3.zero)
				{
					return Points.Count == 0;
				}
				return false;
			}
		}
	}
	internal static class SnapAdjustments
	{
		private static Dictionary<string, PrefabAdjust> _map = new Dictionary<string, PrefabAdjust>(StringComparer.OrdinalIgnoreCase);

		internal static PrefabAdjust Get(string prefab)
		{
			if (!_map.TryGetValue(prefab, out var value))
			{
				return null;
			}
			return value;
		}

		internal static void Edit(string prefab, Action<PrefabAdjust> change)
		{
			PrefabAdjust prefabAdjust = Get(prefab) ?? new PrefabAdjust();
			change(prefabAdjust);
			if (prefabAdjust.IsEmpty)
			{
				_map.Remove(prefab);
			}
			else
			{
				_map[prefab] = prefabAdjust;
			}
			Save();
		}

		private static void Save()
		{
			ChestSnappingPlugin.Adjustments.Value = Serialize(_map);
		}

		internal static void Load(string text)
		{
			Dictionary<string, PrefabAdjust> dictionary = new Dictionary<string, PrefabAdjust>(StringComparer.OrdinalIgnoreCase);
			if (!string.IsNullOrWhiteSpace(text))
			{
				string[] array = text.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
				foreach (string text2 in array)
				{
					if (string.IsNullOrWhiteSpace(text2))
					{
						continue;
					}
					int num = text2.IndexOf(':');
					string text3 = ((num > 0) ? text2.Substring(0, num).Trim() : "");
					if (text3.Length == 0)
					{
						ChestSnappingPlugin.Log.LogWarning((object)("PrefabAdjustments: ignoring '" + text2.Trim() + "' (expected 'prefab: shift=x,y,z ...')."));
						continue;
					}
					PrefabAdjust prefabAdjust = new PrefabAdjust();
					string[] array2 = text2.Substring(num + 1).Split(new char[2] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
					foreach (string token in array2)
					{
						ParseToken(text3, token, prefabAdjust);
					}
					if (!prefabAdjust.IsEmpty)
					{
						dictionary[text3] = prefabAdjust;
					}
				}
			}
			_map = dictionary;
		}

		private static void ParseToken(string prefab, string token, PrefabAdjust adj)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: 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)
			int num = token.IndexOf('=');
			if (num <= 0 || !TryParseVector(token.Substring(num + 1), out var v))
			{
				ChestSnappingPlugin.Log.LogWarning((object)("PrefabAdjustments: ignoring '" + token + "' for " + prefab + " (expected key=x,y,z)."));
				return;
			}
			string text = token.Substring(0, num).Trim().ToLowerInvariant();
			if (text == "shift")
			{
				adj.Shift = v;
				return;
			}
			if (text == "grow")
			{
				adj.Grow = v;
				return;
			}
			if (SnapLayout.TryFindPoint(text, out var index))
			{
				adj.Points[index] = v;
				return;
			}
			ChestSnappingPlugin.Log.LogWarning((object)("PrefabAdjustments: unknown key '" + text + "' for " + prefab + " (use shift, grow, or p1..p" + SnapLayout.Points.Length + ")."));
		}

		private static bool TryParseVector(string csv, out Vector3 v)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: 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_004c: Unknown result type (might be due to invalid IL or missing references)
			v = Vector3.zero;
			string[] array = csv.Split(',');
			if (array.Length != 3)
			{
				return false;
			}
			if (!TryParseFloat(array[0], out var value) || !TryParseFloat(array[1], out var value2) || !TryParseFloat(array[2], out var value3))
			{
				return false;
			}
			v = new Vector3(value, value2, value3);
			return true;
		}

		private static bool TryParseFloat(string s, out float value)
		{
			return float.TryParse(s.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out value);
		}

		private static string Serialize(Dictionary<string, PrefabAdjust> map)
		{
			//IL_0047: 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_0076: 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_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			List<string> list = new List<string>(map.Keys);
			list.Sort(StringComparer.OrdinalIgnoreCase);
			List<string> list2 = new List<string>();
			foreach (string item in list)
			{
				PrefabAdjust prefabAdjust = map[item];
				StringBuilder stringBuilder = new StringBuilder(item).Append(':');
				if (prefabAdjust.Shift != Vector3.zero)
				{
					stringBuilder.Append(" shift=").Append(Csv(prefabAdjust.Shift));
				}
				if (prefabAdjust.Grow != Vector3.zero)
				{
					stringBuilder.Append(" grow=").Append(Csv(prefabAdjust.Grow));
				}
				List<int> list3 = new List<int>(prefabAdjust.Points.Keys);
				list3.Sort();
				foreach (int item2 in list3)
				{
					stringBuilder.Append(" p").Append(item2 + 1).Append('=')
						.Append(Csv(prefabAdjust.Points[item2]));
				}
				list2.Add(stringBuilder.ToString());
			}
			return string.Join("; ", list2.ToArray());
		}

		private static string Csv(Vector3 v)
		{
			//IL_0008: 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_0034: Unknown result type (might be due to invalid IL or missing references)
			return Num(v.x) + "," + Num(v.y) + "," + Num(v.z);
		}

		internal static string Num(float f)
		{
			if (f == 0f)
			{
				f = 0f;
			}
			return f.ToString("0.####", CultureInfo.InvariantCulture);
		}
	}
	internal static class SnapMarkers
	{
		internal const string MarkerName = "chestsnap_marker";

		private const float MarkerSize = 0.1f;

		private static Mesh _sphere;

		private static Material _cornerMaterial;

		private static Material _faceMaterial;

		internal static bool Enabled { get; private set; }

		internal static void SetEnabled(bool on)
		{
			Enabled = on;
			Piece[] array = Object.FindObjectsByType<Piece>((FindObjectsSortMode)0);
			foreach (Piece val in array)
			{
				if (ChestSnapPoints.HasPoints(((Component)val).transform))
				{
					Sync(((Component)val).transform);
				}
			}
		}

		internal static void Sync(Transform chest)
		{
			for (int i = 0; i < chest.childCount; i++)
			{
				Transform child = chest.GetChild(i);
				int num = ChestSnapPoints.PointIndex(child);
				if (num >= 0)
				{
					Transform val = child.Find("chestsnap_marker");
					if (Enabled && (Object)(object)val == (Object)null)
					{
						CreateMarker(child, num < 8);
					}
					else if (!Enabled && (Object)(object)val != (Object)null)
					{
						Object.Destroy((Object)(object)((Component)val).gameObject);
					}
				}
			}
		}

		private static void CreateMarker(Transform point, bool isCorner)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: 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_0029: 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: Unknown result type (might be due to invalid IL or missing references)
			EnsureAssets();
			GameObject val = new GameObject("chestsnap_marker");
			Transform transform = val.transform;
			transform.SetParent(point, false);
			transform.localPosition = Vector3.zero;
			transform.localRotation = Quaternion.identity;
			transform.localScale = Vector3.one * 0.1f;
			val.AddComponent<MeshFilter>().sharedMesh = _sphere;
			MeshRenderer obj = val.AddComponent<MeshRenderer>();
			((Renderer)obj).sharedMaterial = (isCorner ? _cornerMaterial : _faceMaterial);
			((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0;
			((Renderer)obj).receiveShadows = false;
		}

		private static void EnsureAssets()
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_sphere != (Object)null))
			{
				GameObject obj = GameObject.CreatePrimitive((PrimitiveType)0);
				_sphere = obj.GetComponent<MeshFilter>().sharedMesh;
				Material sharedMaterial = ((Renderer)obj.GetComponent<MeshRenderer>()).sharedMaterial;
				Object.DestroyImmediate((Object)(object)obj);
				_cornerMaterial = MakeMaterial(new Color(1f, 0.85f, 0.1f, 1f), sharedMaterial);
				_faceMaterial = MakeMaterial(new Color(0.2f, 0.9f, 1f, 1f), sharedMaterial);
			}
		}

		private static Material MakeMaterial(Color color, Material fallback)
		{
			//IL_0031: 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_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			Shader val = Shader.Find("Sprites/Default");
			if ((Object)(object)val == (Object)null)
			{
				val = Shader.Find("Unlit/Color");
			}
			Material val2 = (((Object)(object)val != (Object)null) ? new Material(val) : new Material(fallback));
			val2.color = color;
			return val2;
		}
	}
}