using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("PlanetwideSupplier")]
[assembly: AssemblyDescription("Dyson Sphere Program BepInEx mod.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("PlanetwideSupplier")]
[assembly: AssemblyCopyright("Copyright (c) 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("00000000-0000-0000-0000-000000000000")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = "")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace PlanetwideSupplier;
internal static class AmmoSourcing
{
private struct StationDist
{
public int index;
public float distSqr;
}
private static readonly List<StationDist> _scratch = new List<StationDist>(64);
private static readonly Comparison<StationDist> _byDist = (StationDist a, StationDist b) => a.distSqr.CompareTo(b.distSqr);
internal static int TryPullFromPlanet(PlanetFactory factory, int itemId, int want, Vector3 pos, float radius, out int incMoved)
{
//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
//IL_01da: Unknown result type (might be due to invalid IL or missing references)
//IL_01db: Unknown result type (might be due to invalid IL or missing references)
//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
incMoved = 0;
if (factory == null || itemId <= 0 || want <= 0)
{
return 0;
}
PlanetTransport transport = factory.transport;
if (transport == null || transport.stationPool == null)
{
return 0;
}
bool value = Plugin.AmmoRequireStationSupplyFlag.Value;
bool value2 = Plugin.AmmoNearestStationFirst.Value;
float num = ((radius > 0f) ? (radius * radius) : 0f);
EntityData[] entityPool = factory.entityPool;
int stationCursor = transport.stationCursor;
int moved = 0;
Vector3 val2;
if (value2)
{
_scratch.Clear();
for (int i = 1; i < stationCursor; i++)
{
StationComponent val = transport.stationPool[i];
if (val == null || val.id != i || val.storage == null)
{
continue;
}
float num2 = 0f;
if (entityPool != null)
{
int entityId = val.entityId;
if (entityId > 0 && entityId < entityPool.Length)
{
val2 = entityPool[entityId].pos - pos;
num2 = ((Vector3)(ref val2)).sqrMagnitude;
if (num > 0f && num2 > num)
{
continue;
}
}
}
if (StationHasItem(val, itemId, value))
{
_scratch.Add(new StationDist
{
index = i,
distSqr = num2
});
}
}
_scratch.Sort(_byDist);
for (int j = 0; j < _scratch.Count; j++)
{
if (moved >= want)
{
break;
}
DrainStation(transport.stationPool[_scratch[j].index], itemId, want, value, ref moved, ref incMoved);
}
}
else
{
for (int k = 1; k < stationCursor && moved < want; k++)
{
StationComponent val3 = transport.stationPool[k];
if (val3 == null || val3.id != k || val3.storage == null)
{
continue;
}
if (num > 0f && entityPool != null)
{
int entityId2 = val3.entityId;
if (entityId2 > 0 && entityId2 < entityPool.Length)
{
val2 = entityPool[entityId2].pos - pos;
if (((Vector3)(ref val2)).sqrMagnitude > num)
{
continue;
}
}
}
DrainStation(val3, itemId, want, value, ref moved, ref incMoved);
}
}
return moved;
}
private static bool StationHasItem(StationComponent station, int itemId, bool requireSupply)
{
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Invalid comparison between Unknown and I4
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Invalid comparison between Unknown and I4
StationStore[] storage = station.storage;
for (int i = 0; i < storage.Length; i++)
{
if (storage[i].itemId == itemId && storage[i].count > 0 && (!requireSupply || (int)storage[i].localLogic == 1 || (int)storage[i].remoteLogic == 1))
{
return true;
}
}
return false;
}
private static void DrainStation(StationComponent station, int itemId, int want, bool requireSupply, ref int moved, ref int incMoved)
{
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Invalid comparison between Unknown and I4
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Invalid comparison between Unknown and I4
StationStore[] storage = station.storage;
for (int i = 0; i < storage.Length; i++)
{
if (moved >= want)
{
break;
}
if (storage[i].itemId != itemId || storage[i].count <= 0 || (requireSupply && (int)storage[i].localLogic != 1 && (int)storage[i].remoteLogic != 1))
{
continue;
}
int num = want - moved;
if (num > storage[i].count)
{
num = storage[i].count;
}
int num2 = 0;
if (storage[i].inc > 0)
{
num2 = (int)((float)storage[i].inc * (float)num / (float)storage[i].count + 0.5f);
if (num2 > storage[i].inc)
{
num2 = storage[i].inc;
}
}
storage[i].count -= num;
storage[i].inc -= num2;
moved += num;
incMoved += num2;
}
}
internal static int FindAvailableAmmo(PlanetFactory factory, EAmmoType ammoType, Vector3 pos, float radius)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: Expected I4, but got Unknown
//IL_006c: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
int num = (int)ammoType;
if (num <= 0 || ItemProto.turretNeeds == null || num >= ItemProto.turretNeeds.Length)
{
return 0;
}
int[] array = ItemProto.turretNeeds[num];
if (array == null)
{
return 0;
}
if (Plugin.AmmoPreferHighestAmmoTier.Value)
{
for (int num2 = array.Length - 1; num2 >= 0; num2--)
{
int num3 = array[num2];
if (num3 > 0 && HasStock(factory, num3, pos, radius))
{
return num3;
}
}
}
else
{
foreach (int num4 in array)
{
if (num4 > 0 && HasStock(factory, num4, pos, radius))
{
return num4;
}
}
}
return 0;
}
internal static float NearestAmmoStationDistance(PlanetFactory factory, int itemId, EAmmoType ammoType, Vector3 pos)
{
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Expected I4, but got Unknown
//IL_010e: Unknown result type (might be due to invalid IL or missing references)
//IL_0113: Unknown result type (might be due to invalid IL or missing references)
//IL_0114: Unknown result type (might be due to invalid IL or missing references)
//IL_0119: Unknown result type (might be due to invalid IL or missing references)
PlanetTransport val = factory?.transport;
if (val == null || val.stationPool == null)
{
return -1f;
}
bool value = Plugin.AmmoRequireStationSupplyFlag.Value;
EntityData[] entityPool = factory.entityPool;
int stationCursor = val.stationCursor;
int[] array = null;
if (itemId <= 0)
{
int num = (int)ammoType;
if (num > 0 && ItemProto.turretNeeds != null && num < ItemProto.turretNeeds.Length)
{
array = ItemProto.turretNeeds[num];
}
}
float num2 = -1f;
for (int i = 1; i < stationCursor; i++)
{
StationComponent val2 = val.stationPool[i];
if (val2 == null || val2.id != i || val2.storage == null)
{
continue;
}
bool flag = false;
if (itemId > 0)
{
flag = StationHasItem(val2, itemId, value);
}
else if (array != null)
{
for (int j = 0; j < array.Length; j++)
{
if (flag)
{
break;
}
if (array[j] > 0)
{
flag = StationHasItem(val2, array[j], value);
}
}
}
if (!flag)
{
continue;
}
float num3 = 0f;
if (entityPool != null)
{
int entityId = val2.entityId;
if (entityId > 0 && entityId < entityPool.Length)
{
Vector3 val3 = entityPool[entityId].pos - pos;
num3 = ((Vector3)(ref val3)).sqrMagnitude;
}
}
if (num2 < 0f || num3 < num2)
{
num2 = num3;
}
}
if (!(num2 < 0f))
{
return Mathf.Sqrt(num2);
}
return -1f;
}
private static bool HasStock(PlanetFactory factory, int itemId, Vector3 pos, float radius)
{
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
//IL_009c: Unknown result type (might be due to invalid IL or missing references)
PlanetTransport transport = factory.transport;
if (transport == null || transport.stationPool == null)
{
return false;
}
bool value = Plugin.AmmoRequireStationSupplyFlag.Value;
float num = ((radius > 0f) ? (radius * radius) : 0f);
EntityData[] entityPool = factory.entityPool;
int stationCursor = transport.stationCursor;
for (int i = 1; i < stationCursor; i++)
{
StationComponent val = transport.stationPool[i];
if (val == null || val.id != i || val.storage == null)
{
continue;
}
if (num > 0f && entityPool != null)
{
int entityId = val.entityId;
if (entityId > 0 && entityId < entityPool.Length)
{
Vector3 val2 = entityPool[entityId].pos - pos;
if (((Vector3)(ref val2)).sqrMagnitude > num)
{
continue;
}
}
}
if (StationHasItem(val, itemId, value))
{
return true;
}
}
return false;
}
}
internal static class GeneratorSourcing
{
private struct StationDist
{
public int index;
public float distSqr;
}
[ThreadStatic]
private static List<StationDist> _scratch;
private static readonly Comparison<StationDist> _byDist = (StationDist a, StationDist b) => a.distSqr.CompareTo(b.distSqr);
internal static int TryPullFromPlanet(PlanetFactory factory, int itemId, int want, Vector3 pos, float radius, out int incMoved)
{
//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
incMoved = 0;
if (factory == null || itemId <= 0 || want <= 0)
{
return 0;
}
PlanetTransport transport = factory.transport;
if (transport == null || transport.stationPool == null)
{
return 0;
}
bool value = Plugin.GeneratorRequireStationSupplyFlag.Value;
bool value2 = Plugin.GeneratorNearestStationFirst.Value;
float num = ((radius > 0f) ? (radius * radius) : 0f);
EntityData[] entityPool = factory.entityPool;
int stationCursor = transport.stationCursor;
int moved = 0;
Vector3 val2;
if (value2)
{
if (_scratch == null)
{
_scratch = new List<StationDist>(64);
}
_scratch.Clear();
for (int i = 1; i < stationCursor; i++)
{
StationComponent val = transport.stationPool[i];
if (val == null || val.id != i || val.storage == null)
{
continue;
}
float num2 = 0f;
if (entityPool != null)
{
int entityId = val.entityId;
if (entityId > 0 && entityId < entityPool.Length)
{
val2 = entityPool[entityId].pos - pos;
num2 = ((Vector3)(ref val2)).sqrMagnitude;
if (num > 0f && num2 > num)
{
continue;
}
}
}
if (StationHasItem(val, itemId, value))
{
_scratch.Add(new StationDist
{
index = i,
distSqr = num2
});
}
}
_scratch.Sort(_byDist);
for (int j = 0; j < _scratch.Count; j++)
{
if (moved >= want)
{
break;
}
DrainStation(transport.stationPool[_scratch[j].index], itemId, want, value, ref moved, ref incMoved);
}
}
else
{
for (int k = 1; k < stationCursor && moved < want; k++)
{
StationComponent val3 = transport.stationPool[k];
if (val3 == null || val3.id != k || val3.storage == null)
{
continue;
}
if (num > 0f && entityPool != null)
{
int entityId2 = val3.entityId;
if (entityId2 > 0 && entityId2 < entityPool.Length)
{
val2 = entityPool[entityId2].pos - pos;
if (((Vector3)(ref val2)).sqrMagnitude > num)
{
continue;
}
}
}
DrainStation(val3, itemId, want, value, ref moved, ref incMoved);
}
}
return moved;
}
internal static int FindAvailableFuel(PlanetFactory factory, short fuelMask, Vector3 pos, float radius, HashSet<int> exclude = null)
{
//IL_0085: 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)
if (fuelMask <= 0 || ItemProto.fuelNeeds == null || fuelMask >= ItemProto.fuelNeeds.Length)
{
return 0;
}
int[] array = ItemProto.fuelNeeds[fuelMask];
if (array == null)
{
return 0;
}
if (Plugin.GeneratorPreferHighestFuelTier.Value)
{
for (int num = array.Length - 1; num >= 0; num--)
{
int num2 = array[num];
if (num2 > 0 && (exclude == null || !exclude.Contains(num2)) && HasStock(factory, num2, pos, radius))
{
return num2;
}
}
}
else
{
foreach (int num3 in array)
{
if (num3 > 0 && (exclude == null || !exclude.Contains(num3)) && HasStock(factory, num3, pos, radius))
{
return num3;
}
}
}
return 0;
}
internal static int FindPriorityFuel(PlanetFactory factory, int[] priorityItemIds, Vector3 pos, float radius)
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
if (priorityItemIds == null)
{
return 0;
}
foreach (int num in priorityItemIds)
{
if (num > 0 && HasStock(factory, num, pos, radius))
{
return num;
}
}
return 0;
}
internal static int[] ResolveItemNamesByCsv(string csv)
{
if (string.IsNullOrWhiteSpace(csv))
{
return Array.Empty<int>();
}
string[] array = csv.Split(',');
List<int> list = new List<int>(array.Length);
for (int i = 0; i < array.Length; i++)
{
string text = array[i].Trim();
if (text.Length != 0)
{
int num = FindItemIdByName(text);
if (num > 0)
{
list.Add(num);
}
else
{
PlanetwideSupplierLog.Warn("[fuel] no item found matching name: " + text);
}
}
}
return list.ToArray();
}
private static int FindItemIdByName(string name)
{
ItemProto[] dataArray = ((ProtoSet<ItemProto>)(object)LDB.items).dataArray;
if (dataArray == null)
{
return 0;
}
foreach (ItemProto val in dataArray)
{
if (val != null && string.Equals(((Proto)val).name, name, StringComparison.OrdinalIgnoreCase))
{
return ((Proto)val).ID;
}
}
return 0;
}
internal static float NearestFuelStationDistance(PlanetFactory factory, short fuelMask, int itemId, Vector3 pos)
{
//IL_0108: Unknown result type (might be due to invalid IL or missing references)
//IL_010d: Unknown result type (might be due to invalid IL or missing references)
//IL_010e: Unknown result type (might be due to invalid IL or missing references)
//IL_0113: Unknown result type (might be due to invalid IL or missing references)
PlanetTransport val = factory?.transport;
if (val == null || val.stationPool == null)
{
return -1f;
}
bool value = Plugin.GeneratorRequireStationSupplyFlag.Value;
EntityData[] entityPool = factory.entityPool;
int stationCursor = val.stationCursor;
int[] array = null;
if (itemId <= 0 && fuelMask > 0 && ItemProto.fuelNeeds != null && fuelMask < ItemProto.fuelNeeds.Length)
{
array = ItemProto.fuelNeeds[fuelMask];
}
float num = -1f;
for (int i = 1; i < stationCursor; i++)
{
StationComponent val2 = val.stationPool[i];
if (val2 == null || val2.id != i || val2.storage == null)
{
continue;
}
bool flag = false;
if (itemId > 0)
{
flag = StationHasItem(val2, itemId, value);
}
else if (array != null)
{
for (int j = 0; j < array.Length; j++)
{
if (flag)
{
break;
}
if (array[j] > 0)
{
flag = StationHasItem(val2, array[j], value);
}
}
}
if (!flag)
{
continue;
}
float num2 = 0f;
if (entityPool != null)
{
int entityId = val2.entityId;
if (entityId > 0 && entityId < entityPool.Length)
{
Vector3 val3 = entityPool[entityId].pos - pos;
num2 = ((Vector3)(ref val3)).sqrMagnitude;
}
}
if (num < 0f || num2 < num)
{
num = num2;
}
}
if (!(num < 0f))
{
return Mathf.Sqrt(num);
}
return -1f;
}
private static bool StationHasItem(StationComponent station, int itemId, bool requireSupply)
{
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Invalid comparison between Unknown and I4
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Invalid comparison between Unknown and I4
StationStore[] storage = station.storage;
for (int i = 0; i < storage.Length; i++)
{
if (storage[i].itemId == itemId && storage[i].count > 0 && (!requireSupply || (int)storage[i].localLogic == 1 || (int)storage[i].remoteLogic == 1))
{
return true;
}
}
return false;
}
private static void DrainStation(StationComponent station, int itemId, int want, bool requireSupply, ref int moved, ref int incMoved)
{
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Invalid comparison between Unknown and I4
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Invalid comparison between Unknown and I4
StationStore[] storage = station.storage;
for (int i = 0; i < storage.Length; i++)
{
if (moved >= want)
{
break;
}
if (storage[i].itemId != itemId || storage[i].count <= 0 || (requireSupply && (int)storage[i].localLogic != 1 && (int)storage[i].remoteLogic != 1))
{
continue;
}
int num = want - moved;
if (num > storage[i].count)
{
num = storage[i].count;
}
int num2 = 0;
if (storage[i].inc > 0)
{
num2 = (int)((float)storage[i].inc * (float)num / (float)storage[i].count + 0.5f);
if (num2 > storage[i].inc)
{
num2 = storage[i].inc;
}
}
storage[i].count -= num;
storage[i].inc -= num2;
moved += num;
incMoved += num2;
}
}
private static bool HasStock(PlanetFactory factory, int itemId, Vector3 pos, float radius)
{
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
//IL_009c: Unknown result type (might be due to invalid IL or missing references)
PlanetTransport transport = factory.transport;
if (transport == null || transport.stationPool == null)
{
return false;
}
bool value = Plugin.GeneratorRequireStationSupplyFlag.Value;
float num = ((radius > 0f) ? (radius * radius) : 0f);
EntityData[] entityPool = factory.entityPool;
int stationCursor = transport.stationCursor;
for (int i = 1; i < stationCursor; i++)
{
StationComponent val = transport.stationPool[i];
if (val == null || val.id != i || val.storage == null)
{
continue;
}
if (num > 0f && entityPool != null)
{
int entityId = val.entityId;
if (entityId > 0 && entityId < entityPool.Length)
{
Vector3 val2 = entityPool[entityId].pos - pos;
if (((Vector3)(ref val2)).sqrMagnitude > num)
{
continue;
}
}
}
if (StationHasItem(val, itemId, value))
{
return true;
}
}
return false;
}
}
internal static class LaunchScan
{
private struct ScanTotals
{
public int total;
public int belowCap;
public int refilled;
public int movedItems;
public int noStock;
public int skippedInserter;
}
private const int BulletTarget = 20;
private const long LogThrottleTicks = 300L;
private static long _lastScannedTick = -1L;
private static long _lastLogTick = long.MinValue;
private static float _lastErrorLogRealtime = float.NegativeInfinity;
private static bool[] _inserterIndex;
internal static void Tick()
{
try
{
if (!Plugin.LaunchEnabled.Value || GameMain.data == null || GameMain.data.factories == null)
{
return;
}
long gameTick = GameMain.gameTick;
int num = Plugin.LaunchRefillIntervalTicks.Value;
if (num < 1)
{
num = 1;
}
if (gameTick < _lastScannedTick)
{
_lastScannedTick = gameTick - num;
_lastLogTick = gameTick - 300;
}
if (gameTick - _lastScannedTick < num)
{
return;
}
_lastScannedTick = gameTick;
float value = Plugin.LaunchSupplyRadius.Value;
ScanTotals totals = default(ScanTotals);
PlanetFactory[] factories = GameMain.data.factories;
foreach (PlanetFactory val in factories)
{
if (val != null && val.factorySystem != null)
{
ScanFactory(val, value, ref totals);
}
}
if (PlanetwideSupplierLog.IsDebugEnabled())
{
bool value2 = Plugin.LaunchVerboseScan.Value;
bool flag = totals.movedItems > 0 || totals.noStock > 0 || totals.skippedInserter > 0;
if ((value2 || flag) && gameTick - _lastLogTick >= 300)
{
_lastLogTick = gameTick;
PlanetwideSupplierLog.Info("[supply] launch{" + (value2 ? ("total=" + totals.total + " belowCap=" + totals.belowCap + " ") : "") + "refilled=" + totals.refilled + " items=" + totals.movedItems + ((totals.noStock > 0) ? (" noStock=" + totals.noStock) : "") + ((totals.skippedInserter > 0) ? (" skippedInserter=" + totals.skippedInserter) : "") + "}");
}
}
}
catch (Exception ex)
{
float realtimeSinceStartup = Time.realtimeSinceStartup;
if (realtimeSinceStartup - _lastErrorLogRealtime >= 5f)
{
_lastErrorLogRealtime = realtimeSinceStartup;
PlanetwideSupplierLog.Error("[patch] LaunchScan.Tick threw: " + ex);
}
}
}
private static void ScanFactory(PlanetFactory factory, float radius, ref ScanTotals totals)
{
//IL_0100: Unknown result type (might be due to invalid IL or missing references)
//IL_0105: Unknown result type (might be due to invalid IL or missing references)
//IL_026b: Unknown result type (might be due to invalid IL or missing references)
//IL_0270: Unknown result type (might be due to invalid IL or missing references)
//IL_0135: Unknown result type (might be due to invalid IL or missing references)
//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
//IL_011e: Unknown result type (might be due to invalid IL or missing references)
//IL_0123: Unknown result type (might be due to invalid IL or missing references)
//IL_0289: Unknown result type (might be due to invalid IL or missing references)
//IL_028e: Unknown result type (might be due to invalid IL or missing references)
FactorySystem factorySystem = factory.factorySystem;
if (factorySystem.ejectorCursor <= 1 && factorySystem.siloCursor <= 1)
{
return;
}
bool value = Plugin.LaunchSkipInserterFedBuildings.Value;
if (value)
{
LaunchSourcing.BuildInserterIndex(factory, ref _inserterIndex);
}
EntityData[] entityPool = factory.entityPool;
if (Plugin.LaunchSupplyEjectors.Value)
{
EjectorComponent[] ejectorPool = factorySystem.ejectorPool;
if (ejectorPool != null)
{
int ejectorCursor = factorySystem.ejectorCursor;
for (int i = 1; i < ejectorCursor; i++)
{
if (ejectorPool[i].id != i || ejectorPool[i].bulletId <= 0)
{
continue;
}
totals.total++;
int entityId = ejectorPool[i].entityId;
if (value && _inserterIndex != null && entityId > 0 && entityId < _inserterIndex.Length && _inserterIndex[entityId])
{
totals.skippedInserter++;
continue;
}
int num = 20 - ejectorPool[i].bulletCount;
if (num > 0)
{
totals.belowCap++;
Vector3 pos = Vector3.zero;
if (entityPool != null && entityId > 0 && entityId < entityPool.Length)
{
pos = entityPool[entityId].pos;
}
int incMoved;
int num2 = LaunchSourcing.TryPullFromPlanet(factory, ejectorPool[i].bulletId, num, pos, radius, out incMoved);
if (num2 <= 0)
{
totals.noStock++;
continue;
}
ejectorPool[i].bulletCount += num2;
ejectorPool[i].bulletInc += incMoved;
totals.refilled++;
totals.movedItems += num2;
}
}
}
}
if (!Plugin.LaunchSupplySilos.Value)
{
return;
}
SiloComponent[] siloPool = factorySystem.siloPool;
if (siloPool == null)
{
return;
}
int siloCursor = factorySystem.siloCursor;
for (int j = 1; j < siloCursor; j++)
{
if (siloPool[j].id != j || siloPool[j].bulletId <= 0)
{
continue;
}
totals.total++;
int entityId2 = siloPool[j].entityId;
if (value && _inserterIndex != null && entityId2 > 0 && entityId2 < _inserterIndex.Length && _inserterIndex[entityId2])
{
totals.skippedInserter++;
continue;
}
int num3 = 20 - siloPool[j].bulletCount;
if (num3 > 0)
{
totals.belowCap++;
Vector3 pos2 = Vector3.zero;
if (entityPool != null && entityId2 > 0 && entityId2 < entityPool.Length)
{
pos2 = entityPool[entityId2].pos;
}
int incMoved2;
int num4 = LaunchSourcing.TryPullFromPlanet(factory, siloPool[j].bulletId, num3, pos2, radius, out incMoved2);
if (num4 <= 0)
{
totals.noStock++;
continue;
}
siloPool[j].bulletCount += num4;
siloPool[j].bulletInc += incMoved2;
totals.refilled++;
totals.movedItems += num4;
}
}
}
}
internal static class LaunchSourcing
{
private struct StationDist
{
public int index;
public float distSqr;
}
private static List<StationDist> _scratch;
private static readonly Comparison<StationDist> _byDist = (StationDist a, StationDist b) => a.distSqr.CompareTo(b.distSqr);
internal static int TryPullFromPlanet(PlanetFactory factory, int itemId, int want, Vector3 pos, float radius, out int incMoved)
{
//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
incMoved = 0;
if (factory == null || itemId <= 0 || want <= 0)
{
return 0;
}
PlanetTransport transport = factory.transport;
if (transport == null || transport.stationPool == null)
{
return 0;
}
bool value = Plugin.LaunchRequireStationSupplyFlag.Value;
bool value2 = Plugin.LaunchNearestStationFirst.Value;
float num = ((radius > 0f) ? (radius * radius) : 0f);
EntityData[] entityPool = factory.entityPool;
int stationCursor = transport.stationCursor;
int moved = 0;
Vector3 val2;
if (value2)
{
if (_scratch == null)
{
_scratch = new List<StationDist>(64);
}
_scratch.Clear();
for (int i = 1; i < stationCursor; i++)
{
StationComponent val = transport.stationPool[i];
if (val == null || val.id != i || val.storage == null)
{
continue;
}
float num2 = 0f;
if (entityPool != null)
{
int entityId = val.entityId;
if (entityId > 0 && entityId < entityPool.Length)
{
val2 = entityPool[entityId].pos - pos;
num2 = ((Vector3)(ref val2)).sqrMagnitude;
if (num > 0f && num2 > num)
{
continue;
}
}
}
if (StationHasItem(val, itemId, value))
{
_scratch.Add(new StationDist
{
index = i,
distSqr = num2
});
}
}
_scratch.Sort(_byDist);
for (int j = 0; j < _scratch.Count; j++)
{
if (moved >= want)
{
break;
}
DrainStation(transport.stationPool[_scratch[j].index], itemId, want, value, ref moved, ref incMoved);
}
}
else
{
for (int k = 1; k < stationCursor && moved < want; k++)
{
StationComponent val3 = transport.stationPool[k];
if (val3 == null || val3.id != k || val3.storage == null)
{
continue;
}
if (num > 0f && entityPool != null)
{
int entityId2 = val3.entityId;
if (entityId2 > 0 && entityId2 < entityPool.Length)
{
val2 = entityPool[entityId2].pos - pos;
if (((Vector3)(ref val2)).sqrMagnitude > num)
{
continue;
}
}
}
DrainStation(val3, itemId, want, value, ref moved, ref incMoved);
}
}
return moved;
}
private static bool StationHasItem(StationComponent station, int itemId, bool requireSupply)
{
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Invalid comparison between Unknown and I4
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Invalid comparison between Unknown and I4
StationStore[] storage = station.storage;
for (int i = 0; i < storage.Length; i++)
{
if (storage[i].itemId == itemId && storage[i].count > 0 && (!requireSupply || (int)storage[i].localLogic == 1 || (int)storage[i].remoteLogic == 1))
{
return true;
}
}
return false;
}
private static void DrainStation(StationComponent station, int itemId, int want, bool requireSupply, ref int moved, ref int incMoved)
{
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Invalid comparison between Unknown and I4
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Invalid comparison between Unknown and I4
StationStore[] storage = station.storage;
for (int i = 0; i < storage.Length; i++)
{
if (moved >= want)
{
break;
}
if (storage[i].itemId != itemId || storage[i].count <= 0 || (requireSupply && (int)storage[i].localLogic != 1 && (int)storage[i].remoteLogic != 1))
{
continue;
}
int num = want - moved;
if (num > storage[i].count)
{
num = storage[i].count;
}
int num2 = 0;
if (storage[i].inc > 0)
{
num2 = (int)((float)storage[i].inc * (float)num / (float)storage[i].count + 0.5f);
if (num2 > storage[i].inc)
{
num2 = storage[i].inc;
}
}
storage[i].count -= num;
storage[i].inc -= num2;
moved += num;
incMoved += num2;
}
}
internal static void BuildInserterIndex(PlanetFactory factory, ref bool[] buffer)
{
int entityCursor = factory.entityCursor;
if (buffer == null || buffer.Length < entityCursor)
{
buffer = new bool[entityCursor];
}
else
{
Array.Clear(buffer, 0, entityCursor);
}
FactorySystem factorySystem = factory.factorySystem;
if (factorySystem == null || factorySystem.inserterPool == null)
{
return;
}
InserterComponent[] inserterPool = factorySystem.inserterPool;
int inserterCursor = factorySystem.inserterCursor;
for (int i = 1; i < inserterCursor; i++)
{
if (inserterPool[i].id == i)
{
int insertTarget = inserterPool[i].insertTarget;
if (insertTarget > 0 && insertTarget < buffer.Length)
{
buffer[insertTarget] = true;
}
}
}
}
}
internal static class PlanetwideSupplierLog
{
private const string Tag = "[PlanetwideSupplier] ";
private static ManualLogSource logger;
private static ConfigEntry<bool> debugGate;
public static void Init(ManualLogSource src, ConfigEntry<bool> debug)
{
logger = src;
debugGate = debug;
}
public static bool IsDebugEnabled()
{
if (debugGate != null)
{
return debugGate.Value;
}
return false;
}
public static void Info(string msg)
{
if (logger != null && IsDebugEnabled())
{
logger.LogInfo((object)("[PlanetwideSupplier] " + msg));
}
}
public static void Warn(string msg)
{
if (logger != null)
{
logger.LogWarning((object)("[PlanetwideSupplier] " + msg));
}
}
public static void Error(string msg)
{
if (logger != null)
{
logger.LogError((object)("[PlanetwideSupplier] " + msg));
}
}
}
[HarmonyPatch(typeof(DefenseSystem), "GameTick", new Type[]
{
typeof(long),
typeof(bool)
})]
internal static class DefenseSystemSupplyPatch
{
private struct TurretScan
{
public int total;
public int belowCap;
public int refilled;
public int movedItems;
public int noStock;
public float nearestSupply;
}
private struct BattleScan
{
public int bases;
public int slotsRefilled;
public int movedItems;
}
private const int TurretAmmoTarget = 5;
private const long LogThrottleTicks = 300L;
private static long _lastLogTick = long.MinValue;
private static void Postfix(DefenseSystem __instance, long tick, bool isActive)
{
try
{
if (!Plugin.AmmoEnabled.Value || __instance == null)
{
return;
}
int num = Plugin.AmmoRefillIntervalTicks.Value;
if (num < 1)
{
num = 1;
}
if (tick % num != 0L)
{
return;
}
PlanetFactory factory = __instance.factory;
if (factory == null)
{
return;
}
float value = Plugin.AmmoSupplyRadius.Value;
TurretScan turretScan = default(TurretScan);
BattleScan battleScan = default(BattleScan);
if (Plugin.AmmoSupplyTurrets.Value)
{
turretScan = RefillTurrets(__instance, factory, value);
}
if (Plugin.AmmoSupplyBattleBases.Value)
{
battleScan = RefillBattleBases(__instance, factory, value);
}
if (!isActive || !PlanetwideSupplierLog.IsDebugEnabled())
{
return;
}
bool value2 = Plugin.AmmoVerboseScan.Value;
bool flag = turretScan.movedItems > 0 || battleScan.movedItems > 0 || turretScan.noStock > 0;
if (!(value2 || flag) || tick - _lastLogTick < 300)
{
return;
}
_lastLogTick = tick;
string text = "[supply] planet=" + factory.planetId + " turrets{" + (value2 ? ("total=" + turretScan.total + " belowCap=" + turretScan.belowCap + " ") : "") + "refilled=" + turretScan.refilled + " items=" + turretScan.movedItems + ((turretScan.noStock > 0) ? (" noStock=" + turretScan.noStock) : "") + "}";
if (value2)
{
text = text + " radius=" + ((value <= 0f) ? "planetwide" : value.ToString("0"));
if (turretScan.belowCap > 0)
{
text = text + " nearestStation=" + ((turretScan.nearestSupply < 0f) ? "none-on-planet" : turretScan.nearestSupply.ToString("0"));
}
}
if (value2 || battleScan.movedItems > 0)
{
text = text + " battlebase{" + (value2 ? ("bases=" + battleScan.bases + " ") : "") + "items=" + battleScan.movedItems + "}";
}
PlanetwideSupplierLog.Info(text);
}
catch (Exception ex)
{
PlanetwideSupplierLog.Error("[patch] DefenseSystem.GameTick postfix threw: " + ex);
}
}
private static TurretScan RefillTurrets(DefenseSystem def, PlanetFactory factory, float radius)
{
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
//IL_015f: Unknown result type (might be due to invalid IL or missing references)
//IL_0125: Unknown result type (might be due to invalid IL or missing references)
//IL_012a: Unknown result type (might be due to invalid IL or missing references)
//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
TurretScan result = default(TurretScan);
DataPool<TurretComponent> turrets = def.turrets;
if (turrets == null || turrets.buffer == null)
{
return result;
}
TurretComponent[] buffer = turrets.buffer;
int cursor = turrets.cursor;
EntityData[] entityPool = factory.entityPool;
bool flag = Plugin.AmmoVerboseScan.Value && PlanetwideSupplierLog.IsDebugEnabled();
bool flag2 = false;
result.nearestSupply = -1f;
for (int i = 1; i < cursor; i++)
{
if (buffer[i].id != i)
{
continue;
}
result.total++;
if (buffer[i].itemCount >= 5)
{
continue;
}
result.belowCap++;
Vector3 pos = Vector3.zero;
int entityId = buffer[i].entityId;
if (entityPool != null && entityId > 0 && entityId < entityPool.Length)
{
pos = entityPool[entityId].pos;
}
if (flag && !flag2)
{
result.nearestSupply = AmmoSourcing.NearestAmmoStationDistance(factory, buffer[i].itemId, buffer[i].ammoType, pos);
flag2 = true;
}
int num = buffer[i].itemId;
if (num == 0)
{
num = AmmoSourcing.FindAvailableAmmo(factory, buffer[i].ammoType, pos, radius);
if (num == 0)
{
result.noStock++;
continue;
}
}
int want = 5 - buffer[i].itemCount;
int incMoved;
int num2 = AmmoSourcing.TryPullFromPlanet(factory, num, want, pos, radius, out incMoved);
if (num2 <= 0)
{
result.noStock++;
continue;
}
if (buffer[i].itemId == 0)
{
((TurretComponent)(ref buffer[i])).SetNewItem(num, (short)num2, (short)incMoved);
}
else
{
buffer[i].itemCount += (short)num2;
buffer[i].itemInc += (short)incMoved;
}
result.refilled++;
result.movedItems += num2;
}
return result;
}
private static BattleScan RefillBattleBases(DefenseSystem def, PlanetFactory factory, float radius)
{
//IL_0095: 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_00bf: Unknown result type (might be due to invalid IL or missing references)
//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
//IL_0144: Unknown result type (might be due to invalid IL or missing references)
BattleScan result = default(BattleScan);
ObjectPool<BattleBaseComponent> battleBases = def.battleBases;
if (battleBases == null || battleBases.buffer == null)
{
return result;
}
BattleBaseComponent[] buffer = battleBases.buffer;
int cursor = battleBases.cursor;
EntityData[] entityPool = factory.entityPool;
string value = Plugin.AmmoFighterItemFilter.Value;
bool flag = !string.IsNullOrEmpty(value);
int num3 = default(int);
for (int i = 1; i < cursor; i++)
{
BattleBaseComponent val = buffer[i];
if (val == null || val.id != i)
{
continue;
}
StorageComponent storage = val.storage;
if (storage == null || storage.grids == null)
{
continue;
}
result.bases++;
Vector3 pos = Vector3.zero;
int entityId = val.entityId;
if (entityPool != null && entityId > 0 && entityId < entityPool.Length)
{
pos = entityPool[entityId].pos;
}
GRID[] grids = storage.grids;
for (int j = 0; j < grids.Length; j++)
{
int itemId = grids[j].itemId;
if (itemId <= 0)
{
continue;
}
int stackSize = grids[j].stackSize;
if (stackSize > 0 && grids[j].count < stackSize && (!flag || value.IndexOf(itemId.ToString(), StringComparison.Ordinal) >= 0))
{
int want = stackSize - grids[j].count;
int incMoved;
int num = AmmoSourcing.TryPullFromPlanet(factory, itemId, want, pos, radius, out incMoved);
if (num > 0)
{
int num2 = storage.AddItem(itemId, num, incMoved, ref num3, false);
result.slotsRefilled++;
result.movedItems += num2;
}
}
}
}
return result;
}
}
[HarmonyPatch(typeof(FactorySystem), "GameTickLabResearchMode", new Type[]
{
typeof(long),
typeof(bool)
})]
internal static class LabResearchSupplyPatch
{
private struct ScanTotals
{
public int total;
public int belowCap;
public int refilled;
public int movedItems;
public int noStock;
public int skippedInserter;
}
private const int MatrixServedTarget = 36000;
private const int MatrixServedPerCube = 3600;
private const long LogThrottleTicks = 300L;
private static long _lastLogTick = long.MinValue;
private static bool[] _inserterIndex;
private static void Postfix(FactorySystem __instance, long time, bool isActive)
{
try
{
if (!Plugin.ProductionEnabled.Value || __instance == null)
{
return;
}
int num = Plugin.ProductionRefillIntervalTicks.Value;
if (num < 1)
{
num = 1;
}
if (time % num != 0L)
{
return;
}
PlanetFactory factory = __instance.factory;
if (factory == null)
{
return;
}
float value = Plugin.ProductionSupplyRadius.Value;
bool value2 = Plugin.ProductionSkipInserterFedBuildings.Value;
if (value2)
{
ProductionSourcing.BuildInserterIndex(factory, ref _inserterIndex);
}
EntityData[] entityPool = factory.entityPool;
LabComponent[] labPool = __instance.labPool;
if (labPool == null)
{
return;
}
ScanTotals totals = default(ScanTotals);
int labCursor = __instance.labCursor;
for (int i = 1; i < labCursor; i++)
{
if (labPool[i].id == i && labPool[i].researchMode)
{
ScanLab(factory, entityPool, ref labPool[i], value, value2, ref totals);
}
}
if (isActive && PlanetwideSupplierLog.IsDebugEnabled())
{
bool value3 = Plugin.ProductionVerboseScan.Value;
bool flag = totals.movedItems > 0 || totals.noStock > 0 || totals.skippedInserter > 0;
if ((value3 || flag) && time - _lastLogTick >= 300)
{
_lastLogTick = time;
PlanetwideSupplierLog.Info("[supply] planet=" + factory.planetId + " labResearch{" + (value3 ? ("total=" + totals.total + " belowCap=" + totals.belowCap + " ") : "") + "refilled=" + totals.refilled + " items=" + totals.movedItems + ((totals.noStock > 0) ? (" noStock=" + totals.noStock) : "") + ((totals.skippedInserter > 0) ? (" skippedInserter=" + totals.skippedInserter) : "") + "}");
}
}
}
catch (Exception ex)
{
PlanetwideSupplierLog.Error("[patch] FactorySystem.GameTickLabResearchMode postfix threw: " + ex);
}
}
private static void ScanLab(PlanetFactory factory, EntityData[] entityPool, ref LabComponent lab, float radius, bool skipInserterFed, ref ScanTotals totals)
{
//IL_004b: 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_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
if (lab.matrixServed == null)
{
return;
}
totals.total++;
int entityId = lab.entityId;
if (skipInserterFed && _inserterIndex != null && entityId > 0 && entityId < _inserterIndex.Length && _inserterIndex[entityId])
{
totals.skippedInserter++;
return;
}
Vector3 pos = Vector3.zero;
if (entityPool != null && entityId > 0 && entityId < entityPool.Length)
{
pos = entityPool[entityId].pos;
}
bool flag = false;
int[] matrixServed = lab.matrixServed;
int[] matrixIncServed = lab.matrixIncServed;
for (int i = 0; i < matrixServed.Length && i < LabComponent.matrixIds.Length && i < matrixIncServed.Length; i++)
{
if (matrixServed[i] >= 36000)
{
continue;
}
flag = true;
int num = (36000 - matrixServed[i]) / 3600;
if (num > 0)
{
int itemId = LabComponent.matrixIds[i];
int incMoved;
int num2 = ProductionSourcing.TryPullFromPlanet(factory, itemId, num, pos, radius, out incMoved);
if (num2 <= 0)
{
totals.noStock++;
continue;
}
matrixServed[i] += 3600 * num2;
matrixIncServed[i] += 3600 * incMoved;
totals.refilled++;
totals.movedItems += num2;
}
}
if (flag)
{
totals.belowCap++;
}
}
}
[HarmonyPatch(typeof(PowerSystem), "GameTick", new Type[]
{
typeof(long),
typeof(bool),
typeof(bool),
typeof(int)
})]
internal static class PowerSystemSupplyPatch
{
private struct GenScan
{
public int total;
public int belowCap;
public int refilled;
public int movedItems;
public int noStock;
public int skippedInserter;
public float nearestSupply;
}
private struct CatalystScan
{
public int total;
public int belowCap;
public int refilled;
public int movedItems;
public int noStock;
public int skippedBelt;
}
private const int FuelTarget = 10;
private const int CatalystTarget = 72000;
private const int CatalystPerLens = 3600;
private const long LogThrottleTicks = 300L;
private static long _lastLogTick = long.MinValue;
private static bool _fuelNamesResolved;
private static int[] _thermalPriorityIds = Array.Empty<int>();
private static HashSet<int> _proliferatorIds = new HashSet<int>();
private const string ProliferatorItemNames = "Proliferator Mk.I,Proliferator Mk.II,Proliferator Mk.III";
[ThreadStatic]
private static bool[] _servicedByInserter;
private static void Postfix(PowerSystem __instance, long time, bool isActive, bool multithreaded, int threadOrdinal)
{
try
{
if (!Plugin.GeneratorEnabled.Value || __instance == null)
{
return;
}
if (!_fuelNamesResolved)
{
ResolveConfiguredFuel();
}
int num = Plugin.GeneratorRefillIntervalTicks.Value;
if (num < 1)
{
num = 1;
}
if (time % num != 0L)
{
return;
}
PlanetFactory factory = __instance.factory;
if (factory == null)
{
return;
}
GenScan genScan = RefillGenerators(__instance, factory, Plugin.GeneratorSupplyRadius.Value);
CatalystScan catalystScan = default(CatalystScan);
if (Plugin.GeneratorSupplyGravitonLens.Value)
{
catalystScan = RefillCatalyst(__instance, factory, Plugin.GeneratorSupplyRadius.Value);
}
if (!isActive || !PlanetwideSupplierLog.IsDebugEnabled())
{
return;
}
bool value = Plugin.GeneratorVerboseScan.Value;
bool flag = genScan.movedItems > 0 || genScan.noStock > 0 || genScan.skippedInserter > 0 || catalystScan.movedItems > 0 || catalystScan.noStock > 0 || catalystScan.skippedBelt > 0;
if (!(value || flag) || time - _lastLogTick < 300)
{
return;
}
_lastLogTick = time;
string text = "[supply] planet=" + factory.planetId + " gens{" + (value ? ("total=" + genScan.total + " belowCap=" + genScan.belowCap + " ") : "") + "refilled=" + genScan.refilled + " items=" + genScan.movedItems + ((genScan.noStock > 0) ? (" noStock=" + genScan.noStock) : "") + ((genScan.skippedInserter > 0) ? (" skippedInserter=" + genScan.skippedInserter) : "") + "}";
if (value)
{
float value2 = Plugin.GeneratorSupplyRadius.Value;
text = text + " radius=" + ((value2 <= 0f) ? "planetwide" : value2.ToString("0"));
if (genScan.belowCap > 0)
{
text = text + " nearestStation=" + ((genScan.nearestSupply < 0f) ? "none-on-planet" : genScan.nearestSupply.ToString("0"));
}
}
if (value || catalystScan.movedItems > 0 || catalystScan.noStock > 0 || catalystScan.skippedBelt > 0)
{
text = text + " lens{" + (value ? ("total=" + catalystScan.total + " belowCap=" + catalystScan.belowCap + " ") : "") + "refilled=" + catalystScan.refilled + " items=" + catalystScan.movedItems + ((catalystScan.noStock > 0) ? (" noStock=" + catalystScan.noStock) : "") + ((catalystScan.skippedBelt > 0) ? (" skippedBelt=" + catalystScan.skippedBelt) : "") + "}";
}
PlanetwideSupplierLog.Info(text);
}
catch (Exception ex)
{
PlanetwideSupplierLog.Error("[patch] PowerSystem.GameTick postfix threw: " + ex);
}
}
private static void ResolveConfiguredFuel()
{
_thermalPriorityIds = GeneratorSourcing.ResolveItemNamesByCsv(Plugin.GeneratorThermalFuelPriority.Value);
_proliferatorIds = new HashSet<int>(GeneratorSourcing.ResolveItemNamesByCsv("Proliferator Mk.I,Proliferator Mk.II,Proliferator Mk.III"));
_fuelNamesResolved = true;
if (_thermalPriorityIds.Length != 0)
{
string text = "";
for (int i = 0; i < _thermalPriorityIds.Length; i++)
{
text = text + ((i > 0) ? ", " : "") + _thermalPriorityIds[i];
}
PlanetwideSupplierLog.Info("[fuel] resolved ThermalFuelPriority -> " + text);
}
}
private static GenScan RefillGenerators(PowerSystem power, PlanetFactory factory, float radius)
{
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_0111: Unknown result type (might be due to invalid IL or missing references)
//IL_0116: Unknown result type (might be due to invalid IL or missing references)
//IL_021b: Unknown result type (might be due to invalid IL or missing references)
//IL_015e: Unknown result type (might be due to invalid IL or missing references)
//IL_0132: Unknown result type (might be due to invalid IL or missing references)
//IL_0137: Unknown result type (might be due to invalid IL or missing references)
//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
GenScan result = default(GenScan);
PowerGeneratorComponent[] genPool = power.genPool;
if (genPool == null)
{
return result;
}
bool value = Plugin.GeneratorSkipInserterFedGenerators.Value;
if (value)
{
BuildInserterIndex(factory);
}
int genCursor = power.genCursor;
EntityData[] entityPool = factory.entityPool;
bool flag = Plugin.GeneratorVerboseScan.Value && PlanetwideSupplierLog.IsDebugEnabled();
bool flag2 = false;
result.nearestSupply = -1f;
for (int i = 1; i < genCursor; i++)
{
if (genPool[i].id != i || !IsFuelBurner(genPool[i]) || !IsEnabledForMask(genPool[i].fuelMask))
{
continue;
}
result.total++;
if (genPool[i].fuelCount >= 10)
{
continue;
}
int entityId = genPool[i].entityId;
if (value && _servicedByInserter != null && entityId > 0 && entityId < _servicedByInserter.Length && _servicedByInserter[entityId])
{
result.skippedInserter++;
continue;
}
result.belowCap++;
Vector3 pos = Vector3.zero;
if (entityPool != null && entityId > 0 && entityId < entityPool.Length)
{
pos = entityPool[entityId].pos;
}
if (flag && !flag2)
{
result.nearestSupply = GeneratorSourcing.NearestFuelStationDistance(factory, genPool[i].fuelMask, genPool[i].fuelId, pos);
flag2 = true;
}
int num = genPool[i].fuelId;
if (num == 0)
{
if (genPool[i].fuelMask == 1 && _thermalPriorityIds.Length != 0)
{
num = GeneratorSourcing.FindPriorityFuel(factory, _thermalPriorityIds, pos, radius);
}
if (num == 0)
{
HashSet<int> exclude = ((genPool[i].fuelMask == 1 && Plugin.GeneratorExcludeProliferatorFuel.Value) ? _proliferatorIds : null);
num = GeneratorSourcing.FindAvailableFuel(factory, genPool[i].fuelMask, pos, radius, exclude);
}
if (num == 0)
{
result.noStock++;
continue;
}
}
int want = 10 - genPool[i].fuelCount;
int incMoved;
int num2 = GeneratorSourcing.TryPullFromPlanet(factory, num, want, pos, radius, out incMoved);
if (num2 <= 0)
{
result.noStock++;
continue;
}
if (genPool[i].fuelId == 0)
{
((PowerGeneratorComponent)(ref genPool[i])).SetNewFuel(num, (short)num2, (short)incMoved);
}
else
{
genPool[i].fuelCount += (short)num2;
genPool[i].fuelInc += (short)incMoved;
}
result.refilled++;
result.movedItems += num2;
}
return result;
}
private static CatalystScan RefillCatalyst(PowerSystem power, PlanetFactory factory, float radius)
{
//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
//IL_011c: Unknown result type (might be due to invalid IL or missing references)
//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
CatalystScan result = default(CatalystScan);
PowerGeneratorComponent[] genPool = power.genPool;
if (genPool == null)
{
return result;
}
bool value = Plugin.GeneratorSkipBeltFedGravitonLens.Value;
int genCursor = power.genCursor;
EntityData[] entityPool = factory.entityPool;
for (int i = 1; i < genCursor; i++)
{
if (genPool[i].id != i || genPool[i].catalystId <= 0)
{
continue;
}
result.total++;
if (genPool[i].catalystPoint >= 72000)
{
continue;
}
if (value && HasBeltCatalystInput(factory, genPool[i].entityId))
{
result.skippedBelt++;
continue;
}
result.belowCap++;
int entityId = genPool[i].entityId;
Vector3 pos = Vector3.zero;
if (entityPool != null && entityId > 0 && entityId < entityPool.Length)
{
pos = entityPool[entityId].pos;
}
int num = (72000 - genPool[i].catalystPoint) / 3600;
if (num > 0)
{
int incMoved;
int num2 = GeneratorSourcing.TryPullFromPlanet(factory, genPool[i].catalystId, num, pos, radius, out incMoved);
if (num2 <= 0)
{
result.noStock++;
continue;
}
genPool[i].catalystPoint += 3600 * num2;
genPool[i].catalystIncPoint += 3600 * incMoved;
result.refilled++;
result.movedItems += num2;
}
}
return result;
}
private static bool HasBeltCatalystInput(PlanetFactory factory, int entityId)
{
if (entityId <= 0)
{
return false;
}
bool flag = default(bool);
int num = default(int);
int num2 = default(int);
factory.ReadObjectConn(entityId, 0, ref flag, ref num, ref num2);
if (num > 0 && !flag)
{
return true;
}
factory.ReadObjectConn(entityId, 1, ref flag, ref num, ref num2);
if (num > 0)
{
return !flag;
}
return false;
}
private static void BuildInserterIndex(PlanetFactory factory)
{
int entityCursor = factory.entityCursor;
if (_servicedByInserter == null || _servicedByInserter.Length < entityCursor)
{
_servicedByInserter = new bool[entityCursor];
}
else
{
Array.Clear(_servicedByInserter, 0, entityCursor);
}
FactorySystem factorySystem = factory.factorySystem;
if (factorySystem == null || factorySystem.inserterPool == null)
{
return;
}
InserterComponent[] inserterPool = factorySystem.inserterPool;
int inserterCursor = factorySystem.inserterCursor;
for (int i = 1; i < inserterCursor; i++)
{
if (inserterPool[i].id == i)
{
int insertTarget = inserterPool[i].insertTarget;
if (insertTarget > 0 && insertTarget < _servicedByInserter.Length)
{
_servicedByInserter[insertTarget] = true;
}
}
}
}
private static bool IsFuelBurner(PowerGeneratorComponent gen)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0009: 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_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
if (gen.fuelMask > 0 && !gen.photovoltaic && !gen.wind && !gen.gamma)
{
return !gen.geothermal;
}
return false;
}
private static bool IsEnabledForMask(short fuelMask)
{
return fuelMask switch
{
1 => Plugin.GeneratorSupplyThermal.Value,
2 => Plugin.GeneratorSupplyFusion.Value,
4 => Plugin.GeneratorSupplyArtificialStar.Value,
_ => false,
};
}
}
[BepInPlugin("com.zicarius.PlanetwideSupplier", "PlanetwideSupplier", "1.0.0")]
public sealed class Plugin : BaseUnityPlugin
{
public const string PluginGuid = "com.zicarius.PlanetwideSupplier";
public const string PluginName = "PlanetwideSupplier";
public const string PluginVersion = "1.0.0";
private const string GeneratorSupplyGuid = "com.zicarius.PlanetwideGeneratorSupply";
private const string AmmoSupplyGuid = "com.zicarius.PlanetwideAmmoSupply";
internal static ConfigEntry<bool> GeneratorEnabled;
internal static ConfigEntry<bool> GeneratorSupplyThermal;
internal static ConfigEntry<bool> GeneratorSupplyFusion;
internal static ConfigEntry<bool> GeneratorSupplyArtificialStar;
internal static ConfigEntry<bool> GeneratorPreferHighestFuelTier;
internal static ConfigEntry<float> GeneratorSupplyRadius;
internal static ConfigEntry<bool> GeneratorNearestStationFirst;
internal static ConfigEntry<int> GeneratorRefillIntervalTicks;
internal static ConfigEntry<bool> GeneratorRequireStationSupplyFlag;
internal static ConfigEntry<bool> GeneratorVerboseScan;
internal static ConfigEntry<string> GeneratorThermalFuelPriority;
internal static ConfigEntry<bool> GeneratorExcludeProliferatorFuel;
internal static ConfigEntry<bool> GeneratorSkipInserterFedGenerators;
internal static ConfigEntry<bool> GeneratorSupplyGravitonLens;
internal static ConfigEntry<bool> GeneratorSkipBeltFedGravitonLens;
internal static ConfigEntry<bool> AmmoEnabled;
internal static ConfigEntry<bool> AmmoSupplyTurrets;
internal static ConfigEntry<bool> AmmoSupplyBattleBases;
internal static ConfigEntry<bool> AmmoPreferHighestAmmoTier;
internal static ConfigEntry<float> AmmoSupplyRadius;
internal static ConfigEntry<bool> AmmoNearestStationFirst;
internal static ConfigEntry<int> AmmoRefillIntervalTicks;
internal static ConfigEntry<bool> AmmoRequireStationSupplyFlag;
internal static ConfigEntry<string> AmmoFighterItemFilter;
internal static ConfigEntry<bool> AmmoVerboseScan;
internal static ConfigEntry<bool> ProductionEnabled;
internal static ConfigEntry<float> ProductionSupplyRadius;
internal static ConfigEntry<bool> ProductionNearestStationFirst;
internal static ConfigEntry<int> ProductionRefillIntervalTicks;
internal static ConfigEntry<bool> ProductionRequireStationSupplyFlag;
internal static ConfigEntry<bool> ProductionSkipInserterFedBuildings;
internal static ConfigEntry<bool> ProductionVerboseScan;
internal static ConfigEntry<bool> LaunchEnabled;
internal static ConfigEntry<bool> LaunchSupplyEjectors;
internal static ConfigEntry<bool> LaunchSupplySilos;
internal static ConfigEntry<float> LaunchSupplyRadius;
internal static ConfigEntry<bool> LaunchNearestStationFirst;
internal static ConfigEntry<int> LaunchRefillIntervalTicks;
internal static ConfigEntry<bool> LaunchRequireStationSupplyFlag;
internal static ConfigEntry<bool> LaunchSkipInserterFedBuildings;
internal static ConfigEntry<bool> LaunchVerboseScan;
internal static ConfigEntry<bool> DebugLog;
private Harmony harmony;
private void Awake()
{
//IL_0a79: Unknown result type (might be due to invalid IL or missing references)
//IL_0a83: Expected O, but got Unknown
DebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "DebugLog", false, "Enable verbose diagnostic logging to the BepInEx console.");
GeneratorEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Generator", "Enabled", true, "Master switch for generator fuel supply. If false this module is fully inert.");
GeneratorSupplyThermal = ((BaseUnityPlugin)this).Config.Bind<bool>("Generator", "SupplyThermal", true, "Auto-refill thermal power plants (chemical fuels).");
GeneratorSupplyFusion = ((BaseUnityPlugin)this).Config.Bind<bool>("Generator", "SupplyFusion", true, "Auto-refill mini fusion power plants (deuterium fuel rods).");
GeneratorSupplyArtificialStar = ((BaseUnityPlugin)this).Config.Bind<bool>("Generator", "SupplyArtificialStar", true, "Auto-refill artificial stars (antimatter fuel rods).");
GeneratorPreferHighestFuelTier = ((BaseUnityPlugin)this).Config.Bind<bool>("Generator", "PreferHighestFuelTier", true, "When a generator's fuel chamber is empty, pick the highest available fuel tier (true) or the lowest/cheapest (false). A generator that already holds fuel keeps that item.");
GeneratorSupplyRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Generator", "SupplyRadius", 0f, "Max straight-line distance from a generator to an eligible station. 0 = planetwide.");
GeneratorNearestStationFirst = ((BaseUnityPlugin)this).Config.Bind<bool>("Generator", "NearestStationFirst", true, "Pull from the closest eligible station first (true) instead of station build order (false).");
GeneratorRefillIntervalTicks = ((BaseUnityPlugin)this).Config.Bind<int>("Generator", "RefillIntervalTicks", 60, "Game ticks between refill scans. ~60 = 1s.");
GeneratorRequireStationSupplyFlag = ((BaseUnityPlugin)this).Config.Bind<bool>("Generator", "RequireStationSupplyFlag", false, "If true, only pull from station slots set to Supply.");
GeneratorVerboseScan = ((BaseUnityPlugin)this).Config.Bind<bool>("Generator", "VerboseScan", false, "Debug aid (needs DebugLog on): periodic scan heartbeat even when nothing moved.");
GeneratorThermalFuelPriority = ((BaseUnityPlugin)this).Config.Bind<string>("Generator", "ThermalFuelPriority", "", "Comma-separated item names exactly as shown in-game (e.g. \"Graphite, Coal, Wood\" - your game's current language), tried in order for Thermal Power Plants only. Falls back to the highest available tier when empty or when none of these have stock.");
GeneratorExcludeProliferatorFuel = ((BaseUnityPlugin)this).Config.Bind<bool>("Generator", "ExcludeProliferatorFuel", true, "If true, never burn Proliferator Mk.I/II/III as Thermal Power Plant fuel, whether via ThermalFuelPriority or the fallback search.");
GeneratorSkipInserterFedGenerators = ((BaseUnityPlugin)this).Config.Bind<bool>("Generator", "SkipInserterFedGenerators", true, "If true, never auto-refill a generator that already has a sorter/inserter delivering fuel to it - only top up generators with no inserter connection at all.");
GeneratorSupplyGravitonLens = ((BaseUnityPlugin)this).Config.Bind<bool>("Generator", "SupplyGravitonLens", true, "Auto-refill Ray Receivers' Graviton Lens catalyst slot from the planet's logistics network. Vanilla only ever fills this via a belt physically connected to the receiver's own port - this setting adds a station-sourced alternative.");
GeneratorSkipBeltFedGravitonLens = ((BaseUnityPlugin)this).Config.Bind<bool>("Generator", "SkipBeltFedGravitonLens", true, "If true, never auto-refill a Ray Receiver that already has a belt physically connected to its catalyst input port - only top up receivers with no belt connection there at all.");
AmmoEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Ammo", "Enabled", true, "Master switch for defense ammo supply. If false this module is fully inert (vanilla belt supply unchanged).");
AmmoSupplyTurrets = ((BaseUnityPlugin)this).Config.Bind<bool>("Ammo", "SupplyTurrets", true, "Auto-refill turret ammo from the planet's logistics stations.");
AmmoSupplyBattleBases = ((BaseUnityPlugin)this).Config.Bind<bool>("Ammo", "SupplyBattleBases", true, "Auto-refill battle-base ammo and fighters from the planet's logistics stations.");
AmmoPreferHighestAmmoTier = ((BaseUnityPlugin)this).Config.Bind<bool>("Ammo", "PreferHighestAmmoTier", true, "When auto-filling an EMPTY turret, pick the highest available ammo tier (true) or the lowest/cheapest (false). A turret that already holds an ammo item keeps that item's tier - this only chooses the first fill.");
AmmoSupplyRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Ammo", "SupplyRadius", 0f, "Max straight-line distance (metres) from a structure to an eligible station. 0 = planetwide (recommended). A standard planet is ~200m radius (~400m across).");
AmmoNearestStationFirst = ((BaseUnityPlugin)this).Config.Bind<bool>("Ammo", "NearestStationFirst", true, "Pull from the closest eligible station first (true) instead of station build order (false). Pairs naturally with SupplyRadius.");
AmmoRefillIntervalTicks = ((BaseUnityPlugin)this).Config.Bind<int>("Ammo", "RefillIntervalTicks", 60, "Game ticks between refill scans (throttle). ~60 = 1s. Higher = cheaper, lower = more responsive.");
AmmoRequireStationSupplyFlag = ((BaseUnityPlugin)this).Config.Bind<bool>("Ammo", "RequireStationSupplyFlag", false, "If true, only pull from station slots set to 'Supply' (never 'Demand'/'Storage'). False = pull from any slot holding the ammo.");
AmmoFighterItemFilter = ((BaseUnityPlugin)this).Config.Bind<string>("Ammo", "FighterItemFilter", "", "Optional: restrict which fighter/ammo items battle bases pull (empty = everything the base already accepts).");
AmmoVerboseScan = ((BaseUnityPlugin)this).Config.Bind<bool>("Ammo", "VerboseScan", false, "Debug aid (needs DebugLog on): log a periodic scan heartbeat on the active planet (~1 per 5s) showing total/belowCap/refilled/noStock even when nothing moved. Off = only log when ammo actually moves.");
ProductionEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Production", "Enabled", true, "Master switch for crafting-building supply (smelters, assemblers, chemical plants, refineries, Matrix Labs). If false this module is fully inert.");
ProductionSupplyRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Production", "SupplyRadius", 0f, "Max straight-line distance from a building to an eligible station. 0 = planetwide.");
ProductionNearestStationFirst = ((BaseUnityPlugin)this).Config.Bind<bool>("Production", "NearestStationFirst", true, "Pull from the closest eligible station first (true) instead of station build order (false).");
ProductionRefillIntervalTicks = ((BaseUnityPlugin)this).Config.Bind<int>("Production", "RefillIntervalTicks", 60, "Game ticks between refill scans. ~60 = 1s.");
ProductionRequireStationSupplyFlag = ((BaseUnityPlugin)this).Config.Bind<bool>("Production", "RequireStationSupplyFlag", false, "If true, only pull from station slots set to Supply.");
ProductionSkipInserterFedBuildings = ((BaseUnityPlugin)this).Config.Bind<bool>("Production", "SkipInserterFedBuildings", true, "If true, never auto-refill a building that already has any sorter/inserter delivering to it - only top up buildings with no inserter connection at all. Whole-building, not per-slot: a multi-input building with even one fed slot is left alone entirely.");
ProductionVerboseScan = ((BaseUnityPlugin)this).Config.Bind<bool>("Production", "VerboseScan", false, "Debug aid (needs DebugLog on): periodic scan heartbeat even when nothing moved.");
LaunchEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Launch", "Enabled", true, "Master switch for EM-Rail Ejector / Vertical Launching Silo supply. If false this module is fully inert.");
LaunchSupplyEjectors = ((BaseUnityPlugin)this).Config.Bind<bool>("Launch", "SupplyEjectors", true, "Auto-refill EM-Rail Ejectors with whatever item they're already loaded to launch.");
LaunchSupplySilos = ((BaseUnityPlugin)this).Config.Bind<bool>("Launch", "SupplySilos", true, "Auto-refill Vertical Launching Silos with whatever item they're already loaded to launch.");
LaunchSupplyRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Launch", "SupplyRadius", 0f, "Max straight-line distance from an ejector/silo to an eligible station. 0 = planetwide.");
LaunchNearestStationFirst = ((BaseUnityPlugin)this).Config.Bind<bool>("Launch", "NearestStationFirst", true, "Pull from the closest eligible station first (true) instead of station build order (false).");
LaunchRefillIntervalTicks = ((BaseUnityPlugin)this).Config.Bind<int>("Launch", "RefillIntervalTicks", 60, "Game ticks between refill scans. ~60 = 1s.");
LaunchRequireStationSupplyFlag = ((BaseUnityPlugin)this).Config.Bind<bool>("Launch", "RequireStationSupplyFlag", false, "If true, only pull from station slots set to Supply.");
LaunchSkipInserterFedBuildings = ((BaseUnityPlugin)this).Config.Bind<bool>("Launch", "SkipInserterFedBuildings", true, "If true, never auto-refill an ejector/silo that already has a sorter/inserter delivering to it - only top up ones with no inserter connection at all.");
LaunchVerboseScan = ((BaseUnityPlugin)this).Config.Bind<bool>("Launch", "VerboseScan", false, "Debug aid (needs DebugLog on): periodic scan heartbeat even when nothing moved.");
PlanetwideSupplierLog.Init(((BaseUnityPlugin)this).Logger, DebugLog);
PlanetwideSupplierLog.Info("[config] Generator.Enabled=" + GeneratorEnabled.Value + " SupplyThermal=" + GeneratorSupplyThermal.Value + " SupplyFusion=" + GeneratorSupplyFusion.Value + " SupplyArtificialStar=" + GeneratorSupplyArtificialStar.Value + " SupplyRadius=" + GeneratorSupplyRadius.Value + " RefillIntervalTicks=" + GeneratorRefillIntervalTicks.Value + " PreferHighestFuelTier=" + GeneratorPreferHighestFuelTier.Value + " NearestStationFirst=" + GeneratorNearestStationFirst.Value + " RequireStationSupplyFlag=" + GeneratorRequireStationSupplyFlag.Value + " VerboseScan=" + GeneratorVerboseScan.Value + " ThermalFuelPriority=" + GeneratorThermalFuelPriority.Value + " ExcludeProliferatorFuel=" + GeneratorExcludeProliferatorFuel.Value + " SkipInserterFedGenerators=" + GeneratorSkipInserterFedGenerators.Value + " SupplyGravitonLens=" + GeneratorSupplyGravitonLens.Value + " SkipBeltFedGravitonLens=" + GeneratorSkipBeltFedGravitonLens.Value);
PlanetwideSupplierLog.Info("[config] Ammo.Enabled=" + AmmoEnabled.Value + " SupplyTurrets=" + AmmoSupplyTurrets.Value + " SupplyBattleBases=" + AmmoSupplyBattleBases.Value + " SupplyRadius=" + AmmoSupplyRadius.Value + " RefillIntervalTicks=" + AmmoRefillIntervalTicks.Value + " RequireStationSupplyFlag=" + AmmoRequireStationSupplyFlag.Value + " PreferHighestAmmoTier=" + AmmoPreferHighestAmmoTier.Value + " NearestStationFirst=" + AmmoNearestStationFirst.Value + " FighterItemFilter=" + AmmoFighterItemFilter.Value + " VerboseScan=" + AmmoVerboseScan.Value);
PlanetwideSupplierLog.Info("[config] Production.Enabled=" + ProductionEnabled.Value + " SupplyRadius=" + ProductionSupplyRadius.Value + " RefillIntervalTicks=" + ProductionRefillIntervalTicks.Value + " RequireStationSupplyFlag=" + ProductionRequireStationSupplyFlag.Value + " NearestStationFirst=" + ProductionNearestStationFirst.Value + " SkipInserterFedBuildings=" + ProductionSkipInserterFedBuildings.Value + " VerboseScan=" + ProductionVerboseScan.Value);
PlanetwideSupplierLog.Info("[config] Launch.Enabled=" + LaunchEnabled.Value + " SupplyEjectors=" + LaunchSupplyEjectors.Value + " SupplySilos=" + LaunchSupplySilos.Value + " SupplyRadius=" + LaunchSupplyRadius.Value + " RefillIntervalTicks=" + LaunchRefillIntervalTicks.Value + " RequireStationSupplyFlag=" + LaunchRequireStationSupplyFlag.Value + " NearestStationFirst=" + LaunchNearestStationFirst.Value + " SkipInserterFedBuildings=" + LaunchSkipInserterFedBuildings.Value + " VerboseScan=" + LaunchVerboseScan.Value);
harmony = new Harmony("com.zicarius.PlanetwideSupplier");
try
{
harmony.PatchAll();
PlanetwideSupplierLog.Info("[patch] PatchAll complete.");
}
catch (Exception ex)
{
PlanetwideSupplierLog.Error("[patch] PatchAll failed: " + ex);
}
if (DebugLog.Value)
{
DumpTargetMethodSignatures();
}
PlanetwideSupplierLog.Info("PlanetwideSupplier 1.0.0 loaded.");
}
private void Start()
{
WarnIfPredecessorModsPresent();
}
private void Update()
{
ProductionScan.Tick();
LaunchScan.Tick();
}
private void OnDestroy()
{
if (harmony != null)
{
harmony.UnpatchSelf();
harmony = null;
}
PlanetwideSupplierLog.Info("PlanetwideSupplier unloaded.");
}
private static void WarnIfPredecessorModsPresent()
{
try
{
if (Chainloader.PluginInfos != null)
{
bool num = Chainloader.PluginInfos.ContainsKey("com.zicarius.PlanetwideGeneratorSupply");
bool flag = Chainloader.PluginInfos.ContainsKey("com.zicarius.PlanetwideAmmoSupply");
if (num)
{
PlanetwideSupplierLog.Warn("[compat] PlanetwideGeneratorSupply is also installed - its generator fuel supply overlaps with this mod's own. Not harmful, but wasteful; consider running only one.");
}
if (flag)
{
PlanetwideSupplierLog.Warn("[compat] PlanetwideAmmoSupply is also installed - its ammo supply overlaps with this mod's own. Not harmful, but wasteful; consider running only one.");
}
}
}
catch (Exception ex)
{
PlanetwideSupplierLog.Warn("[compat] predecessor-mod detection failed: " + ex.Message);
}
}
private static void DumpTargetMethodSignatures()
{
string[][] array = new string[4][]
{
new string[2] { "PowerSystem", "GameTick" },
new string[2] { "DefenseSystem", "GameTick" },
new string[2] { "StorageComponent", "AddItem" },
new string[2] { "FactorySystem", "GameTickLabResearchMode" }
};
foreach (string[] array2 in array)
{
try
{
Type type = AccessTools.TypeByName(array2[0]);
if (type == null)
{
PlanetwideSupplierLog.Warn("[diag] Type not found: " + array2[0]);
continue;
}
MethodInfo methodInfo = ((array2[0] == "PowerSystem" && array2[1] == "GameTick") ? AccessTools.Method(type, array2[1], new Type[4]
{
typeof(long),
typeof(bool),
typeof(bool),
typeof(int)
}, (Type[])null) : ((array2[0] == "DefenseSystem" && array2[1] == "GameTick") ? AccessTools.Method(type, array2[1], new Type[2]
{
typeof(long),
typeof(bool)
}, (Type[])null) : ((array2[0] == "FactorySystem" && array2[1] == "GameTickLabResearchMode") ? AccessTools.Method(type, array2[1], new Type[2]
{
typeof(long),
typeof(bool)
}, (Type[])null) : ((!(array2[0] == "StorageComponent") || !(array2[1] == "AddItem")) ? AccessTools.Method(type, array2[1], (Type[])null, (Type[])null) : AccessTools.Method(type, array2[1], new Type[5]
{
typeof(int),
typeof(int),
typeof(int),
typeof(int).MakeByRefType(),
typeof(bool)
}, (Type[])null)))));
if (methodInfo == null)
{
PlanetwideSupplierLog.Warn("[diag] Method not found: " + array2[0] + "." + array2[1]);
continue;
}
ParameterInfo[] parameters = methodInfo.GetParameters();
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("[diag] ").Append(array2[0]).Append('.')
.Append(array2[1])
.Append('(');
for (int j = 0; j < parameters.Length; j++)
{
if (j > 0)
{
stringBuilder.Append(", ");
}
stringBuilder.Append(parameters[j].ParameterType.Name).Append(' ').Append(parameters[j].Name);
}
stringBuilder.Append(')');
PlanetwideSupplierLog.Info(stringBuilder.ToString());
}
catch (Exception ex)
{
PlanetwideSupplierLog.Error("[diag] Failed to inspect " + array2[0] + "." + array2[1] + ": " + ex.Message);
}
}
array = new string[22][]
{
new string[2] { "PowerSystem", "genPool" },
new string[2] { "PowerSystem", "genCursor" },
new string[2] { "PowerSystem", "factory" },
new string[2] { "PlanetFactory", "transport" },
new string[2] { "PlanetTransport", "stationPool" },
new string[2] { "DefenseSystem", "turrets" },
new string[2] { "DefenseSystem", "battleBases" },
new string[2] { "BattleBaseComponent", "storage" },
new string[2] { "StationComponent", "storage" },
new string[2] { "FactorySystem", "assemblerPool" },
new string[2] { "FactorySystem", "assemblerCursor" },
new string[2] { "FactorySystem", "labPool" },
new string[2] { "FactorySystem", "labCursor" },
new string[2] { "AssemblerComponent", "served" },
new string[2] { "AssemblerComponent", "needs" },
new string[2] { "LabComponent", "matrixServed" },
new string[2] { "FactorySystem", "ejectorPool" },
new string[2] { "FactorySystem", "ejectorCursor" },
new string[2] { "FactorySystem", "siloPool" },
new string[2] { "FactorySystem", "siloCursor" },
new string[2] { "EjectorComponent", "bulletId" },
new string[2] { "SiloComponent", "bulletId" }
};
foreach (string[] array3 in array)
{
try
{
Type type2 = AccessTools.TypeByName(array3[0]);
if (type2 == null)
{
PlanetwideSupplierLog.Warn("[diag] Type not found: " + array3[0]);
continue;
}
FieldInfo fieldInfo = AccessTools.Field(type2, array3[1]);
if (fieldInfo == null)
{
PlanetwideSupplierLog.Warn("[diag] Field not found: " + array3[0] + "." + array3[1]);
continue;
}
PlanetwideSupplierLog.Info("[diag] field " + array3[0] + "." + array3[1] + " : " + fieldInfo.FieldType.Name);
}
catch (Exception ex2)
{
PlanetwideSupplierLog.Error("[diag] Failed to inspect field " + array3[0] + "." + array3[1] + ": " + ex2.Message);
}
}
}
}
internal static class ProductionScan
{
private struct ScanTotals
{
public int total;
public int belowCap;
public int refilled;
public int movedItems;
public int noStock;
public int skippedInserter;
}
private const long LogThrottleTicks = 300L;
private static long _lastScannedTick = -1L;
private static long _lastLogTick = long.MinValue;
private static float _lastErrorLogRealtime = float.NegativeInfinity;
private static bool[] _inserterIndex;
internal static void Tick()
{
try
{
if (!Plugin.ProductionEnabled.Value || GameMain.data == null || GameMain.data.factories == null)
{
return;
}
long gameTick = GameMain.gameTick;
int num = Plugin.ProductionRefillIntervalTicks.Value;
if (num < 1)
{
num = 1;
}
if (gameTick < _lastScannedTick)
{
_lastScannedTick = gameTick - num;
_lastLogTick = gameTick - 300;
}
if (gameTick - _lastScannedTick < num)
{
return;
}
_lastScannedTick = gameTick;
float value = Plugin.ProductionSupplyRadius.Value;
ScanTotals totals = default(ScanTotals);
PlanetFactory[] factories = GameMain.data.factories;
foreach (PlanetFactory val in factories)
{
if (val != null && val.factorySystem != null)
{
ScanFactory(val, value, ref totals);
}
}
if (PlanetwideSupplierLog.IsDebugEnabled())
{
bool value2 = Plugin.ProductionVerboseScan.Value;
bool flag = totals.movedItems > 0 || totals.noStock > 0 || totals.skippedInserter > 0;
if ((value2 || flag) && gameTick - _lastLogTick >= 300)
{
_lastLogTick = gameTick;
PlanetwideSupplierLog.Info("[supply] production{" + (value2 ? ("total=" + totals.total + " belowCap=" + totals.belowCap + " ") : "") + "refilled=" + totals.refilled + " items=" + totals.movedItems + ((totals.noStock > 0) ? (" noStock=" + totals.noStock) : "") + ((totals.skippedInserter > 0) ? (" skippedInserter=" + totals.skippedInserter) : "") + "}");
}
}
}
catch (Exception ex)
{
float realtimeSinceStartup = Time.realtimeSinceStartup;
if (realtimeSinceStartup - _lastErrorLogRealtime >= 5f)
{
_lastErrorLogRealtime = realtimeSinceStartup;
PlanetwideSupplierLog.Error("[patch] ProductionScan.Tick threw: " + ex);
}
}
}
private static void ScanFactory(PlanetFactory factory, float radius, ref ScanTotals totals)
{
FactorySystem factorySystem = factory.factorySystem;
if (factorySystem.assemblerCursor <= 1 && factorySystem.labCursor <= 1)
{
return;
}
bool value = Plugin.ProductionSkipInserterFedBuildings.Value;
if (value)
{
ProductionSourcing.BuildInserterIndex(factory, ref _inserterIndex);
}
EntityData[] entityPool = factory.entityPool;
AssemblerComponent[] assemblerPool = factorySystem.assemblerPool;
if (assemblerPool != null)
{
int assemblerCursor = factorySystem.assemblerCursor;
for (int i = 1; i < assemblerCursor; i++)
{
if (assemblerPool[i].id == i && assemblerPool[i].recipeId != 0)
{
ScanRequires(factory, entityPool, assemblerPool[i].entityId, assemblerPool[i].recipeExecuteData, assemblerPool[i].served, assemblerPool[i].incServed, assemblerPool[i].needs, radius, value, assemblerPool[i].speedOverride, isLab: false, ref totals);
}
}
}
LabComponent[] labPool = factorySystem.labPool;
if (labPool == null)
{
return;
}
int labCursor = factorySystem.labCursor;
for (int j = 1; j < labCursor; j++)
{
if (labPool[j].id == j && !labPool[j].researchMode && labPool[j].recipeId != 0)
{
ScanRequires(factory, entityPool, labPool[j].entityId, labPool[j].recipeExecuteData, labPool[j].served, labPool[j].incServed, labPool[j].needs, radius, value, labPool[j].speedOverride, isLab: true, ref totals);
}
}
}
private static void ScanRequires(PlanetFactory factory, EntityData[] entityPool, int entityId, RecipeExecuteData recipeExecuteData, int[] served, int[] incServed, int[] needs, float radius, bool skipInserterFed, int speedOverride, bool isLab, ref ScanTotals totals)
{
//IL_0052: 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_006c: Unknown result type (might be due to invalid IL or missing references)
//IL_0071: Unknown result type (might be due to invalid IL or missing references)
//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
if (recipeExecuteData == null || needs == null || served == null)
{
return;
}
totals.total++;
if (skipInserterFed && _inserterIndex != null && entityId > 0 && entityId < _inserterIndex.Length && _inserterIndex[entityId])
{
totals.skippedInserter++;
return;
}
int[] requireCounts = recipeExecuteData.requireCounts;
if (requireCounts == null)
{
return;
}
Vector3 pos = Vector3.zero;
if (entityPool != null && entityId > 0 && entityId < entityPool.Length)
{
pos = entityPool[entityId].pos;
}
int num;
if (isLab)
{
num = ((recipeExecuteData.timeSpend > 5400000) ? 6 : (3 * ((speedOverride + 5001) / 10000) + 3));
}
else
{
num = speedOverride * 180 / recipeExecuteData.timeSpend + 1;
if (num < 2)
{
num = 2;
}
}
bool flag = false;
for (int i = 0; i < needs.Length && i < requireCounts.Length && i < served.Length && i < incServed.Length; i++)
{
int num2 = needs[i];
if (num2 == 0)
{
continue;
}
int num3 = (isLab ? num : (requireCounts[i] * num)) - served[i];
if (num3 > 0)
{
flag = true;
int incMoved;
int num4 = ProductionSourcing.TryPullFromPlanet(factory, num2, num3, pos, radius, out incMoved);
if (num4 <= 0)
{
totals.noStock++;
continue;
}
served[i] += num4;
incServed[i] += incMoved;
totals.refilled++;
totals.movedItems += num4;
}
}
if (flag)
{
totals.belowCap++;
}
}
}
internal static class ProductionSourcing
{
private struct StationDist
{
public int index;
public float distSqr;
}
private static List<StationDist> _scratch;
private static readonly Comparison<StationDist> _byDist = (StationDist a, StationDist b) => a.distSqr.CompareTo(b.distSqr);
internal static int TryPullFromPlanet(PlanetFactory factory, int itemId, int want, Vector3 pos, float radius, out int incMoved)
{
//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
incMoved = 0;
if (factory == null || itemId <= 0 || want <= 0)
{
return 0;
}
PlanetTransport transport = factory.transport;
if (transport == null || transport.stationPool == null)
{
return 0;
}
bool value = Plugin.ProductionRequireStationSupplyFlag.Value;
bool value2 = Plugin.ProductionNearestStationFirst.Value;
float num = ((radius > 0f) ? (radius * radius) : 0f);
EntityData[] entityPool = factory.entityPool;
int stationCursor = transport.stationCursor;
int moved = 0;
Vector3 val2;
if (value2)
{
if (_scratch == null)
{
_scratch = new List<StationDist>(64);
}
_scratch.Clear();
for (int i = 1; i < stationCursor; i++)
{
StationComponent val = transport.stationPool[i];
if (val == null || val.id != i || val.storage == null)
{
continue;
}
float num2 = 0f;
if (entityPool != null)
{
int entityId = val.entityId;
if (entityId > 0 && entityId < entityPool.Length)
{
val2 = entityPool[entityId].pos - pos;
num2 = ((Vector3)(ref val2)).sqrMagnitude;
if (num > 0f && num2 > num)
{
continue;
}
}
}
if (StationHasItem(val, itemId, value))
{
_scratch.Add(new StationDist
{
index = i,
distSqr = num2
});
}
}
_scratch.Sort(_byDist);
for (int j = 0; j < _scratch.Count; j++)
{
if (moved >= want)
{
break;
}
DrainStation(transport.stationPool[_scratch[j].index], itemId, want, value, ref moved, ref incMoved);
}
}
else
{
for (int k = 1; k < stationCursor && moved < want; k++)
{
StationComponent val3 = transport.stationPool[k];
if (val3 == null || val3.id != k || val3.storage == null)
{
continue;
}
if (num > 0f && entityPool != null)
{
int entityId2 = val3.entityId;
if (entityId2 > 0 && entityId2 < entityPool.Length)
{
val2 = entityPool[entityId2].pos - pos;
if (((Vector3)(ref val2)).sqrMagnitude > num)
{
continue;
}
}
}
DrainStation(val3, itemId, want, value, ref moved, ref incMoved);
}
}
return moved;
}
private static bool StationHasItem(StationComponent station, int itemId, bool requireSupply)
{
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Invalid comparison between Unknown and I4
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Invalid comparison between Unknown and I4
StationStore[] storage = station.storage;
for (int i = 0; i < storage.Length; i++)
{
if (storage[i].itemId == itemId && storage[i].count > 0 && (!requireSupply || (int)storage[i].localLogic == 1 || (int)storage[i].remoteLogic == 1))
{
return true;
}
}
return false;
}
private static void DrainStation(StationComponent station, int itemId, int want, bool requireSupply, ref int moved, ref int incMoved)
{
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Invalid comparison between Unknown and I4
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Invalid comparison between Unknown and I4
StationStore[] storage = station.storage;
for (int i = 0; i < storage.Length; i++)
{
if (moved >= want)
{
break;
}
if (storage[i].itemId != itemId || storage[i].count <= 0 || (requireSupply && (int)storage[i].localLogic != 1 && (int)storage[i].remoteLogic != 1))
{
continue;
}
int num = want - moved;
if (num > storage[i].count)
{
num = storage[i].count;
}
int num2 = 0;
if (storage[i].inc > 0)
{
num2 = (int)((float)storage[i].inc * (float)num / (float)storage[i].count + 0.5f);
if (num2 > storage[i].inc)
{
num2 = storage[i].inc;
}
}
storage[i].count -= num;
storage[i].inc -= num2;
moved += num;
incMoved += num2;
}
}
internal static void BuildInserterIndex(PlanetFactory factory, ref bool[] buffer)
{
int entityCursor = factory.entityCursor;
if (buffer == null || buffer.Length < entityCursor)
{
buffer = new bool[entityCursor];
}
else
{
Array.Clear(buffer, 0, entityCursor);
}
FactorySystem factorySystem = factory.factorySystem;
if (factorySystem == null || factorySystem.inserterPool == null)
{
return;
}
InserterComponent[] inserterPool = factorySystem.inserterPool;
int inserterCursor = factorySystem.inserterCursor;
for (int i = 1; i < inserterCursor; i++)
{
if (inserterPool[i].id == i)
{
int insertTarget = inserterPool[i].insertTarget;
if (insertTarget > 0 && insertTarget < buffer.Length)
{
buffer[insertTarget] = true;
}
}
}
}
}