Decompiled source of LogisticsCapacities v0.1.3

LogisticsCapacities.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;

[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: InternalsVisibleTo("LogisticsCapacities.Tests")]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyTitle("Logistics Capacities")]
[assembly: AssemblyCompany("Loki Moon Labs")]
[assembly: AssemblyFileVersion("0.1.3.0")]
[assembly: AssemblyVersion("0.1.3.0")]
namespace LokiMoonLabs.LogisticsCapacities;

[HarmonyPatch]
internal static class Cargo
{
	internal static int Drone(int original)
	{
		return Limits.Scale(original, Plugin.Options.DroneCarry.Value, 536870911);
	}

	internal static int Ship(int original)
	{
		return Limits.Scale(original, Plugin.Options.ShipCarry.Value, 536870911);
	}

	internal static int Courier(int original)
	{
		return Limits.Scale(original, Plugin.Options.CourierCarry.Value, 536870911);
	}

	[HarmonyTargetMethods]
	private static IEnumerable<MethodBase> Targets()
	{
		List<MethodBase> list = new List<MethodBase>();
		Add(list, typeof(PlanetTransport), "GameTick");
		Add(list, typeof(PlanetTransport), "RefreshStationTraffic");
		Add(list, typeof(GalacticTransport), "GameTick");
		Add(list, typeof(GalacticTransport), "RefreshTraffic");
		Add(list, typeof(StationComponent), "DetermineDispatch");
		Add(list, typeof(StationComponent), "InternalTickLocal");
		Add(list, typeof(DispenserComponent), "InternalTick");
		Add(list, typeof(UITechTree), "RefreshDataValueText");
		Add(list, typeof(ItemProto), "GetPropValue");
		Add(list, typeof(UIPlayerDeliveryPanel), "_OnUpdate");
		Type type = AccessTools.TypeByName("BuildToolOpt.GalacticTransport_Patch");
		if (type != null)
		{
			MethodInfo methodInfo = AccessTools.Method(type, "RefreshTraffic_Prefix", (Type[])null, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(type, "Guard_Postfix", (Type[])null, (Type[])null);
			if (methodInfo != null)
			{
				list.Add(methodInfo);
			}
			if (methodInfo2 != null)
			{
				list.Add(methodInfo2);
			}
		}
		return list;
	}

	private static void Add(List<MethodBase> targets, Type type, string name)
	{
		MethodInfo methodInfo = AccessTools.Method(type, name, (Type[])null, (Type[])null);
		if (methodInfo == null)
		{
			throw new MissingMethodException(type.FullName, name);
		}
		targets.Add(methodInfo);
	}

	[HarmonyTranspiler]
	internal static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> source)
	{
		//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00da: Expected O, but got Unknown
		List<CodeInstruction> list = new List<CodeInstruction>(source);
		for (int num = list.Count - 1; num >= 0; num--)
		{
			FieldInfo fieldInfo = list[num].operand as FieldInfo;
			if (!(list[num].opcode != OpCodes.Ldfld) && !(fieldInfo == null) && !(fieldInfo.DeclaringType != typeof(GameHistoryData)))
			{
				string text = ((fieldInfo.Name == "logisticDroneCarries") ? "Drone" : ((fieldInfo.Name == "logisticShipCarries") ? "Ship" : ((fieldInfo.Name == "logisticCourierCarries") ? "Courier" : null)));
				if (text != null)
				{
					list.Insert(num + 1, new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(Cargo), text, (Type[])null, (Type[])null)));
				}
			}
		}
		return list;
	}
}
[HarmonyPatch]
internal static class ExtraStorage
{
	internal static int Local(int amount)
	{
		return Limits.Scale(amount, Plugin.Options.PLS.Storage.Value, 536870911);
	}

	internal static int Remote(int amount)
	{
		return Limits.Scale(amount, Plugin.Options.ILS.Storage.Value, 536870911);
	}

	[HarmonyTargetMethods]
	private static IEnumerable<MethodBase> Targets()
	{
		return new MethodBase[2]
		{
			AccessTools.Method(typeof(PlanetTransport), "NewStationComponent", (Type[])null, (Type[])null),
			AccessTools.Method(typeof(PlanetTransport), "SetStationStorage", (Type[])null, (Type[])null)
		};
	}

