Decompiled source of QuickSort v0.1.26

QuickSort.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ChatCommandAPI;
using ChatCommandAPI.Utils;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Unity.Collections;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("0Harmony")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: IgnoresAccessChecksTo("BepInEx")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem")]
[assembly: IgnoresAccessChecksTo("Unity.Netcode.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")]
[assembly: IgnoresAccessChecksTo("UnityEngine.IMGUIModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UI")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("QuickSort")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("made by Asta")]
[assembly: AssemblyFileVersion("0.1.26.0")]
[assembly: AssemblyInformationalVersion("0.1.26+73d391632d6865e132cc9b45eed99aaef62db280")]
[assembly: AssemblyProduct("QuickSort")]
[assembly: AssemblyTitle("QuickSort")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.26.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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]
	[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 QuickSort
{
	public static class Chat
	{
		[HarmonyPatch(typeof(HUDManager), "SubmitChat_performed")]
		[HarmonyPrefix]
		[HarmonyWrapSafe]
		public static bool OnChatSubmit(HUDManager __instance, CallbackContext context)
		{
			if (!((CallbackContext)(ref context)).performed || !Player.Local.isTypingChat)
			{
				return true;
			}
			string text = __instance.chatTextField.text;
			if (text == "/help")
			{
				Log.Chat("Commands: " + string.Join(", ", ChatCommand.Commands));
				CloseChat(__instance);
				return false;
			}
			if (text.StartsWith("/"))
			{
				text = text.Substring(1).Trim();
				foreach (ChatCommand command in ChatCommand.Commands)
				{
					if (text.StartsWith(command.keyword))
					{
						CloseChat(__instance);
						try
						{
							command.action(command.GetArgs(text));
						}
						catch (Exception e)
						{
							Log.Exception(e);
						}
						return false;
					}
				}
			}
			return true;
		}

		public static void CloseChat(HUDManager instance)
		{
			instance.localPlayer.isTypingChat = false;
			instance.chatTextField.text = "";
			EventSystem.current.SetSelectedGameObject((GameObject)null);
			((Behaviour)instance.typingIndicator).enabled = false;
		}
	}
	public abstract class Argument
	{
		public string name;
	}
	public class Argument<T> : Argument
	{
		public T value;

		public Argument(string name, T value)
		{
			base.name = name;
			this.value = value;
		}

		public static implicit operator T(Argument<T> arg)
		{
			return arg.value;
		}
	}
	public struct ChatArgs
	{
		public Argument[] arguments;

		public string help;

		public int Length => arguments.Length;

		public bool Empty => arguments.Length == 0;

		public bool this[string name] => Get<bool>(name);

		public string this[int name] => Get<string>(name);

		public T Get<T>(string name)
		{
			Argument[] array = arguments;
			foreach (Argument argument in array)
			{
				if (argument.name == name)
				{
					return ((Argument<T>)argument).value;
				}
			}
			return default(T);
		}

		public T Get<T>(int name)
		{
			Argument[] array = arguments;
			foreach (Argument argument in array)
			{
				if (argument.name == name.ToString())
				{
					return ((Argument<T>)argument).value;
				}
			}
			return default(T);
		}
	}
	public class ChatCommand
	{
		public static List<ChatCommand> Commands = new List<ChatCommand>();

		public string keyword;

		public Action<ChatArgs> action;

		public string help;

		public ChatCommand(string keyword, string help, Action<ChatArgs> action)
		{
			this.keyword = keyword;
			this.help = help;
			this.action = action;
		}

		public static ChatCommand New(string keyword, string help, Action<ChatArgs> action)
		{
			ChatCommand chatCommand = new ChatCommand(keyword, help, action);
			Commands.Add(chatCommand);
			return chatCommand;
		}

		public ChatArgs GetArgs(string raw)
		{
			List<Argument> list = new List<Argument>();
			string[] array = raw.Split(' ');
			keyword = array[0];
			for (int i = 1; i < array.Length; i++)
			{
				if (array[i].StartsWith("-"))
				{
					string name = array[i].Substring(1);
					list.Add(new Argument<bool>(name, value: true));
				}
				else
				{
					list.Add(new Argument<string>((i - 1).ToString(), array[i]));
				}
			}
			return new ChatArgs
			{
				arguments = list.ToArray(),
				help = help
			};
		}

		public override string ToString()
		{
			return keyword;
		}
	}
	internal static class CruiserPositions
	{
		[Serializable]
		private sealed class PositionsFile
		{
			public List<PositionEntry> positions = new List<PositionEntry>();
		}

		[Serializable]
		private sealed class PositionEntry
		{
			public string item = "";

			public float x;

			public float y;

			public float z;

			public int maxCount = 10;
		}

		public static string PositionsPath => Path.Combine(Paths.ConfigPath, "pasta.quicksort.cruiser.positions.json");

		public static void EnsureFileExists()
		{
			try
			{
				if (!File.Exists(PositionsPath))
				{
					Save(new PositionsFile(), out string _);
				}
			}
			catch (Exception ex)
			{
				Log.Warning("Failed to create cruiser positions file: " + ex.Message);
			}
		}

		private static PositionsFile Load(out string? error)
		{
			error = null;
			EnsureFileExists();
			try
			{
				PositionsFile positionsFile = JsonConvert.DeserializeObject<PositionsFile>(File.ReadAllText(PositionsPath, Encoding.UTF8));
				if (positionsFile == null || positionsFile.positions == null)
				{
					throw new InvalidDataException("Missing positions list.");
				}
				return positionsFile;
			}
			catch (Exception ex)
			{
				error = "Failed to load cruiser positions: " + ex.Message;
				return new PositionsFile();
			}
		}

		private static bool Save(PositionsFile data, out string? error)
		{
			error = null;
			string positionsPath = PositionsPath;
			string text = positionsPath + ".tmp";
			try
			{
				string directoryName = Path.GetDirectoryName(positionsPath);
				if (!string.IsNullOrWhiteSpace(directoryName))
				{
					Directory.CreateDirectory(directoryName);
				}
				File.WriteAllText(text, JsonConvert.SerializeObject((object)data, (Formatting)1), Encoding.UTF8);
				if (File.Exists(positionsPath))
				{
					try
					{
						File.Replace(text, positionsPath, positionsPath + ".bak", ignoreMetadataErrors: true);
					}
					catch
					{
						File.Copy(text, positionsPath, overwrite: true);
						File.Delete(text);
					}
				}
				else
				{
					File.Move(text, positionsPath);
				}
				return true;
			}
			catch (Exception ex)
			{
				error = "Failed to save cruiser positions: " + ex.Message;
				return false;
			}
		}

		private static bool Valid(Vector3 point, int count)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			if (count > 0 && count <= 10000 && !float.IsNaN(point.x) && !float.IsNaN(point.y) && !float.IsNaN(point.z) && !float.IsInfinity(point.x) && !float.IsInfinity(point.y))
			{
				return !float.IsInfinity(point.z);
			}
			return false;
		}

		public static bool Set(string itemKey, Vector3 cruiserLocalPos, int maxCount, out string? error)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: 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)
			itemKey = Extensions.NormalizeName(itemKey);
			if (string.IsNullOrWhiteSpace(itemKey) || !Valid(cruiserLocalPos, maxCount))
			{
				error = "Invalid cruiser item, position, or maximum (1-10000).";
				return false;
			}
			PositionsFile positionsFile = Load(out error);
			if (error != null)
			{
				return false;
			}
			positionsFile.positions.RemoveAll((PositionEntry p) => p != null && Extensions.NormalizeName(p.item) == itemKey);
			positionsFile.positions.Add(new PositionEntry
			{
				item = itemKey,
				x = cruiserLocalPos.x,
				y = cruiserLocalPos.y,
				z = cruiserLocalPos.z,
				maxCount = maxCount
			});
			return Save(positionsFile, out error);
		}

		public static bool Remove(string itemKey, out bool removed, out string? error)
		{
			itemKey = Extensions.NormalizeName(itemKey);
			PositionsFile positionsFile = Load(out error);
			removed = false;
			if (error != null)
			{
				return false;
			}
			removed = positionsFile.positions.RemoveAll((PositionEntry p) => p != null && Extensions.NormalizeName(p.item) == itemKey) > 0;
			if (removed)
			{
				return Save(positionsFile, out error);
			}
			return true;
		}

		public static List<(string itemKey, Vector3 cruiserLocalPos, int maxCount)> ListAll(out string? error)
		{
			//IL_0076: 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)
			PositionsFile positionsFile = Load(out error);
			if (error != null)
			{
				return new List<(string, Vector3, int)>();
			}
			List<(string, Vector3, int)> list = new List<(string, Vector3, int)>();
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			Vector3 val = default(Vector3);
			foreach (PositionEntry position in positionsFile.positions)
			{
				if (position != null)
				{
					string text = Extensions.NormalizeName(position.item);
					((Vector3)(ref val))..ctor(position.x, position.y, position.z);
					if (string.IsNullOrWhiteSpace(text) || !Valid(val, position.maxCount) || !hashSet.Add(text))
					{
						error = "Invalid or duplicate cruiser position for '" + position.item + "'.";
						return new List<(string, Vector3, int)>();
					}
					list.Add((text, val, position.maxCount));
				}
			}
			return list.OrderBy<(string, Vector3, int), string>(((string itemKey, Vector3 cruiserLocalPos, int maxCount) p) => p.itemKey).ToList();
		}

		public static bool ReplaceAll(IEnumerable<(string itemKey, Vector3 cruiserLocalPos, int maxCount)> positions, out string? error)
		{
			//IL_0041: 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_005b: 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_00a2: 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)
			error = null;
			if (positions == null)
			{
				error = "Cruiser positions are missing.";
				return false;
			}
			List<PositionEntry> list = new List<PositionEntry>();
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			foreach (var position in positions)
			{
				string text = Extensions.NormalizeName(position.itemKey);
				Vector3 item = position.cruiserLocalPos;
				if (string.IsNullOrWhiteSpace(text) || !hashSet.Add(text) || !Valid(item, position.maxCount))
				{
					error = "Invalid or duplicate cruiser position for '" + position.itemKey + "'.";
					return false;
				}
				list.Add(new PositionEntry
				{
					item = text,
					x = item.x,
					y = item.y,
					z = item.z,
					maxCount = position.maxCount
				});
			}
			Load(out error);
			if (error != null)
			{
				return false;
			}
			return Save(new PositionsFile
			{
				positions = list
			}, out error);
		}
	}
	internal sealed class CruiserShelfAnchor : MonoBehaviour
	{
		private GrabbableObject? item;

		private Rigidbody? body;

		private Transform? cargoParent;

		private Transform? cruiserTransform;

		private Vector3 localPosition;

		private Quaternion shelfRotation;

		private bool originalKinematic;

		private bool initialized;

		internal static void Attach(GrabbableObject item, Transform cargoParent, Transform cruiserTransform)
		{
			if (!((Object)(object)item == (Object)null) && !((Object)(object)cargoParent == (Object)null) && !((Object)(object)cruiserTransform == (Object)null) && !((Object)(object)((Component)item).transform.parent != (Object)(object)cargoParent) && !item.isHeld)
			{
				CruiserShelfAnchor cruiserShelfAnchor = ((Component)item).GetComponent<CruiserShelfAnchor>();
				if ((Object)(object)cruiserShelfAnchor == (Object)null)
				{
					cruiserShelfAnchor = ((Component)item).gameObject.AddComponent<CruiserShelfAnchor>();
				}
				cruiserShelfAnchor.Configure(item, cargoParent, cruiserTransform);
			}
		}

		internal static void Detach(GrabbableObject item)
		{
			if (!((Object)(object)item == (Object)null))
			{
				CruiserShelfAnchor component = ((Component)item).GetComponent<CruiserShelfAnchor>();
				if ((Object)(object)component != (Object)null)
				{
					component.ReleaseForPickup();
				}
			}
		}

		private void Configure(GrabbableObject placedItem, Transform parent, Transform cruiser)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: 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_0081: 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)
			if (!initialized)
			{
				item = placedItem;
				body = ((Component)placedItem).GetComponent<Rigidbody>();
				originalKinematic = (Object)(object)body != (Object)null && body.isKinematic;
				initialized = true;
			}
			cargoParent = parent;
			cruiserTransform = cruiser;
			localPosition = ((Component)placedItem).transform.localPosition;
			Vector3 restingRotation = placedItem.itemProperties.restingRotation;
			shelfRotation = Quaternion.Euler(restingRotation.x, 0f, restingRotation.z);
			PinItem();
		}

		private void FixedUpdate()
		{
			if (!StillOnCruiser())
			{
				Release();
				Object.Destroy((Object)(object)this);
			}
			else
			{
				PinBody();
			}
		}

		private void LateUpdate()
		{
			if (!StillOnCruiser())
			{
				Release();
				Object.Destroy((Object)(object)this);
			}
			else
			{
				PinItem();
			}
		}

		private bool StillOnCruiser()
		{
			if (initialized && (Object)(object)item != (Object)null && (Object)(object)cargoParent != (Object)null && (Object)(object)cruiserTransform != (Object)null && (Object)(object)((Component)item).transform.parent == (Object)(object)cargoParent && !item.isHeld && !item.isPocketed)
			{
				return !item.deactivated;
			}
			return false;
		}

		private void PinItem()
		{
			//IL_0029: 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_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_0060: 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_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)item == (Object)null) && !((Object)(object)cruiserTransform == (Object)null))
			{
				((Component)item).transform.localPosition = localPosition;
				((Component)item).transform.rotation = cruiserTransform.rotation * shelfRotation;
				item.targetFloorPosition = localPosition;
				item.startFallingPosition = localPosition;
				item.fallTime = 1.1f;
				item.reachedFloorTarget = true;
				item.hasHitGround = true;
				PinBody();
			}
		}

		private void PinBody()
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: 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)
			//IL_0097: 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_004e: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)body == (Object)null) && !((Object)(object)cargoParent == (Object)null) && !((Object)(object)cruiserTransform == (Object)null))
			{
				if (!body.isKinematic)
				{
					body.velocity = Vector3.zero;
					body.angularVelocity = Vector3.zero;
					body.isKinematic = true;
				}
				body.position = cargoParent.TransformPoint(localPosition);
				body.rotation = cruiserTransform.rotation * shelfRotation;
			}
		}

		private void Release()
		{
			if (initialized)
			{
				initialized = false;
				if ((Object)(object)body != (Object)null)
				{
					body.isKinematic = originalKinematic;
				}
			}
		}

		internal void ReleaseForPickup()
		{
			Release();
			Object.Destroy((Object)(object)this);
		}

		private void OnDisable()
		{
			Release();
		}

		private void OnDestroy()
		{
			Release();
		}
	}
	internal static class CruiserShelfAnchorPatch
	{
		[HarmonyPatch(typeof(PlayerControllerB), "PlaceGrabbableObject")]
		[HarmonyPostfix]
		private static void AfterPlacement(Transform parentObject, bool matchRotationOfParent, GrabbableObject placeObject)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: 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)
			if (!matchRotationOfParent || (Object)(object)parentObject == (Object)null || (Object)(object)placeObject == (Object)null)
			{
				return;
			}
			VehicleController componentInParent = ((Component)parentObject).GetComponentInParent<VehicleController>();
			if (!((Object)(object)componentInParent == (Object)null))
			{
				Vector3 cruiserLocalPosition = ((Component)componentInParent).transform.InverseTransformPoint(((Component)placeObject).transform.position);
				if (CruiserSorter.IsShelfSlot(placeObject, cruiserLocalPosition))
				{
					PlayerPhysicsRegion componentInChildren = ((Component)componentInParent).GetComponentInChildren<PlayerPhysicsRegion>();
					Transform cargoParent = (((Object)(object)componentInChildren != (Object)null && componentInChildren.allowDroppingItems && (Object)(object)componentInChildren.physicsTransform != (Object)null) ? componentInChildren.physicsTransform : ((Component)componentInParent).transform);
					CruiserShelfAnchor.Attach(placeObject, cargoParent, ((Component)componentInParent).transform);
				}
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "GrabObjectClientRpc")]
		[HarmonyPrefix]
		private static void BeforePickup(bool grabValidated, NetworkObjectReference grabbedObject)
		{
			NetworkObject val = default(NetworkObject);
			if (grabValidated && ((NetworkObjectReference)(ref grabbedObject)).TryGet(ref val, (NetworkManager)null))
			{
				CruiserShelfAnchor componentInChildren = ((Component)val).GetComponentInChildren<CruiserShelfAnchor>();
				if ((Object)(object)componentInChildren != (Object)null)
				{
					componentInChildren.ReleaseForPickup();
				}
			}
		}
	}
	internal static class CruiserSorter
	{
		private const int MaxShelfZoneSlots = 20;

		internal const float SavedHeightOffset = 0.3f;

		private static readonly Dictionary<string, Vector3> Zones = new Dictionary<string, Vector3>(StringComparer.OrdinalIgnoreCase)
		{
			["A1"] = new Vector3(-1.15f, -0.4f, -2.6f),
			["A2"] = new Vector3(-1.15f, 0.46f, -2.6f),
			["A3"] = new Vector3(-1.15f, 1.22f, -2.6f),
			["B1"] = new Vector3(-1.15f, -0.4f, -1.7f),
			["B2"] = new Vector3(-1.15f, 0.46f, -1.7f),
			["B3"] = new Vector3(-1.15f, 1.22f, -1.7f),
			["C1"] = new Vector3(-1.15f, -0.4f, -0.8f),
			["C2"] = new Vector3(-1.15f, 0.46f, -0.8f),
			["C3"] = new Vector3(-1.15f, 1.22f, -0.8f),
			["D1"] = new Vector3(-0.91f, 0f, 0.3f),
			["D2"] = new Vector3(0f, -0.5f, -0.55f),
			["D3"] = new Vector3(0.82f, 0f, 0.3f),
			["E1"] = new Vector3(1.15f, -0.4f, -2.6f),
			["E2"] = new Vector3(1.15f, 0.46f, -2.6f),
			["E3"] = new Vector3(1.15f, 1.22f, -2.6f),
			["F1"] = new Vector3(1.15f, -0.4f, -1.7f),
			["F2"] = new Vector3(1.15f, 0.46f, -1.7f),
			["F3"] = new Vector3(1.15f, 1.22f, -1.7f),
			["G1"] = new Vector3(1.15f, -0.4f, -0.8f),
			["G2"] = new Vector3(1.15f, 0.46f, -0.8f),
			["G3"] = new Vector3(1.15f, 1.22f, -0.8f)
		};

		private static int cargoParentCacheFrame = -1;

		private static Transform[] cargoParentCache = Array.Empty<Transform>();

		private static int ZoneCapacity(string zone)
		{
			if (!(zone == "D2"))
			{
				return 20;
			}
			return 1;
		}

		internal static bool TryGetZone(string? name, out string zoneName, out Vector3 position)
		{
			zoneName = (name ?? "").Trim().ToUpperInvariant();
			return Zones.TryGetValue(zoneName, out position);
		}

		internal static string? ZoneAt(Vector3 position)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: 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_0043: 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_0062: 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_0087: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyValuePair<string, Vector3> zone in Zones)
			{
				if (Mathf.Abs(zone.Value.x - position.x) < 0.001f && Mathf.Abs(zone.Value.z - position.z) < 0.001f && (Mathf.Abs(zone.Value.y - position.y) < 0.001f || Mathf.Abs(zone.Value.y + 0.3f - position.y) < 0.001f))
				{
					return zone.Key;
				}
			}
			return null;
		}

		private static VehicleController? FindNearestCruiser()
		{
			PlayerControllerB player = Player.Local;
			if ((Object)(object)player == (Object)null)
			{
				return null;
			}
			return Object.FindObjectsOfType<VehicleController>().OrderBy(delegate(VehicleController c)
			{
				//IL_0006: 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)
				//IL_001b: 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)
				Vector3 val = ((Component)c).transform.position - ((Component)player).transform.position;
				return ((Vector3)(ref val)).sqrMagnitude;
			}).FirstOrDefault();
		}

		private static VehicleController? FindCruiserNearPlayer()
		{
			//IL_006a: 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_0074: 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_0084: 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)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			PlayerControllerB player = Player.Local;
			if ((Object)(object)player == (Object)null)
			{
				return null;
			}
			foreach (VehicleController item in Object.FindObjectsOfType<VehicleController>().OrderBy(delegate(VehicleController c)
			{
				//IL_0006: 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)
				//IL_001b: 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)
				Vector3 val2 = ((Component)c).transform.position - ((Component)player).transform.position;
				return ((Vector3)(ref val2)).sqrMagnitude;
			}))
			{
				Vector3 val = ((Component)item).transform.InverseTransformPoint(((Component)player).transform.position);
				if (val.x >= -2.2f && val.x <= 2.2f && val.y >= -2f && val.y <= 3f && val.z >= -4f && val.z <= 1.6f)
				{
					return item;
				}
			}
			return null;
		}

		internal static bool TryGetPlayerPosition(out VehicleController? cruiser, out Vector3 localPosition, out string? error)
		{
			//IL_0008: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			cruiser = FindCruiserNearPlayer();
			localPosition = default(Vector3);
			error = null;
			if ((Object)(object)cruiser == (Object)null)
			{
				error = "Stand on the cruiser to use this command.";
				return false;
			}
			PlayerControllerB local = Player.Local;
			if ((Object)(object)local == (Object)null)
			{
				error = "Local player not ready yet.";
				return false;
			}
			localPosition = ((Component)cruiser).transform.InverseTransformPoint(((Component)local).transform.position);
			return true;
		}

		internal static bool TryResolveItemKey(string? query, out string key, out string? error)
		{
			error = null;
			key = "";
			if (string.IsNullOrWhiteSpace(query))
			{
				GrabbableObject val = Player.Local?.currentlyHeldObjectServer;
				if ((Object)(object)val == (Object)null)
				{
					error = "Hold an item or provide its name.";
					return false;
				}
				key = val.Name();
				return true;
			}
			string wanted = Extensions.NormalizeName(query);
			if (string.IsNullOrWhiteSpace(wanted))
			{
				error = "Missing item name.";
				return false;
			}
			HashSet<string> hashSet = KnownItemKeys();
			if (hashSet.Contains(wanted))
			{
				key = wanted;
				return true;
			}
			List<string> list = (from n in hashSet
				where n.Contains(wanted) || n.Replace("_", "").Contains(wanted.Replace("_", ""))
				orderby n
				select n).ToList();
			if (list.Count == 1)
			{
				key = list[0];
				return true;
			}
			if (list.Count > 1)
			{
				error = "Ambiguous item name: " + string.Join(", ", list.Take(8));
				return false;
			}
			key = wanted;
			return true;
		}

		private static HashSet<string> KnownItemKeys()
		{
			HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
			List<Item> list = StartOfRound.Instance?.allItemsList?.itemsList;
			if (list != null)
			{
				foreach (Item item in list)
				{
					if ((Object)(object)item != (Object)null)
					{
						hashSet.Add(item.Name());
					}
				}
			}
			GrabbableObject[] array = Object.FindObjectsOfType<GrabbableObject>();
			foreach (GrabbableObject val in array)
			{
				if ((Object)(object)val != (Object)null && (Object)(object)val.itemProperties != (Object)null)
				{
					hashSet.Add(val.Name());
				}
			}
			return hashSet;
		}

		internal static bool IsExactAvailableItem(string query)
		{
			return KnownItemKeys().Contains(Extensions.NormalizeName(query));
		}

		internal static bool TryStart(out string? error)
		{
			if (!CheckCruiserReady(out VehicleController cruiser, out error) || (Object)(object)cruiser == (Object)null)
			{
				return false;
			}
			List<(string, Vector3, int)> list = CruiserPositions.ListAll(out error);
			if (error != null)
			{
				return false;
			}
			if (list.Count == 0)
			{
				error = "No cruiser positions saved. Use /css [item] [max] while on the cruiser.";
				return false;
			}
			return StartSort(cruiser, list, dropMatchingHeld: false, out error);
		}

		internal static bool TryStartScrapPileAtShipRejoinLocation(out string? error)
		{
			//IL_0067: 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_0085: 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_008d: 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)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			error = null;
			if (!CheckCruiserReady(out VehicleController cruiser, out error) || (Object)(object)cruiser == (Object)null)
			{
				return false;
			}
			GameObject val = GameObject.Find("Environment/HangarShip");
			if ((Object)(object)val == (Object)null)
			{
				error = "Ship not found; cannot locate its rejoin item area.";
				return false;
			}
			Transform[] array = StartOfRound.Instance?.playerSpawnPositions;
			if (array == null || array.Length <= 1 || (Object)(object)array[1] == (Object)null)
			{
				error = "Ship rejoin item area is not available yet.";
				return false;
			}
			Vector3 val2 = array[1].position + new Vector3(0f, 0.5f, 2f);
			Vector3 targetShipLocalPosition = val.transform.InverseTransformPoint(val2);
			return StartScrapPileSort(cruiser, targetShipLocalPosition, out error);
		}

		internal static bool TryStartRule(VehicleController cruiser, string itemKey, Vector3 localPosition, int maximum, out string? error)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			if (!CheckCruiserReady(cruiser, out error))
			{
				return false;
			}
			List<(string, Vector3, int)> rules = new List<(string, Vector3, int)> { (itemKey, localPosition, maximum) };
			return StartSort(cruiser, rules, dropMatchingHeld: true, out error);
		}

		private static bool StartSort(VehicleController cruiser, List<(string itemKey, Vector3 cruiserLocalPos, int maxCount)> rules, bool dropMatchingHeld, out string? error)
		{
			if (Sorter.inProgress)
			{
				error = "Operation in progress.";
				return false;
			}
			if (!TryGetSortHost(out Sorter host, out error) || (Object)(object)host == (Object)null)
			{
				return false;
			}
			Sorter.inProgress = true;
			try
			{
				if (((MonoBehaviour)host).StartCoroutine(SortCruiser(cruiser, rules, dropMatchingHeld)) == null)
				{
					Sorter.inProgress = false;
					error = "Unable to start cruiser sort.";
					return false;
				}
				return true;
			}
			catch (Exception ex)
			{
				Sorter.inProgress = false;
				error = "Unable to start cruiser sort: " + ex.Message;
				Log.Error(error);
				return false;
			}
		}

		private static bool StartScrapPileSort(VehicleController cruiser, Vector3 targetShipLocalPosition, out string? error)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			if (Sorter.inProgress)
			{
				error = "Operation in progress.";
				return false;
			}
			List<GrabbableObject> list = (from item in CruiserCargoItems(cruiser)
				where Eligible(item) && item.itemProperties.isScrap
				select item).ToList();
			if (list.Count == 0)
			{
				error = "No loose scrap found on the cruiser.";
				return false;
			}
			if (!TryGetSortHost(out Sorter host, out error) || (Object)(object)host == (Object)null)
			{
				return false;
			}
			Sorter.inProgress = true;
			try
			{
				if (((MonoBehaviour)host).StartCoroutine(SortScrapPile(cruiser, targetShipLocalPosition, list)) == null)
				{
					Sorter.inProgress = false;
					error = "Unable to start cruiser scrap gather.";
					return false;
				}
				Chat.Print($"Gathering {list.Count} cruiser scrap item(s) at the ship's rejoin item area.", (Color?)null);
				return true;
			}
			catch (Exception ex)
			{
				Sorter.inProgress = false;
				error = "Unable to start cruiser scrap gather: " + ex.Message;
				Log.Error(error);
				return false;
			}
		}

		private static bool TryGetSortHost(out Sorter? host, out string? error)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Expected O, but got Unknown
			host = null;
			error = null;
			try
			{
				if ((Object)(object)Plugin.sorterObject == (Object)null)
				{
					Plugin.sorterObject = new GameObject("PastaSorter");
					Object.DontDestroyOnLoad((Object)(object)Plugin.sorterObject);
				}
				host = Plugin.sorterObject.GetComponent<Sorter>();
				if ((Object)(object)host == (Object)null)
				{
					host = Plugin.sorterObject.AddComponent<Sorter>();
				}
				if ((Object)(object)host == (Object)null || !((Behaviour)host).isActiveAndEnabled)
				{
					error = "Cruiser sorter is not active.";
					return false;
				}
				return true;
			}
			catch (Exception ex)
			{
				error = "Unable to initialize cruiser sorter: " + ex.Message;
				Log.Error(error);
				return false;
			}
		}

		internal static bool CheckCruiserReady(out VehicleController? cruiser, out string? error)
		{
			cruiser = FindNearestCruiser();
			return CheckCruiserReady(cruiser, out error);
		}

		internal static bool CheckCruiserReady(VehicleController? cruiser, out string? error)
		{
			error = null;
			if (Sorter.inProgress)
			{
				error = "Operation in progress.";
				return false;
			}
			if ((Object)(object)cruiser == (Object)null)
			{
				error = "Cruiser not found.";
				return false;
			}
			NetworkObject component = ((Component)cruiser).GetComponent<NetworkObject>();
			if ((Object)(object)component == (Object)null || !component.IsSpawned)
			{
				error = "Cruiser network object not ready yet.";
				return false;
			}
			return true;
		}

		private static bool Eligible(GrabbableObject item)
		{
			if ((Object)(object)item != (Object)null && (Object)(object)item.itemProperties != (Object)null && (Object)(object)((NetworkBehaviour)item).NetworkObject != (Object)null && ((NetworkBehaviour)item).NetworkObject.IsSpawned && item.grabbable && !item.deactivated && !item.isHeld)
			{
				return !item.isPocketed;
			}
			return false;
		}

		private static Transform PlacementParent(VehicleController cruiser)
		{
			PlayerPhysicsRegion componentInChildren = ((Component)cruiser).GetComponentInChildren<PlayerPhysicsRegion>();
			if (!((Object)(object)componentInChildren != (Object)null) || !componentInChildren.allowDroppingItems || !((Object)(object)componentInChildren.physicsTransform != (Object)null))
			{
				return ((Component)cruiser).transform;
			}
			return componentInChildren.physicsTransform;
		}

		internal static bool IsCruiserCargo(GrabbableObject item)
		{
			if ((Object)(object)item == (Object)null || (Object)(object)((Component)item).transform == (Object)null)
			{
				return false;
			}
			if ((Object)(object)((Component)item).GetComponentInParent<VehicleController>() != (Object)null)
			{
				return true;
			}
			if (cargoParentCacheFrame != Time.frameCount)
			{
				cargoParentCacheFrame = Time.frameCount;
				cargoParentCache = (from cruiser in Object.FindObjectsOfType<VehicleController>()
					where (Object)(object)cruiser != (Object)null
					select cruiser).Select(PlacementParent).Distinct().ToArray();
			}
			Transform[] array = cargoParentCache;
			foreach (Transform val in array)
			{
				if ((Object)(object)val != (Object)null && ((Component)item).transform.IsChildOf(val))
				{
					return true;
				}
			}
			return false;
		}

		private static Vector3 PlacementOffset(VehicleController cruiser, Transform parent, Vector3 cruiserLocalPosition)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			return parent.InverseTransformPoint(((Component)cruiser).transform.TransformPoint(cruiserLocalPosition));
		}

		private static List<GrabbableObject> CruiserCargoItems(VehicleController cruiser)
		{
			Transform val = PlacementParent(cruiser);
			return ((Component)cruiser).GetComponentsInChildren<GrabbableObject>().Concat(((Component)val).GetComponentsInChildren<GrabbableObject>()).Distinct()
				.ToList();
		}

		private static Dictionary<string, int> ReservedZoneSlots(VehicleController cruiser, List<(string itemKey, Vector3 cruiserLocalPos, int maxCount)> movingRules)
		{
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.Ordinal);
			HashSet<string> hashSet = new HashSet<string>(movingRules.Select<(string, Vector3, int), string>(((string itemKey, Vector3 cruiserLocalPos, int maxCount) r) => r.itemKey), StringComparer.Ordinal);
			string error;
			List<(string, Vector3, int)> list = CruiserPositions.ListAll(out error);
			if (error != null)
			{
				Log.Warning(error);
				return dictionary;
			}
			List<GrabbableObject> source = CruiserCargoItems(cruiser).Where(Eligible).ToList();
			foreach (var rule in list)
			{
				if (hashSet.Contains(rule.Item1))
				{
					continue;
				}
				string text = ZoneAt(rule.Item2);
				if (text != null)
				{
					int num = source.Count((GrabbableObject item) => item.Name() == rule.Item1);
					if (num > 0)
					{
						dictionary[text] = (dictionary.TryGetValue(text, out var value) ? (value + num) : num);
					}
				}
			}
			return dictionary;
		}

		private static bool IsShipCargo(GrabbableObject item, GameObject? ship)
		{
			if ((Object)(object)ship == (Object)null || (Object)(object)((Component)item).transform == (Object)null)
			{
				return false;
			}
			if (((Component)item).transform.IsChildOf(ship.transform))
			{
				return true;
			}
			if ((Object)(object)((Component)item).transform.parent != (Object)null)
			{
				return ((Object)((Component)item).transform.parent).name == "StorageCloset";
			}
			return false;
		}

		private static Vector3 Placement(Vector3 origin, int index)
		{
			//IL_0000: 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_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: 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_00c0: Unknown result type (might be due to invalid IL or missing references)
			string text = ZoneAt(origin);
			if (text != null && Mathf.Abs(origin.y - Zones[text].y) < 0.001f)
			{
				origin.y += 0.3f;
			}
			GameObject sorterObject = Plugin.sorterObject;
			float num = ((sorterObject == null) ? ((float?)null) : sorterObject.GetComponent<Sorter>()?.sameTypeStackStepY?.Value).GetValueOrDefault();
			if (float.IsNaN(num) || float.IsInfinity(num))
			{
				num = 0f;
			}
			return origin + new Vector3(0f, (float)index * Mathf.Max(0f, num), 0f);
		}

		internal static bool IsShelfSlot(GrabbableObject item, Vector3 cruiserLocalPosition)
		{
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: 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_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)item == (Object)null || (Object)(object)item.itemProperties == (Object)null)
			{
				return false;
			}
			string text = item.Name();
			string error;
			List<(string, Vector3, int)> list = CruiserPositions.ListAll(out error);
			if (error != null)
			{
				Log.Warning(error);
				return false;
			}
			GameObject sorterObject = Plugin.sorterObject;
			float num = ((sorterObject == null) ? ((float?)null) : sorterObject.GetComponent<Sorter>()?.sameTypeStackStepY?.Value).GetValueOrDefault();
			if (float.IsNaN(num) || float.IsInfinity(num))
			{
				num = 0f;
			}
			num = Mathf.Max(0f, num);
			foreach (var item2 in list)
			{
				if (item2.Item1 != text || Mathf.Abs(item2.Item2.x - cruiserLocalPosition.x) >= 0.03f || Mathf.Abs(item2.Item2.z - cruiserLocalPosition.z) >= 0.03f)
				{
					continue;
				}
				string text2 = ZoneAt(item2.Item2);
				float num2 = item2.Item2.y;
				if (text2 != null && Mathf.Abs(num2 - Zones[text2].y) < 0.001f)
				{
					num2 += 0.3f;
				}
				int num3 = ((text2 == null) ? item2.Item3 : ZoneCapacity(text2));
				if (num3 <= 0)
				{
					continue;
				}
				float num4 = cruiserLocalPosition.y - num2;
				if (num <= 0f)
				{
					if (Mathf.Abs(num4) < 0.03f)
					{
						return true;
					}
					continue;
				}
				float num5 = num4 / num;
				if (!(num5 < -0.03f / num) && !(num5 > (float)(num3 - 1) + 0.03f / num))
				{
					int num6 = Mathf.RoundToInt(num5);
					if (num6 >= 0 && num6 < num3 && Mathf.Abs(num4 - (float)num6 * num) < 0.03f)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static bool PlaceOnCruiser(GrabbableObject item, VehicleController cruiser, Vector3 localPosition)
		{
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: 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_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			PlayerControllerB local = Player.Local;
			NetworkObject component = ((Component)cruiser).GetComponent<NetworkObject>();
			if ((Object)(object)local == (Object)null || (Object)(object)component == (Object)null || !component.IsSpawned || !Eligible(item))
			{
				return false;
			}
			Transform val = PlacementParent(cruiser);
			Vector3 val2 = PlacementOffset(cruiser, val, localPosition);
			Transform parent = ((Component)item).transform.parent;
			Vector3 position = ((Component)item).transform.position;
			Quaternion rotation = ((Component)item).transform.rotation;
			float fallTime = item.fallTime;
			bool reachedFloorTarget = item.reachedFloorTarget;
			bool hasHitGround = item.hasHitGround;
			Vector3 targetFloorPosition = item.targetFloorPosition;
			Vector3 startFallingPosition = item.startFallingPosition;
			try
			{
				((Component)item).transform.SetParent(val, true);
				((Component)item).transform.localPosition = val2;
				Vector3 restingRotation = item.itemProperties.restingRotation;
				((Component)item).transform.rotation = ((Component)cruiser).transform.rotation * Quaternion.Euler(restingRotation.x, 0f, restingRotation.z);
				item.fallTime = 1.1f;
				item.reachedFloorTarget = true;
				item.hasHitGround = true;
				item.targetFloorPosition = val2;
				item.startFallingPosition = val2;
				local.PlaceObjectServerRpc(NetworkObjectReference.op_Implicit(((NetworkBehaviour)item).NetworkObject), NetworkObjectReference.op_Implicit(component), val2, true);
			}
			catch (Exception ex)
			{
				((Component)item).transform.SetParent(parent, true);
				((Component)item).transform.position = position;
				((Component)item).transform.rotation = rotation;
				item.fallTime = fallTime;
				item.reachedFloorTarget = reachedFloorTarget;
				item.hasHitGround = hasHitGround;
				item.targetFloorPosition = targetFloorPosition;
				item.startFallingPosition = startFallingPosition;
				Log.Warning("Failed to place '" + item.Name() + "' on cruiser: " + ex.Message);
				return false;
			}
			if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsHost)
			{
				try
				{
					Rigidbody component2 = ((Component)item).GetComponent<Rigidbody>();
					if ((Object)(object)component2 != (Object)null)
					{
						component2.position = val.TransformPoint(val2);
						component2.velocity = Vector3.zero;
						component2.angularVelocity = Vector3.zero;
					}
					Physics.SyncTransforms();
				}
				catch (Exception ex2)
				{
					Log.Warning("Cruiser physics sync failed for '" + item.Name() + "': " + ex2.Message);
				}
			}
			CruiserShelfAnchor.Attach(item, val, ((Component)cruiser).transform);
			return true;
		}

		private static IEnumerator SortCruiser(VehicleController cruiser, List<(string itemKey, Vector3 cruiserLocalPos, int maxCount)> rules, bool dropMatchingHeld)
		{
			Sorter.inProgress = true;
			int placed = 0;
			bool shelfCapacityReached = false;
			try
			{
				Dictionary<string, int> zoneSlots = ReservedZoneSlots(cruiser, rules);
				GrabbableObject droppedHeld = null;
				int heldSlot = -1;
				if (dropMatchingHeld && rules.Count == 1 && (Object)(object)cruiser != (Object)null)
				{
					(string itemKey, Vector3 cruiserLocalPos, int maxCount) rule = rules[0];
					PlayerControllerB player = Player.Local;
					GrabbableObject held = player?.currentlyHeldObjectServer;
					int num = CruiserCargoItems(cruiser).Count((GrabbableObject item2) => Eligible(item2) && item2.Name() == rule.itemKey);
					string text = ZoneAt(rule.cruiserLocalPos);
					int value;
					int num2 = ((text != null && zoneSlots.TryGetValue(text, out value)) ? value : 0);
					if (text != null && (Object)(object)held != (Object)null && held.Name() == rule.itemKey && num < rule.maxCount && num2 + num >= ZoneCapacity(text))
					{
						shelfCapacityReached = true;
					}
					if ((Object)(object)player != (Object)null && (Object)(object)held != (Object)null && held.Name() == rule.itemKey && num < rule.maxCount && (text == null || num2 + num < ZoneCapacity(text)))
					{
						NetworkObject component = ((Component)cruiser).GetComponent<NetworkObject>();
						if ((Object)(object)component != (Object)null && component.IsSpawned && (Object)(object)((NetworkBehaviour)held).NetworkObject != (Object)null && ((NetworkBehaviour)held).NetworkObject.IsSpawned)
						{
							heldSlot = num2 + num;
							bool flag = false;
							try
							{
								using (Sorter.BeginInteractionBypass())
								{
									held.floorYRot = -1;
									Vector3 cruiserLocalPosition = Placement(rule.cruiserLocalPos, heldSlot);
									Transform parent = PlacementParent(cruiser);
									player.DiscardHeldObject(true, component, PlacementOffset(cruiser, parent, cruiserLocalPosition), true);
								}
								flag = true;
							}
							catch (Exception ex)
							{
								Log.Warning("Failed to drop '" + rule.itemKey + "' on cruiser: " + ex.Message);
							}
							if (flag)
							{
								yield return null;
								int frames = 0;
								while (frames++ < 30 && (Object)(object)player != (Object)null && (Object)(object)player.currentlyHeldObjectServer == (Object)(object)held)
								{
									yield return null;
								}
								if ((Object)(object)player != (Object)null && (Object)(object)player.currentlyHeldObjectServer != (Object)(object)held)
								{
									droppedHeld = held;
									int confirmFrames = 0;
									while ((Object)(object)held != (Object)null && (Object)(object)cruiser != (Object)null && (held.isHeld || (!((Component)held).transform.IsChildOf(PlacementParent(cruiser)) && !Eligible(held))) && confirmFrames++ < 30)
									{
										yield return null;
									}
									if ((Object)(object)held != (Object)null && (Object)(object)cruiser != (Object)null && !held.isHeld && ((Component)held).transform.IsChildOf(PlacementParent(cruiser)))
									{
										Transform val = PlacementParent(cruiser);
										Vector3 val2 = PlacementOffset(cruiser, val, Placement(rule.cruiserLocalPos, heldSlot));
										((Component)held).transform.localPosition = val2;
										held.targetFloorPosition = val2;
										held.startFallingPosition = val2;
										held.fallTime = 1.1f;
										held.reachedFloorTarget = true;
										held.hasHitGround = true;
										if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsHost)
										{
											try
											{
												Rigidbody component2 = ((Component)held).GetComponent<Rigidbody>();
												if ((Object)(object)component2 != (Object)null)
												{
													component2.position = val.TransformPoint(val2);
													component2.velocity = Vector3.zero;
													component2.angularVelocity = Vector3.zero;
												}
												Physics.SyncTransforms();
											}
											catch (Exception ex2)
											{
												Log.Warning("Cruiser physics sync failed for held '" + rule.itemKey + "': " + ex2.Message);
											}
										}
										CruiserShelfAnchor.Attach(held, val, ((Component)cruiser).transform);
										placed++;
									}
									else if ((Object)(object)held != (Object)null && (Object)(object)cruiser != (Object)null && Eligible(held) && PlaceOnCruiser(held, cruiser, Placement(rule.cruiserLocalPos, heldSlot)))
									{
										placed++;
									}
									else
									{
										Log.Warning("Could not confirm cruiser placement for held '" + rule.itemKey + "'.");
									}
								}
								else
								{
									Log.Warning("Held '" + rule.itemKey + "' was not released onto the cruiser.");
								}
							}
						}
					}
				}
				if (!Sorter.inProgress || (Object)(object)cruiser == (Object)null || (Object)(object)Player.Local == (Object)null)
				{
					yield break;
				}
				GameObject ship = GameObject.Find("Environment/HangarShip");
				List<GrabbableObject> cruiserItems = (from val3 in CruiserCargoItems(cruiser)
					where (Object)(object)val3 != (Object)(object)droppedHeld && Eligible(val3)
					select val3).ToList();
				bool includeOutsideItems = Ship.ShouldSortAllDetectedItems;
				List<GrabbableObject> sourceItems = (from val3 in Object.FindObjectsOfType<GrabbableObject>()
					where (Object)(object)val3 != (Object)(object)droppedHeld && Eligible(val3) && !IsCruiserCargo(val3) && (includeOutsideItems || IsShipCargo(val3, ship))
					select val3).ToList();
				foreach (var rule2 in rules)
				{
					if (!Sorter.inProgress || (Object)(object)cruiser == (Object)null || (Object)(object)Player.Local == (Object)null || (Keyboard.current != null && ((ButtonControl)Keyboard.current.escapeKey).wasPressedThisFrame))
					{
						yield break;
					}
					int frames = (((Object)(object)droppedHeld != (Object)null && droppedHeld.Name() == rule2.itemKey) ? 1 : 0);
					string zone = ZoneAt(rule2.cruiserLocalPos);
					int value2;
					int confirmFrames = ((zone != null && zoneSlots.TryGetValue(zone, out value2)) ? value2 : 0);
					int num3 = rule2.maxCount - frames;
					if (zone != null)
					{
						int num4 = Math.Max(0, ZoneCapacity(zone) - confirmFrames - frames);
						if (num3 > num4)
						{
							num3 = num4;
							shelfCapacityReached = true;
						}
					}
					List<GrabbableObject> list = cruiserItems.Where((GrabbableObject item2) => item2.Name() == rule2.itemKey).Take(num3).ToList();
					int count = num3 - list.Count;
					List<GrabbableObject> second = sourceItems.Where((GrabbableObject item2) => item2.Name() == rule2.itemKey).Take(count).ToList();
					List<GrabbableObject> selected = list.Concat(second).ToList();
					for (int index = 0; index < selected.Count; index++)
					{
						if (!Sorter.inProgress || (Object)(object)cruiser == (Object)null || (Object)(object)Player.Local == (Object)null || (Keyboard.current != null && ((ButtonControl)Keyboard.current.escapeKey).wasPressedThisFrame))
						{
							yield break;
						}
						GrabbableObject item = selected[index];
						int num5 = confirmFrames + index;
						if (frames > 0 && num5 >= heldSlot)
						{
							num5++;
						}
						if (Eligible(item) && PlaceOnCruiser(item, cruiser, Placement(rule2.cruiserLocalPos, num5)))
						{
							placed++;
						}
						yield return null;
					}
					if (zone != null)
					{
						zoneSlots[zone] = confirmFrames + selected.Count + frames;
					}
				}
			}
			finally
			{
				Sorter.inProgress = false;
				Chat.Print($"Cruiser sort finished: placed {placed} item(s)." + (shelfCapacityReached ? $" Shelf zones are limited to {20} items each (D2: 1)." : ""), (Color?)null);
			}
		}

		private static IEnumerator SortScrapPile(VehicleController cruiser, Vector3 targetShipLocalPosition, List<GrabbableObject> scrap)
		{
			//IL_000e: 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)
			int moved = 0;
			int failed = 0;
			try
			{
				for (int index = 0; index < scrap.Count; index++)
				{
					if (!Sorter.inProgress)
					{
						break;
					}
					if ((Object)(object)cruiser == (Object)null)
					{
						break;
					}
					if ((Object)(object)Player.Local == (Object)null)
					{
						break;
					}
					if (Keyboard.current != null && ((ButtonControl)Keyboard.current.escapeKey).wasPressedThisFrame)
					{
						break;
					}
					GrabbableObject val = scrap[index];
					if (Eligible(val) && val.itemProperties.isScrap && MoveUtils.MoveItemOnShipLocal(val, targetShipLocalPosition, val.floorYRot))
					{
						moved++;
					}
					else
					{
						failed++;
					}
					yield return null;
				}
			}
			finally
			{
				Sorter.inProgress = false;
				Chat.Print($"Cruiser scrap gather finished: moved {moved} item(s) to the ship" + ((failed > 0) ? $", skipped {failed}." : "."), (Color?)null);
			}
		}
	}
	public sealed class CruiserSetCommand : QuickSortCommand
	{
		public override string Name => "css";

		public override string Description => "Save a cruiser position, then immediately place that item type up to its maximum.\nUsage: /css test, /css [item] [max=10], /css <zone> [item] [max=10], /css zones, /css list, /css reset [item]";

		protected override bool InvokeParsed(string[] args, out string? error)
		{
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0224: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_0255: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0253: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0305: Unknown result type (might be due to invalid IL or missing references)
			error = null;
			if (args.Length != 0 && string.Equals(args[0], "help", StringComparison.OrdinalIgnoreCase))
			{
				Chat.Print(((BaseCommand)this).Description, (Color?)null);
				return true;
			}
			if (args.Length != 0 && string.Equals(args[0], "test", StringComparison.OrdinalIgnoreCase))
			{
				if (args.Length != 1)
				{
					error = "Usage: /css test (gathers cruiser scrap to the ship's rejoin item area).";
					return false;
				}
				return CruiserSorter.TryStartScrapPileAtShipRejoinLocation(out error);
			}
			if (args.Length != 0 && string.Equals(args[0], "list", StringComparison.OrdinalIgnoreCase))
			{
				List<(string, Vector3, int)> list = CruiserPositions.ListAll(out error);
				if (error != null)
				{
					return false;
				}
				Chat.Print((list.Count == 0) ? "No cruiser positions saved." : string.Join(", ", list.Select<(string, Vector3, int), string>(delegate((string itemKey, Vector3 cruiserLocalPos, int maxCount) r)
				{
					//IL_0001: 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_0025: Unknown result type (might be due to invalid IL or missing references)
					//IL_0035: Unknown result type (might be due to invalid IL or missing references)
					string arg = CruiserSorter.ZoneAt(r.cruiserLocalPos) ?? $"({r.cruiserLocalPos.x:F1},{r.cruiserLocalPos.y:F1},{r.cruiserLocalPos.z:F1})";
					return $"{r.itemKey}={r.maxCount}@{arg}";
				})), (Color?)null);
				return true;
			}
			if (args.Length != 0 && string.Equals(args[0], "zones", StringComparison.OrdinalIgnoreCase))
			{
				Chat.Print("Cruiser zones: A1-A3, B1-B3, C1-C3, D1-D3, E1-E3, F1-F3, G1-G3. Side shelves: 1=bottom, 2=middle, 3=top. Use /css A2 [item] [max].", (Color?)null);
				return true;
			}
			if (args.Length != 0 && string.Equals(args[0], "reset", StringComparison.OrdinalIgnoreCase))
			{
				if (!CruiserSorter.TryResolveItemKey((args.Length > 1) ? string.Join(" ", args.Skip(1)) : null, out string key, out error))
				{
					return false;
				}
				if (!CruiserPositions.Remove(key, out var removed, out error))
				{
					return false;
				}
				Chat.Print(removed ? ("Removed cruiser position for " + key + ".") : ("No cruiser position for " + key + "."), (Color?)null);
				return true;
			}
			string zoneName = null;
			Vector3 position = default(Vector3);
			string[] array = args;
			string zoneName2;
			Vector3 position2;
			string zoneName3;
			Vector3 position3;
			if (args.Length != 0 && (string.Equals(args[0], "shelf", StringComparison.OrdinalIgnoreCase) || string.Equals(args[0], "zone", StringComparison.OrdinalIgnoreCase)))
			{
				if (args.Length < 2 || !CruiserSorter.TryGetZone(args[1], out zoneName, out position))
				{
					error = "Usage: /css shelf <A1-G3 zone> [item name] [max=10]. Use /css zones to list zones.";
					return false;
				}
				array = args.Skip(2).ToArray();
			}
			else if (args.Length != 0 && CruiserSorter.TryGetZone(args[0], out zoneName2, out position2))
			{
				zoneName = zoneName2;
				position = position2;
				array = args.Skip(1).ToArray();
			}
			else if (args.Length != 0 && !CruiserSorter.IsExactAvailableItem(string.Join(" ", args)) && CruiserSorter.TryGetZone(args[^1], out zoneName3, out position3))
			{
				zoneName = zoneName3;
				position = position3;
				array = args.Take(args.Length - 1).ToArray();
			}
			if (!CruiserSorter.TryGetPlayerPosition(out VehicleController cruiser, out Vector3 localPosition, out error) || (Object)(object)cruiser == (Object)null)
			{
				return false;
			}
			if (zoneName != null)
			{
				localPosition = position;
			}
			localPosition += Vector3.up * 0.3f;
			int num = 10;
			string[] array2 = array;
			if (array.Length != 0 && !CruiserSorter.IsExactAvailableItem(string.Join(" ", array)) && int.TryParse(array[^1], out var result))
			{
				num = result;
				array2 = array.Take(array.Length - 1).ToArray();
			}
			if (num <= 0 || num > 10000)
			{
				error = "Maximum must be between 1 and 10000.";
				return false;
			}
			if (!CruiserSorter.TryResolveItemKey((array2.Length != 0) ? string.Join(" ", array2) : null, out string key2, out error))
			{
				return false;
			}
			if (!CruiserSorter.CheckCruiserReady(cruiser, out error))
			{
				return false;
			}
			if (!CruiserPositions.Set(key2, localPosition, num, out error))
			{
				return false;
			}
			if (!CruiserSorter.TryStartRule(cruiser, key2, localPosition, num, out error))
			{
				Log.Warning("Cruiser position for '" + key2 + "' was saved, but placement could not start: " + error);
				return false;
			}
			Chat.Print($"Cruiser position saved: {key2}, max {num}" + ((zoneName == null) ? "." : (" at " + zoneName + ".")) + " Placing items now.", (Color?)null);
			return true;
		}
	}
	public sealed class CruiserSortCommand : QuickSortCommand
	{
		public override string Name => "csort";

		public override string[] Commands => new string[2] { "csort", "cs" };

		public override string Description => "Sort cruiser cargo up to each saved maximum. Usage: /csort or /cs.";

		protected override bool InvokeParsed(string[] args, out string? error)
		{
			return CruiserSorter.TryStart(out error);
		}
	}
	public static class Extensions
	{
		private static readonly Dictionary<string, string> NameAliases = BuildNameAliases();

		private static string NormalizeKeyNoAlias(string s)
		{
			if (string.IsNullOrWhiteSpace(s))
			{
				return "";
			}
			return s.Trim().ToLowerInvariant().Replace(" ", "_")
				.Replace("-", "_");
		}

		private static Dictionary<string, string> BuildNameAliases()
		{
			Dictionary<string, string> d = new Dictionary<string, string>();
			(string, string[])[] array = new(string, string[])[19]
			{
				("boombox", new string[1] { "붐박스" }),
				("flashlight", new string[1] { "손전등" }),
				("jetpack", new string[1] { "제트팩" }),
				("key", new string[1] { "열쇠" }),
				("lockpicker", new string[1] { "자물쇠 따개" }),
				("apparatus", new string[2] { "장치", "apparatice" }),
				("pro_flashlight", new string[2] { "프로 손전등", "pro-flashlight" }),
				("shovel", new string[1] { "철제 삽" }),
				("stun_grenade", new string[2] { "기절 수류탄", "stun grenade" }),
				("extension_ladder", new string[2] { "연장형 사다리", "extension ladder" }),
				("tzp_inhalant", new string[2] { "tzp-흡입제", "tzp-inhalant" }),
				("walkie_talkie", new string[2] { "무전기", "walkie-talkie" }),
				("zap_gun", new string[2] { "잽건", "zap gun" }),
				("radar_booster", new string[3] { "레이더 부스터", "radar booster", "radar-booster" }),
				("spray_paint", new string[3] { "페인트 스프레이", "스프레이 페인트", "spray paint" }),
				("shotgun", new string[4] { "산탄총", "더블 배럴", "double barrel", "double_barrel" }),
				("ammo", new string[4] { "탄약", "산탄총 탄약", "shotgun shell", "shotgun_shell" }),
				("clipboard", new string[1] { "클립보드" }),
				("sticky_note", new string[3] { "스티커 메모", "스티커메모", "sticky note" })
			};
			for (int i = 0; i < array.Length; i++)
			{
				(string, string[]) tuple = array[i];
				AddAliases(tuple.Item1, tuple.Item2);
			}
			array = new(string, string[])[9]
			{
				("coffee_mug", new string[4] { "mug", "머그잔", "coffee mug", "커피 머그잔" }),
				("hair_brush", new string[3] { "brush", "hair brush", "빗" }),
				("brass_bell", new string[4] { "bell", "brass bell", "황동 종", "종" }),
				("bee_hive", new string[3] { "hive", "bee hive", "벌집" }),
				("wedding_ring", new string[3] { "ring", "wedding ring", "반지" }),
				("robot_toy", new string[4] { "toy robot", "robot toy", "장난감 로봇", "로봇 장난감" }),
				("rubber_ducky", new string[2] { "rubber ducky", "고무 오리" }),
				("tattered_metal_sheet", new string[4] { "metal sheet", "tattered metal sheet", "금속 판", "너덜너덜한 금속 판" }),
				("homemade_flashbang", new string[2] { "homemade flashbang", "사제 섬광탄" })
			};
			for (int i = 0; i < array.Length; i++)
			{
				(string, string[]) tuple2 = array[i];
				AddAliases(tuple2.Item1, tuple2.Item2);
			}
			array = new(string, string[])[31]
			{
				("bubblegun", new string[1] { "비눗방울 총" }),
				("broken_p88", new string[2] { "망가진 p88", "broken p88" }),
				("employee", new string[1] { "직원" }),
				("mine", new string[1] { "지뢰" }),
				("toothles", new string[2] { "투슬리스", "toothles" }),
				("crossbow", new string[2] { "석궁", "crossbow" }),
				("physgun", new string[2] { "피직스건", "physgun" }),
				("ammo_crate", new string[2] { "탄약 상자", "ammo crate" }),
				("drink", new string[1] { "음료수" }),
				("radio", new string[1] { "라디오" }),
				("mouse", new string[1] { "마우스" }),
				("monitor", new string[1] { "모니터" }),
				("battery", new string[1] { "건전지" }),
				("cannon", new string[1] { "대포" }),
				("health_drink", new string[2] { "건강 음료", "health drink" }),
				("chemical", new string[1] { "화학 약품" }),
				("disinfecting_alcohol", new string[2] { "소독용 알코올", "disinfecting alcohol" }),
				("ampoule", new string[1] { "앰풀" }),
				("blood_pack", new string[2] { "혈액 팩", "blood pack" }),
				("flip_lighter", new string[2] { "라이터", "flip lighter" }),
				("rubber_ball", new string[2] { "고무 공", "rubber ball" }),
				("video_tape", new string[2] { "비디오 테이프", "video tape" }),
				("first_aid_kit", new string[2] { "구급 상자", "first aid kit" }),
				("gold_medallion", new string[2] { "금메달", "gold medallion" }),
				("steel_pipe", new string[2] { "금속 파이프", "steel pipe" }),
				("axe", new string[1] { "도끼" }),
				("emergency_hammer", new string[2] { "비상용 망치", "emergency hammer" }),
				("katana", new string[1] { "카타나" }),
				("silver_medallion", new string[2] { "은메달", "silver medallion" }),
				("pocket_radio", new string[2] { "휴대용 라디오", "pocket radio" }),
				("teddy_plush", new string[2] { "곰 인형", "teddy plush" })
			};
			for (int i = 0; i < array.Length; i++)
			{
				(string, string[]) tuple3 = array[i];
				AddAliases(tuple3.Item1, tuple3.Item2);
			}
			Add("마법의 7번 공", "Magic 7 ball");
			Add("에어혼", "Airhorn");
			Add("황동 종", "Brass bell");
			Add("큰 나사", "Big bolt");
			Add("병 묶음", "Bottles");
			Add("빗", "Hair brush");
			Add("사탕", "Candy");
			Add("금전 등록기", "Cash register");
			Add("화학 용기", "Chemical jug");
			Add("광대 나팔", "Clown horn");
			Add("대형 축", "Large axle");
			Add("틀니", "Teeth");
			Add("쓰레받기", "Dust pan");
			Add("달걀 거품기", "Egg beater");
			Add("v형 엔진", "V-type engine");
			Add("황금 컵", "Golden cup");
			Add("멋진 램프", "Fancy lamp");
			Add("그림", "Painting");
			Add("플라스틱 물고기", "Plastic fish");
			Add("레이저 포인터", "Laser pointer");
			Add("금 주괴", "Gold Bar");
			Add("헤어 드라이기", "Hairdryer");
			Add("돋보기", "Magnifying glass");
			Add("너덜너덜한 금속 판", "Tattered metal sheet");
			Add("쿠키 틀", "Cookie mold pan");
			Add("머그잔", "Coffee mug");
			Add("커피 머그잔", "Coffee mug");
			Add("향수 병", "Perfume bottle");
			Add("구식 전화기", "Old phone");
			Add("피클 병", "Jar of pickles");
			Add("약 병", "Pill bottle");
			Add("리모컨", "Remote");
			Add("결혼 반지", "Wedding ring");
			Add("로봇 장난감", "Robot Toy");
			Add("고무 오리", "Rubber ducky");
			Add("빨간색 소다", "Red soda");
			Add("운전대", "Steering wheel");
			Add("정지 표지판", "Stop sign");
			Add("찻주전자", "Tea Kettle");
			Add("치약", "Toothpaste");
			Add("장난감 큐브", "Toy cube");
			Add("벌집", "Bee hive");
			Add("양보 표지판", "Yield sign");
			Add("산탄총", "Shotgun");
			Add("더블 배럴", "Double-barrel");
			Add("산탄총 탄약", "ammo");
			Add("탄약", "ammo");
			Add("사제 섬광탄", "Homemade Flashbang");
			Add("선물", "Gift");
			Add("선물 상자", "Gift box");
			Add("플라스크", "Flask");
			Add("비극", "Tragedy");
			Add("희극", "Comedy");
			Add("방귀 쿠션", "Whoopie cushion");
			Add("방퀴 쿠션", "Whoopie cushion");
			Add("식칼", "Kitchen knife");
			Add("부활절 달걀", "Easter egg");
			Add("제초제", "Weed killer");
			Add("벨트 배낭", "Belt bag");
			Add("축구공", "Soccer ball");
			Add("조작 패드", "Control pad");
			Add("쓰레기통 뚜껑", "Garbage lid");
			Add("플라스틱 컵", "Plastic cup");
			Add("화장실 휴지", "Toilet paper");
			Add("장난감 기차", "Toy train");
			Add("제드 도그", "Zed Dog");
			Add("시계", "Clock");
			Add("시체", "Body");
			Add("알", "Egg");
			Add("열쇠", "Key");
			Add("데이터 칩", "Data chip");
			Add("교육용 지침서", "Training manual");
			Add("장치", "Apparatus");
			Add("장치", "Apparatice");
			Add("알코올 플라스크", "Alcohol Flask");
			Add("모루", "Anvil");
			Add("야구 방망이", "Baseball bat");
			Add("맥주 캔", "Beer can");
			Add("벽돌", "Brick");
			Add("망가진 엔진", "Broken engine");
			Add("양동이", "Bucket");
			Add("페인트 캔", "Can paint");
			Add("수통", "Canteen");
			Add("자동차 배터리", "Car battery");
			Add("조임틀", "Clamp");
			Add("멋진 그림", "Fancy Painting");
			Add("선풍기", "Fan");
			Add("소방 도끼", "Fireaxe");
			Add("소화기", "Fire extinguisher");
			Add("소화전", "Fire hydrant");
			Add("통조림", "Food can");
			Add("게임보이", "Gameboy");
			Add("쓰레기", "Garbage");
			Add("망치", "Hammer");
			Add("기름통", "Jerrycan");
			Add("키보드", "Keyboard");
			Add("랜턴", "Lantern");
			Add("도서관 램프", "Library lamp");
			Add("식물", "Plant");
			Add("플라이어", "Pliers");
			Add("뚫어뻥", "Plunger");
			Add("레트로 장난감", "Retro Toy");
			Add("스크류 드라이버", "Screwdriver");
			Add("싱크대", "Sink");
			Add("소켓 렌치", "Socket Wrench");
			Add("여행 가방", "Suitcase");
			Add("토스터기", "Toaster");
			Add("공구 상자", "Toolbox");
			Add("실크햇", "Top hat");
			Add("라바콘", "Traffic cone");
			Add("환풍구", "Vent");
			Add("물뿌리개", "Watering Can");
			Add("바퀴", "Wheel");
			Add("와인 병", "Wine bottle");
			Add("렌치", "Wrench");
			Add("자수정 군집", "Amethyst Cluster");
			Add("주사기", "Syringe");
			Add("주사기총", "Syringe Gun");
			Add("코너 파이프", "Corner Pipe");
			Add("작은 파이프", "Small Pipe");
			Add("파이프", "Flow Pipe");
			Add("뇌가 담긴 병", "Brain Jar");
			Add("호두까기 인형 장난감", "Toy Nutcracker");
			Add("시험관", "Test Tube");
			Add("시험관 랙", "Test Tube Rack");
			Add("호두까기 인형 눈", "Nutcracker Eye");
			Add("파란색 시험관", "Blue Test Tube");
			Add("노란색 시험관", "Yellow Test Tube");
			Add("빨간색 시험관", "Red Test Tube");
			Add("초록색 시험관", "Green Test Tube");
			Add("쇠지렛대", "Crowbar");
			Add("플젠", "Plzen");
			Add("컵", "Cup");
			Add("전자레인지", "Microwave");
			Add("hyper acid 실험 기록", "Experiment Log Hyper Acid");
			Add("희극 가면 실험 기록", "Experiment Log Comedy Mask");
			Add("저주받은 동전 실험 기록", "Experiment Log Cursed Coin");
			Add("바이오 hxnv7 실험 기록", "Experiment Log BIO HXNV7");
			Add("파란색 폴더", "Blue Folder");
			Add("빨간색 폴더", "Red Folder");
			Add("코일", "Coil");
			Add("타자기", "Typewriter");
			Add("서류 더미", "Documents");
			Add("스테이플러", "Stapler");
			Add("구식 컴퓨터", "Old Computer");
			Add("브론즈 트로피", "Bronze Trophy");
			Add("바나나", "Banana");
			Add("스턴봉", "Stun Baton");
			Add("바이오-hxnv7", "BIO-HXNV7");
			Add("복구된 비밀 일지", "Recovered Secret Log");
			Add("황금 단검 실험 기록", "Experiment Log Golden Dagger");
			Add("대합", "Clam");
			Add("거북이 등딱지", "Turtle Shell");
			Add("생선 뼈", "Fish Bones");
			Add("뿔 달린 껍질", "Horned Shell");
			Add("도자기 찻잔", "Porcelain Teacup");
			Add("대리석", "Marble");
			Add("도자기 병", "Porcelain Bottle");
			Add("도자기 향수 병", "Porcelain Perfume Bottle");
			Add("발광구", "Glowing Orb");
			Add("황금 해골", "Golden Skull");
			Add("코스모코스 지도", "Map of Cosmocos");
			Add("젖은 노트 1", "Wet Note 1");
			Add("젖은 노트 2", "Wet Note 2");
			Add("젖은 노트 3", "Wet Note 3");
			Add("젖은 노트 4", "Wet Note 4");
			Add("우주빛 파편", "Cosmic Shard");
			Add("우주 생장물", "Cosmic Growth");
			Add("천상의 두뇌 덩어리", "Chunk of Celestial Brain");
			Add("파편이 든 양동이", "Bucket of Shards");
			Add("우주빛 손전등", "Cosmic Flashlight");
			Add("잊혀진 일지 1", "Forgotten Log 1");
			Add("잊혀진 일지 2", "Forgotten Log 2");
			Add("잊혀진 일지 3", "Forgotten Log 3");
			Add("안경", "Glasses");
			Add("생장한 배양 접시", "Grown Petri Dish");
			Add("배양 접시", "Petri Dish");
			Add("코스모채드", "Cosmochad");
			Add("죽어가는 우주빛 손전등", "Dying Cosmic Flashlight");
			Add("죽어가는 우주 생장물", "Dying Cosmic Growth");
			Add("혈액 배양 접시", "Blood Petri Dish");
			Add("악마 코스모채드", "Evil Cosmochad");
			Add("악마 코스모", "Evil Cosmo");
			Add("릴 코스모", "Lil Cosmo");
			Add("죽어가는 생장물 배양 접시", "Dying Grown Petri Dish");
			Add("감시하는 배양 접시", "Watching Petri Dish");
			Add("현미경", "Microscope");
			Add("원통형 바일", "Round Vile");
			Add("사각형 바일", "Square Vile");
			Add("타원형 바일", "Oval Vile");
			Add("해링턴 일지 1", "Harrington Log 1");
			Add("해링턴 일지 2", "Harrington Log 2");
			Add("해링턴 일지 3", "Harrington Log 3");
			Add("해링턴 일지 4", "Harrington Log 4");
			Add("생장물이 든 병", "Jar of Growth");
			Add("테이프 플레이어 일지 1", "Tape Player Log 1");
			Add("테이프 플레이어 일지 2", "Tape Player Log 2");
			Add("테이프 플레이어 일지 3", "Tape Player Log 3");
			Add("테이프 플레이어 일지 4", "Tape Player Log 4");
			Add("쇼핑 카트", "Shopping Cart");
			return d;
			void Add(string localized, string canonical)
			{
				string text = NormalizeKeyNoAlias(localized);
				string value = NormalizeKeyNoAlias(canonical);
				if (!string.IsNullOrWhiteSpace(text) && !string.IsNullOrWhiteSpace(value) && !d.ContainsKey(text))
				{
					d.Add(text, value);
				}
			}
			void AddAliases(string canonicalKey, params string[] aliases)
			{
				Add(canonicalKey, canonicalKey);
				if (aliases != null)
				{
					for (int j = 0; j < aliases.Length; j++)
					{
						Add(aliases[j], canonicalKey);
					}
				}
			}
		}

		public static string NormalizeName(string s)
		{
			string text = NormalizeKeyNoAlias(s);
			if (!NameAliases.TryGetValue(text, out string value))
			{
				return text;
			}
			return value;
		}

		public static string Name(this GrabbableObject item)
		{
			return NormalizeName(item.itemProperties.itemName);
		}

		public static string Name(this Item item)
		{
			return NormalizeName(item.itemName);
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "BeginGrabObject")]
	internal static class GrabPatch
	{
		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator ilGenerator)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Expected O, but got Unknown
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected O, but got Unknown
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Expected O, but got Unknown
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Expected O, but got Unknown
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Expected O, but got Unknown
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Expected O, but got Unknown
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Expected O, but got Unknown
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Expected O, but got Unknown
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Expected O, but got Unknown
			List<CodeInstruction> list = new List<CodeInstruction>(instructions);
			CodeMatcher val = new CodeMatcher((IEnumerable<CodeInstruction>)list, ilGenerator);
			CodeInstruction val2 = null;
			MethodInfo methodInfo = AccessTools.Method(typeof(NetworkBehaviour), "get_NetworkObject", (Type[])null, (Type[])null);
			for (int i = 0; i < list.Count - 1; i++)
			{
				CodeInstruction val3 = list[i];
				if (val3.opcode == OpCodes.Callvirt && val3.operand is MethodInfo methodInfo2 && methodInfo2 == methodInfo)
				{
					CodeInstruction val4 = list[i + 1];
					if (IsStloc(val4.opcode))
					{
						val2 = val4.Clone();
						break;
					}
				}
			}
			if (val2 == null)
			{
				val2 = new CodeInstruction(OpCodes.Stloc_0, (object)null);
			}
			Label label = default(Label);
			return val.MatchForward(true, (CodeMatch[])(object)new CodeMatch[1]
			{
				new CodeMatch((OpCode?)OpCodes.Callvirt, (object)AccessTools.Method(typeof(GrabbableObject), "InteractItem", (Type[])null, (Type[])null), (string)null)
			}).MatchBack(true, (CodeMatch[])(object)new CodeMatch[1]
			{
				new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null)
			}).Insert((CodeInstruction[])(object)new CodeInstruction[4]
			{
				new CodeInstruction(OpCodes.Ldarg_0, (object)null),
				new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(PlayerControllerB), "currentlyGrabbingObject")),
				new CodeInstruction(OpCodes.Callvirt, (object)methodInfo),
				val2
			})
				.ThrowIfInvalid("QuickSort: BeginGrabObject pattern not found (InteractItem)")
				.CreateLabel(ref label)
				.Start()
				.Insert((CodeInstruction[])(object)new CodeInstruction[2]
				{
					new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(Player), "OverrideGrabbingObject", (Type[])null, (Type[])null)),
					new CodeInstruction(OpCodes.Brtrue, (object)label)
				})
				.InstructionEnumeration();
		}

		private static bool IsStloc(OpCode op)
		{
			if (!(op == OpCodes.Stloc) && !(op == OpCodes.Stloc_S) && !(op == OpCodes.Stloc_0) && !(op == OpCodes.Stloc_1) && !(op == OpCodes.Stloc_2))
			{
				return op == OpCodes.Stloc_3;
			}
			return true;
		}
	}
	internal static class InteractionLockPatch
	{
		[HarmonyPatch(typeof(PlayerControllerB), "BeginGrabObject")]
		[HarmonyPrefix]
		private static bool BlockBeginGrabObject()
		{
			if (!Sorter.IsInteractionLocked)
			{
				return true;
			}
			if (Sorter.IsInteractionBypassActive)
			{
				return true;
			}
			return false;
		}

		[HarmonyPatch(typeof(PlayerControllerB), "DiscardHeldObject")]
		[HarmonyPrefix]
		private static bool BlockDiscardHeldObject()
		{
			if (!Sorter.IsInteractionLocked)
			{
				return true;
			}
			if (Sorter.IsInteractionBypassActive)
			{
				return true;
			}
			return false;
		}
	}
	public class Log
	{
		private static ManualLogSource _log;

		public static void Init(ManualLogSource log)
		{
			_log = log;
		}

		public static void NotifyPlayer(string header, string body = "", bool isWarning = false)
		{
			if ((Object)(object)HUDManager.Instance != (Object)null)
			{
				HUDManager.Instance.DisplayTip(header, body, isWarning, false, "LC_Tip1");
			}
			Debug(header);
			Debug(body);
		}

		public static void Chat(string body, string color = "FFFFFF")
		{
			if ((Object)(object)HUDManager.Instance != (Object)null)
			{
				HUDManager.Instance.AddChatMessage("<color=#" + color + ">[Pasta] " + body + "</color>", "", -1, false);
			}
			Debug(body);
		}

		public static void ConfirmSound()
		{
			if ((Object)(object)HUDManager.Instance != (Object)null && (Object)(object)GameNetworkManager.Instance != (Object)null)
			{
				HUDManager.Instance.UIAudio.PlayOneShot(GameNetworkManager.Instance.buttonTuneSFX);
			}
		}

		public static void Exception(Exception e)
		{
			string message = e.Message;
			string stackTrace = e.StackTrace;
			_log.LogError((object)message);
			_log.LogError((object)stackTrace);
		}

		public static void Error(params object[] objects)
		{
			_log.LogError((object)string.Join(" ", objects));
		}

		public static void Warning(params object[] objects)
		{
			_log.LogWarning((object)string.Join(" ", objects));
		}

		public static void Info(params object[] objects)
		{
			_log.LogInfo((object)string.Join(" ", objects));
		}

		public static void Debug(params object[] objects)
		{
			_log.LogDebug((object)string.Join(" ", objects));
		}
	}
	internal static class MoveUtils
	{
		private static bool ShouldAvoidHeldSideEffects(PlayerControllerB player, GrabbableObject targetItem)
		{
			if ((Object)(object)player == (Object)null)
			{
				return true;
			}
			if ((Object)(object)targetItem == (Object)null)
			{
				return true;
			}
			GrabbableObject currentlyHeldObjectServer = player.currentlyHeldObjectServer;
			if ((Object)(object)currentlyHeldObjectServer != (Object)null)
			{
				return (Object)(object)currentlyHeldObjectServer != (Object)(object)targetItem;
			}
			return false;
		}

		public static bool MoveItemOnShip(GrabbableObject item, Vector3 worldPos, int floorYRot = -1)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: 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_0072: 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_0063: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)item == (Object)null)
			{
				return false;
			}
			PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController;
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			GameObject val2 = GameObject.Find("Environment/HangarShip");
			if ((Object)(object)val2 == (Object)null)
			{
				return false;
			}
			Vector3 val3 = val2.transform.InverseTransformPoint(worldPos);
			((Component)item).transform.position = worldPos;
			if (!ShouldAvoidHeldSideEffects(val, item))
			{
				val.SetObjectAsNoLongerHeld(true, true, val3, item, floorYRot);
			}
			val.ThrowObjectServerRpc(NetworkObjectReference.op_Implicit(((NetworkBehaviour)item).NetworkObject), true, true, val3, floorYRot);
			return true;
		}

		public static bool MoveItemOnShipLocal(GrabbableObject item, Vector3 shipLocalPos, int floorYRot = -1)
		{
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: 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_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: 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_004b: 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)
			if ((Object)(object)item == (Object)null)
			{
				return false;
			}
			PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController;
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			GameObject val2 = GameObject.Find("Environment/HangarShip");
			if ((Object)(object)val2 == (Object)null)
			{
				return false;
			}
			((Component)item).transform.position = val2.transform.TransformPoint(shipLocalPos);
			try
			{
				if (!ShouldAvoidHeldSideEffects(val, item))
				{
					val.SetObjectAsNoLongerHeld(true, true, shipLocalPos, item, floorYRot);
				}
			}
			catch
			{
			}
			try
			{
				val.PlaceGrabbableObject(val2.transform, shipLocalPos, false, item);
				CruiserShelfAnchor.Detach(item);
				val.PlaceObjectServerRpc(NetworkObjectReference.op_Implicit(((NetworkBehaviour)item).NetworkObject), NetworkObjectReference.op_Implicit(val2), shipLocalPos, false);
			}
			catch
			{
				try
				{
					val.ThrowObjectServerRpc(NetworkObjectReference.op_Implicit(((NetworkBehaviour)item).NetworkObject), true, true, shipLocalPos, floorYRot);
				}
				catch
				{
					return false;
				}
			}
			return true;
		}

		public static bool TryTeleportToWorld(GameObject go, Vector3 worldPos, Quaternion worldRot)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			GrabbableObject val = (((Object)(object)go != (Object)null) ? go.GetComponent<GrabbableObject>() : null);
			if ((Object)(object)val != (Object)null)
			{
				return MoveItemOnShip(val, worldPos, val.floorYRot);
			}
			if ((Object)(object)go == (Object)null)
			{
				return false;
			}
			go.transform.SetPositionAndRotation(worldPos, worldRot);
			return true;
		}
	}
	public static class Player
	{
		public static GrabbableObject overrideObject;

		public static PlayerControllerB Local => StartOfRound.Instance?.localPlayerController;

		public static bool CanGrabObject(GrabbableObject item)
		{
			if ((Object)(object)item == (Object)null || !item.grabbable || item.deactivated || item.isHeld || item.isPocketed)
			{
				return false;
			}
			if ((Object)(object)Local == (Object)null || Local.isPlayerDead || Local.isTypingChat || Local.inTerminalMenu || Local.throwingObject || Local.IsInspectingItem || Local.isGrabbingObjectAnimation || (Object)(object)Local.inAnimationWithEnemy != (Object)null || Local.inSpecialInteractAnimation || Local.jetpackControls || Local.disablingJetpackControls || Local.activatingItem || Local.waitingToDropItem || Local.FirstEmptyItemSlot((GrabbableObject)null) == -1)
			{
				return false;
			}
			return true;
		}

		public static bool OverrideGrabbingObject()
		{
			if ((Object)(object)overrideObject == (Object)null)
			{
				return false;
			}
			Local.currentlyGrabbingObject = overrideObject;
			overrideObject = null;
			return true;
		}

		public static IEnumerator StartGrabbingObject(GrabbableObject grabbableObject)
		{
			if (CanGrabObject(grabbableObject))
			{
				overrideObject = grabbableObject;
				Local.BeginGrabObject();
				yield return Local.grabObjectCoroutine;
			}
		}

		public static IEnumerator StartMovingObject(GrabbableObject item, Vector3 position, NetworkObject? parent = null)
		{
			//IL_000e: 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)
			yield return StartGrabbingObject(item);
			if ((Object)(object)Local == (Object)null)
			{
				yield break;
			}
			int frames = 0;
			while (frames < 30 && ((Object)(object)Local.currentlyHeldObjectServer == (Object)null || (Object)(object)Local.currentlyHeldObjectServer != (Object)(object)item))
			{
				frames++;
				yield return null;
			}
			if ((Object)(object)Local.currentlyHeldObjectServer == (Object)null || (Object)(object)Local.currentlyHeldObjectServer != (Object)(object)item)
			{
				Log.Warning("Failed to grab " + (item?.itemProperties?.itemName ?? "item") + "; skipping move to avoid crash.");
				yield break;
			}
			try
			{
				item.floorYRot = -1;
				Local.DiscardHeldObject(true, parent, position, false);
			}
			catch (Exception e)
			{
				Log.Exception(e);
			}
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("pasta.quicksort", "QuickSort", "0.1.26")]
	public class Plugin : BaseUnityPlugin
	{
		private const string CurrentConfigSchemaVersion = "0.1.10";

		public static ManualLogSource Log;

		public static ConfigFile config;

		public static ConfigEntry<string> configVersion;

		public static ConfigEntry<bool> SyncHostProfile;

		private static Harmony harmony;

		public static GameObject sorterObject;

		private static bool applicationIsQuitting;

		public static Plugin Instance { get; private set; }

		private void Awake()
		{
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Expected O, but got Unknown
			//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cf: Expected O, but got Unknown
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Expected O, but got Unknown
			applicationIsQuitting = false;
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			config = ((BaseUnityPlugin)this).Config;
			SyncHostProfile = config.Bind<bool>("Profiles", "Sync Host Profile", true, "Automatically select a temporary copy of the host's QuickSort profile while in their lobby. When disabled, /pu host still selects it manually.");
			SyncHostProfile.SettingChanged -= OnSyncHostProfileSettingChanged;
			SyncHostProfile.SettingChanged += OnSyncHostProfileSettingChanged;
			bool num = File.Exists(config.ConfigFilePath);
			ConfigEntry<string> val = default(ConfigEntry<string>);
			bool flag = config.TryGetEntry<string>(new ConfigDefinition("General", "configVersion"), ref val);
			configVersion = config.Bind<string>("General", "configVersion", "0.1.10", "Config schema version (used for internal migrations).");
			bool flag2 = false;
			string text = configVersion.Value ?? "";
			if (string.IsNullOrWhiteSpace(text))
			{
				text = "0.0.0";
				configVersion.Value = text;
				flag2 = true;
			}
			int num2;
			if (num)
			{
				if (flag)
				{
					num2 = (IsVersionLessThan(text, "0.1.10") ? 1 : 0);
					if (num2 == 0)
					{
						goto IL_017a;
					}
				}
				else
				{
					num2 = 1;
				}
				if (!flag || IsVersionLessThan(text, "0.1.5"))
				{
					ConfigEntry<float> val2 = config.Bind<float>("Sorter", "sortOriginY", 0.1f, "Y coordinate of the origin position for sorting items (relative to ship)");
					if (Mathf.Abs(val2.Value - 0.5f) < 0.0001f)
					{
						val2.Value = 0.1f;
						flag2 = true;
					}
				}
			}
			else
			{
				num2 = 0;
			}
			goto IL_017a;
			IL_017a:
			if (num2 != 0 && !string.Equals(configVersion.Value, "0.1.10", StringComparison.Ordinal))
			{
				configVersion.Value = "0.1.10";
				flag2 = true;
			}
			if (flag2)
			{
				config.Save();
			}
			QuickSort.Log.Init(((BaseUnityPlugin)this).Logger);
			QuickSort.Log.Info("QuickSort - Item Sorter loading...");
			SortShortcuts.EnsureFileExists();
			SortPositions.EnsureFileExists();
			CruiserPositions.EnsureFileExists();
			SortProfiles.EnsureFileExists();
			harmony = new Harmony("pasta.quicksort");
			harmony.PatchAll(typeof(Ship));
			harmony.PatchAll(typeof(Startup));
			harmony.PatchAll(typeof(GrabPatch));
			harmony.PatchAll(typeof(InteractionLockPatch));
			harmony.PatchAll(typeof(CruiserShelfAnchorPatch));
			try
			{
				Startup.RegisterCommandsOnce();
				QuickSort.Log.Info("Sort command registered in Awake");
			}
			catch (Exception ex)
			{
				QuickSort.Log.Error("Failed to register sort command in Awake: " + ex.Message);
				QuickSort.Log.Error("Stack trace: " + ex.StackTrace);
			}
			try
			{
				if ((Object)(object)sorterObject == (Object)null)
				{
					sorterObject = new GameObject("PastaSorter");
					sorterObject.AddComponent<Sorter>();
					sorterObject.AddComponent<ProfileNetworkBehaviour>();
					Object.DontDestroyOnLoad((Object)(object)sorterObject);
					QuickSort.Log.Info("Sorter initialized in Awake");
				}
				else if ((Object)(object)sorterObject.GetComponent<ProfileNetworkBehaviour>() == (Object)null)
				{
					sorterObject.AddComponent<ProfileNetworkBehaviour>();
				}
				SortProfiles.RecoverInterruptedHostSession();
				SortProfiles.EnsureDefaultProfile();
			}
			catch (Exception ex2)
			{
				QuickSort.Log.Error("Failed to initialize Sorter in Awake: " + ex2.Message);
				QuickSort.Log.Error("Stack trace: " + ex2.StackTrace);
			}
			QuickSort.Log.Info("QuickSort - Item Sorter loaded!");
		}

		private void OnDestroy()
		{
			if (Instance == this)
			{
				Instance = null;
			}
			if (!applicationIsQuitting)
			{
				QuickSort.Log.Warning("Plugin OnDestroy fired before application quit; skipping cleanup to avoid self-unpatching.");
				return;
			}
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			if ((Object)(object)sorterObject != (Object)null)
			{
				Object.Destroy((Object)(object)sorterObject);
			}
		}

		private void OnApplicationQuit()
		{
			applicationIsQuitting = true;
			ProfileNetwork.EndSession();
		}

		private static void OnSyncHostProfileSettingChanged(object sender, EventArgs args)
		{
			SortProfiles.OnSyncHostProfileChanged();
		}

		private static bool IsVersionLessThan(string a, string b)
		{
			int[] array = Parse(a);
			int[] array2 = Parse(b);
			for (int i = 0; i < 3; i++)
			{
				if (array[i] < array2[i])
				{
					return true;
				}
				if (array[i] > array2[i])
				{
					return false;
				}
			}
			return false;
			static int[] Parse(string s)
			{
				if (string.IsNullOrWhiteSpace(s))
				{
					return new int[3];
				}
				string[] array3 = s.Trim().Split('.');
				int[] array4 = new int[3];
				for (int j = 0; j < 3; j++)
				{
					if (j < array3.Length && int.TryParse(array3[j], out var result))
					{
						array4[j] = result;
					}
					else
					{
						array4[j] = 0;
					}
				}
				return array4;
			}
		}
	}
	public static class Startup
	{
		private static bool commandRegistered;

		public static void RegisterCommandsOnce()
		{
			if (!commandRegistered)
			{
				new SortCommand();
				new SortBindCommand();
				new SortSetCommand();
				new SortResetCommand();
				new SortPositionsCommand();
				new SortBindingsListCommand();
				new SortSkipCommand();
				new PileCommand();
				new CruiserSetCommand();
				new CruiserSortCommand();
				new ProfileCommand();
				new ProfileSaveShortcutCommand();
				new ProfileUseShortcutCommand();
				new ProfileListShortcutCommand();
				new ProfileDeleteShortcutCommand();
				commandRegistered = true;
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")]
		[HarmonyPostfix]
		private static void OnLocalPlayerCreated(PlayerControllerB __instance)
		{
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			if ((Object)(object)__instance != (Object)(object)StartOfRound.Instance.localPlayerController)
			{
				return;
			}
			if (!commandRegistered)
			{
				try
				{
					RegisterCommandsOnce();
					Log.Info("Sort command registered");
				}
				catch (Exception ex)
				{
					Log.Error("Failed to register sort command: " + ex.Message);
				}
			}
			if ((Object)(object)Plugin.sorterObject == (Object)null)
			{
				Plugin.sorterObject = new GameObject("PastaSorter");
				Plugin.sorterObject.AddComponent<Sorter>();
				Object.DontDestroyOnLoad((Object)(object)Plugin.sorterObject);
			}
			else if ((Object)(object)Plugin.sorterObject.GetComponent<Sorter>() == (Object)null)
			{
				Plugin.sorterObject.AddComponent<Sorter>();
			}
			if ((Object)(object)Plugin.sorterObject.GetComponent<ProfileNetworkBehaviour>() == (Object)null)
			{
				Plugin.sorterObject.AddComponent<ProfileNetworkBehaviour>();
			}
			SortProfiles.EnsureDefaultProfile();
			ProfileNetwork.OnLocalPlayerCreated();
		}

		[HarmonyPatch(typeof(GameNetworkManager), "Disconnect")]
		[HarmonyPrefix]
		private static void OnLobbyDisconnect()
		{
			ProfileNetwork.EndSession();
		}
	}
	internal static class ProfileNetwork
	{
		[CompilerGenerated]
		private static class <>O
		{
			public static HandleNamedMessageDelegate <0>__OnRequest;

			public static HandleNamedMessageDelegate <1>__OnSnapshot;

			public static Action<ulong> <2>__OnClientDisconnect;
		}

		private const string RequestMessage = "pasta.quicksort.profile.v1.request";

		private const string SnapshotMessage = "pasta.quicksort.profile.v1.snapshot";

		private const float RetrySeconds = 3f;

		private const float HostScanSeconds = 2f;

		private const int MaxSerialize