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();
}
}
}