	[HarmonyTranspiler]
	internal static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> source)
	{
		//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bb: Expected O, but got Unknown
		List<CodeInstruction> list = new List<CodeInstruction>(source);
		for (int num = list.Count - 1; num >= 0; num--)
		{
			FieldInfo fieldInfo = list[num].operand as FieldInfo;
			if (!(list[num].opcode != OpCodes.Ldfld) && !(fieldInfo == null) && !(fieldInfo.DeclaringType != typeof(GameHistoryData)))
			{
				string text = ((fieldInfo.Name == "localStationExtraStorage") ? "Local" : ((fieldInfo.Name == "remoteStationExtraStorage") ? "Remote" : null));
				if (text != null)
				{
					list.Insert(num + 1, new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(ExtraStorage), text, (Type[])null, (Type[])null)));
				}
			}
		}
		return list;
	}
}
[HarmonyPatch]
internal static class AssemblyBuffers
{
	[HarmonyPrepare]
	private static bool Prepare()
	{
		return AccessTools.TypeByName("MoreMegaStructure.StarAssembly") != null;
	}

	[HarmonyTargetMethod]
	private static MethodBase Target()
	{
		return AccessTools.Method(AccessTools.TypeByName("MoreMegaStructure.StarAssembly"), "InternalUpdate", (Type[])null, (Type[])null);
	}

	[HarmonyTranspiler]
	internal static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> source)
	{
		List<CodeInstruction> list = new List<CodeInstruction>(source);
		foreach (CodeInstruction item in list)
		{
			if (!(item.opcode != OpCodes.Ldc_I4))
			{
				int num = (int)item.operand;
				if (num == 99999 || num == 10000)
				{
					item.operand = Limits.Scale(num, Plugin.Options.AssemblyStorage.Value, 536870911);
				}
			}
		}
		return list;
	}
}
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("LokiMoonLabs.LogisticsCapacities", "Logistics Capacities", "0.1.3")]
[BepInIncompatibility("org.fyyy.interstellarlogisticsopt")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInIncompatibility("com.Valoneu.SpaciousStations")]
[BepInIncompatibility("com.Valoneu.DistributeWarpers")]
public sealed class Plugin : BaseUnityPlugin
{
	[HarmonyPatch(typeof(VFPreload), "InvokeOnLoadWorkEnded")]
	private static class Prototypes
	{
		[HarmonyPostfix]
		[HarmonyPriority(0)]
		private static void Postfix()
		{
			Stations.Prepare();
		}
	}

	[HarmonyPatch(typeof(GameMain), "Begin")]
	private static class Loaded
	{
		[HarmonyPriority(0)]
		[HarmonyPostfix]
		private static void Postfix()
		{
			Stations.Prepare();
			Existing(GameMain.data);
			Warpers.Attach();
		}
	}

	[HarmonyPatch(typeof(PlanetTransport), "NewStationComponent")]
	private static class NewStation
	{
		[HarmonyPriority(800)]
		[HarmonyPostfix]
		private static void Postfix(PlanetTransport __instance, StationComponent __result)
		{
			Stations.Apply(__instance.factory, __result, (__instance.factory == null || __instance.factory.gameData == null) ? null : __instance.factory.gameData.history);
		}
	}

	[HarmonyPatch(typeof(GameHistoryData), "UnlockTechFunction")]
	private static class Research
	{
		[HarmonyPostfix]
		private static void Postfix(GameHistoryData __instance)
		{
			if (__instance.localStationExtraStorage != lastLocal || __instance.remoteStationExtraStorage != lastRemote)
			{
				Existing(GameMain.data);
			}
		}
	}

	[HarmonyPatch(typeof(UIStationStorage), "GetAdditionStorage")]
	private static class StorageDisplay
	{
		[HarmonyPostfix]
		private static void Postfix(StationComponent ___station, ref int __result)
		{
			__result = Stations.UIExtra(__result, ___station, (GameMain.localPlanet == null) ? null : GameMain.localPlanet.factory);
		}
	}

	[HarmonyPatch(typeof(UIControlPanelStationStorage), "GetAdditionStorage")]
	private static class ControlDisplay
	{
		[HarmonyPostfix]
		private static void Postfix(StationComponent ___station, PlanetFactory ___factory, ref int __result)
		{
			__result = Stations.UIExtra(__result, ___station, ___factory);
		}
	}

