Decompiled source of ShipSort v3.3.0

baer1.ShipSort.dll

Decompiled 4 days ago
using System;
using System.Collections;
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.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ChatCommandAPI;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("baer1.ShipSort")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("3.3.0.0")]
[assembly: AssemblyInformationalVersion("3.3.0+df2dccaf709be357173d89d9c41950bdd64ff6b6")]
[assembly: AssemblyProduct("LethalShipSort")]
[assembly: AssemblyTitle("baer1.ShipSort")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("3.3.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 LethalShipSort
{
	public class AutoSortToggle : ToggleCommand
	{
		public override string Name => "AutoSort";

		public override string ToggleDescription => "Toggles automatic item sorting when leaving a planet";

		public override bool Value
		{
			get
			{
				return LethalShipSort.Instance.AutoSort;
			}
			set
			{
				LethalShipSort.Instance.AutoSort = value;
			}
		}
	}
	public struct ItemPosition
	{
		public struct Flags
		{
			public const char NO_AUTO_SORT = 'A';

			public bool NoAutoSort;

			public const char KEEP_ON_CRUISER = 'C';

			public bool KeepOnCruiser;

			public const char IGNORE = 'N';

			public bool Ignore;

			public const char PARENT = 'P';

			public bool Parent;

			public const char EXACT = 'X';

			public bool Exact;

			public Flags(string s)
			{
				NoAutoSort = false;
				KeepOnCruiser = false;
				Ignore = false;
				Parent = false;
				Exact = false;
				foreach (char c in s)
				{
					switch (c)
					{
					case 'A':
						NoAutoSort = true;
						break;
					case 'C':
						KeepOnCruiser = true;
						break;
					case 'N':
						Ignore = true;
						break;
					case 'P':
						Parent = true;
						break;
					case 'X':
						Exact = true;
						break;
					default:
						throw new ArgumentException($"Unknown flag ({c})");
					}
				}
			}

			public override string ToString()
			{
				return $"{(NoAutoSort ? ((object)'A') : string.Empty)}{(KeepOnCruiser ? ((object)'C') : string.Empty)}{(Ignore ? ((object)'N') : string.Empty)}{(Parent ? ((object)'P') : string.Empty)}{(Exact ? ((object)'X') : string.Empty)}";
			}

			public Flags FilterPositionRelated()
			{
				return this & new Flags
				{
					Parent = true,
					Exact = true
				};
			}

			public Flags FilterFilteringRelated()
			{
				return this & new Flags
				{
					NoAutoSort = true,
					KeepOnCruiser = true,
					Ignore = true
				};
			}

			public static Flags operator |(Flags _this, Flags other)
			{
				Flags result = default(Flags);
				result.NoAutoSort = _this.NoAutoSort || other.NoAutoSort;
				result.KeepOnCruiser = _this.KeepOnCruiser || other.KeepOnCruiser;
				result.Ignore = _this.Ignore || other.Ignore;
				result.Parent = _this.Parent || other.Parent;
				result.Exact = _this.Exact || other.Exact;
				return result;
			}

			public static Flags operator &(Flags _this, Flags other)
			{
				Flags result = default(Flags);
				result.NoAutoSort = _this.NoAutoSort && other.NoAutoSort;
				result.KeepOnCruiser = _this.KeepOnCruiser && other.KeepOnCruiser;
				result.Ignore = _this.Ignore && other.Ignore;
				result.Parent = _this.Parent && other.Parent;
				result.Exact = _this.Exact && other.Exact;
				return result;
			}
		}

		public Vector3? position;

		public GameObject? parentTo;

		public int? floorYRot;

		public Flags flags;

		public ItemPosition(string s)
		{
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			position = null;
			parentTo = null;
			floorYRot = null;
			Match match = new Regex("(?:([\\w/\\\\]+):)?(?:([\\d-.]+),){2}([\\d-.]+)(?:,([\\d-.]+))?(?::([A-Z]+))?$", RegexOptions.Multiline).Match(s);
			if (!match.Success)
			{
				Match match2 = new Regex("([A-Z]+)$", RegexOptions.Multiline).Match(s);
				if (!match2.Success)
				{
					throw new ArgumentException("Invalid format (" + s + ")");
				}
				StringBuilder stringBuilder = new StringBuilder(">> ItemPosition init flags \"" + s + "\"");
				flags = new Flags(match2.Groups[1].Value);
				LethalShipSort.Logger.LogDebug((object)stringBuilder.ToString());
				return;
			}
			StringBuilder stringBuilder2 = new StringBuilder(">> ItemPosition init \"" + s + "\"");
			string value = match.Groups[2].Captures[0].Value;
			string value2 = match.Groups[2].Captures[1].Value;
			string value3 = match.Groups[3].Value;
			if (!float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || !float.TryParse(value2, NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) || !float.TryParse(value3, NumberStyles.Float, CultureInfo.InvariantCulture, out var result3))
			{
				throw new ArgumentException("Invalid float (" + s + ") [\"" + value + "\", \"" + value2 + "\", \"" + value3 + "\"]");
			}
			position = new Vector3(result, result2, result3);
			stringBuilder2.Append($"\n   position is {position}");
			string value4 = match.Groups[4].Value;
			if (match.Groups[4].Success)
			{
				if (!int.TryParse(value4, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result4))
				{
					throw new ArgumentException("Invalid integer (" + s + ") \"" + value4 + "\"");
				}
				floorYRot = result4;
				stringBuilder2.Append($"\n   rotation is {floorYRot}");
			}
			else
			{
				stringBuilder2.Append("\n   rotation not specified");
			}
			flags = new Flags(match.Groups[5].Value);
			stringBuilder2.Append($"\n   flags are {flags}");
			if (match.Groups[1].Success)
			{
				switch (match.Groups[1].Value.ToLower().Trim('/', '\\'))
				{
				case "cupboard":
				case "closet":
				case "storage":
				case "storagecloset":
					stringBuilder2.Append("\n   parent object is closet");
					parentTo = GameObject.Find("Environment/HangarShip/StorageCloset");
					if ((Object)(object)parentTo == (Object)null)
					{
						throw new Exception("Storage closet not found");
					}
					break;
				case "file":
				case "filecabinet":
				case "filecabinets":
					stringBuilder2.Append("\n   parent object is file cabinet");
					parentTo = GameObject.Find("Environment/HangarShip/FileCabinet");
					if ((Object)(object)parentTo == (Object)null)
					{
						throw new Exception("File cabinet not found");
					}
					break;
				case "bunkbed":
				case "bunkbeds":
					stringBuilder2.Append("\n   parent object is bunkbeds");
					parentTo = GameObject.Find("Environment/HangarShip/Bunkbeds");
					if ((Object)(object)parentTo == (Object)null)
					{
						throw new Exception("Bunkbeds not found");
					}
					break;
				case "ship":
					stringBuilder2.Append("\n   parent object is ship");
					parentTo = null;
					break;
				case "environment":
				case "none":
					stringBuilder2.Append("\n   parent object is none (environment)");
					parentTo = GameObject.Find("Environment");
					if ((Object)(object)parentTo == (Object)null)
					{
						throw new Exception("Environment not found, what the actual fuck");
					}
					break;
				default:
					stringBuilder2.Append("\n   parent object is custom (" + match.Groups[1].Value + ") ");
					parentTo = GameObject.Find(match.Groups[1].Value);
					if ((Object)(object)parentTo == (Object)null)
					{
						throw new ArgumentException("Invalid parent object");
					}
					stringBuilder2.Append(((object)parentTo).ToString());
					break;
				}
			}
			else
			{
				stringBuilder2.Append("\n   parent object not specified");
			}
			LethalShipSort.Logger.LogDebug((object)stringBuilder2.ToString());
		}

		public override string ToString()
		{
			//IL_009a: 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_00c4: Unknown result type (might be due to invalid IL or missing references)
			string text = "";
			if ((Object)(object)parentTo != (Object)null)
			{
				text = ((Object)parentTo).name;
				Transform parent = parentTo.transform.parent;
				while ((Object)(object)parent != (Object)null)
				{
					text = ((Object)parent).name + "/" + text;
					parent = parent.parent;
				}
				text += ":";
			}
			string[] obj = new string[5]
			{
				text,
				position.HasValue ? string.Format(CultureInfo.InvariantCulture, "{0},{1},{2}", position.Value.x, position.Value.y, position.Value.z) : string.Empty,
				(!floorYRot.HasValue) ? string.Empty : string.Format(CultureInfo.InvariantCulture, ",{0}", floorYRot),
				((this.flags.ToString().Length > 0) ? ((object)':') : string.Empty)?.ToString(),
				null
			};
			Flags flags = this.flags;
			obj[4] = flags.ToString();
			return string.Concat(obj);
		}
	}
	[BepInPlugin("baer1.ShipSort", "LethalShipSort", "3.3.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class LethalShipSort : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(NetworkManager), "StartClient")]
		[HarmonyPatch(typeof(NetworkManager), "StartServer")]
		[HarmonyPatch(typeof(NetworkManager), "StartHost")]
		internal class RoundOverrideResetPatch
		{
			private static void Postfix()
			{
				int count = Instance.roundOverrides.Count;
				Instance.roundOverrides.Clear();
				Logger.LogDebug((object)$"roundOverrides cleared (was {count} items)");
			}
		}

		[HarmonyPatch(typeof(HUDManager), "Start")]
		internal class HUDManager_Start
		{
			private static void Postfix()
			{
				if (Instance.ConfigVersion < Instance.CurrentConfigVersion)
				{
					ChatCommandAPI.PrintWarning("[LethalShipSort] Your configuration file is outdated.\nPlease verify your configuration file and update it accordingly.\n" + $"<indent=10px>Expected: v{Instance.CurrentConfigVersion}\n" + $"Config: v{Instance.ConfigVersion}</indent>");
					Logger.LogWarning((object)$"Config file outdated: Expected v{Instance.CurrentConfigVersion}, got v{Instance.ConfigVersion}");
				}
				else if (Instance.ConfigVersion > Instance.CurrentConfigVersion)
				{
					ChatCommandAPI.PrintWarning("[LethalShipSort] Your configuration file is using a newer, unsupported format.\nThere have been changes to the configuration file format which could cause errors.\nPlease verify your configuration file and mod version.\n" + $"<indent=10px>Expected: v{Instance.CurrentConfigVersion}\n" + $"Config: v{Instance.ConfigVersion}</indent>");
					Logger.LogWarning((object)$"Config file unsupported: Expected v{Instance.CurrentConfigVersion}, got v{Instance.ConfigVersion}");
				}
			}
		}

		private ConfigEntry<int> configVersion = null;

		private ConfigEntry<bool> autoSort = null;

		private ConfigEntry<uint> sortDelay = null;

		private ConfigEntry<string> defaultOneHand = null;

		private ConfigEntry<string> defaultTwoHand = null;

		private ConfigEntry<string> defaultTool = null;

		private ConfigEntry<string> customItemPositions = null;

		internal Dictionary<string, ConfigEntry<string>> itemPositions = new Dictionary<string, ConfigEntry<string>>();

		internal Dictionary<string, string> vanillaItems = new Dictionary<string, string>();

		internal Dictionary<string, (Vector3, GameObject?)> roundOverrides = new Dictionary<string, (Vector3, GameObject)>();

		private const float CUPBOARD_ABOVE = 3.2f;

		private const float CUPBOARD_TOP = 2.4f;

		private const float CUPBOARD_MIDDLE_1 = 2f;

		private const float CUPBOARD_MIDDLE_2 = 1.5f;

		private const float CUPBOARD_BOTTOM = 0.5f;

		public static LethalShipSort Instance { get; private set; }

		internal static ManualLogSource Logger { get; private set; }

		internal static Harmony? Harmony { get; set; }

		public int ConfigVersion => configVersion.Value;

		public int CurrentConfigVersion => (int)((ConfigEntryBase)configVersion).DefaultValue;

		public bool AutoSort
		{
			get
			{
				return autoSort.Value;
			}
			set
			{
				autoSort.Value = value;
			}
		}

		public uint SortDelay
		{
			get
			{
				return sortDelay.Value;
			}
			set
			{
				sortDelay.Value = value;
			}
		}

		public ItemPosition DefaultOneHand
		{
			get
			{
				try
				{
					return new ItemPosition(defaultOneHand.Value);
				}
				catch (ArgumentException)
				{
					Logger.LogError((object)("Invalid DefaultOneHand position (" + defaultOneHand.Value + "), using fallback"));
					return new ItemPosition((string)((ConfigEntryBase)defaultOneHand).DefaultValue);
				}
			}
			set
			{
				defaultOneHand.Value = value.ToString();
			}
		}

		public ItemPosition DefaultTwoHand
		{
			get
			{
				try
				{
					return new ItemPosition(defaultTwoHand.Value);
				}
				catch (ArgumentException)
				{
					Logger.LogError((object)("Invalid DefaultTwoHand position (" + defaultTwoHand.Value + "), using fallback"));
					return new ItemPosition((string)((ConfigEntryBase)defaultTwoHand).DefaultValue);
				}
			}
			set
			{
				defaultTwoHand.Value = value.ToString();
			}
		}

		public ItemPosition DefaultTool
		{
			get
			{
				try
				{
					return new ItemPosition(defaultTool.Value);
				}
				catch (ArgumentException)
				{
					Logger.LogError((object)("Invalid DefaultTool position (" + defaultTool.Value + "), using fallback"));
					return new ItemPosition((string)((ConfigEntryBase)defaultTool).DefaultValue);
				}
			}
			set
			{
				defaultTool.Value = value.ToString();
			}
		}

		public Dictionary<string, ItemPosition> CustomItemPositions
		{
			get
			{
				Dictionary<string, ItemPosition> dictionary = new Dictionary<string, ItemPosition>();
				string[] array = customItemPositions.Value.Split(';');
				foreach (string text in array)
				{
					string[] array2 = text.Split(":", 2);
					if (array2.Length != 2)
					{
						Logger.LogDebug((object)"split.Length != 2");
						goto IL_00c2;
					}
					if (dictionary.ContainsKey(array2[0]))
					{
						Logger.LogWarning((object)("Multiple CustomItemPositions for item " + array2[0]));
					}
					try
					{
						dictionary[array2[0]] = new ItemPosition(array2[1]);
					}
					catch (ArgumentException arg)
					{
						Logger.LogDebug((object)$"{array2[0]} {array2[1]} {arg}");
						goto IL_00c2;
					}
					continue;
					IL_00c2:
					Logger.LogError((object)("Invalid CustomItemPosition (" + text + ")"));
				}
				return dictionary;
			}
		}

		public Dictionary<string, ItemPosition?> VanillaItemPositions
		{
			get
			{
				Dictionary<string, ItemPosition?> dictionary = new Dictionary<string, ItemPosition?>();
				foreach (KeyValuePair<string, ConfigEntry<string>> itemPosition in itemPositions)
				{
					try
					{
						dictionary[itemPosition.Key] = ((itemPosition.Value.Value == "") ? null : new ItemPosition?(new ItemPosition(itemPosition.Value.Value)));
					}
					catch (ArgumentException)
					{
						Logger.LogError((object)("Invalid item position for " + itemPosition.Key + " (" + itemPosition.Value.Value + "), using fallback"));
						dictionary[itemPosition.Key] = (((string)((ConfigEntryBase)itemPosition.Value).DefaultValue == "") ? null : new ItemPosition?(new ItemPosition((string)((ConfigEntryBase)itemPosition.Value).DefaultValue)));
					}
				}
				return dictionary;
			}
		}

		public ItemPosition GetPosition(GrabbableObject item)
		{
			//IL_0083: 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)
			string text = Utils.RemoveClone(((Object)item).name);
			ItemPosition? itemPosition = null;
			Logger.LogDebug((object)$">> GetPosition({item}) itemName:{text} isScrap:{item.itemProperties.isScrap} twoHanded:{item.itemProperties.twoHanded}");
			ConfigEntry<string> value2;
			ItemPosition value3;
			if (roundOverrides.TryGetValue(text.ToLower(), out (Vector3, GameObject) value))
			{
				itemPosition = new ItemPosition
				{
					position = value.Item1,
					parentTo = value.Item2
				};
				Logger.LogDebug((object)$"<< GetPosition (roundOverrides) {itemPosition} ({value.Item1}, {value.Item2})");
			}
			else if (itemPositions.TryGetValue(text, out value2))
			{
				try
				{
					if (!Utility.IsNullOrWhiteSpace(value2.Value))
					{
						itemPosition = new ItemPosition(value2.Value);
						Logger.LogDebug((object)$"<< GetPosition (itemPositions) {itemPosition} ({value2.Value})");
					}
				}
				catch (ArgumentException)
				{
					Logger.LogError((object)("Invalid item position for " + text + " (" + value2.Value + "), using fallback"));
					if (!Utility.IsNullOrWhiteSpace((string)((ConfigEntryBase)value2).DefaultValue))
					{
						itemPosition = new ItemPosition((string)((ConfigEntryBase)value2).DefaultValue);
						Logger.LogDebug((object)$"<< GetPosition (itemPositions - DefaultValue) {itemPosition} ({((ConfigEntryBase)value2).DefaultValue})");
					}
				}
			}
			else if (CustomItemPositions.TryGetValue(text, out value3))
			{
				itemPosition = value3;
				Logger.LogDebug((object)$"<< GetPosition (CustomItemPositions) {itemPosition}");
			}
			if (!itemPosition.HasValue)
			{
				itemPosition = ((!item.itemProperties.isScrap) ? DefaultTool : (item.itemProperties.twoHanded ? DefaultTwoHand : DefaultOneHand));
				Logger.LogDebug((object)string.Format("<< GetPosition ({0}) {1}", (!item.itemProperties.isScrap) ? "DefaultTool" : (item.itemProperties.twoHanded ? "DefaultTwoHand" : "DefaultOneHand"), itemPosition));
			}
			else if (!itemPosition.Value.position.HasValue)
			{
				ItemPosition itemPosition2 = ((!item.itemProperties.isScrap) ? DefaultTool : (item.itemProperties.twoHanded ? DefaultTwoHand : DefaultOneHand));
				itemPosition = new ItemPosition
				{
					flags = (itemPosition.Value.flags.FilterFilteringRelated() | itemPosition2.flags.FilterPositionRelated()),
					position = itemPosition2.position,
					parentTo = itemPosition2.parentTo
				};
				Logger.LogDebug((object)string.Format("<< GetPosition ({0} with flags) {1}", (!item.itemProperties.isScrap) ? "DefaultTool" : (item.itemProperties.twoHanded ? "DefaultTwoHand" : "DefaultOneHand"), itemPosition));
			}
			return itemPosition.Value;
		}

		private void Awake()
		{
			Logger = ((BaseUnityPlugin)this).Logger;
			Instance = this;
			configVersion = ((BaseUnityPlugin)this).Config.Bind<int>("General", "ConfigVersion", 2, "The version of this config file");
			autoSort = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AutoSort", false, "Whether to automatically sort the ship when leaving a planet (toggle ingame with /autosort)");
			sortDelay = ((BaseUnityPlugin)this).Config.Bind<uint>("General", "SortDelay", 0u, "The amount of milliseconds to wait between moving items, mostly for the satisfying visual effect.\nYou can't pick anything up while sorting items.");
			BindItemPositionConfigs();
			Patch();
			new SortItemsCommand();
			new AutoSortToggle();
			new SetItemPositionCommand();
			new PrintItemNames();
			Logger.LogInfo((object)"baer1.ShipSort v3.3.0 has loaded!");
			static void Patch()
			{
				//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_0018: Expected O, but got Unknown
				if (Harmony == null)
				{
					Harmony = new Harmony("baer1.ShipSort");
				}
				Logger.LogDebug((object)"Patching...");
				Harmony.PatchAll();
				Logger.LogDebug((object)"Finished patching!");
			}
		}

		private void BindItemPositionConfigs()
		{
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_041b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0686: Unknown result type (might be due to invalid IL or missing references)
			//IL_06c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0842: Unknown result type (might be due to invalid IL or missing references)
			//IL_089e: Unknown result type (might be due to invalid IL or missing references)
			//IL_08df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0920: Unknown result type (might be due to invalid IL or missing references)
			//IL_0961: Unknown result type (might be due to invalid IL or missing references)
			//IL_09a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_09e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a24: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a60: Unknown result type (might be due to invalid IL or missing references)
			//IL_0aa1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ae2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b23: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b9a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bdb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c1c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c58: Unknown result type (might be due to invalid IL or missing references)
			//IL_0c99: Unknown result type (might be due to invalid IL or missing references)
			defaultOneHand = ((BaseUnityPlugin)this).Config.Bind<string>("Items", "DefaultOneHand", "-2.25,3,-5.25", "Default position for one-handed items.");
			defaultTwoHand = ((BaseUnityPlugin)this).Config.Bind<string>("Items", "DefaultTwoHand", "-4.5,3,-5.25", "Default position for two-handed items.");
			defaultTool = ((BaseUnityPlugin)this).Config.Bind<string>("Items", "DefaultTool", $"cupboard:-2,0.6,{0.5f},0:{'C'}{'P'}", "Default position for tool items.");
			ItemPositionConfig("Airhorn");
			ItemPositionConfig("LungApparatus", "Apparatice", new Vector3(-6.8f, 4.4f, -6.65f));
			itemPositions["LungApparatusTurnedOff"] = itemPositions["LungApparatus"];
			ItemPositionConfig("HandBell", "Brass bell");
			ItemPositionConfig("BigBolt", "Big bolt");
			ItemPositionConfig("Bone");
			ItemPositionConfig("BinFullOfBottles", "Bottles");
			ItemPositionConfig("Hairbrush", "Hair brush");
			ItemPositionConfig("Candy");
			ItemPositionConfig("CashRegisterItem", "Cash register");
			ItemPositionConfig("ChemicalJug", "Chemical jug");
			ItemPositionConfig("Clock");
			ItemPositionConfig("Clownhorn", "Clown horn");
			ItemPositionConfig("ComedyMask", "Comedy");
			ItemPositionConfig("ControlPad", "Control pad");
			ItemPositionConfig("CookieMoldPan", "Cookie mold pan");
			ItemPositionConfig("Dustpan", "Dust pan");
			ItemPositionConfig("Ear");
			ItemPositionConfig("EasterEgg", "Easter egg");
			ItemPositionConfig("KiwiBabyItem", "Egg", new Vector3(4.85f, 2f, -4f));
			ItemPositionConfig("EggBeater", "Egg beater");
			ItemPositionConfig("FancyLamp", "Fancy lamp");
			ItemPositionConfig("Flask");
			ItemPositionConfig("SeveredFootLOD0", "Foot");
			ItemPositionConfig("GarbageLid", "Garbage lid");
			ItemPositionConfig("GiftBox", "Gift box");
			ItemPositionConfig("GoldBar", "Gold Bar");
			ItemPositionConfig("FancyGlass", "Golden cup");
			ItemPositionConfig("SeveredHandLOD0", "Hand");
			ItemPositionConfig("HeartContainer", "Heart");
			ItemPositionConfig("Hairdryer");
			ItemPositionConfig("RedLocustHive", "Bee hive", new Vector3(-6.8f, 4.4f, -5.65f));
			ItemPositionConfig("DiyFlashbang", "Homemade Flashbang");
			ItemPositionConfig("PickleJar", "Jar of pickles");
			ItemPositionConfig("KnifeItem", "Kitchen knife", isTool: false, (bool?)true);
			ItemPositionConfig("SeveredThighLOD0", "Knee");
			ItemPositionConfig("Cog", "Large axle");
			ItemPositionConfig("LaserPointer", "Laser pointer");
			ItemPositionConfig("Magic7Ball", "Magic 7 ball");
			ItemPositionConfig("MagnifyingGlass", "Magnifying glass");
			ItemPositionConfig("MetalSheet", "Tattered metal sheet");
			ItemPositionConfig("Mug", "Coffee mug");
			ItemPositionConfig("OldPhone", "Old phone");
			ItemPositionConfig("Painting");
			ItemPositionConfig("PerfumeBottle", "Perfume bottle");
			ItemPositionConfig("PillBottle", "Pill bottle");
			ItemPositionConfig("PlasticCup", "Plastic cup");
			ItemPositionConfig("FishTestProp", "Plastic fish");
			ItemPositionConfig("RedSodaCan", "Red soda");
			ItemPositionConfig("Remote");
			ItemPositionConfig("RibcageBone", "Ribcage");
			ItemPositionConfig("FancyRing", "Wedding ring");
			ItemPositionConfig("RubberDucky", "Rubber ducky");
			Vector3 defaultPosition = new Vector3(8.75f, 2f, -5.5f);
			bool? defaultKeepOnCruiser = true;
			int? defaultFloorYRot = 0;
			ItemPositionConfig("ShotgunItem", "Double-barrel", defaultPosition, isTool: false, null, defaultKeepOnCruiser, defaultFloorYRot);
			ItemPositionConfig("SoccerBall", "Soccer ball", new Vector3(-6.8f, 4.4f, -7.75f));
			ItemPositionConfig("SteeringWheel", "Steering wheel");
			ItemPositionConfig("StopSign", "Stop sign");
			ItemPositionConfig("TeaKettle", "Tea Kettle");
			ItemPositionConfig("Dentures", "Teeth");
			ItemPositionConfig("ToiletPaperRolls", "Toilet paper");
			ItemPositionConfig("Toothpaste");
			ItemPositionConfig("Tongue");
			ItemPositionConfig("ToyCube", "Toy cube");
			ItemPositionConfig("RobotToy", "Robot Toy");
			ItemPositionConfig("ToyTrain", "Toy train");
			ItemPositionConfig("TragedyMask", "Tragedy");
			ItemPositionConfig("EnginePart", "V-type engine");
			ItemPositionConfig("WhoopieCushion", "Whoopie cushion", new Vector3(9f, 2f, -8.25f));
			ItemPositionConfig("YieldSign", "Yield sign");
			ItemPositionConfig("ZeddogPlushie", "Zed Dog", new Vector3(9f, 1.21f, -5.55f));
			Vector3 defaultPosition2 = new Vector3(-1.4f, 0.6f, 2.4f);
			defaultFloorYRot = 0;
			ItemPositionConfig("WalkieTalkie", "Walkie-talkie", defaultPosition2, isTool: true, null, null, defaultFloorYRot);
			Vector3 defaultPosition3 = new Vector3(-1.3f, 0.2f, 2f);
			defaultFloorYRot = 0;
			ItemPositionConfig("BBFlashlight", "Flashlight", defaultPosition3, isTool: true, null, null, defaultFloorYRot);
			Vector3 defaultPosition4 = new Vector3(-1.5f, 0.3f, 1.5f);
			defaultFloorYRot = 0;
			ItemPositionConfig("ShovelItem", "Shovel", defaultPosition4, isTool: true, null, null, defaultFloorYRot);
			Vector3 defaultPosition5 = new Vector3(-2f, 0.5f, 2.4f);
			defaultFloorYRot = 0;
			ItemPositionConfig("LockPickerItem", "Lockpicker", defaultPosition5, isTool: true, null, null, defaultFloorYRot);
			Vector3 defaultPosition6 = new Vector3(-1.3f, 0.65f, 2f);
			defaultFloorYRot = 0;
			ItemPositionConfig("FlashlightItem", "Pro-flashlight", defaultPosition6, isTool: true, null, null, defaultFloorYRot);
			Vector3 defaultPosition7 = new Vector3(-1.2f, 0.5f, 2f);
			defaultFloorYRot = 0;
			ItemPositionConfig("StunGrenade", "Stun grenade", defaultPosition7, isTool: true, null, null, defaultFloorYRot);
			Vector3 defaultPosition8 = new Vector3(-0.3f, 0.5f, 3.2f);
			defaultFloorYRot = 0;
			ItemPositionConfig("Boombox", defaultPosition8, isTool: true, null, null, defaultFloorYRot);
			Vector3 defaultPosition9 = new Vector3(-0.55f, 0.2f, 2f);
			defaultFloorYRot = 0;
			ItemPositionConfig("TZPChemical", "TZP-Inhalant", defaultPosition9, isTool: true, null, null, defaultFloorYRot);
			Vector3 defaultPosition10 = new Vector3(-1.1f, 0.6f, 2.4f);
			defaultFloorYRot = 0;
			ItemPositionConfig("PatcherGunItem", "Zap gun", defaultPosition10, isTool: true, null, null, defaultFloorYRot);
			Vector3 defaultPosition11 = new Vector3(-0.3f, 0.2f, 0.5f);
			defaultFloorYRot = 0;
			ItemPositionConfig("JetpackItem", "Jetpack", defaultPosition11, isTool: true, null, null, defaultFloorYRot);
			ItemPositionConfig("ExtensionLadderItem", "Extension ladder", isTool: true);
			ItemPositionConfig("RadarBoosterDevice", "Radar booster", isTool: true);
			Vector3 defaultPosition12 = new Vector3(-1.7f, 0.5f, 2f);
			defaultFloorYRot = 0;
			ItemPositionConfig("SprayPaintItem", "Spray paint", defaultPosition12, isTool: true, null, null, defaultFloorYRot);
			Vector3 defaultPosition13 = new Vector3(-2.05f, 0.5f, 2f);
			defaultFloorYRot = 0;
			ItemPositionConfig("WeedKillerItem", "Weed killer", defaultPosition13, isTool: true, null, null, defaultFloorYRot);
			Vector3 defaultPosition14 = new Vector3(-0.35f, 0.5f, 2.3000002f);
			defaultFloorYRot = 0;
			ItemPositionConfig("BeltBagItem", "Belt bag", defaultPosition14, isTool: true, null, null, defaultFloorYRot);
			Vector3 defaultPosition15 = new Vector3(-0.3f, 0.6f, 1.5f);
			defaultFloorYRot = 0;
			ItemPositionConfig("Key", defaultPosition15, isTool: true, null, null, defaultFloorYRot);
			Vector3 defaultPosition16 = new Vector3(-0.3f, 0.6f, 2f);
			defaultFloorYRot = 0;
			ItemPositionConfig("ShotgunShell", "Shotgun Shell", defaultPosition16, isTool: true, null, null, defaultFloorYRot);
			customItemPositions = ((BaseUnityPlugin)this).Config.Bind<string>("Items", "CustomItemPositions", "MyItem1:0,0,0;MyItem2:cupboard:1.5,-2,3", "Semicolon-separated list of internal item names and their positions.");
		}

		private void ItemPositionConfig(string internalName, string itemName, bool isTool = false, bool? defaultKeepOnCruiser = null)
		{
			itemPositions[internalName] = ((BaseUnityPlugin)this).Config.Bind<string>(isTool ? "Tools" : "Scrap", internalName, $"{(defaultKeepOnCruiser.GetValueOrDefault(isTool) ? ((object)'C') : string.Empty)}", "Position for the " + itemName + " item.");
			vanillaItems[itemName.ToLower()] = internalName.ToLower();
		}

		private void ItemPositionConfig(string itemName, bool isTool = false, bool? defaultKeepOnCruiser = null)
		{
			itemPositions[itemName] = ((BaseUnityPlugin)this).Config.Bind<string>(isTool ? "Tools" : "Scrap", itemName, $"{(defaultKeepOnCruiser.GetValueOrDefault(isTool) ? ((object)'C') : string.Empty)}", "Position for the " + itemName + " item.");
			vanillaItems[itemName.ToLower()] = itemName.ToLower();
		}

		private static string Flags(bool keepOnCruiser, bool inCupboard)
		{
			return (keepOnCruiser || inCupboard) ? $":{(keepOnCruiser ? ((object)'C') : string.Empty)}{(inCupboard ? ((object)'P') : string.Empty)}" : string.Empty;
		}

		private void ItemPositionConfig(string internalName, string itemName, Vector3 defaultPosition, bool isTool = false, bool? defaultInCupboard = null, bool? defaultKeepOnCruiser = null, int? defaultFloorYRot = null)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: 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)
			itemPositions[internalName] = ((BaseUnityPlugin)this).Config.Bind<string>(isTool ? "Tools" : "Scrap", internalName, string.Format(CultureInfo.InvariantCulture, "{0}{1},{2},{3}{4}{5}", defaultInCupboard.GetValueOrDefault(isTool) ? "cupboard:" : "", defaultPosition.x, defaultPosition.y, defaultPosition.z, defaultFloorYRot.HasValue ? string.Format(CultureInfo.InvariantCulture, ",{0}", defaultFloorYRot) : string.Empty, Flags(defaultKeepOnCruiser.GetValueOrDefault(isTool), defaultInCupboard.GetValueOrDefault(isTool))), "Position for the " + itemName + " item.");
			vanillaItems[itemName.ToLower()] = internalName.ToLower();
		}

		private void ItemPositionConfig(string itemName, Vector3 defaultPosition, bool isTool = false, bool? defaultInCupboard = null, bool? defaultKeepOnCruiser = null, int? defaultFloorYRot = null)
		{
			//IL_0049: 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_0065: Unknown result type (might be due to invalid IL or missing references)
			itemPositions[itemName] = ((BaseUnityPlugin)this).Config.Bind<string>(isTool ? "Tools" : "Scrap", itemName, string.Format(CultureInfo.InvariantCulture, "{0}{1},{2},{3}{4}{5}", defaultInCupboard.GetValueOrDefault(isTool) ? "cupboard:" : "", defaultPosition.x, defaultPosition.y, defaultPosition.z, defaultFloorYRot.HasValue ? string.Format(CultureInfo.InvariantCulture, ",{0}", defaultFloorYRot) : string.Empty, Flags(defaultKeepOnCruiser.GetValueOrDefault(isTool), defaultInCupboard.GetValueOrDefault(isTool))), "Position for the " + itemName + " item.");
			vanillaItems[itemName.ToLower()] = itemName.ToLower();
		}
	}
	public class PrintItemNames : Command
	{
		public override string[] Commands => new string[2]
		{
			"itemnames",
			((Command)this).Name
		};

		public override string Description => "Lists all currently loaded item names";

		public override string[] Syntax => new string[2] { "", "[ -a | --all ]" };

		public override bool Invoke(string[] args, Dictionary<string, string> kwargs, out string? error)
		{
			error = "The ship must be in orbit";
			if (!StartOfRound.Instance.inShipPhase)
			{
				return false;
			}
			bool flag = args.Contains("-a") || args.Contains("--all");
			error = "No items on the ship";
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			GrabbableObject[] array = Object.FindObjectsOfType<GrabbableObject>();
			foreach (GrabbableObject val in array)
			{
				string text = Utils.RemoveClone(((Object)val).name);
				if (flag || !LethalShipSort.Instance.vanillaItems.ContainsValue(text.ToLower()))
				{
					dictionary.TryAdd(text, val.itemProperties?.itemName);
				}
			}
			if (dictionary.Count == 0)
			{
				return false;
			}
			string text2 = string.Join('\n', dictionary.Select((KeyValuePair<string, string> kvp) => kvp.Key + ((kvp.Value != null) ? (": " + kvp.Value) : "")).OrderBy<string, string>((string i) => i, StringComparer.CurrentCultureIgnoreCase));
			string text3 = "The following" + (flag ? "" : " unknown") + " items are currently on the ship:\n";
			ChatCommandAPI.Print(text3 + "<indent=10px>" + text2 + "</indent>");
			LethalShipSort.Logger.LogInfo((object)(text3 + text2));
			return true;
		}
	}
	public class SetItemPositionCommand : Command
	{
		public enum where
		{
			here,
			there,
			error
		}

		public enum when
		{
			once,
			game,
			always,
			error
		}

		public override string Name => "SetItemPosition";

		public override string Description => "Sets the position for an item when sorting";

		public override string[] Commands => new string[2]
		{
			"put",
			((Command)this).Name
		};

		public override string[] Syntax => new string[1] { "\"<item>\" { here | there } [ once | game | always ]\nExample: /put \"easter egg\" there always" };

		public override bool Invoke(string[] args, Dictionary<string, string> kwargs, out string error)
		{
			error = "The ship must be in orbit";
			return StartOfRound.Instance.inShipPhase && SetItemPosition(args, out error);
		}

		public static bool SetItemPosition(string[] args, out string error)
		{
			error = "Invalid arguments";
			switch (args.Length)
			{
			case 2:
			{
				string name2 = args[0];
				string text3 = args[1].ToLower();
				if (1 == 0)
				{
				}
				where where = ((!(text3 == "here")) ? ((text3 == "there") ? where.there : where.error) : where.here);
				if (1 == 0)
				{
				}
				return SetItemPosition(name2, where, when.once, out error);
			}
			case 3:
			{
				string name = args[0];
				string text = args[1].ToLower();
				if (1 == 0)
				{
				}
				where where = ((!(text == "here")) ? ((text == "there") ? where.there : where.error) : where.here);
				if (1 == 0)
				{
				}
				where where2 = where;
				string text2 = args[2].ToLower();
				if (1 == 0)
				{
				}
				when when;
				switch (text2)
				{
				case "once":
				case "now":
					when = when.once;
					break;
				case "game":
				case "round":
					when = when.game;
					break;
				case "always":
				case "save":
					when = when.always;
					break;
				default:
					when = when.error;
					break;
				}
				if (1 == 0)
				{
				}
				return SetItemPosition(name, where2, when, out error);
			}
			default:
				return false;
			}
		}

		public static bool SetItemPosition(string name, where where, when when, out string error)
		{
			//IL_014c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0333: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_037b: Unknown result type (might be due to invalid IL or missing references)
			//IL_036e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0373: Unknown result type (might be due to invalid IL or missing references)
			//IL_046f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0462: Unknown result type (might be due to invalid IL or missing references)
			//IL_0467: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0547: Unknown result type (might be due to invalid IL or missing references)
			error = "Invalid arguments";
			if (where == where.error || when == when.error)
			{
				return false;
			}
			error = "Invalid item name";
			if (!LethalShipSort.Instance.vanillaItems.TryGetValue(name.ToLower(), out string internalName))
			{
				if (!LethalShipSort.Instance.vanillaItems.ContainsValue(name.ToLower()))
				{
					return false;
				}
				internalName = name;
			}
			LethalShipSort.Logger.LogDebug((object)("internalName: " + internalName + " (" + name + ")"));
			ConfigEntry<string> val = null;
			if (when == when.always)
			{
				if (LethalShipSort.Instance.itemPositions.All<KeyValuePair<string, ConfigEntry<string>>>((KeyValuePair<string, ConfigEntry<string>> kvp) => !string.Equals(kvp.Key, internalName, StringComparison.CurrentCultureIgnoreCase)))
				{
					return false;
				}
				val = LethalShipSort.Instance.itemPositions.First<KeyValuePair<string, ConfigEntry<string>>>((KeyValuePair<string, ConfigEntry<string>> kvp) => string.Equals(kvp.Key, internalName, StringComparison.CurrentCultureIgnoreCase)).Value;
			}
			error = "Error getting position";
			if (!GetPosition(where, out Vector3 position, out GameObject relativeTo))
			{
				return false;
			}
			LethalShipSort.Logger.LogDebug((object)string.Format("position: {0} relative to {1} ({2}, {3})", position, relativeTo, ((Object)(object)relativeTo == (Object)null) ? "null" : Utils.GameObjectPath(relativeTo), ((Object)(object)relativeTo == (Object)null) ? "" : ((string)(object)GameObject.Find(Utils.GameObjectPath(relativeTo)))));
			GrabbableObject[] array;
			switch (when)
			{
			case when.once:
				ChatCommandAPI.Print($"Moving all items of type {internalName} to position {(((Object)(object)relativeTo == (Object)null) ? position : relativeTo.transform.InverseTransformPoint(position))}");
				error = "No items to sort";
				array = Object.FindObjectsOfType<GrabbableObject>();
				if (array == null)
				{
					return false;
				}
				array = array.Where((GrabbableObject i) => i != null && i.playerHeldBy == null && !(i is RagdollGrabbableObject) && string.Equals(Utils.RemoveClone(((Object)i).name), internalName, StringComparison.CurrentCultureIgnoreCase)).ToArray();
				if (array.Length == 0)
				{
					return false;
				}
				if (LethalShipSort.Instance.SortDelay < 10)
				{
					int num = array.Count(delegate(GrabbableObject item)
					{
						//IL_000e: Unknown result type (might be due to invalid IL or missing references)
						try
						{
							return !Utils.MoveItem(item, new ItemPosition
							{
								position = position,
								parentTo = relativeTo
							});
						}
						catch (Exception ex2)
						{
							LethalShipSort.Logger.LogError((object)ex2);
							return true;
						}
					});
					error = $"{num} items couldn't be sorted";
					ChatCommandAPI.Print("Finished sorting items");
					return num == 0;
				}
				if (SortItemsCommand.sorting != null)
				{
					((MonoBehaviour)GameNetworkManager.Instance.localPlayerController).StopCoroutine(SortItemsCommand.sorting);
				}
				SortItemsCommand.sorting = ((MonoBehaviour)GameNetworkManager.Instance.localPlayerController).StartCoroutine(SortItemsDelayed(LethalShipSort.Instance.SortDelay, array, position, relativeTo));
				return true;
			case when.game:
				LethalShipSort.Instance.roundOverrides[internalName.ToLower()] = (position, relativeTo);
				ChatCommandAPI.Print($"Items of type {internalName} will be put on position {(((Object)(object)relativeTo == (Object)null) ? position : relativeTo.transform.InverseTransformPoint(position))} for this game");
				goto IL_0484;
			case when.always:
				{
					val.Value = (((Object)(object)relativeTo == (Object)null) ? $"none:{position.x},{position.y},{position.z}" : $"{Utils.GameObjectPath(relativeTo)}:{position.x},{position.y},{position.z}");
					ChatCommandAPI.Print($"Items of type {internalName} will be put on position {(((Object)(object)relativeTo == (Object)null) ? position : relativeTo.transform.InverseTransformPoint(position))}");
					goto IL_0484;
				}
				IL_0484:
				array = Object.FindObjectsOfType<GrabbableObject>();
				if (array == null)
				{
					break;
				}
				array = array.Where((GrabbableObject i) => i != null && i.playerHeldBy == null && !(i is RagdollGrabbableObject) && string.Equals(Utils.RemoveClone(((Object)i).name), internalName, StringComparison.CurrentCultureIgnoreCase)).ToArray();
				if (array.Length == 0)
				{
					break;
				}
				if (LethalShipSort.Instance.SortDelay < 10)
				{
					int num2 = array.Count(delegate(GrabbableObject item)
					{
						//IL_000e: Unknown result type (might be due to invalid IL or missing references)
						try
						{
							return !Utils.MoveItem(item, new ItemPosition
							{
								position = position,
								parentTo = relativeTo
							});
						}
						catch (Exception ex)
						{
							LethalShipSort.Logger.LogError((object)ex);
							return true;
						}
					});
					error = $"{num2} items couldn't be sorted";
					return num2 == 0;
				}
				if (SortItemsCommand.sorting != null)
				{
					((MonoBehaviour)GameNetworkManager.Instance.localPlayerController).StopCoroutine(SortItemsCommand.sorting);
				}
				SortItemsCommand.sorting = ((MonoBehaviour)GameNetworkManager.Instance.localPlayerController).StartCoroutine(SortItemsDelayed(LethalShipSort.Instance.SortDelay, array, position, relativeTo));
				break;
			}
			return true;
		}

		private static IEnumerator SortItemsDelayed(uint delay, GrabbableObject[] items, Vector3 position, GameObject? relativeTo, string errorPrefix = "Error running command")
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			int itemsFailed = 0;
			foreach (GrabbableObject item in items)
			{
				try
				{
					if (!Utils.MoveItem(item, new ItemPosition
					{
						position = position,
						parentTo = relativeTo
					}))
					{
						itemsFailed++;
					}
				}
				catch (Exception e)
				{
					LethalShipSort.Logger.LogError((object)e);
					itemsFailed++;
				}
				yield return (object)new WaitForSeconds((float)delay / 1000f);
			}
			string error = $"{itemsFailed} items couldn't be sorted";
			if (itemsFailed != 0)
			{
				ChatCommandAPI.PrintError(errorPrefix + ": <noparse>" + error + "</noparse>");
			}
			else
			{
				ChatCommandAPI.Print("Finished sorting items");
			}
		}

		private static bool GetPosition(where where, out Vector3 position, out GameObject? relativeTo)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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)
			//IL_0064: 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_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_0087: 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_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: 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_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			position = default(Vector3);
			relativeTo = null;
			RaycastHit val = default(RaycastHit);
			switch (where)
			{
			case where.here:
				if (Physics.Raycast(((Component)GameNetworkManager.Instance.localPlayerController).transform.position, Vector3.down, ref val, 80f, 268437760, (QueryTriggerInteraction)1))
				{
					position = ((Component)((RaycastHit)(ref val)).collider).gameObject.transform.InverseTransformPoint(((RaycastHit)(ref val)).point + new Vector3(0f, 0.2f, 0f));
					relativeTo = ((Component)((RaycastHit)(ref val)).collider).gameObject;
					return true;
				}
				break;
			case where.there:
				if (Physics.Raycast(((Component)GameNetworkManager.Instance.localPlayerController.gameplayCamera).transform.position, ((Component)GameNetworkManager.Instance.localPlayerController.gameplayCamera).transform.forward, ref val, 80f, 268437760, (QueryTriggerInteraction)1))
				{
					position = ((Component)((RaycastHit)(ref val)).collider).gameObject.transform.InverseTransformPoint(((RaycastHit)(ref val)).point + new Vector3(0f, 0.2f, 0f));
					relativeTo = ((Component)((RaycastHit)(ref val)).collider).gameObject;
					return true;
				}
				break;
			}
			return false;
		}
	}
	public class SortItemsCommand : Command
	{
		private enum ForceLevel
		{
			None,
			IncludeCruiser,
			IncludeAll
		}

		[HarmonyPatch(typeof(StartOfRound), "SetShipReadyToLand")]
		internal static class AutoSortPatch
		{
			private static void Prefix()
			{
				if (LethalShipSort.Instance.AutoSort && GameNetworkManager.Instance.localPlayerController.isHostPlayerObject)
				{
					AutoSortAllItems();
				}
			}
		}

		internal static Coroutine? sorting;

		public override string Name => "SortItems";

		public override string[] Commands => new string[3]
		{
			"sort",
			"ShipSort",
			((Command)this).Name
		};

		public override string Description => "Sorts all items on the ship\n-a: sort all items, even items on cruiser";

		public override string[] Syntax => new string[3] { "", "[ -a | -A ]", "<item> { here | there } [ once | game | always ]" };

		public override bool Invoke(string[] args, Dictionary<string, string> kwargs, out string error)
		{
			error = "The ship must be in orbit";
			return StartOfRound.Instance.inShipPhase && ((args.Length < 2) ? SortAllItems((args.Contains("-A") || args.Contains<string>("--all", StringComparer.InvariantCultureIgnoreCase)) ? ForceLevel.IncludeAll : (args.Contains("-a") ? ForceLevel.IncludeCruiser : ForceLevel.None), out error) : SetItemPositionCommand.SetItemPosition(args, out error));
		}

		private static bool SortAllItems(ForceLevel forceLevel, out string error)
		{
			error = "No items to sort";
			GameNetworkManager.Instance.localPlayerController.DropAllHeldItemsAndSync();
			GrabbableObject[] array = Object.FindObjectsOfType<GrabbableObject>();
			if (array == null)
			{
				return false;
			}
			array = array.Where((GrabbableObject i) => i != null && i.playerHeldBy == null && !(i is RagdollGrabbableObject)).ToArray();
			if (array.Length == 0)
			{
				return false;
			}
			ChatCommandAPI.Print("Sorting all items...");
			VehicleController[] cars = Object.FindObjectsOfType<VehicleController>() ?? Array.Empty<VehicleController>();
			Dictionary<GrabbableObject, ItemPosition> dictionary = FilterFlags(array.Where((GrabbableObject i) => i.itemProperties.isScrap).ToDictionary((GrabbableObject i) => i, (GrabbableObject item) => LethalShipSort.Instance.GetPosition(item)));
			Dictionary<GrabbableObject, ItemPosition> dictionary2 = FilterFlags(array.Where((GrabbableObject i) => !i.itemProperties.isScrap).ToDictionary((GrabbableObject i) => i, (GrabbableObject item) => LethalShipSort.Instance.GetPosition(item)));
			if (LethalShipSort.Instance.SortDelay < 10)
			{
				int num = 0;
				int num2 = 0;
				if (dictionary.Count != 0)
				{
					num = SortItems(dictionary);
				}
				if (dictionary2.Count != 0)
				{
					num2 = SortItems(dictionary2);
				}
				error = ((num > 0) ? string.Format("{0} scrap items {1}", num, (num2 > 0) ? "and " : "") : "") + ((num2 > 0) ? $"{num2} tool items" : "") + " couldn't be sorted";
				if (num != 0 || num2 != 0)
				{
					return false;
				}
				ChatCommandAPI.Print("Finished sorting items");
			}
			else
			{
				if (sorting != null)
				{
					((MonoBehaviour)GameNetworkManager.Instance.localPlayerController).StopCoroutine(sorting);
				}
				sorting = ((MonoBehaviour)GameNetworkManager.Instance.localPlayerController).StartCoroutine(SortAllItemsDelayed(LethalShipSort.Instance.SortDelay, dictionary, dictionary2));
			}
			return true;
			Dictionary<GrabbableObject, ItemPosition> FilterFlags(Dictionary<GrabbableObject, ItemPosition> dict)
			{
				return dict.Where<KeyValuePair<GrabbableObject, ItemPosition>>((KeyValuePair<GrabbableObject, ItemPosition> kvp) => (forceLevel == ForceLevel.IncludeAll || !kvp.Value.flags.Ignore) && (forceLevel >= ForceLevel.IncludeCruiser || !kvp.Value.flags.KeepOnCruiser || !cars.Any((VehicleController car) => (Object)(object)((Component)kvp.Key).transform.parent == (Object)(object)((Component)car).transform))).ToDictionary((KeyValuePair<GrabbableObject, ItemPosition> kvp) => kvp.Key, (KeyValuePair<GrabbableObject, ItemPosition> kvp) => kvp.Value);
			}
		}

		private static void AutoSortAllItems()
		{
			try
			{
				GameNetworkManager.Instance.localPlayerController.DropAllHeldItemsAndSync();
				GrabbableObject[] array = Object.FindObjectsOfType<GrabbableObject>();
				if (array == null)
				{
					return;
				}
				array = array.Where((GrabbableObject i) => i != null && i.playerHeldBy == null && !(i is RagdollGrabbableObject)).ToArray();
				if (array.Length == 0)
				{
					return;
				}
				ChatCommandAPI.Print("Sorting all items...");
				VehicleController[] cars = Object.FindObjectsOfType<VehicleController>() ?? Array.Empty<VehicleController>();
				Dictionary<GrabbableObject, ItemPosition> dictionary = FilterFlags(array.Where((GrabbableObject i) => i.itemProperties.isScrap).ToDictionary((GrabbableObject i) => i, (GrabbableObject item) => LethalShipSort.Instance.GetPosition(item)));
				Dictionary<GrabbableObject, ItemPosition> dictionary2 = FilterFlags(array.Where((GrabbableObject i) => !i.itemProperties.isScrap).ToDictionary((GrabbableObject i) => i, (GrabbableObject item) => LethalShipSort.Instance.GetPosition(item)));
				if (LethalShipSort.Instance.SortDelay < 10)
				{
					int num = 0;
					int num2 = 0;
					if (dictionary.Count != 0)
					{
						num = SortItems(dictionary);
					}
					if (dictionary2.Count != 0)
					{
						num2 = SortItems(dictionary2);
					}
					if (num != 0 || num2 != 0)
					{
						ChatCommandAPI.PrintError("Automatic sorting failed: " + ((num > 0) ? string.Format("{0} scrap items {1}", num, (num2 > 0) ? "and " : "") : "") + ((num2 > 0) ? $"{num2} tool items" : "") + " couldn't be sorted");
					}
					else
					{
						ChatCommandAPI.Print("Finished sorting items");
					}
				}
				else
				{
					if (sorting != null)
					{
						((MonoBehaviour)GameNetworkManager.Instance.localPlayerController).StopCoroutine(sorting);
					}
					sorting = ((MonoBehaviour)GameNetworkManager.Instance.localPlayerController).StartCoroutine(SortAllItemsDelayed(LethalShipSort.Instance.SortDelay, dictionary, dictionary2, "Automatic sorting failed"));
				}
				Dictionary<GrabbableObject, ItemPosition> FilterFlags(Dictionary<GrabbableObject, ItemPosition> dict)
				{
					return dict.Where<KeyValuePair<GrabbableObject, ItemPosition>>(delegate(KeyValuePair<GrabbableObject, ItemPosition> kvp)
					{
						ItemPosition.Flags flags = kvp.Value.flags;
						return !flags.Ignore && !flags.NoAutoSort && (!kvp.Value.flags.KeepOnCruiser || !cars.Any((VehicleController car) => (Object)(object)((Component)kvp.Key).transform.parent == (Object)(object)((Component)car).transform));
					}).ToDictionary((KeyValuePair<GrabbableObject, ItemPosition> kvp) => kvp.Key, (KeyValuePair<GrabbableObject, ItemPosition> kvp) => kvp.Value);
				}
			}
			catch (Exception arg)
			{
				ChatCommandAPI.PrintError("Automatic sorting failed due to an internal error, check the log for details");
				LethalShipSort.Logger.LogError((object)$"Error while autosorting items: {arg}");
			}
		}

		public static IEnumerator SortAllItemsDelayed(uint delay, Dictionary<GrabbableObject, ItemPosition> scrap, Dictionary<GrabbableObject, ItemPosition> tools, string errorPrefix = "Error running command")
		{
			int scrapFailed = 0;
			int toolsFailed = 0;
			foreach (KeyValuePair<GrabbableObject, ItemPosition> kvp in scrap)
			{
				try
				{
					if (!Utils.MoveItem(kvp.Key, kvp.Value))
					{
						scrapFailed++;
					}
				}
				catch (Exception e2)
				{
					LethalShipSort.Logger.LogError((object)e2);
					scrapFailed++;
				}
				yield return (object)new WaitForSeconds((float)delay / 1000f);
			}
			foreach (KeyValuePair<GrabbableObject, ItemPosition> kvp2 in tools)
			{
				try
				{
					if (!Utils.MoveItem(kvp2.Key, kvp2.Value))
					{
						toolsFailed++;
					}
				}
				catch (Exception e)
				{
					LethalShipSort.Logger.LogError((object)e);
					toolsFailed++;
				}
				yield return (object)new WaitForSeconds((float)delay / 1000f);
			}
			string error = ((scrapFailed > 0) ? string.Format("{0} scrap items {1}", scrapFailed, (toolsFailed > 0) ? "and " : "") : "") + ((toolsFailed > 0) ? $"{toolsFailed} tool items" : "") + " couldn't be sorted";
			if (scrapFailed != 0 || toolsFailed != 0)
			{
				ChatCommandAPI.PrintError(errorPrefix + ": <noparse>" + error + "</noparse>");
			}
			else
			{
				ChatCommandAPI.Print("Finished sorting items");
			}
		}

		public static int SortItems(Dictionary<GrabbableObject, ItemPosition> items)
		{
			return items.Count<KeyValuePair<GrabbableObject, ItemPosition>>(delegate(KeyValuePair<GrabbableObject, ItemPosition> kvp)
			{
				try
				{
					return !Utils.MoveItem(kvp.Key, kvp.Value);
				}
				catch (Exception ex)
				{
					LethalShipSort.Logger.LogError((object)ex);
					return true;
				}
			});
		}
	}
	public static class Utils
	{
		[Flags]
		private enum Layers
		{
			Default = 1,
			TransparentFX = 2,
			IgnoreRaycast = 4,
			Player = 8,
			Water = 0x10,
			UI = 0x20,
			Props = 0x40,
			HelmetVisor = 0x80,
			Room = 0x100,
			InteractableObject = 0x200,
			Foliage = 0x400,
			Colliders = 0x800,
			PhysicsObject = 0x1000,
			Triggers = 0x2000,
			MapRadar = 0x4000,
			NavigationSurface = 0x8000,
			MoldSpore = 0x10000,
			Anomaly = 0x20000,
			LineOfSight = 0x40000,
			Enemies = 0x80000,
			PlayerRagdoll = 0x100000,
			MapHazards = 0x200000,
			ScanNode = 0x400000,
			EnemiesNotRendered = 0x800000,
			MiscLevelGeometry = 0x1000000,
			Terrain = 0x2000000,
			PlaceableShipObjects = 0x4000000,
			PlacementBlocker = 0x8000000,
			Railing = 0x10000000,
			DecalStickableSurface = 0x20000000,
			Vehicle = 0x40000000
		}

		private const string CLONE = "(Clone)";

		internal const int LAYER_MASK = 268437760;

		public static string RemoveClone(string name)
		{
			string result;
			if (!name.EndsWith("(Clone)"))
			{
				result = name;
			}
			else
			{
				int length = "(Clone)".Length;
				result = name.Substring(0, name.Length - length);
			}
			return result;
		}

		public static bool MoveItem(GrabbableObject item, ItemPosition position)
		{
			//IL_0031: 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)
			if (position.position.HasValue)
			{
				return (position.flags.Parent && (Object)(object)position.parentTo != (Object)null) ? MoveItem(item, position.position.Value, position.parentTo, position.floorYRot.GetValueOrDefault(-1), position.flags) : MoveItemRelativeTo(item, position.position.Value, position.parentTo, position.floorYRot.GetValueOrDefault(-1), position.flags);
			}
			throw new ArgumentNullException("ItemPosition.position can not be null");
		}

		public static bool MoveItemRelativeTo(GrabbableObject item, Vector3 position, GameObject? relativeTo, int floorYRot, ItemPosition.Flags flags)
		{
			//IL_0016: 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_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: 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_012d: 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_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: 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_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: 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_00d4: 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_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			LethalShipSort.Logger.LogDebug((object)string.Format(">> Moving item {0} to position {1} relative to {2}", RemoveClone(((Object)item).name), position, ((Object)(object)relativeTo == (Object)null) ? "ship" : RemoveClone(((Object)relativeTo).name)));
			GameObject val = GameObject.Find("Environment/HangarShip");
			if ((Object)(object)val == (Object)null)
			{
				LethalShipSort.Logger.LogWarning((object)"   Couldn't find ship");
				return false;
			}
			if ((Object)(object)relativeTo == (Object)null)
			{
				relativeTo = val;
			}
			if (!flags.Exact)
			{
				RaycastHit val2 = default(RaycastHit);
				if (!Physics.Raycast(relativeTo.transform.TransformPoint(position), Vector3.down, ref val2, 80f, 268437760, (QueryTriggerInteraction)1))
				{
					LethalShipSort.Logger.LogWarning((object)"   Raycast unsuccessful");
					return false;
				}
				position = Randomize(val.transform.InverseTransformPoint(((RaycastHit)(ref val2)).point + item.itemProperties.verticalOffset * Vector3.up));
			}
			else
			{
				position = Randomize(position + item.itemProperties.verticalOffset * Vector3.up);
			}
			GameNetworkManager.Instance.localPlayerController.SetObjectAsNoLongerHeld(true, true, position, item, floorYRot);
			GameNetworkManager.Instance.localPlayerController.ThrowObjectServerRpc(NetworkObjectReference.op_Implicit(((NetworkBehaviour)item).NetworkObject), true, true, position, floorYRot);
			return true;
		}

		public static bool MoveItem(GrabbableObject item, Vector3 position, GameObject parentTo, int floorYRot, ItemPosition.Flags flags)
		{
			//IL_0016: 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_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_00ed: 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_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: 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_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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_013c: 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_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: 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_0072: 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_0087: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			LethalShipSort.Logger.LogDebug((object)$">> Moving item {RemoveClone(((Object)item).name)} to position {position} in {RemoveClone(((Object)parentTo).name)}");
			if (!flags.Exact)
			{
				RaycastHit val = default(RaycastHit);
				if (!Physics.Raycast(parentTo.transform.TransformPoint(position), Vector3.down, ref val, 80f, 268437760, (QueryTriggerInteraction)1))
				{
					LethalShipSort.Logger.LogWarning((object)"   Raycast unsuccessful");
					return false;
				}
				position = parentTo.transform.InverseTransformPoint(Randomize(((RaycastHit)(ref val)).point + item.itemProperties.verticalOffset * Vector3.up - new Vector3(0f, 0.05f, 0f), 0.02f));
			}
			else
			{
				position = Randomize(position + item.itemProperties.verticalOffset * Vector3.up - new Vector3(0f, 0.05f, 0f), 0.02f);
			}
			GameNetworkManager.Instance.localPlayerController.SetObjectAsNoLongerHeld(true, true, position, item, floorYRot);
			GameNetworkManager.Instance.localPlayerController.ThrowObjectServerRpc(NetworkObjectReference.op_Implicit(((NetworkBehaviour)item).NetworkObject), true, true, position, floorYRot);
			GameNetworkManager.Instance.localPlayerController.PlaceGrabbableObject(parentTo.transform, position, false, item);
			GameNetworkManager.Instance.localPlayerController.PlaceObjectServerRpc(NetworkObjectReference.op_Implicit(((NetworkBehaviour)item).NetworkObject), NetworkObjectReference.op_Implicit(parentTo), position, false);
			return true;
		}

		public static Vector3 Randomize(Vector3 position, float maxDistance = 0.05f)
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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_0057: 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_005f: Unknown result type (might be due to invalid IL or missing references)
			if (maxDistance <= 0f)
			{
				throw new ArgumentException("Invalid maxDistance (must be positive)");
			}
			Random random = new Random();
			return new Vector3(position.x + (float)random.NextDouble() * maxDistance * 2f - maxDistance, position.y, position.z + (float)random.NextDouble() * maxDistance * 2f - maxDistance);
		}

		public static string GameObjectPath(GameObject gameObject)
		{
			Transform parent = gameObject.transform.parent;
			string text = ((Object)gameObject).name;
			while ((Object)(object)parent != (Object)null)
			{
				text = ((Object)parent).name + "/" + text;
				parent = ((Component)parent).transform.parent;
			}
			return text;
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "baer1.ShipSort";

		public const string PLUGIN_NAME = "LethalShipSort";

		public const string PLUGIN_VERSION = "3.3.0";
	}
}