Decompiled source of CollectorDeployer v1.1.0

CollectorDeployer.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
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 HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
internal static class PluginInfo
{
	public const string PLUGIN_GUID = "com.yummi.dsp.collectordeployer";

	public const string PLUGIN_NAME = "CollectorDeployer";

	public const string PLUGIN_VERSION = "1.1.0";
}
namespace CollectorDeployer
{
	internal static class CollectorDeploy
	{
		private enum PlanetStatus
		{
			Ok,
			NoPower,
			TooSmall,
			TooMany
		}

		private struct ExistingCollector
		{
			public int objId;

			public int protoId;

			public Vector3 pos;

			public bool recoverable;

			public bool isEntity;
		}

		private sealed class PlanetPlan
		{
			public PlanetData planet;

			public PlanetFactory factory;

			public bool isLocal;

			public readonly List<Vector3> missingTargets = new List<Vector3>();

			public readonly List<ExistingCollector> dismantle = new List<ExistingCollector>();

			public int existingCount;

			public int keptCount;

			public int recoverableCount;

			public int NeededCount => missingTargets.Count;

			public bool IsDone
			{
				get
				{
					if (NeededCount == 0)
					{
						return dismantle.Count == 0;
					}
					return false;
				}
			}
		}

		private sealed class Batch
		{
			public Player player;

			public ItemProto item;

			public int packageCount;

			public readonly List<PlanetPlan> plans = new List<PlanetPlan>();

			public int doneCount;

			public int tooManyCount;

			public int unusableCount;

			public int NeededCount => plans.Sum((PlanetPlan p) => p.NeededCount);

			public int RecoverableCount => plans.Sum((PlanetPlan p) => p.recoverableCount);

			public int DismantleCount => plans.Sum((PlanetPlan p) => p.dismantle.Count);

			public int AvailableCount => packageCount + RecoverableCount;

			public int ReservedFromPackage => Math.Min(packageCount, NeededCount);
		}

		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static Response <>9__12_0;

			public static Func<KeyValuePair<int, int>, string> <>9__26_0;

			internal void <Confirm>b__12_0()
			{
				_dialogOpen = false;
			}

			internal string <FormatItems>b__26_0(KeyValuePair<int, int> kv)
			{
				return $"{ItemName(kv.Key)} ×{kv.Value}";
			}
		}

		public const int CollectorCount = 40;

		private const int OrbitalCollectorItemId = 2105;

		private const int SandItemId = 1099;

		private const float CollectorMinSqrDistance = 14297f;

		private const float MatchSqrDistance = 1f;

		private static bool _dialogOpen;

		public static void RequestLocal()
		{
			if (_dialogOpen)
			{
				return;
			}
			Batch batch = MakeLocalBatch();
			if (batch != null)
			{
				Dictionary<int, int> dictionary = PredictOverflow(batch);
				if (dictionary.Count == 0)
				{
					Execute(batch);
					return;
				}
				string message = Lang.T("背包空间不足,拆除旧的轨道采集器后以下物品会掉落:\n" + FormatItems(dictionary) + "\n\n是否继续?", "Not enough inventory space. Removing the old orbital collectors will drop:\n" + FormatItems(dictionary) + "\n\nContinue?");
				Confirm(Lang.TipTitle, message, MakeLocalBatch);
			}
		}

		public static void RequestGalaxy()
		{
			if (_dialogOpen)
			{
				return;
			}
			Batch batch = MakeGalaxyBatch();
			if (batch != null)
			{
				Dictionary<int, int> dictionary = PredictOverflow(batch);
				string text = Lang.T($"将在 {batch.plans.Count} 颗气态巨星上部署轨道采集器:新建 {batch.NeededCount} 个,拆除 {batch.DismantleCount} 个不在格点上的。", $"Orbital collectors will be deployed on {batch.plans.Count} gas giant(s): {batch.NeededCount} built, {batch.DismantleCount} off-grid removed.");
				List<string> list = new List<string>();
				if (batch.doneCount > 0)
				{
					list.Add(Lang.T($"已部署完毕 {batch.doneCount} 颗", $"{batch.doneCount} already done"));
				}
				if (batch.tooManyCount > 0)
				{
					list.Add(Lang.T($"采集器超过 {40} 个,跳过 {batch.tooManyCount} 颗", $"{batch.tooManyCount} skipped (more than {40} collectors)"));
				}
				if (batch.unusableCount > 0)
				{
					list.Add(Lang.T($"无法使用采集器,跳过 {batch.unusableCount} 颗", $"{batch.unusableCount} skipped (collectors can't work there)"));
				}
				if (list.Count > 0)
				{
					text = text + "\n" + string.Join(Lang.T(";", "; "), list);
				}
				if (dictionary.Count > 0)
				{
					text += Lang.T("\n\n背包空间不足,以下物品会掉落:\n" + FormatItems(dictionary), "\n\nNot enough inventory space. These items will drop:\n" + FormatItems(dictionary));
				}
				text += Lang.T("\n\n是否继续?", "\n\nContinue?");
				Confirm(Lang.GalaxyTipTitle, text, MakeGalaxyBatch);
			}
		}