	internal static Settings Options;

	private Harmony harmony;

	private static Plugin instance;

	private static int lastLocal;

	private static int lastRemote;

	private void Awake()
	{
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Expected O, but got Unknown
		Options = new Settings(((BaseUnityPlugin)this).Config);
		((BaseUnityPlugin)this).Config.Save();
		instance = this;
		harmony = new Harmony("LokiMoonLabs.LogisticsCapacities");
		harmony.PatchAll(typeof(Plugin).Assembly);
		((BaseUnityPlugin)this).Logger.LogInfo((object)("Logistics Capacities ready. Settings are in " + ((BaseUnityPlugin)this).Config.ConfigFilePath));
	}

	private void OnDestroy()
	{
		Warpers.Detach();
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
		if ((Object)(object)instance == (Object)(object)this)
		{
			instance = null;
		}
	}

	internal static void WarperError(Exception error)
	{
		if ((Object)(object)instance != (Object)null)
		{
			((BaseUnityPlugin)instance).Logger.LogError((object)("Warper distribution stopped until the next save load: " + error));
		}
	}

	internal static void Existing(GameData data)
	{
		if (data == null || data.factories == null || data.history == null)
		{
			return;
		}
		lastLocal = data.history.localStationExtraStorage;
		lastRemote = data.history.remoteStationExtraStorage;
		int num = 0;
		PlanetFactory[] factories = data.factories;
		foreach (PlanetFactory val in factories)
		{
			if (val == null || val.transport == null || val.transport.stationPool == null)
			{
				continue;
			}
			StationComponent[] stationPool = val.transport.stationPool;
			foreach (StationComponent val2 in stationPool)
			{
				if (val2 != null && val2.id > 0)
				{
					Stations.Apply(val, val2, data.history);
					num++;
				}
			}
		}
		if ((Object)(object)instance != (Object)null)
		{
			((BaseUnityPlugin)instance).Logger.LogInfo((object)("Updated limits for " + num + " stations; item counts and working carriers retained."));
		}
	}
}
[HarmonyPatch(typeof(GalacticTransport), "GameTick")]
internal static class Scheduling
{
	[HarmonyPriority(800)]
	[HarmonyPrefix]
	internal static bool Tick(GalacticTransport __instance, long time)
	{
		//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0103: Expected I4, but got Unknown
		Settings options = Plugin.Options;
		if (!options.Optimize.Value || options.Factor.Value <= 1)
		{
			return true;
		}
		GameData gameData = __instance.gameData;
		if (gameData == null || gameData.history == null || gameData.statistics == null || gameData.statistics.production == null || __instance.stationPool == null)
		{
			return true;
		}
		GameHistoryData history = gameData.history;
		int cargo = Cargo.Ship(history.logisticShipCarries);
		float logisticShipSailSpeedModified = history.logisticShipSailSpeedModified;
		float warp = (history.logisticShipWarpDrive ? history.logisticShipWarpSpeedModified : logisticShipSailSpeedModified);
		int num = Math.Min(__instance.stationCursor, __instance.stationPool.Length);
		for (int i = 1; i <= 6; i++)
		{
			int num2 = i % 6;
			int num3 = Limits.Period(i, options.ShipInterval.Value, options.Factor.Value);
			for (int j = Limits.First(time, num3); j < num; j += num3)
			{
				StationComponent val = __instance.stationPool[j];
				if (val != null && val.id > 0 && val.gid == j && Limits.Eligible(num2, (int)val.routePriority))
				{
					Dispatch(val, logisticShipSailSpeedModified, warp, cargo, num2, __instance.stationPool, gameData.statistics.production.factoryStatPool, gameData.factories, gameData.galaxy, gameData.statistics.traffic);
				}
			}
		}
		return false;
	}

	internal static void Dispatch(StationComponent station, float sail, float warp, int cargo, int priority, StationComponent[] pool, FactoryProductionStat[] stats, PlanetFactory[] factories, GalaxyData galaxy, TrafficStatistics traffic)
	{
		for (int i = 0; i < Plugin.Options.ShipsPerVisit.Value; i++)
		{
			int idleShipCount = station.idleShipCount;
			station.DetermineDispatch(sail, warp, cargo, priority, pool, stats, factories, galaxy, traffic);
			if (station.idleShipCount >= idleShipCount)
			{
				break;
			}
		}
	}

