Decompiled source of ShipCargo v2.3.5

plugins/ShipCargo.dll

Decompiled 10 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Unity.Netcode;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ShipCargo")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ShipCargo")]
[assembly: AssemblyTitle("ShipCargo")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ShipCargo
{
	internal static class PluginInfo
	{
		public const string GUID = "Soul.ShipCargo";

		public const string NAME = "ShipCargo";

		public const string AUTHOR = "By Soul";

		public const string VERSION = "2.3.5";
	}
	[BepInPlugin("Soul.ShipCargo", "ShipCargo", "2.3.5")]
	public class ShipCargoPlugin : BaseUnityPlugin
	{
		internal static ShipCargoPlugin Instance;

		internal static ManualLogSource Log;

		private Harmony _harmony;

		public static ConfigEntry<bool> AllowClientsToStore;

		public static ConfigEntry<bool> AllowClientsToRetrieve;

		public static ConfigEntry<bool> AllowClientsToList;

		public static ConfigEntry<bool> AllowClientsToSort;

		public static ConfigEntry<float> ItemSpawnSpread;

		private void Awake()
		{
			//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Info("[ShipCargo] Initializing...");
			AllowClientsToStore = ((BaseUnityPlugin)this).Config.Bind<bool>("Permissions", "AllowClientsToStore", true, "If false, only host can store items.");
			AllowClientsToRetrieve = ((BaseUnityPlugin)this).Config.Bind<bool>("Permissions", "AllowClientsToRetrieve", true, "If false, only host can retrieve items.");
			AllowClientsToList = ((BaseUnityPlugin)this).Config.Bind<bool>("Permissions", "AllowClientsToList", true, "If false, clients cannot use cargo list or scan.");
			AllowClientsToSort = ((BaseUnityPlugin)this).Config.Bind<bool>("Permissions", "AllowClientsToSort", true, "If false, clients cannot change sorting mode.");
			ItemSpawnSpread = ((BaseUnityPlugin)this).Config.Bind<float>("Tweaks", "ItemSpawnSpread", 0.45f, "Radius for item spawn randomization in the ship.");
			ShipCargoManager.Init();
			_harmony = new Harmony("Soul.ShipCargo");
			_harmony.PatchAll();
			try
			{
				Type type = Type.GetType("InteractiveTerminalAPI.TerminalAPI, InteractiveTerminalAPI");
				if (type != null)
				{
					MethodInfo method = type.GetMethod("RegisterWord", BindingFlags.Static | BindingFlags.Public, null, new Type[1] { typeof(string) }, null);
					if (method != null)
					{
						method.Invoke(null, new object[1] { "cargo" });
						Info("[ShipCargo] Registered keyword 'cargo' with ITA.");
					}
					else
					{
						Warn("[ShipCargo] ITA found, but RegisterWord() was not detected.");
					}
				}
			}
			catch (Exception arg)
			{
				Error($"ITA integration failed: {arg}");
			}
			Info("[ShipCargo] Loaded successfully.");
		}

		public static string Red(string s)
		{
			return "<color=red>" + s + "</color>";
		}

		public static string Green(string s)
		{
			return "<color=green>" + s + "</color>";
		}

		public static string Gold(string s)
		{
			return "<color=#FFD700>" + s + "</color>";
		}

		public static string Yellow(string s)
		{
			return "<color=yellow>" + s + "</color>";
		}

		public static string Blue(string s)
		{
			return "<color=#5dcaff>" + s + "</color>";
		}

		public static string Cyan(string s)
		{
			return "<color=#00FFFF>" + s + "</color>";
		}

		public static string Money(int v)
		{
			return $"<color=white>${v}</color>";
		}

		public static string Index(int i)
		{
			return $"<color=green>{i}.</color>";
		}

		public static string StripPunctuation(string s)
		{
			if (string.IsNullOrEmpty(s))
			{
				return s;
			}
			StringBuilder stringBuilder = new StringBuilder(s.Length);
			foreach (char c in s)
			{
				if (!char.IsPunctuation(c))
				{
					stringBuilder.Append(c);
				}
			}
			return stringBuilder.ToString();
		}

		public static void Info(string msg)
		{
			Log.LogInfo((object)msg);
		}

		public static void Warn(string msg)
		{
			Log.LogWarning((object)msg);
		}

		public static void Error(string msg)
		{
			Log.LogError((object)msg);
		}

		public static bool IsHost()
		{
			if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsServer)
			{
				return NetworkManager.Singleton.IsListening;
			}
			return false;
		}

		public static bool HostAllows(ConfigEntry<bool> entry)
		{
			return entry.Value;
		}
	}
	[Serializable]
	public class StoredScrapItem
	{
		public string ItemName;

		public int ScrapValue;
	}
	public static class ShipCargoManager
	{
		private enum SortMode
		{
			Name,
			Value
		}

		private class ShipGroup
		{
			public string Name;

			public int Count;

			public int Value;
		}

		private class CargoGroup
		{
			public string Name;

			public int Count;

			public int Value;
		}

		internal static readonly object _lock = new object();

		private static readonly List<StoredScrapItem> _storedSaved = new List<StoredScrapItem>();

		internal static readonly List<StoredScrapItem> _storedCurrent = new List<StoredScrapItem>();

		private static SortMode _sortMode = SortMode.Name;

		private static bool _menuInjected = false;

		private static readonly HashSet<string> ExcludedNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "ClipboardManual", "StickyNoteItem" };

		private static readonly HashSet<string> ToolNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
		{
			"Shovel", "Flashlight", "Pro-flashlight", "ProFlashlight", "Walkie-talkie", "WalkieTalkie", "Zap gun", "ZapGun", "Jetpack", "Extension ladder",
			"ExtensionLadder", "Stun grenade", "StunGrenade", "Radar-booster", "RadarBooster", "Spray paint", "SprayPaint", "Boombox", "TZP-Inhalant", "TZPInhalant",
			"Lockpicker"
		};

		public static DateTime _lastKnownSaveTime = DateTime.MinValue;

		private static List<StoredScrapItem> CombinedStored
		{
			get
			{
				lock (_lock)
				{
					List<StoredScrapItem> source = _storedSaved.Concat(_storedCurrent).ToList();
					if (_sortMode == SortMode.Name)
					{
						return source.OrderBy((StoredScrapItem x) => x.ItemName).ToList();
					}
					return source.OrderBy((StoredScrapItem x) => x.ScrapValue).ToList();
				}
			}
		}

		private static string FilePath
		{
			get
			{
				string text = GameNetworkManager.Instance?.currentSaveFileName;
				if (string.IsNullOrWhiteSpace(text))
				{
					return Path.Combine(Paths.ConfigPath, "ShipCargo", "NO_SAVE_LOADED.json");
				}
				string text2 = Path.Combine(Paths.ConfigPath, "ShipCargo");
				if (!Directory.Exists(text2))
				{
					Directory.CreateDirectory(text2);
				}
				return Path.Combine(text2, text + ".inventory.json");
			}
		}

		public static void Init()
		{
		}

		public static void TryPatchMainMenu()
		{
			if (_menuInjected)
			{
				return;
			}
			try
			{
				TerminalNode[] array = Resources.FindObjectsOfTypeAll<TerminalNode>();
				foreach (TerminalNode val in array)
				{
					string displayText = val.displayText;
					if (!string.IsNullOrEmpty(displayText) && displayText.Contains(">MOONS") && displayText.Contains(">STORE") && displayText.Contains(">OTHER"))
					{
						if (displayText.Contains(">CARGO"))
						{
							_menuInjected = true;
							break;
						}
						int num = displayText.IndexOf(">OTHER", StringComparison.Ordinal);
						if (num >= 0)
						{
							string value = ">CARGO\nCargo management commands\n\n";
							val.displayText = displayText.Insert(num, value);
							ShipCargoPlugin.Info("[ShipCargo] CARGO added to main terminal menu.");
							_menuInjected = true;
							break;
						}
					}
				}
			}
			catch (Exception arg)
			{
				ShipCargoPlugin.Error($"Failed to patch main menu: {arg}");
			}
		}

		public static List<GrabbableObject> GetShipScrap()
		{
			List<GrabbableObject> list = new List<GrabbableObject>();
			try
			{
				GameObject val = GameObject.Find("/Environment/HangarShip");
				if ((Object)(object)val == (Object)null)
				{
					return list;
				}
				GrabbableObject[] componentsInChildren = val.GetComponentsInChildren<GrabbableObject>(true);
				foreach (GrabbableObject val2 in componentsInChildren)
				{
					if ((Object)(object)val2?.itemProperties == (Object)null)
					{
						continue;
					}
					string text = val2.itemProperties.itemName ?? "";
					if (!ExcludedNames.Contains(text) && !ToolNames.Contains(text))
					{
						bool flag = text.Equals("Key", StringComparison.OrdinalIgnoreCase) || text.Equals("Apparatus", StringComparison.OrdinalIgnoreCase);
						if ((val2.itemProperties.isScrap || flag) && !((Object)(object)val2.playerHeldBy != (Object)null) && !val2.isHeld && !val2.isPocketed)
						{
							list.Add(val2);
						}
					}
				}
			}
			catch (Exception arg)
			{
				ShipCargoPlugin.Error($"Scan error: {arg}");
			}
			return list;
		}

		private static List<ShipGroup> GetShipGroups()
		{
			List<ShipGroup> list = (from x in GetShipScrap()
				group x by x.itemProperties.itemName into g
				select new ShipGroup
				{
					Name = g.Key,
					Count = g.Count(),
					Value = g.Sum((GrabbableObject o) => o.scrapValue)
				}).ToList();
			SortShip(list);
			return list;
		}

		private static List<CargoGroup> GetCargoGroups()
		{
			List<StoredScrapItem> combinedStored;
			lock (_lock)
			{
				combinedStored = CombinedStored;
			}
			List<CargoGroup> list = (from x in combinedStored
				group x by x.ItemName into g
				select new CargoGroup
				{
					Name = g.Key,
					Count = g.Count(),
					Value = g.Sum((StoredScrapItem o) => o.ScrapValue)
				}).ToList();
			SortCargo(list);
			return list;
		}

		private static void SortShip(List<ShipGroup> g)
		{
			if (_sortMode == SortMode.Name)
			{
				g.Sort((ShipGroup a, ShipGroup b) => string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase));
				return;
			}
			g.Sort(delegate(ShipGroup a, ShipGroup b)
			{
				int num = a.Value.CompareTo(b.Value);
				return (num != 0) ? num : string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase);
			});
		}

		private static void SortCargo(List<CargoGroup> g)
		{
			if (_sortMode == SortMode.Name)
			{
				g.Sort((CargoGroup a, CargoGroup b) => string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase));
				return;
			}
			g.Sort(delegate(CargoGroup a, CargoGroup b)
			{
				int num = a.Value.CompareTo(b.Value);
				return (num != 0) ? num : string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase);
			});
		}

		public static int ShipValue()
		{
			return GetShipScrap().Sum((GrabbableObject g) => g.scrapValue);
		}

		public static int CargoValue()
		{
			lock (_lock)
			{
				return CombinedStored.Sum((StoredScrapItem x) => x.ScrapValue);
			}
		}

		public static string CmdScan(ulong sender)
		{
			if (!ShipCargoPlugin.IsHost() && !ShipCargoPlugin.HostAllows(ShipCargoPlugin.AllowClientsToList))
			{
				return ShipCargoPlugin.Red("Clients cannot scan ship (disabled by host).\n\n");
			}
			List<ShipGroup> shipGroups = GetShipGroups();
			if (shipGroups.Count == 0)
			{
				return ShipCargoPlugin.Green("No sellable items inside the ship.\n\n");
			}
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine(ShipCargoPlugin.Cyan("=== SHIP SCAN ===\n"));
			stringBuilder.AppendLine();
			int num = 1;
			foreach (ShipGroup item in shipGroups)
			{
				stringBuilder.AppendLine($"{ShipCargoPlugin.Index(num)} {item.Name}  <color=green>(</color><color=blue>x{item.Count}</color><color=green>)</color>  ({ShipCargoPlugin.Money(item.Value)})");
				num++;
			}
			stringBuilder.AppendLine();
			stringBuilder.AppendLine("\nTotal ship value: " + ShipCargoPlugin.Money(ShipValue()));
			return stringBuilder.ToString() + "\n";
		}

		public static string CmdList(ulong sender)
		{
			if (!ShipCargoPlugin.IsHost() && !ShipCargoPlugin.HostAllows(ShipCargoPlugin.AllowClientsToList))
			{
				return ShipCargoPlugin.Red("Clients cannot list cargo (disabled by host).\n\n");
			}
			List<CargoGroup> cargoGroups = GetCargoGroups();
			if (cargoGroups.Count == 0)
			{
				return ShipCargoPlugin.Green("Stored cargo is empty.\n\n");
			}
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.AppendLine(ShipCargoPlugin.Cyan("=== STORED CARGO ===\n"));
			stringBuilder.AppendLine();
			int num = 1;
			foreach (CargoGroup item in cargoGroups)
			{
				stringBuilder.AppendLine($"{ShipCargoPlugin.Index(num)} {item.Name}  <color=green>(</color><color=blue>x{item.Count}</color><color=green>)</color>  ({ShipCargoPlugin.Money(item.Value)})");
				num++;
			}
			stringBuilder.AppendLine();
			stringBuilder.AppendLine("\nTotal stored value: " + ShipCargoPlugin.Money(CargoValue()));
			return stringBuilder.ToString() + "\n";
		}

		public static string CmdSortName(ulong sender)
		{
			if (!ShipCargoPlugin.IsHost() && !ShipCargoPlugin.HostAllows(ShipCargoPlugin.AllowClientsToSort))
			{
				return ShipCargoPlugin.Red("Clients cannot change sorting (disabled by host).\n\n");
			}
			_sortMode = SortMode.Name;
			return ShipCargoPlugin.Green("Sorting mode set to alphabetical.\n\n");
		}

		public static string CmdSortValue(ulong sender)
		{
			if (!ShipCargoPlugin.IsHost() && !ShipCargoPlugin.HostAllows(ShipCargoPlugin.AllowClientsToSort))
			{
				return ShipCargoPlugin.Red("Clients cannot change sorting (disabled by host).\n\n");
			}
			_sortMode = SortMode.Value;
			return ShipCargoPlugin.Green("Sorting mode set to value (low → high).\n\n");
		}

		private static void StoreItems(IEnumerable<GrabbableObject> items, out int storedCount, out int storedValue)
		{
			storedCount = 0;
			storedValue = 0;
			lock (_lock)
			{
				foreach (GrabbableObject item in items)
				{
					if ((Object)(object)item == (Object)null || (Object)(object)item.itemProperties == (Object)null)
					{
						continue;
					}
					_storedCurrent.Add(new StoredScrapItem
					{
						ItemName = item.itemProperties.itemName,
						ScrapValue = item.scrapValue
					});
					storedCount++;
					storedValue += item.scrapValue;
					try
					{
						NetworkObject component = ((Component)item).GetComponent<NetworkObject>();
						if ((Object)(object)component != (Object)null && component.IsSpawned)
						{
							component.Despawn(true);
						}
						else
						{
							Object.Destroy((Object)(object)((Component)item).gameObject);
						}
					}
					catch
					{
					}
				}
			}
		}

		public static string CmdStoreAll(ulong sender)
		{
			if (!ShipCargoPlugin.HostAllows(ShipCargoPlugin.AllowClientsToStore) && sender != 0L)
			{
				return ShipCargoPlugin.Red("Clients storing is disabled by host.\n\n");
			}
			List<GrabbableObject> shipScrap = GetShipScrap();
			if (shipScrap.Count == 0)
			{
				return ShipCargoPlugin.Green("No sellable items found in ship.\n\n");
			}
			StoreItems(shipScrap, out var storedCount, out var storedValue);
			ShipCargoRPC.SendCargoSync();
			return string.Format("{0} {1} items ({2}).\n\n", ShipCargoPlugin.Green("Stored"), storedCount, ShipCargoPlugin.Money(storedValue));
		}

		public static string CmdStoreAllByIndex(int index, ulong sender)
		{
			if (!ShipCargoPlugin.HostAllows(ShipCargoPlugin.AllowClientsToStore) && sender != 0L)
			{
				return ShipCargoPlugin.Red("Clients storing is disabled by host.\n\n");
			}
			List<ShipGroup> shipGroups = GetShipGroups();
			if (shipGroups.Count == 0)
			{
				return ShipCargoPlugin.Green("No sellable items found in ship.\n\n");
			}
			if (index < 1 || index > shipGroups.Count)
			{
				return ShipCargoPlugin.Red($"No ship item at index {index}.\n\n");
			}
			return CmdStoreAllByName(shipGroups[index - 1].Name, sender);
		}

		public static string CmdStoreAllByName(string name, ulong sender)
		{
			if (!ShipCargoPlugin.HostAllows(ShipCargoPlugin.AllowClientsToStore) && sender != 0L)
			{
				return ShipCargoPlugin.Red("Clients storing is disabled by host.\n\n");
			}
			if (string.IsNullOrWhiteSpace(name))
			{
				return ShipCargoPlugin.Red("You must provide a name.\n\n");
			}
			string target = name.Trim();
			List<GrabbableObject> list = (from s in GetShipScrap()
				where string.Equals(s.itemProperties.itemName, target, StringComparison.OrdinalIgnoreCase)
				select s).ToList();
			if (list.Count == 0)
			{
				return ShipCargoPlugin.Green("No ship items named \"" + target + "\".\n\n");
			}
			StoreItems(list, out var storedCount, out var storedValue);
			ShipCargoRPC.SendCargoSync();
			return string.Format("{0} {1} {2} ({3}).\n\n", ShipCargoPlugin.Green("Stored"), storedCount, target, ShipCargoPlugin.Money(storedValue));
		}

		public static string CmdStoreOneByIndex(int index, ulong sender)
		{
			if (!ShipCargoPlugin.HostAllows(ShipCargoPlugin.AllowClientsToStore) && sender != 0L)
			{
				return ShipCargoPlugin.Red("Clients storing is disabled by host.\n\n");
			}
			List<ShipGroup> shipGroups = GetShipGroups();
			if (shipGroups.Count == 0)
			{
				return ShipCargoPlugin.Green("No sellable items in ship.\n\n");
			}
			if (index < 1 || index > shipGroups.Count)
			{
				return ShipCargoPlugin.Red($"No ship item at index {index}.\n\n");
			}
			return CmdStoreOneByName(shipGroups[index - 1].Name, sender);
		}

		public static string CmdStoreOneByName(string name, ulong sender)
		{
			if (!ShipCargoPlugin.HostAllows(ShipCargoPlugin.AllowClientsToStore) && sender != 0L)
			{
				return ShipCargoPlugin.Red("Clients storing is disabled by host.\n\n");
			}
			if (string.IsNullOrWhiteSpace(name))
			{
				return ShipCargoPlugin.Red("You must provide a name.\n\n");
			}
			string target = name.Trim();
			List<GrabbableObject> list = (from s in GetShipScrap()
				where string.Equals(s.itemProperties.itemName, target, StringComparison.OrdinalIgnoreCase)
				select s).ToList();
			if (list.Count == 0)
			{
				return ShipCargoPlugin.Green("No ship items named \"" + target + "\".\n\n");
			}
			StoreItems(list.Take(1), out var _, out var storedValue);
			ShipCargoRPC.SendCargoSync();
			return ShipCargoPlugin.Green("Stored") + " 1 " + target + " (" + ShipCargoPlugin.Money(storedValue) + ").\n\n";
		}

		private static bool TryGetShipInterior(out Bounds bounds)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			bounds = default(Bounds);
			GameObject val = GameObject.Find("/Environment/HangarShip");
			if (!Object.op_Implicit((Object)(object)val))
			{
				return false;
			}
			BoxCollider val2 = ((IEnumerable<BoxCollider>)val.GetComponentsInChildren<BoxCollider>(true)).FirstOrDefault((Func<BoxCollider, bool>)((BoxCollider c) => ((Object)c).name.Contains("StrictInnerRoomBounds") || ((Object)c).name.Contains("InnerRoomBounds")));
			if ((Object)(object)val2 != (Object)null)
			{
				bounds = ((Collider)val2).bounds;
				return true;
			}
			return false;
		}

		private static void SpawnStoredItems(List<StoredScrapItem> list, out int spawned, out int value)
		{
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			spawned = 0;
			value = 0;
			GameObject val = GameObject.Find("/Environment/HangarShip");
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Bounds bounds;
			bool flag = TryGetShipInterior(out bounds);
			Vector3 val3 = default(Vector3);
			foreach (StoredScrapItem it in list)
			{
				try
				{
					Item val2 = ((IEnumerable<Item>)StartOfRound.Instance.allItemsList.itemsList).FirstOrDefault((Func<Item, bool>)((Item d) => string.Equals(d.itemName, it.ItemName, StringComparison.OrdinalIgnoreCase)));
					if (!((Object)(object)val2 == (Object)null))
					{
						if (flag)
						{
							((Vector3)(ref val3))..ctor(((Bounds)(ref bounds)).center.x + Random.Range(0f - ShipCargoPlugin.ItemSpawnSpread.Value, ShipCargoPlugin.ItemSpawnSpread.Value), ((Bounds)(ref bounds)).min.y + 1.1f, ((Bounds)(ref bounds)).center.z + Random.Range(0f - ShipCargoPlugin.ItemSpawnSpread.Value, ShipCargoPlugin.ItemSpawnSpread.Value));
						}
						else
						{
							val3 = val.transform.position + Vector3.up;
						}
						GameObject obj = Object.Instantiate<GameObject>(val2.spawnPrefab, val3, Quaternion.identity);
						obj.transform.SetParent(val.transform, true);
						NetworkObject component = obj.GetComponent<NetworkObject>();
						if ((Object)(object)component != (Object)null && !component.IsSpawned)
						{
							component.Spawn(true);
						}
						GrabbableObject component2 = obj.GetComponent<GrabbableObject>();
						if ((Object)(object)component2 != (Object)null)
						{
							component2.SetScrapValue(it.ScrapValue);
						}
						spawned++;
						value += it.ScrapValue;
					}
				}
				catch
				{
				}
			}
		}

		public static string CmdRetrieveAll(ulong sender)
		{
			if (!ShipCargoPlugin.HostAllows(ShipCargoPlugin.AllowClientsToRetrieve) && sender != 0L)
			{
				return ShipCargoPlugin.Red("Clients retrieving is disabled by host.\n\n");
			}
			if (ShipBusy())
			{
				return ShipCargoPlugin.Red("Cannot retrieve items while the ship is moving.\n\n");
			}
			List<StoredScrapItem> list;
			lock (_lock)
			{
				list = CombinedStored.ToList();
			}
			if (list.Count == 0)
			{
				return ShipCargoPlugin.Green("Stored cargo is empty.\n\n");
			}
			lock (_lock)
			{
				_storedSaved.Clear();
				_storedCurrent.Clear();
				SaveSavedToDisk();
			}
			SpawnStoredItems(list, out var spawned, out var value);
			ShipCargoRPC.SendCargoSync();
			return string.Format("{0} {1} items ({2}).\n\n", ShipCargoPlugin.Green("Retrieved"), spawned, ShipCargoPlugin.Money(value));
		}

		public static string CmdRetrieveAllByIndex(int index, ulong sender)
		{
			if (!ShipCargoPlugin.HostAllows(ShipCargoPlugin.AllowClientsToRetrieve) && sender != 0L)
			{
				return ShipCargoPlugin.Red("Clients retrieving is disabled by host.\n\n");
			}
			if (ShipBusy())
			{
				return ShipCargoPlugin.Red("Cannot retrieve items while the ship is moving.\n\n");
			}
			List<CargoGroup> cargoGroups = GetCargoGroups();
			if (cargoGroups.Count == 0)
			{
				return ShipCargoPlugin.Green("Stored cargo is empty.\n\n");
			}
			if (index < 1 || index > cargoGroups.Count)
			{
				return ShipCargoPlugin.Red($"No stored item at index {index}.\n\n");
			}
			return CmdRetrieveAllByName(cargoGroups[index - 1].Name, sender);
		}

		public static string CmdRetrieveAllByName(string name, ulong sender)
		{
			if (!ShipCargoPlugin.HostAllows(ShipCargoPlugin.AllowClientsToRetrieve) && sender != 0L)
			{
				return ShipCargoPlugin.Red("Clients retrieving is disabled by host.\n\n");
			}
			if (ShipBusy())
			{
				return ShipCargoPlugin.Red("Cannot retrieve items while the ship is moving.\n\n");
			}
			if (string.IsNullOrWhiteSpace(name))
			{
				return ShipCargoPlugin.Red("You must provide a name.\n\n");
			}
			string target = name.Trim();
			List<StoredScrapItem> list;
			lock (_lock)
			{
				list = CombinedStored.Where((StoredScrapItem s) => s.ItemName.Equals(target, StringComparison.OrdinalIgnoreCase)).ToList();
				if (list.Count == 0)
				{
					return ShipCargoPlugin.Green("No stored items named \"" + target + "\".\n\n");
				}
				foreach (StoredScrapItem item in list)
				{
					if (!_storedCurrent.Remove(item))
					{
						_storedSaved.Remove(item);
					}
				}
				SaveSavedToDisk();
			}
			SpawnStoredItems(list, out var spawned, out var value);
			ShipCargoRPC.SendCargoSync();
			return string.Format("{0} {1} {2} ({3}).\n\n", ShipCargoPlugin.Green("Retrieved"), spawned, target, ShipCargoPlugin.Money(value));
		}

		public static string CmdRetrieveOneByIndex(int index, ulong sender)
		{
			if (!ShipCargoPlugin.HostAllows(ShipCargoPlugin.AllowClientsToRetrieve) && sender != 0L)
			{
				return ShipCargoPlugin.Red("Clients retrieving is disabled by host.\n\n");
			}
			if (ShipBusy())
			{
				return ShipCargoPlugin.Red("Cannot retrieve items while the ship is moving.\n\n");
			}
			List<CargoGroup> cargoGroups = GetCargoGroups();
			if (cargoGroups.Count == 0)
			{
				return ShipCargoPlugin.Green("Stored cargo is empty.\n\n");
			}
			if (index < 1 || index > cargoGroups.Count)
			{
				return ShipCargoPlugin.Red($"No stored item at index {index}.\n\n");
			}
			return CmdRetrieveOneByName(cargoGroups[index - 1].Name, sender);
		}

		public static string CmdRetrieveOneByName(string name, ulong sender)
		{
			if (!ShipCargoPlugin.HostAllows(ShipCargoPlugin.AllowClientsToRetrieve) && sender != 0L)
			{
				return ShipCargoPlugin.Red("Clients retrieving is disabled by host.\n\n");
			}
			if (ShipBusy())
			{
				return ShipCargoPlugin.Red("Cannot retrieve items while the ship is moving.\n\n");
			}
			if (string.IsNullOrWhiteSpace(name))
			{
				return ShipCargoPlugin.Red("You must provide a name.\n\n");
			}
			string target = name.Trim();
			StoredScrapItem storedScrapItem;
			lock (_lock)
			{
				storedScrapItem = CombinedStored.FirstOrDefault((StoredScrapItem s) => s.ItemName.Equals(target, StringComparison.OrdinalIgnoreCase));
				if (storedScrapItem == null)
				{
					return ShipCargoPlugin.Green("No stored items named \"" + target + "\".\n\n");
				}
				if (!_storedCurrent.Remove(storedScrapItem))
				{
					_storedSaved.Remove(storedScrapItem);
				}
				SaveSavedToDisk();
			}
			SpawnStoredItems(new List<StoredScrapItem> { storedScrapItem }, out var _, out var value);
			ShipCargoRPC.SendCargoSync();
			return ShipCargoPlugin.Green("Retrieved") + " 1 " + target + " (" + ShipCargoPlugin.Money(value) + ").\n\n";
		}

		public static string CmdCargoMenu()
		{
			int v = ShipValue();
			int v2 = CargoValue();
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("<align=\"center\">" + ShipCargoPlugin.Gold("== ShipCargo ==") + "</align>\n");
			stringBuilder.AppendLine("<align=\"center\">" + ShipCargoPlugin.Green("By ") + "<color=#000000>Soul</color></align>");
			stringBuilder.AppendLine("<align=\"center\">" + ShipCargoPlugin.Green("Version ") + ShipCargoPlugin.Red("2.3.5") + "</align>");
			stringBuilder.AppendLine();
			stringBuilder.AppendLine("<color=green>Ship Value:</color>   " + ShipCargoPlugin.Money(v));
			stringBuilder.AppendLine("<color=green>Cargo Value:</color>  " + ShipCargoPlugin.Money(v2));
			stringBuilder.AppendLine(ShipCargoPlugin.Cyan("===== LIST COMMANDS ====="));
			stringBuilder.AppendLine(ShipCargoPlugin.Yellow("cargo scan") + "  - Scan ship for storable items");
			stringBuilder.AppendLine(ShipCargoPlugin.Yellow("cargo list") + "  - List stored cargo");
			stringBuilder.AppendLine(ShipCargoPlugin.Cyan("===== STORE COMMANDS ====="));
			stringBuilder.AppendLine(ShipCargoPlugin.Yellow("cargo s all") + "             - Store ALL items");
			stringBuilder.AppendLine(ShipCargoPlugin.Yellow("cargo s <index>") + "         - Store ONE by index");
			stringBuilder.AppendLine(ShipCargoPlugin.Yellow("cargo s <name>") + "          - Store ONE by name");
			stringBuilder.AppendLine(ShipCargoPlugin.Yellow("cargo s all <name/index>") + "   - Store ALL by name or index");
			stringBuilder.AppendLine(ShipCargoPlugin.Cyan("===== RETRIEVE COMMANDS ====="));
			stringBuilder.AppendLine(ShipCargoPlugin.Yellow("cargo r all") + "             - Retrieve ALL items");
			stringBuilder.AppendLine(ShipCargoPlugin.Yellow("cargo r <index>") + "         - Retrieve ONE by index");
			stringBuilder.AppendLine(ShipCargoPlugin.Yellow("cargo r <name>") + "          - Retrieve ONE by name");
			stringBuilder.AppendLine(ShipCargoPlugin.Yellow("cargo r all <name/index>") + "   - Retrieve ALL by name or index");
			stringBuilder.AppendLine(ShipCargoPlugin.Cyan("===== SORT COMMANDS ====="));
			stringBuilder.AppendLine(ShipCargoPlugin.Yellow("cargo sort name") + "   - Sort alphabetically");
			stringBuilder.AppendLine(ShipCargoPlugin.Yellow("cargo sort value") + "  - Sort by total value");
			return stringBuilder.ToString();
		}

		public static string HandleCargoCommand(string input, ulong sender)
		{
			if (string.IsNullOrWhiteSpace(input))
			{
				return ShipCargoPlugin.Red("Invalid command.\n");
			}
			string[] array = input.Split(' ', StringSplitOptions.RemoveEmptyEntries);
			if (array.Length == 0)
			{
				return ShipCargoPlugin.Red("Invalid command.\n");
			}
			if (!array[0].Equals("cargo", StringComparison.OrdinalIgnoreCase))
			{
				return null;
			}
			if (array.Length == 1)
			{
				return CmdCargoMenu();
			}
			switch (array[1].ToLowerInvariant())
			{
			case "scan":
				return CmdScan(sender);
			case "list":
				return CmdList(sender);
			case "sort":
				if (array.Length < 3)
				{
					return ShipCargoPlugin.Yellow("Usage: cargo sort name | value\n");
				}
				if (array[2].Equals("name", StringComparison.OrdinalIgnoreCase))
				{
					return CmdSortName(sender);
				}
				if (array[2].Equals("value", StringComparison.OrdinalIgnoreCase))
				{
					return CmdSortValue(sender);
				}
				return ShipCargoPlugin.Yellow("Usage: cargo sort name | value\n");
			case "s":
				return HandleStoreCommand(array, sender);
			case "r":
				return HandleRetrieveCommand(array, sender);
			default:
				return ShipCargoPlugin.Red("Unknown cargo command.\n\n");
			}
		}

		private static string HandleStoreCommand(string[] t, ulong sender)
		{
			if (t.Length == 2)
			{
				return ShipCargoPlugin.Red("Invalid store command.\n\n");
			}
			bool flag = t[2].Equals("all", StringComparison.OrdinalIgnoreCase);
			if (flag && t.Length == 3)
			{
				return CmdStoreAll(sender);
			}
			if (flag && t.Length >= 4)
			{
				string text = string.Join(" ", t.Skip(3));
				if (int.TryParse(text, out var result))
				{
					return CmdStoreAllByIndex(result, sender);
				}
				return CmdStoreAllByName(text, sender);
			}
			if (int.TryParse(t[2], out var result2))
			{
				return CmdStoreOneByIndex(result2, sender);
			}
			return CmdStoreOneByName(string.Join(" ", t.Skip(2)), sender);
		}

		private static string HandleRetrieveCommand(string[] t, ulong sender)
		{
			if (t.Length == 2)
			{
				return ShipCargoPlugin.Red("Invalid retrieve command.");
			}
			bool flag = t[2].Equals("all", StringComparison.OrdinalIgnoreCase);
			if (flag && t.Length == 3)
			{
				return CmdRetrieveAll(sender);
			}
			if (flag && t.Length >= 4)
			{
				string text = string.Join(" ", t.Skip(3));
				if (int.TryParse(text, out var result))
				{
					return CmdRetrieveAllByIndex(result, sender);
				}
				return CmdRetrieveAllByName(text, sender);
			}
			if (int.TryParse(t[2], out var result2))
			{
				return CmdRetrieveOneByIndex(result2, sender);
			}
			return CmdRetrieveOneByName(string.Join(" ", t.Skip(2)), sender);
		}

		public static List<StoredScrapItem> GetStoredSnapshot()
		{
			lock (_lock)
			{
				return CombinedStored;
			}
		}

		public static void ClientApplyCargoState(List<StoredScrapItem> newList)
		{
			lock (_lock)
			{
				_storedSaved.Clear();
				_storedSaved.AddRange(newList);
				_storedCurrent.Clear();
			}
		}

		public static string HandleCargoCommandStatic(string cmd, ulong sender)
		{
			return HandleCargoCommand(cmd, sender);
		}

		private static bool IsInOrbit(StartOfRound sor)
		{
			if ((Object)(object)sor.currentLevel != (Object)null)
			{
				return sor.currentLevel.sceneName == "CompanyBuilding";
			}
			return false;
		}

		private static bool ShipBusy()
		{
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance == (Object)null)
			{
				return true;
			}
			bool flag = !instance.shipHasLanded && instance.inShipPhase && !instance.shipIsLeaving && !instance.travellingToNewLevel && !instance.shipLeftAutomatically;
			if (flag)
			{
				return false;
			}
			if (instance.shipIsLeaving)
			{
				return true;
			}
			if (instance.travellingToNewLevel)
			{
				return true;
			}
			if (instance.shipLeftAutomatically)
			{
				return true;
			}
			if (instance.firingPlayersCutsceneRunning || instance.suckingPlayersOutOfShip)
			{
				return true;
			}
			if ((Object)(object)instance.currentLevel != (Object)null && !flag)
			{
				return !instance.shipHasLanded;
			}
			return false;
		}

		public static void ReloadAfterSaveChange()
		{
			lock (_lock)
			{
				_storedSaved.Clear();
				_storedCurrent.Clear();
			}
			LoadFromDiskIntoSaved();
		}

		public static void ClearMemory()
		{
			lock (_lock)
			{
				_storedSaved.Clear();
				_storedCurrent.Clear();
			}
		}

		internal static void LoadFromDiskIntoSaved()
		{
			try
			{
				if (!File.Exists(FilePath))
				{
					return;
				}
				List<StoredScrapItem> list = JsonConvert.DeserializeObject<List<StoredScrapItem>>(File.ReadAllText(FilePath));
				lock (_lock)
				{
					_storedSaved.Clear();
					if (list != null)
					{
						_storedSaved.AddRange(list);
					}
					_storedCurrent.Clear();
				}
			}
			catch
			{
			}
		}

		private static void SaveSavedToDisk()
		{
			lock (_lock)
			{
				File.WriteAllText(FilePath, JsonConvert.SerializeObject((object)_storedSaved, (Formatting)1));
			}
		}

		public static void PromoteCurrentToSaved()
		{
			lock (_lock)
			{
				_storedSaved.AddRange(_storedCurrent);
				_storedCurrent.Clear();
				SaveSavedToDisk();
			}
		}

		private static string GetActiveSavePath()
		{
			string text = GameNetworkManager.Instance?.currentSaveFileName;
			if (string.IsNullOrWhiteSpace(text))
			{
				return null;
			}
			return Path.Combine(Application.persistentDataPath, text);
		}

		public static DateTime GetActiveSaveTimestamp()
		{
			string activeSavePath = GetActiveSavePath();
			if (string.IsNullOrEmpty(activeSavePath) || !File.Exists(activeSavePath))
			{
				return DateTime.MinValue;
			}
			return File.GetLastWriteTime(activeSavePath);
		}
	}
	public class ShipCargoRPC : NetworkBehaviour
	{
		public static ShipCargoRPC Instance;

		public static void Init()
		{
		}

		[ServerRpc(RequireOwnership = false)]
		public void ForwardCargoCommandServerRpc(string command, ulong sender)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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_003f: Unknown result type (might be due to invalid IL or missing references)
			if (ShipCargoPlugin.IsHost())
			{
				string text = ShipCargoManager.HandleCargoCommand(command, sender);
				if (text != null)
				{
					SendReplyClientRpc(text, new ClientRpcParams
					{
						Send = new ClientRpcSendParams
						{
							TargetClientIds = new ulong[1] { sender }
						}
					});
				}
			}
		}

		[ClientRpc]
		public void SendReplyClientRpc(string text, ClientRpcParams p = default(ClientRpcParams))
		{
			Terminal val = Object.FindObjectOfType<Terminal>();
			if (!((Object)(object)val == (Object)null))
			{
				TerminalNode val2 = ScriptableObject.CreateInstance<TerminalNode>();
				val2.displayText = text;
				val2.clearPreviousText = true;
				val.currentNode = val2;
				val.LoadNewNode(val2);
			}
		}

		[ClientRpc]
		public void SyncCargoClientRpc(byte[] jsonData)
		{
			try
			{
				List<StoredScrapItem> list = JsonConvert.DeserializeObject<List<StoredScrapItem>>(Encoding.UTF8.GetString(jsonData));
				if (list != null)
				{
					ShipCargoManager.ClientApplyCargoState(list);
				}
			}
			catch (Exception arg)
			{
				ShipCargoPlugin.Error($"Cargo sync failed: {arg}");
			}
		}

		public static void SendCargoSync()
		{
			if (ShipCargoPlugin.IsHost())
			{
				string s = JsonConvert.SerializeObject((object)ShipCargoManager.GetStoredSnapshot(), (Formatting)1);
				byte[] bytes = Encoding.UTF8.GetBytes(s);
				Instance?.SyncCargoClientRpc(bytes);
			}
		}
	}
	[HarmonyPatch(typeof(Terminal), "Awake")]
	public static class TerminalCargoMenuInject
	{
		private static void Postfix(Terminal __instance)
		{
			try
			{
				ShipCargoManager.TryPatchMainMenu();
			}
			catch (Exception arg)
			{
				ShipCargoPlugin.Error($"Menu inject error: {arg}");
			}
		}
	}
	[HarmonyPatch(typeof(Terminal), "ParsePlayerSentence")]
	public static class TerminalParsePatch_Final
	{
		private static bool Prefix(Terminal __instance, ref TerminalNode __result)
		{
			int length = __instance.screenText.text.Length;
			int textAdded = __instance.textAdded;
			if (textAdded <= 0 || textAdded > length)
			{
				return true;
			}
			string s = __instance.screenText.text.Substring(length - textAdded);
			s = ShipCargoPlugin.StripPunctuation(s);
			s = s.Trim().TrimStart('>').Trim();
			if (!s.StartsWith("cargo", StringComparison.OrdinalIgnoreCase))
			{
				return true;
			}
			ShipCargoPlugin.Info("[ShipCargo] Intercepted cargo command: '" + s + "'");
			PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController;
			if ((Object)(object)val == (Object)null)
			{
				return true;
			}
			if (!ShipCargoPlugin.IsHost())
			{
				ShipCargoRPC.Instance.ForwardCargoCommandServerRpc(s, val.playerClientId);
				TerminalNode val2 = ScriptableObject.CreateInstance<TerminalNode>();
				val2.displayText = ShipCargoPlugin.Yellow("Request sent to host...\n");
				val2.clearPreviousText = true;
				__instance.currentNode = val2;
				__instance.LoadNewNode(val2);
				__result = val2;
				return false;
			}
			string text = ShipCargoManager.HandleCargoCommand(s, val.playerClientId);
			if (!string.IsNullOrEmpty(text))
			{
				TerminalNode val3 = ScriptableObject.CreateInstance<TerminalNode>();
				val3.displayText = text;
				val3.clearPreviousText = true;
				__instance.currentNode = val3;
				__instance.LoadNewNode(val3);
				__result = val3;
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(GameNetworkManager), "Start")]
	public static class Patch_GNM_Start_SpawnRPC
	{
		private static void Postfix(GameNetworkManager __instance)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			if (!((Object)(object)ShipCargoRPC.Instance != (Object)null))
			{
				GameObject val = new GameObject("ShipCargoRPC_Prefab");
				val.AddComponent<NetworkObject>();
				val.AddComponent<ShipCargoRPC>();
				((Component)__instance).GetComponent<NetworkManager>().PrefabHandler.AddNetworkPrefab(val);
				if (NetworkManager.Singleton.IsServer)
				{
					GameObject obj = Object.Instantiate<GameObject>(val);
					obj.GetComponent<NetworkObject>().Spawn(true);
					ShipCargoRPC.Instance = obj.GetComponent<ShipCargoRPC>();
					ShipCargoPlugin.Info("[ShipCargo] RPC network prefab spawned.");
				}
			}
		}
	}
	[HarmonyPatch(typeof(ShipCargoRPC), "OnNetworkSpawn")]
	public static class Patch_RPC_OnSpawn
	{
		private static void Postfix(ShipCargoRPC __instance)
		{
			ShipCargoRPC.Instance = __instance;
			ShipCargoPlugin.Info("[ShipCargo] RPC instance linked on client.");
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "Start")]
	public static class Patch_SOR_Start
	{
		private static void Postfix()
		{
			string text = GameNetworkManager.Instance?.currentSaveFileName;
			if (string.IsNullOrWhiteSpace(text))
			{
				ShipCargoPlugin.Info("[ShipCargo] SOR_Start: No active save → Clearing memory.");
				ShipCargoManager.ClearMemory();
			}
			else
			{
				ShipCargoPlugin.Info("[ShipCargo] SOR_Start: Active save = " + text);
			}
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "LoadUnlockables")]
	public static class Patch_SOR_AfterLoad
	{
		private static void Postfix()
		{
			if ((Object)(object)StartOfRound.Instance == (Object)null || (Object)(object)StartOfRound.Instance.unlockablesList == (Object)null || StartOfRound.Instance.unlockablesList.unlockables == null)
			{
				ShipCargoPlugin.Warn("[ShipCargo] AfterLoad: UnlockablesList not ready yet. Skipping.");
				return;
			}
			if (string.IsNullOrWhiteSpace(GameNetworkManager.Instance?.currentSaveFileName))
			{
				ShipCargoPlugin.Info("[ShipCargo] AfterLoad: No active save. Clearing memory.");
				ShipCargoManager.ClearMemory();
				if (ShipCargoPlugin.IsHost())
				{
					ShipCargoRPC.SendCargoSync();
				}
				return;
			}
			DateTime activeSaveTimestamp = ShipCargoManager.GetActiveSaveTimestamp();
			if (activeSaveTimestamp == DateTime.MinValue)
			{
				ShipCargoPlugin.Warn("[ShipCargo] AfterLoad: No active save timestamp. Clearing cargo.");
				ShipCargoManager.ClearMemory();
				if (ShipCargoPlugin.IsHost())
				{
					ShipCargoRPC.SendCargoSync();
				}
			}
			else if (activeSaveTimestamp == ShipCargoManager._lastKnownSaveTime)
			{
				ShipCargoPlugin.Warn("[ShipCargo] AfterLoad: Save unchanged → wiping UNSAVED cargo.");
				lock (ShipCargoManager._lock)
				{
					ShipCargoManager._storedCurrent.Clear();
					ShipCargoManager.LoadFromDiskIntoSaved();
				}
				if (ShipCargoPlugin.IsHost())
				{
					ShipCargoRPC.SendCargoSync();
				}
			}
			else
			{
				ShipCargoPlugin.Info("[ShipCargo] AfterLoad: Save updated → loading cargo.");
				ShipCargoManager._lastKnownSaveTime = activeSaveTimestamp;
				ShipCargoManager.ReloadAfterSaveChange();
				if (ShipCargoPlugin.IsHost())
				{
					ShipCargoRPC.SendCargoSync();
				}
			}
		}
	}
	[HarmonyPatch(typeof(StartOfRound), "ShipLeave")]
	public static class Patch_SaveOnTakeoff
	{
		private static void Prefix()
		{
			ShipCargoManager.PromoteCurrentToSaved();
		}
	}
}