		private static void Confirm(string title, string message, Func<Batch> rebuild)
		{
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Expected O, but got Unknown
			//IL_003e: 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_0049: Expected O, but got Unknown
			_dialogOpen = true;
			string text = Localization.Translate("否");
			string text2 = Localization.Translate("是");
			object obj = <>c.<>9__12_0;
			if (obj == null)
			{
				Response val = delegate
				{
					_dialogOpen = false;
				};
				<>c.<>9__12_0 = val;
				obj = (object)val;
			}
			UIMessageBox.Show(title, message, text, text2, 1, (Response)obj, (Response)delegate
			{
				_dialogOpen = false;
				Batch batch = rebuild();
				if (batch != null)
				{
					Execute(batch);
				}
			});
		}

		private static Batch MakeLocalBatch()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Invalid comparison between Unknown and I4
			if (!TryGetContext(out var player, out var item))
			{
				return null;
			}
			PlanetData localPlanet = GameMain.localPlanet;
			if (localPlanet == null || (int)localPlanet.type != 5)
			{
				UIRealtimeTip.Popup(Lang.T("只能在气态巨星上使用", "Only available on gas giants"), true, 0);
				return null;
			}
			if (player.factory == null || player.factory.planet != localPlanet)
			{
				UIRealtimeTip.Popup(Lang.T("星球数据尚未加载", "Planet data is not loaded yet"), true, 0);
				return null;
			}
			PlanetStatus status;
			PlanetPlan planetPlan = PlanPlanet(player, localPlanet, item, out status);
			switch (status)
			{
			case PlanetStatus.NoPower:
				UIRealtimeTip.Popup(Lang.T("该星球的资源不足以驱动轨道采集器", "This planet cannot power orbital collectors"), true, 0);
				return null;
			case PlanetStatus.TooSmall:
				UIRealtimeTip.Popup(Lang.T($"星球太小,赤道上放不下 {40} 个轨道采集器", $"Planet is too small to fit {40} orbital collectors on the equator"), true, 0);
				return null;
			case PlanetStatus.TooMany:
				UIRealtimeTip.Popup(Lang.T($"本星球已有 {planetPlan.existingCount} 个轨道采集器,超过 {40} 个,不进行部署", $"This planet already has {planetPlan.existingCount} orbital collectors (more than {40}); nothing deployed"), true, 0);
				return null;
			default:
			{
				if (planetPlan.IsDone)
				{
					UIRealtimeTip.Popup(Lang.T($"赤道上已部署 {40} 个轨道采集器", $"{40} orbital collectors are already deployed on the equator"), false, 0);
					return null;
				}
				Batch batch = new Batch
				{
					player = player,
					item = item,
					packageCount = player.package.GetItemCount(((Proto)item).ID)
				};
				batch.plans.Add(planetPlan);
				if (!CheckEnough(batch))
				{
					return null;
				}
				return batch;
			}
			}
		}

		private static Batch MakeGalaxyBatch()
		{
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Invalid comparison between Unknown and I4
			if (!TryGetContext(out var player, out var item))
			{
				return null;
			}
			GalaxyData galaxy = GameMain.galaxy;
			if (galaxy?.stars == null)
			{
				return null;
			}
			Batch batch = new Batch
			{
				player = player,
				item = item,
				packageCount = player.package.GetItemCount(((Proto)item).ID)
			};
			StarData[] stars = galaxy.stars;
			foreach (StarData val in stars)
			{
				if (val?.planets == null)
				{
					continue;
				}
				PlanetData[] planets = val.planets;
				foreach (PlanetData val2 in planets)
				{
					if (val2 == null || (int)val2.type != 5)
					{
						continue;
					}
					PlanetStatus status;
					PlanetPlan planetPlan = PlanPlanet(player, val2, item, out status);
					switch (status)
					{
					case PlanetStatus.TooMany:
						batch.tooManyCount++;
						break;
					default:
						batch.unusableCount++;
						break;
					case PlanetStatus.Ok:
						if (planetPlan.IsDone)
						{
							batch.doneCount++;
						}
						else
						{
							batch.plans.Add(planetPlan);
						}
						break;
					}
				}
			}
			if (batch.plans.Count == 0)
			{
				UIRealtimeTip.Popup((batch.doneCount > 0) ? Lang.T($"全银河 {batch.doneCount} 颗气态巨星均已部署完毕", $"All {batch.doneCount} gas giants in the galaxy are already deployed") : Lang.T("没有可以部署的气态巨星", "No gas giant to deploy on"), false, 0);
				return null;
			}
			VectorLF3 playerPos = player.uPosition;
			batch.plans.Sort(delegate(PlanetPlan a, PlanetPlan b)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_0037: Unknown result type (might be due to invalid IL or missing references)
				VectorLF3 val3 = a.planet.uPosition - playerPos;
				double sqrMagnitude = ((VectorLF3)(ref val3)).sqrMagnitude;
				val3 = b.planet.uPosition - playerPos;
				return sqrMagnitude.CompareTo(((VectorLF3)(ref val3)).sqrMagnitude);
			});
			if (!CheckEnough(batch))
			{
				return null;
			}
			return batch;
		}

		private static bool TryGetContext(out Player player, out ItemProto item)
		{
			player = GameMain.mainPlayer;
			item = ((ProtoSet<ItemProto>)(object)LDB.items).Select(2105);
			Player obj = player;
			if (((obj != null) ? obj.package : null) == null || GameMain.data == null)
			{
				UIRealtimeTip.Popup(Lang.T("游戏数据尚未加载", "Game data is not loaded yet"), true, 0);
				return false;
			}
			if (item?.prefabDesc == null || !item.prefabDesc.isCollectStation)
			{
				UIRealtimeTip.Popup(Lang.T("找不到轨道采集器数据", "Orbital collector data not found"), true, 0);
				return false;
			}
			return true;
		}

		private static bool CheckEnough(Batch batch)
		{
			if (batch.AvailableCount >= batch.NeededCount)
			{
				return true;
			}
			int recoverableCount = batch.RecoverableCount;
			UIRealtimeTip.Popup((recoverableCount > 0) ? Lang.T($"轨道采集器不足:需要 {batch.NeededCount} 个,背包 {batch.packageCount} 个 + 拆除返还 {recoverableCount} 个", $"Not enough orbital collectors: need {batch.NeededCount}, have {batch.packageCount} in inventory + {recoverableCount} from removal") : Lang.T($"轨道采集器不足:需要 {batch.NeededCount} 个,背包中只有 {batch.packageCount} 个", $"Not enough orbital collectors: need {batch.NeededCount}, only {batch.packageCount} in inventory"), true, 0);
			return false;
		}

		private static PlanetPlan PlanPlanet(Player player, PlanetData planet, ItemProto item, out PlanetStatus status)
		{
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			PlanetFactory factory = planet.factory;
			PlanetPlan planetPlan = new PlanetPlan
			{
				planet = planet,
				factory = factory,
				isLocal = (factory != null && factory == player.factory)
			};
			if (!CanCollectorWork(planet, item.prefabDesc))
			{
				status = PlanetStatus.NoPower;
				return planetPlan;
			}
			List<ExistingCollector> list = ((factory != null) ? FindExistingCollectors(factory) : new List<ExistingCollector>());
			planetPlan.existingCount = list.Count;
			if (list.Count > 40)
			{
				status = PlanetStatus.TooMany;
				return planetPlan;
			}
			List<Vector3> list2 = ChooseTargets(planet, list);
			if (!TargetsAreFarEnough(list2))
			{
				status = PlanetStatus.TooSmall;
				return planetPlan;
			}
			bool[] array = new bool[list2.Count];
			foreach (ExistingCollector item2 in list)
			{
				int num = (item2.isEntity ? FindUnclaimedMatch(list2, array, item2.pos) : (-1));
				if (num >= 0)
				{
					array[num] = true;
					planetPlan.keptCount++;
					continue;
				}
				planetPlan.dismantle.Add(item2);
				if (item2.recoverable)
				{
					planetPlan.recoverableCount++;
				}
			}
			for (int i = 0; i < list2.Count; i++)
			{
				if (!array[i])
				{
					planetPlan.missingTargets.Add(list2[i]);
				}
			}
			status = PlanetStatus.Ok;
			return planetPlan;
		}

		private static void Execute(Batch batch)
		{
			//IL_01ca: 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_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			Player player = batch.player;
			ItemProto item = batch.item;
			int num = TakeCollectors(player, ((Proto)item).ID, batch.ReservedFromPackage);
			int num2 = 0;
			foreach (PlanetPlan plan in batch.plans)
			{
				foreach (ExistingCollector item2 in plan.dismantle)
				{
					if (Dismantle(player, plan, item2))
					{
						num2++;
					}
				}
			}
			int neededCount = batch.NeededCount;
			num += TakeCollectors(player, ((Proto)item).ID, neededCount - num);
			int num3 = 0;
			int num4 = 0;
			foreach (PlanetPlan plan2 in batch.plans)
			{
				if (plan2.NeededCount == 0)
				{
					num4++;
					continue;
				}
				if (num <= 0)
				{
					break;
				}
				PlanetFactory val = plan2.factory ?? CreateFactory(plan2.planet);
				if (val == null)
				{
					ManualLogSource log = CollectorDeployerPlugin.Log;
					if (log != null)
					{
						log.LogWarning((object)("Could not create a factory for " + plan2.planet.displayName));
					}
					continue;
				}
				foreach (Vector3 missingTarget in plan2.missingTargets)
				{
					if (num <= 0)
					{
						break;
					}
					if (BuildCollector(player, val, item, missingTarget))
					{
						num--;
						num3++;
					}
				}
				num4++;
			}
			if (num > 0)
			{
				player.TryAddItemToPackage(((Proto)item).ID, num, 0, true, 0, false);
			}
			if (num3 > 0 || num2 > 0)
			{
				VFAudio.Create("ui-click-2", (Transform)null, Vector3.zero, true, 7, -1, -1L);
			}
			int num5 = neededCount - num3;
			if (num5 > 0)
			{
				UIRealtimeTip.Popup(Lang.T($"轨道采集器不足:已新建 {num3} 个,还差 {num5} 个", $"Not enough orbital collectors: built {num3}, {num5} missing"), true, 0);
			}
			else if (batch.plans.Count == 1)
			{
				UIRealtimeTip.Popup(Lang.T($"已部署 {40} 个轨道采集器", $"{40} orbital collectors deployed"), false, 0);
			}
			else
			{
				UIRealtimeTip.Popup(Lang.T($"已在 {num4} 颗气态巨星上部署轨道采集器,新建 {num3} 个", $"Deployed on {num4} gas giants, {num3} orbital collectors built"), false, 0);
			}
			ManualLogSource log2 = CollectorDeployerPlugin.Log;
			if (log2 != null)
			{
				log2.LogInfo((object)$"Deploy: {batch.plans.Count} planet(s), built {num3}, dismantled {num2}, missing {Math.Max(0, num5)}");
			}
		}

		private static int TakeCollectors(Player player, int itemId, int count)
		{
			if (count <= 0)
			{
				return 0;
			}
			int num = default(int);
			player.package.TakeTailItems(ref itemId, ref count, ref num, false);
			return count;
		}

		private static PlanetFactory CreateFactory(PlanetData planet)
		{
			GameData data = GameMain.data;
			if (data.factoryCount >= data.factories.Length)
			{
				return null;
			}
			PlanetFactory orCreateFactory = data.GetOrCreateFactory(planet);
			data.galaxy.astrosFactory[planet.id] = orCreateFactory;
			return orCreateFactory;
		}

		private static bool BuildCollector(Player player, PlanetFactory factory, ItemProto item, Vector3 pos)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: 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_008c: Unknown result type (might be due to invalid IL or missing references)
			Quaternion val = Maths.SphericalRotation(pos, 0f);
			PrebuildData val2 = new PrebuildData
			{
				isDestroyed = false,
				protoId = (short)((Proto)item).ID,
				modelIndex = (short)item.prefabDesc.modelIndex,
				pos = pos,
				pos2 = pos,
				rot = val,
				rot2 = val
			};
			((PrebuildData)(ref val2)).InitParametersArray(0);
			int num = factory.AddPrebuildDataWithComponents(val2);
			if (num <= 0)
			{
				ManualLogSource log = CollectorDeployerPlugin.Log;
				if (log != null)
				{
					log.LogWarning((object)$"AddPrebuildDataWithComponents failed on {factory.planet.displayName} at {pos}");
				}
				return false;
			}
			if (factory.planet.factoryLoaded)
			{
				factory.BuildFinally(player, num, true, true);
			}
			else
			{
				factory.BuildFinally(player, num, false, false);
			}
			return true;
		}

		private static bool Dismantle(Player player, PlanetPlan plan, ExistingCollector collector)
		{
			if (plan.isLocal)
			{
				return player.controller.actionBuild.DoDismantleObject(collector.objId);
			}
			PlanetFactory factory = plan.factory;
			if (collector.recoverable)
			{
				ReturnItem(player, collector.protoId, 1, 0);
			}
			if (collector.isEntity && TryGetStation(factory, collector.objId, out var station))
			{
				for (int i = 0; i < station.storage.Length; i++)
				{
					ReturnItem(player, station.storage[i].itemId, station.storage[i].count, station.storage[i].inc);
					station.storage[i].count = 0;
					station.storage[i].inc = 0;
				}
				ReturnItem(player, 5001, station.idleDroneCount, 0);
				ReturnItem(player, 5002, station.idleShipCount, 0);
				ReturnItem(player, 1210, station.warperCount, 0);
				station.idleDroneCount = 0;
				station.idleShipCount = 0;
				station.warperCount = 0;
			}
			int protoId = collector.protoId;
			factory.DismantleFinally(player, collector.objId, ref protoId);
			return true;
		}

		private static void ReturnItem(Player player, int itemId, int count, int inc)
		{
			if (itemId > 0 && count > 0)
			{
				int num = player.TryAddItemToPackage(itemId, count, inc, true, 0, false);
				UIItemup.Up(itemId, num);
			}
		}

		private static bool TryGetStation(PlanetFactory factory, int entityId, out StationComponent station)
		{
			station = null;
			int stationId = factory.entityPool[entityId].stationId;
			if (stationId <= 0 || stationId >= factory.transport.stationCursor)
			{
				return false;
			}
			station = factory.transport.stationPool[stationId];
			if (station != null && station.id == stationId)
			{
				return station.storage != null;
			}
			return false;
		}

		private static Dictionary<int, int> PredictOverflow(Batch batch)
		{
			//IL_0030: 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)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			Dictionary<int, int> overflow = new Dictionary<int, int>();
			if (batch.DismantleCount == 0)
			{
				return overflow;
			}
			Player player = batch.player;
			StorageComponent package = player.package;
			StorageComponent sim = new StorageComponent(package.size)
			{
				type = package.type
			};
			Array.Copy(package.grids, sim.grids, package.size);
			int iD = ((Proto)batch.item).ID;
			int reservedFromPackage = batch.ReservedFromPackage;
			if (reservedFromPackage > 0)
			{
				int num = default(int);
				sim.TakeTailItems(ref iD, ref reservedFromPackage, ref num, false);
			}
			Dictionary<int, int> deliveryFree = new Dictionary<int, int>();
			DeliveryPackage deliveryPackage = player.deliveryPackage;
			if (deliveryPackage != null && deliveryPackage.unlocked)
			{
				for (int i = 0; i < deliveryPackage.gridLength; i++)
				{
					int itemId = deliveryPackage.grids[i].itemId;
					if (itemId > 0 && !deliveryFree.ContainsKey(itemId))
					{
						deliveryFree[itemId] = Math.Max(0, ((GRID)(ref deliveryPackage.grids[i])).stackSizeModified - deliveryPackage.grids[i].count);
					}
				}
			}
			foreach (PlanetPlan plan in batch.plans)
			{
				foreach (ExistingCollector item in plan.dismantle)
				{
					if (item.recoverable)
					{
						Add(item.protoId, 1);
					}
					if (item.isEntity && TryGetStation(plan.factory, item.objId, out var station))
					{
						StationStore[] storage = station.storage;
						foreach (StationStore val in storage)
						{
							Add(val.itemId, val.count);
						}
						Add(5001, station.idleDroneCount);
						Add(5002, station.idleShipCount);
						Add(1210, station.warperCount);
					}
				}
			}
			return overflow;
			void Add(int num2, int count)
			{
				if (num2 > 0 && count > 0 && num2 != 1099)
				{
					int num4 = default(int);
					int num3 = count - sim.AddItemStacked(num2, count, 0, ref num4);
					if (num3 > 0 && deliveryFree.TryGetValue(num2, out var value) && value > 0)
					{
						int num5 = Math.Min(value, num3);
						deliveryFree[num2] = value - num5;
						num3 -= num5;
					}
					if (num3 > 0)
					{
						overflow[num2] = (overflow.TryGetValue(num2, out var value2) ? value2 : 0) + num3;
					}
				}
			}
		}

		private static string FormatItems(Dictionary<int, int> items)
		{
			return string.Join(Lang.T("、", ", "), items.Select((KeyValuePair<int, int> kv) => $"{ItemName(kv.Key)} ×{kv.Value}"));
		}

		private static string ItemName(int itemId)
		{
			ItemProto val = ((ProtoSet<ItemProto>)(object)LDB.items).Select(itemId);
			if (val == null)
			{
				return itemId.ToString();
			}
			if (!string.IsNullOrEmpty(((Proto)val).name))
			{
				return ((Proto)val).name;
			}
			return Localization.Translate(((Proto)val).Name);
		}

		private static bool CanCollectorWork(PlanetData planet, PrefabDesc desc)
		{
			if (planet.gasItems == null || planet.gasItems.Length == 0)
			{
				return false;
			}
			double num = (double)desc.stationCollectSpeed * planet.gasTotalHeat;
			if (num == 0.0)
			{
				return false;
			}
			return 1.0 - (double)desc.workEnergyPerTick / (num * (1.0 / 60.0)) > 0.0;
		}

		private static List<ExistingCollector> FindExistingCollectors(PlanetFactory factory)
		{
			//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_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			List<ExistingCollector> list = new List<ExistingCollector>();
			EntityData[] entityPool = factory.entityPool;
			for (int i = 1; i < factory.entityCursor; i++)
			{
				if (entityPool[i].id == i && IsCollectorProto(entityPool[i].protoId))
				{
					list.Add(new ExistingCollector
					{
						objId = i,
						protoId = entityPool[i].protoId,
						pos = entityPool[i].pos,
						recoverable = true,
						isEntity = true
					});
				}
			}
			PrebuildData[] prebuildPool = factory.prebuildPool;
			for (int j = 1; j < factory.prebuildCursor; j++)
			{
				if (prebuildPool[j].id == j && IsCollectorProto(prebuildPool[j].protoId))
				{
					list.Add(new ExistingCollector
					{
						objId = -j,
						protoId = prebuildPool[j].protoId,
						pos = prebuildPool[j].pos,
						recoverable = (prebuildPool[j].itemRequired == 0),
						isEntity = false
					});
				}
			}
			return list;
		}

		private static bool IsCollectorProto(int protoId)
		{
			ItemProto val = ((ProtoSet<ItemProto>)(object)LDB.items).Select(protoId);
			if (val?.prefabDesc != null)
			{
				return val.prefabDesc.isCollectStation;
			}
			return false;
		}

		private static List<Vector3> ChooseTargets(PlanetData planet, List<ExistingCollector> existing)
		{
			PlanetGrid val = planet.aux?.mainGrid;
			int num = val?.segment ?? ((int)(planet.radius / 4f + 0.1f) * 4);
			int num2 = PlanetGrid.DetermineLongitudeSegmentCount(0, num) * 5;
			bool flag = num2 > 0 && num2 % 40 == 0;
			int num3 = ((!flag) ? 1 : (num2 / 40));
			List<Vector3> result = null;
			int num4 = -1;
			for (int i = 0; i < num3; i++)
			{
				List<Vector3> list = ComputeTargets(planet, val, num2, flag, i);
				int num5 = CountMatches(list, existing);
				if (num5 > num4)
				{
					result = list;
					num4 = num5;
				}
			}
			return result;
		}

		private static List<Vector3> ComputeTargets(PlanetData planet, PlanetGrid grid, int gridPoints, bool alignedToGrid, int phase)
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: 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_0098: Unknown result type (might be due to invalid IL or missing references)
			float num = planet.realRadius + 0.2f + planet.realRadius * 0.025f;
			int num2 = (alignedToGrid ? (gridPoints / 40) : 0);
			List<Vector3> list = new List<Vector3>(40);
			for (int i = 0; i < 40; i++)
			{
				float num3 = (alignedToGrid ? ((float)(phase + i * num2) * ((float)Math.PI * 2f) / (float)gridPoints) : ((float)i * ((float)Math.PI * 2f) / 40f));
				Vector3 val = (Vector3)((grid != null) ? grid.SnapTo(num3, 0f) : new Vector3(Mathf.Sin(num3), 0f, 0f - Mathf.Cos(num3)));
				val.y = 0f;
				list.Add(((Vector3)(ref val)).normalized * num);
			}
			return list;
		}

		private static int CountMatches(List<Vector3> targets, List<ExistingCollector> existing)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			bool[] array = new bool[targets.Count];
			int num = 0;
			foreach (ExistingCollector item in existing)
			{
				if (item.isEntity)
				{
					int num2 = FindUnclaimedMatch(targets, array, item.pos);
					if (num2 >= 0)
					{
						array[num2] = true;
						num++;
					}
				}
			}
			return num;
		}

		private static int FindUnclaimedMatch(List<Vector3> targets, bool[] claimed, Vector3 pos)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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)
			for (int i = 0; i < targets.Count; i++)
			{
				if (!claimed[i])
				{
					Vector3 val = targets[i] - pos;
					if (((Vector3)(ref val)).sqrMagnitude < 1f)
					{
						return i;
					}
				}
			}
			return -1;
		}

		private static bool TargetsAreFarEnough(List<Vector3> targets)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < targets.Count; i++)
			{
				Vector3 val = targets[(i + 1) % targets.Count];
				Vector3 val2 = targets[i] - val;
				if (((Vector3)(ref val2)).sqrMagnitude < 14297f)
				{
					return false;
				}
			}
			return true;
		}
	}
	[BepInPlugin("com.yummi.dsp.collectordeployer", "轨道采集器一键部署 (Collector Deployer)", "1.1.0")]
	public class CollectorDeployerPlugin : BaseUnityPlugin
	{
		public const string PLUGIN_GUID = "com.yummi.dsp.collectordeployer";

		public const string PLUGIN_NAME = "轨道采集器一键部署 (Collector Deployer)";

		public const string PLUGIN_VERSION = "1.1.0";

		private static readonly Harmony Harmony = new Harmony("com.yummi.dsp.collectordeployer");

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> EnableGalaxyDeploy;

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			EnableGalaxyDeploy = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableGalaxyDeploy", false, "Show a second button that deploys 40 orbital collectors on every gas giant in the galaxy, including ones you have never visited.\n显示第二个按钮,在全银河所有气态巨星(包括没去过的)上各部署 40 个轨道采集器。");
			Harmony.PatchAll(typeof(UIFunctionPanelPatch));
			Log.LogInfo((object)"轨道采集器一键部署 (Collector Deployer) v1.1.0 已加载");
		}

		private void OnDestroy()
		{
			UIFunctionPanelPatch.DestroyButtons();
			Harmony.UnpatchSelf();
		}
	}
	internal static class Lang
	{
		public static bool IsChinese
		{
			get
			{
				int currentLanguageLCID = Localization.CurrentLanguageLCID;
				if (currentLanguageLCID != 2052)
				{
					return currentLanguageLCID == 1028;
				}
				return true;
			}
		}

		public static string ButtonLabel => T("一键部署\n轨道采集器", "Deploy Orbital\nCollectors");

		public static string TipTitle => T("一键部署轨道采集器", "Deploy Orbital Collectors");

		public static string TipText => T($"在赤道上按格点均匀部署 {40} 个轨道采集器,不在格点上的会被拆除重建。", $"Deploys {40} orbital collectors evenly on the equator grid; off-grid ones are rebuilt.");

		public static string GalaxyButtonLabel => T("一键部署\n全银河", "Deploy in\nWhole Galaxy");

		public static string GalaxyTipTitle => T("全银河部署轨道采集器", "Deploy Orbital Collectors in the Whole Galaxy");

		public static string GalaxyTipText => T($"在全银河所有气态巨星(包括没去过的)的赤道上各部署 {40} 个轨道采集器,执行前会显示汇总。", $"Deploys {40} orbital collectors on the equator of every gas giant in the galaxy, including unvisited ones. A summary is shown first.");

		public static string T(string zh, string en)
		{
			if (!IsChinese)
			{
				return en;
			}
			return zh;
		}
	}
	[HarmonyPatch(typeof(UIFunctionPanel))]
	public static class UIFunctionPanelPatch
	{
		private sealed class DeployButton
		{
			public UIButton button;

			public RectTransform rect;

			public RectTransform widthRect;

			public Text[] texts;

			public int labelLcid = -1;

			public Func<string> label;

			public Func<string> tipTitle;

			public Func<string> tipText;
		}

		private const float Gap = 8f;

		private const int CollectorItemId = 2105;

		private static DeployButton _local;

		private static DeployButton _galaxy;

		private static bool _createFailed;

		private static readonly Vector3[] Corners = (Vector3[])(object)new Vector3[4];

		[HarmonyPostfix]
		[HarmonyPatch("_OnUpdate")]
		public static void OnUpdate_Postfix(UIFunctionPanel __instance)
		{
			UIButton extractButton = __instance.extractButton;
			if ((Object)(object)extractButton == (Object)null)
			{
				return;
			}
			if (_local == null || _galaxy == null)
			{
				if (_createFailed)
				{
					return;
				}
				CreateButtons(__instance);
				if (_local == null || _galaxy == null)
				{
					return;
				}
			}
			bool activeSelf = ((Component)extractButton).gameObject.activeSelf;
			bool flag = activeSelf && CollectorDeployerPlugin.EnableGalaxyDeploy.Value;
			SetActive(_local, activeSelf);
			SetActive(_galaxy, flag);
			if (activeSelf)
			{
				float width = SyncSizeAndGetWidth(__instance, _local);
				RefreshLabel(_local);
				int slot = 1;
				if (flag)
				{
					SyncSizeAndGetWidth(__instance, _galaxy);
					RefreshLabel(_galaxy);
					Place(__instance, _galaxy, width, slot++);
				}
				Place(__instance, _local, width, slot);
			}
		}

		internal static void DestroyButtons()
		{
			if ((Object)(object)_local?.button != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)_local.button).gameObject);
			}
			if ((Object)(object)_galaxy?.button != (Object)null)
			{
				Object.Destroy((Object)(object)((Component)_galaxy.button).gameObject);
			}
			_local = null;
			_galaxy = null;
		}

		private static void CreateButtons(UIFunctionPanel panel)
		{
			try
			{
				_local = CreateButton(panel, "collector-deployer-button", CollectorDeploy.RequestLocal, () => Lang.ButtonLabel, () => Lang.TipTitle, () => Lang.TipText);
				_galaxy = CreateButton(panel, "collector-deployer-galaxy-button", CollectorDeploy.RequestGalaxy, () => Lang.GalaxyButtonLabel, () => Lang.GalaxyTipTitle, () => Lang.GalaxyTipText);
				ManualLogSource log = CollectorDeployerPlugin.Log;
				if (log != null)
				{
					log.LogDebug((object)("一键部署按钮已创建:\n" + DumpHierarchy(((Component)_local.button).transform, 0)));
				}
			}
			catch (Exception arg)
			{
				_createFailed = true;
				ManualLogSource log2 = CollectorDeployerPlugin.Log;
				if (log2 != null)
				{
					log2.LogError((object)$"创建按钮失败: {arg}");
				}
				DestroyButtons();
			}
		}

		private static DeployButton CreateButton(UIFunctionPanel panel, string name, Action onClick, Func<string> label, Func<string> tipTitle, Func<string> tipText)
		{
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Expected O, but got Unknown
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Expected O, but got Unknown
			UIButton extractButton = panel.extractButton;
			GameObject val = Object.Instantiate<GameObject>(((Component)extractButton).gameObject, ((Component)extractButton).transform.parent, false);
			((Object)val).name = name;
			Localizer[] componentsInChildren = val.GetComponentsInChildren<Localizer>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Object.Destroy((Object)(object)componentsInChildren[i]);
			}
			EventTrigger[] componentsInChildren2 = val.GetComponentsInChildren<EventTrigger>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				Object.Destroy((Object)(object)componentsInChildren2[i]);
			}
			DeployButton deployButton = new DeployButton
			{
				button = val.GetComponent<UIButton>(),
				rect = val.GetComponent<RectTransform>(),
				label = label,
				tipTitle = tipTitle,
				tipText = tipText
			};
			UIButton button = deployButton.button;
			button.eventReceiver = null;
			button.highlighted = false;
			button.tips.itemId = 0;
			if ((Object)(object)button.button != (Object)null)
			{
				button.button.onClick = new ButtonClickedEvent();
				((UnityEvent)button.button.onClick).AddListener((UnityAction)delegate
				{
					onClick();
				});
			}
			else
			{
				button.onClick += delegate
				{
					onClick();
				};
			}
			ref RectTransform widthRect = ref deployButton.widthRect;
			Transform obj = FindCounterpart(((Component)extractButton).transform, (Transform)(object)panel.extractButtonTrans, val.transform);
			widthRect = (RectTransform)(((object)((obj is RectTransform) ? obj : null)) ?? ((object)deployButton.rect));
			if ((Object)(object)panel.extractProgressImage != (Object)null)
			{
				Transform val2 = FindCounterpart(((Component)extractButton).transform, ((Component)panel.extractProgressImage).transform, val.transform);
				if (val2 != null)
				{
					Image component = ((Component)val2).GetComponent<Image>();
					if (component != null)
					{
						component.fillAmount = 0f;
						((Behaviour)component).enabled = false;
					}
				}
			}
			deployButton.texts = val.GetComponentsInChildren<Text>(true);
			SetIcon(val);
			val.SetActive(false);
			return deployButton;
		}

		private static void SetActive(DeployButton b, bool active)
		{
			if (((Component)b.button).gameObject.activeSelf != active)
			{
				((Component)b.button).gameObject.SetActive(active);
			}
		}

		private static void RefreshLabel(DeployButton b)
		{
			int currentLanguageLCID = Localization.CurrentLanguageLCID;
			if (currentLanguageLCID == b.labelLcid)
			{
				return;
			}
			b.labelLcid = currentLanguageLCID;
			string text = b.label();
			Text[] texts = b.texts;
			if (texts != null && texts.Length != 0)
			{
				string[] array = text.Split(new char[1] { '\n' });
				if (texts.Length >= array.Length && array.Length > 1)
				{
					for (int i = 0; i < texts.Length; i++)
					{
						texts[i].text = ((i < array.Length) ? array[i] : "");
					}
				}
				else
				{
					texts[0].text = text;
					for (int j = 1; j < texts.Length; j++)
					{
						texts[j].text = "";
					}
				}
			}
			b.button.tips.tipTitle = b.tipTitle();
			b.button.tips.tipText = b.tipText();
		}

		private static float SyncSizeAndGetWidth(UIFunctionPanel panel, DeployButton b)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_0030: 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_007c: 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_0054: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = (RectTransform)((Component)panel.extractButton).transform;
			RectTransform val2 = (((Object)(object)panel.extractButtonTrans != (Object)null) ? panel.extractButtonTrans : val);
			b.rect.sizeDelta = val.sizeDelta;
			if ((Object)(object)b.widthRect != (Object)(object)b.rect)
			{
				b.widthRect.sizeDelta = val2.sizeDelta;
			}
			Transform parent = ((Transform)val).parent;
			val2.GetWorldCorners(Corners);
			return parent.InverseTransformPoint(Corners[2]).x - parent.InverseTransformPoint(Corners[0]).x;
		}

		private static void Place(UIFunctionPanel panel, DeployButton b, float width, int slot)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			RectTransform val = (RectTransform)((Component)panel.extractButton).transform;
			b.rect.anchoredPosition = val.anchoredPosition - new Vector2((width + 8f) * (float)slot, 0f);
		}

		private static void SetIcon(GameObject go)
		{
			ItemProto val = ((ProtoSet<ItemProto>)(object)LDB.items).Select(2105);
			if ((Object)(object)((val != null) ? val.iconSprite : null) == (Object)null)
			{
				return;
			}
			Image[] componentsInChildren = go.GetComponentsInChildren<Image>(true);
			foreach (Image val2 in componentsInChildren)
			{
				if (((Object)val2).name.ToLowerInvariant().Contains("icon"))
				{
					val2.sprite = val.iconSprite;
				}
			}
		}

		private static Transform FindCounterpart(Transform srcRoot, Transform srcTarget, Transform cloneRoot)
		{
			if ((Object)(object)srcTarget == (Object)null)
			{
				return null;
			}
			if ((Object)(object)srcTarget == (Object)(object)srcRoot)
			{
				return cloneRoot;
			}
			if (!srcTarget.IsChildOf(srcRoot))
			{
				return null;
			}
			List<int> list = new List<int>();
			Transform val = srcTarget;
			while ((Object)(object)val != (Object)(object)srcRoot)
			{
				list.Add(val.GetSiblingIndex());
				val = val.parent;
			}
			Transform val2 = cloneRoot;
			for (int num = list.Count - 1; num >= 0; num--)
			{
				if (list[num] >= val2.childCount)
				{
					return null;
				}
				val2 = val2.GetChild(list[num]);
			}
			return val2;
		}

		private static string DumpHierarchy(Transform t, int depth)
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append(' ', depth * 2).Append(((Object)t).name);
			Component[] components = ((Component)t).GetComponents<Component>();
			foreach (Component val in components)
			{
				stringBuilder.Append(" [").Append(((object)val).GetType().Name).Append(']');
			}
			stringBuilder.Append('\n');
			for (int j = 0; j < t.childCount; j++)
			{
				stringBuilder.Append(DumpHierarchy(t.GetChild(j), depth + 1));
			}
			return stringBuilder.ToString();
		}
	}
}