	[HarmonyTranspiler]
	internal static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> source)
	{
		List<CodeInstruction> list = new List<CodeInstruction>(source);
		MethodInfo objB = AccessTools.Method(typeof(StationComponent), "DetermineDispatch", (Type[])null, (Type[])null);
		MethodInfo operand = AccessTools.Method(typeof(Scheduling), "Dispatch", (Type[])null, (Type[])null);
		int num = 0;
		foreach (CodeInstruction item in list)
		{
			if (object.Equals(item.operand, objB))
			{
				item.opcode = OpCodes.Call;
				item.operand = operand;
				num++;
			}
		}
		if (num != 3)
		{
			throw new InvalidOperationException("Logistics Capacities: native vessel scheduling signature changed.");
		}
		return list;
	}
}
[HarmonyPatch(typeof(StationComponent), "DetermineFramingDispatchTime")]
internal static class NativeCadence
{
	[HarmonyPrefix]
	internal static bool Prefix(long time, int priorityIndex, ref bool __result)
	{
		__result = time % Limits.Period(priorityIndex, Plugin.Options.ShipInterval.Value, 1) == 0;
		return false;
	}
}
[HarmonyPatch(typeof(StationComponent), "InternalTickLocal")]
internal static class DroneCadence
{
	[HarmonyPrefix]
	private static void Prefix(StationComponent __instance)
	{
		__instance.droneTaskInterval = Plugin.Options.DroneInterval.Value;
	}
}
internal sealed class StationSettings
{
	internal readonly ConfigEntry<double> Drones;

	internal readonly ConfigEntry<double> Vessels;

	internal readonly ConfigEntry<double> Charge;

	internal readonly ConfigEntry<double> Energy;

	internal readonly ConfigEntry<float> Storage;

	internal StationSettings(Settings owner, string section, bool ships)
	{
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a6: Expected O, but got Unknown
		Drones = owner.Number(section, "DroneMultiplier", 1.0, 1.0, 100.0, "Station drone-count multiplier. Native work arrays are preserved and enlarged as needed, up to 1,000 drones.");
		Vessels = (ships ? owner.Number(section, "ShipMultiplier", 1.0, 1.0, 6.4, "Station vessel-count multiplier. Native ship-index masks impose a maximum of 64 vessels.") : null);
		Storage = owner.File.Bind<float>(section, "StorageMultiplier", 1f, new ConfigDescription("Item storage multiplier. Existing occupied slots and their limits are never reduced on load. Restart to apply changes.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 1000f), new object[0]));
		Charge = owner.Number(section, "ChargeMultiplier", 1.0, 1.0, 1000.0, "Charging power limit multiplier. Existing chosen charging rates are retained; Logistics Architect can still set them.");
		Energy = owner.Number(section, "EnergyMultiplier", 1.0, 1.0, 1000.0, "Station energy-buffer multiplier. Existing stored energy is retained.");
	}
}
internal sealed class Settings
{
	internal readonly ConfigFile File;

	internal readonly ConfigEntry<double> DroneCarry;

	internal readonly ConfigEntry<double> ShipCarry;

	internal readonly ConfigEntry<double> CourierCarry;

	internal readonly ConfigEntry<double> AssemblyStorage;

	internal readonly ConfigEntry<int> DroneInterval;

	internal readonly ConfigEntry<int> ShipInterval;

	internal readonly ConfigEntry<int> Factor;

	internal readonly ConfigEntry<int> ShipsPerVisit;

	internal readonly ConfigEntry<bool> Optimize;

	internal readonly ConfigEntry<bool> WarperDistribution;

	internal readonly ConfigEntry<int> WarperTarget;

	internal readonly ConfigEntry<int> WarperInterval;

	internal readonly StationSettings PLS;

	internal readonly StationSettings ILS;

	internal readonly StationSettings Exchange;

	internal Settings(ConfigFile file)
	{
		File = file;
		File.SaveOnConfigSet = false;
		WarperDistribution = file.Bind<bool>("Warper Distribution", "Enabled", false, "Automatically move real warpers from station cargo slots into ILS reserves on the same planet. Off preserves vanilla behavior. Disable the separate DistributeWarpers mod.");
		WarperTarget = Integer("Warper Distribution", "TargetCount", 50, 0, 50, "Desired internal warper reserve per ILS. Never removes reserves above this target. No local/remote slot-mode requirement.");
		WarperInterval = Integer("Warper Distribution", "CheckInterval", 120, 1, 36000, "Ticks between checks per planet. Planet checks are staggered across ticks; 120 ticks is about two seconds at normal simulation speed.");
		RemoveObsolete(file, "General", "ImportExistingSettings");
		RemoveObsolete(file, "Internal", "ImportedLegacySettings");
		RemoveObsolete(file, "Planetary Logistics Station", "ShipMultiplier");
		DroneCarry = Number("General", "DroneCarryMultiplier", 1.0, 1.0, 1000.0, "Cargo multiplier for each station logistics drone, applied to researched cargo capacity.");
		ShipCarry = Number("General", "ShipCarryMultiplier", 1.0, 1.0, 1000.0, "Cargo multiplier for each logistics vessel. Both native and optimized dispatch use the same value.");
		CourierCarry = Number("General", "CourierCarryMultiplier", 1.0, 1.0, 1000.0, "Cargo multiplier for logistics courier bots. Independent bot-capacity overrides from other mods may take precedence.");
		DroneInterval = Integer("General", "DroneTaskInterval", 20, 1, 600, "Ticks between local drone dispatch attempts. Lower values dispatch more often and can cost more CPU.");
		ShipInterval = Integer("General", "ShipTaskInterval", 10, 1, 600, "Base vessel dispatch interval in ticks. Native priority tiers use 1x, 3x and 6x this interval.");
		Optimize = file.Bind<bool>("Scheduling", "Enabled", false, "Spread vessel visits across ticks using station IDs. Off restores the native scheduler with this mod's cargo multipliers and dispatch intervals.");
		Factor = Integer("Scheduling", "AmortizeFactor", 1, 1, 30, "Visit-interval multiplier. At N, dispatch checks occur at 1/N frequency. Trades responsiveness and cross-station priority ordering for less scheduling work. 1 retains native scheduling order.");
		ShipsPerVisit = Integer("Interstellar Logistics Station", "ShipReleasePerTick", 1, 1, 64, "Maximum native dispatch passes per station visit; stop if no vessel launches. More passes increase throughput and CPU work. This is not a separate vessel spawn or instant-delivery feature.");
		PLS = new StationSettings(this, "Planetary Logistics Station", ships: false);
		ILS = new StationSettings(this, "Interstellar Logistics Station", ships: true);
		Exchange = new StationSettings(this, "Megastructures Exchange Station", ships: true);
		AssemblyStorage = Number("Megastructures Exchange Station", "InternalsMultiplier", 1.0, 1.0, 1000.0, "Optional MoreMegaStructure interstellar assembly internal-buffer multiplier.");
	}

	private static void RemoveObsolete(ConfigFile file, string section, string key)
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_0020: Expected O, but got Unknown
		file.Bind<string>(section, key, "", "");
		file.Remove(new ConfigDefinition(section, key));
	}

	internal ConfigEntry<double> Number(string section, string key, double fallback, double minimum, double maximum, string description)
	{
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Expected O, but got Unknown
		return File.Bind<double>(section, key, Math.Max(minimum, Math.Min(maximum, fallback)), new ConfigDescription(description + " Restart to apply changes.", (AcceptableValueBase)(object)new AcceptableValueRange<double>(minimum, maximum), new object[0]));
	}

	private ConfigEntry<int> Integer(string section, string key, int fallback, int minimum, int maximum, string description)
	{
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Expected O, but got Unknown
		return File.Bind<int>(section, key, Math.Max(minimum, Math.Min(maximum, fallback)), new ConfigDescription(description + " Restart to apply changes.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(minimum, maximum), new object[0]));
	}
}
internal static class Limits
{
	internal static int Scale(int original, double multiplier, int ceiling)
	{
		if (original <= 0)
		{
			return original;
		}
		if (double.IsNaN(multiplier) || double.IsInfinity(multiplier) || multiplier < 1.0)
		{
			multiplier = 1.0;
		}
		return (int)Math.Min(ceiling, Math.Max(original, Math.Floor((double)original * multiplier)));
	}

	internal static long ScaleEnergy(long original, double multiplier)
	{
		if (original <= 0)
		{
			return original;
		}
		if (double.IsNaN(multiplier) || double.IsInfinity(multiplier) || multiplier < 1.0)
		{
			multiplier = 1.0;
		}
		double num = Math.Max(original, Math.Floor((double)original * multiplier));
		if (!(num >= 9.223372036854776E+17))
		{
			return (long)num;
		}
		return 922337203685477580L;
	}

	internal static bool Eligible(int pass, int route)
	{
		switch (pass)
		{
		case 1:
		case 2:
		case 3:
		case 4:
			if (route != 2 && route != 3)
			{
				return route == 4;
			}
			return true;
		default:
			return false;
		case 5:
			return route == 2;
		case 0:
			return route == 1;
		}
	}

	internal static int Period(int pass, int interval, int factor)
	{
		int num = Math.Max(1, interval) * Math.Max(1, factor);
		int num2;
		switch (pass)
		{
		default:
			num2 = 6;
			break;
		case 2:
		case 3:
			num2 = 3;
			break;
		case 1:
			num2 = 1;
			break;
		}
		return num * num2;
	}

	internal static int First(long tick, int period)
	{
		return (int)((tick % period + period) % period) + 1;
	}
}
internal sealed class Shape
{
	internal int Drones;

	internal int Ships;

	internal int Storage;

	internal long Energy;

	internal long Charge;

	internal StationSettings Settings;

	internal Shape(PrefabDesc desc, StationSettings settings)
	{
		Drones = desc.stationMaxDroneCount;
		Ships = desc.stationMaxShipCount;
		Storage = desc.stationMaxItemCount;
		Energy = desc.stationMaxEnergyAcc;
		Charge = desc.workEnergyPerTick;
		Settings = settings;
	}
}
internal static class Stations
{
	internal static readonly Dictionary<PrefabDesc, Shape> Shapes = new Dictionary<PrefabDesc, Shape>();

	internal static bool IsExchange(string name)
	{
		if (!string.IsNullOrEmpty(name))
		{
			if (name.IndexOf("Exchange", StringComparison.OrdinalIgnoreCase) < 0 && name.IndexOf("Interstellar Assembly", StringComparison.OrdinalIgnoreCase) < 0 && !name.Contains("交换"))
			{
				return name.Contains("星际组装");
			}
			return true;
		}
		return false;
	}

	internal static void Prepare()
	{
		if ((Object)(object)LDB.items == (Object)null || ((ProtoSet<ItemProto>)(object)LDB.items).dataArray == null)
		{
			return;
		}
		ItemProto[] dataArray = ((ProtoSet<ItemProto>)(object)LDB.items).dataArray;
		foreach (ItemProto val in dataArray)
		{
			if (val != null)
			{
				PrefabDesc prefabDesc = val.prefabDesc;
				if (prefabDesc != null && prefabDesc.isStation && !prefabDesc.isCollectStation && !Shapes.ContainsKey(prefabDesc))
				{
					StationSettings stationSettings = (IsExchange(((Proto)val).Name) ? Plugin.Options.Exchange : (prefabDesc.isStellarStation ? Plugin.Options.ILS : Plugin.Options.PLS));
					ApplyShape(prefabDesc, stationSettings);
				}
			}
		}
	}

	internal static void ApplyShape(PrefabDesc desc, StationSettings group)
	{
		if (!Shapes.ContainsKey(desc))
		{
			Shape shape = new Shape(desc, group);
			Shapes.Add(desc, shape);
			desc.stationMaxDroneCount = Limits.Scale(shape.Drones, group.Drones.Value, 1000);
			if (desc.isStellarStation)
			{
				desc.stationMaxShipCount = Limits.Scale(shape.Ships, group.Vessels.Value, 64);
			}
			desc.stationMaxItemCount = Limits.Scale(shape.Storage, group.Storage.Value, 536870911);
			desc.stationMaxEnergyAcc = Limits.ScaleEnergy(shape.Energy, group.Energy.Value);
			desc.workEnergyPerTick = Limits.ScaleEnergy(shape.Charge, group.Charge.Value);
		}
	}

	internal static PrefabDesc Description(PlanetFactory factory, StationComponent station)
	{
		//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 (factory == null || station == null || factory.entityPool == null || station.entityId <= 0 || station.entityId >= factory.entityPool.Length)
		{
			return null;
		}
		EntityData val = factory.entityPool[station.entityId];
		if (val.id != station.entityId)
		{
			return null;
		}
		ItemProto val2 = (((Object)(object)LDB.items == (Object)null) ? null : ((ProtoSet<ItemProto>)(object)LDB.items).Select((int)val.protoId));
		if (val2 != null && val2.prefabDesc != null)
		{
			return val2.prefabDesc;
		}
		PrefabDesc[] prefabDescByModelIndex = PlanetFactory.PrefabDescByModelIndex;
		if (prefabDescByModelIndex == null || val.modelIndex < 0 || val.modelIndex >= prefabDescByModelIndex.Length)
		{
			return null;
		}
		return prefabDescByModelIndex[val.modelIndex];
	}

	internal static int StorageMaximum(PrefabDesc desc, StationComponent station, GameHistoryData history)
	{
		if (desc == null)
		{
			return 0;
		}
		int num = ((history != null) ? (station.isStellar ? history.remoteStationExtraStorage : history.localStationExtraStorage) : 0);
		Shape value;
		int num2 = (Shapes.TryGetValue(desc, out value) ? Limits.Scale(num, value.Settings.Storage.Value, 536870911) : Math.Max(0, num));
		return (int)Math.Min(536870911L, (long)desc.stationMaxItemCount + (long)num2);
	}

	internal static void Grow<T>(ref T[] array, int count)
	{
		if (array == null)
		{
			array = new T[count];
		}
		else if (array.Length < count)
		{
			Array.Resize(ref array, count);
		}
	}

	internal static void Apply(PlanetFactory factory, StationComponent station, GameHistoryData history)
	{
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_010c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0126: Unknown result type (might be due to invalid IL or missing references)
		//IL_0164: Unknown result type (might be due to invalid IL or missing references)
		//IL_014f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0169: Unknown result type (might be due to invalid IL or missing references)
		if (station == null || station.id <= 0 || station.isCollector || station.isVeinCollector)
		{
			return;
		}
		PrefabDesc val = Description(factory, station);
		if (val == null)
		{
			return;
		}
		Grow(ref station.workDroneDatas, Math.Max(val.stationMaxDroneCount, station.idleDroneCount + station.workDroneCount));
		Grow(ref station.workDroneOrders, station.workDroneDatas.Length);
		if (station.isStellar)
		{
			int num = Math.Min(64, Math.Max(val.stationMaxShipCount, station.idleShipCount + station.workShipCount));
			Grow(ref station.workShipDatas, num);
			Grow(ref station.workShipOrders, num);
			Grow(ref station.shipRenderers, num);
			Grow(ref station.shipUIRenderers, num);
			int num2 = ((station.shipDiskPos != null) ? station.shipDiskPos.Length : 0);
			Grow(ref station.shipDiskPos, num);
			Grow(ref station.shipDiskRot, num);
			for (int i = num2; i < num; i++)
			{
				ref Vector3 reference = ref station.shipDiskPos[i];
				reference = (Vector3)((num2 > 0) ? station.shipDiskPos[i % num2] : new Vector3(0f, 0f, 0f));
				ref Quaternion reference2 = ref station.shipDiskRot[i];
				reference2 = (Quaternion)((num2 > 0) ? station.shipDiskRot[i % num2] : new Quaternion(0f, 0f, 0f, 1f));
			}
		}
		int val2 = StorageMaximum(val, station, history);
		if (station.storage != null)
		{
			for (int j = 0; j < station.storage.Length; j++)
			{
				station.storage[j].max = Math.Max(station.storage[j].max, Math.Max(val2, station.storage[j].count));
			}
		}
		station.energyMax = Math.Max(station.energy, val.stationMaxEnergyAcc);
	}

	internal static int UIExtra(int original, StationComponent station, PlanetFactory factory)
	{
		if (station == null || station.isCollector || station.isVeinCollector)
		{
			return original;
		}
		PrefabDesc val = Description(factory, station);
		if (val == null || !Shapes.TryGetValue(val, out var value))
		{
			return original;
		}
		return Math.Min(Math.Max(0, 536870911 - val.stationMaxItemCount), Math.Max(0, Limits.Scale(original, value.Settings.Storage.Value, 536870911)));
	}
}
internal static class Warpers
{
	[HarmonyPatch(typeof(GameMain), "End")]
	private static class Ended
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			Detach();
		}
	}

	private static readonly List<StationComponent> donors = new List<StationComponent>();

	private static readonly List<StationComponent> receivers = new List<StationComponent>();

	private static Action detach;

	private static bool failed;

	private static long lastTick = -1L;

	internal static void Attach()
	{
		Detach();
		failed = false;
		lastTick = -1L;
		GameLogic logic = GameMain.logic;
		if (logic != null)
		{
			logic.onFactoryFrameEnd += Tick;
			detach = delegate
			{
				logic.onFactoryFrameEnd -= Tick;
			};
		}
	}

	internal static void Detach()
	{
		if (detach != null)
		{
			detach();
			detach = null;
		}
		donors.Clear();
		receivers.Clear();
		lastTick = -1L;
	}

	private static void Tick()
	{
		Settings options = Plugin.Options;
		if (failed || options == null || !options.WarperDistribution.Value)
		{
			return;
		}
		GameData data = GameMain.data;
		long gameTick = GameMain.gameTick;
		if (data == null || data.factories == null || gameTick == lastTick)
		{
			return;
		}
		lastTick = gameTick;
		int num = Math.Max(1, options.WarperInterval.Value);
		int num2 = (int)((gameTick % num + num) % num);
		try
		{
			for (int i = num2; i < Math.Min(data.factoryCount, data.factories.Length); i += num)
			{
				PlanetFactory val = data.factories[i];
				if (val != null)
				{
					Transfer(val.transport, options.WarperTarget.Value, gameTick / num);
				}
			}
		}
		catch (Exception error)
		{
			failed = true;
			Plugin.WarperError(error);
		}
	}

	internal static int Remove(ref StationStore slot, int wanted)
	{
		if (slot.itemId != 1210 || slot.count <= 0 || slot.inc < 0 || wanted <= 0)
		{
			return 0;
		}
		int num = Math.Min(slot.count, wanted);
		int num2 = (int)((long)(slot.inc / slot.count) * (long)num + Math.Max(0, slot.inc % slot.count - (slot.count - num)));
		slot.count -= num;
		slot.inc -= num2;
		return num;
	}

	internal static int Transfer(PlanetTransport transport, int target, long cycle)
	{
		if (transport == null || transport.stationPool == null)
		{
			return 0;
		}
		target = Math.Max(0, Math.Min(50, target));
		if (target == 0)
		{
			return 0;
		}
		donors.Clear();
		receivers.Clear();
		try
		{
			StationComponent[] stationPool = transport.stationPool;
			for (int i = 1; i < Math.Min(transport.stationCursor, stationPool.Length); i++)
			{
				StationComponent val = stationPool[i];
				if (val == null || val.id != i || val.isCollector || val.isVeinCollector)
				{
					continue;
				}
				if (val.isStellar && val.warperCount >= 0 && val.warperCount < target)
				{
					receivers.Add(val);
				}
				if (val.storage == null)
				{
					continue;
				}
				for (int j = 0; j < val.storage.Length; j++)
				{
					if (val.storage[j].itemId == 1210 && val.storage[j].count > 0 && val.storage[j].inc >= 0)
					{
						donors.Add(val);
						break;
					}
				}
			}
			int num = 0;
			int num2 = 0;
			int num3 = 0;
			if (donors.Count == 0 || receivers.Count == 0)
			{
				return 0;
			}
			int num4 = (int)((cycle % receivers.Count + receivers.Count) % receivers.Count);
			for (int k = 0; k < receivers.Count; k++)
			{
				StationComponent val2 = receivers[(num4 + k) % receivers.Count];
				while (val2.warperCount < target && num < donors.Count)
				{
					StationStore[] storage = donors[num].storage;
					if (num2 >= storage.Length)
					{
						num++;
						num2 = 0;
						continue;
					}
					int num5 = Remove(ref storage[num2], target - val2.warperCount);
					val2.warperCount += num5;
					num3 += num5;
					if (val2.warperCount < target || storage[num2].count <= 0)
					{
						num2++;
					}
				}
				if (num >= donors.Count)
				{
					break;
				}
			}
			return num3;
		}
		finally
		{
			donors.Clear();
			receivers.Clear();
		}
	}
}