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 _scratch = new List(64); private static readonly Comparison _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 _scratch; private static readonly Comparison _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(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 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(); } string[] array = csv.Split(','); List list = new List(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)(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 _scratch; private static readonly Comparison _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(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 debugGate; public static void Init(ManualLogSource src, ConfigEntry 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 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 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(); private static HashSet _proliferatorIds = new HashSet(); 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(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 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 GeneratorEnabled; internal static ConfigEntry GeneratorSupplyThermal; internal static ConfigEntry GeneratorSupplyFusion; internal static ConfigEntry GeneratorSupplyArtificialStar; internal static ConfigEntry GeneratorPreferHighestFuelTier; internal static ConfigEntry GeneratorSupplyRadius; internal static ConfigEntry GeneratorNearestStationFirst; internal static ConfigEntry GeneratorRefillIntervalTicks; internal static ConfigEntry GeneratorRequireStationSupplyFlag; internal static ConfigEntry GeneratorVerboseScan; internal static ConfigEntry GeneratorThermalFuelPriority; internal static ConfigEntry GeneratorExcludeProliferatorFuel; internal static ConfigEntry GeneratorSkipInserterFedGenerators; internal static ConfigEntry GeneratorSupplyGravitonLens; internal static ConfigEntry GeneratorSkipBeltFedGravitonLens; internal static ConfigEntry AmmoEnabled; internal static ConfigEntry AmmoSupplyTurrets; internal static ConfigEntry AmmoSupplyBattleBases; internal static ConfigEntry AmmoPreferHighestAmmoTier; internal static ConfigEntry AmmoSupplyRadius; internal static ConfigEntry AmmoNearestStationFirst; internal static ConfigEntry AmmoRefillIntervalTicks; internal static ConfigEntry AmmoRequireStationSupplyFlag; internal static ConfigEntry AmmoFighterItemFilter; internal static ConfigEntry AmmoVerboseScan; internal static ConfigEntry ProductionEnabled; internal static ConfigEntry ProductionSupplyRadius; internal static ConfigEntry ProductionNearestStationFirst; internal static ConfigEntry ProductionRefillIntervalTicks; internal static ConfigEntry ProductionRequireStationSupplyFlag; internal static ConfigEntry ProductionSkipInserterFedBuildings; internal static ConfigEntry ProductionVerboseScan; internal static ConfigEntry LaunchEnabled; internal static ConfigEntry LaunchSupplyEjectors; internal static ConfigEntry LaunchSupplySilos; internal static ConfigEntry LaunchSupplyRadius; internal static ConfigEntry LaunchNearestStationFirst; internal static ConfigEntry LaunchRefillIntervalTicks; internal static ConfigEntry LaunchRequireStationSupplyFlag; internal static ConfigEntry LaunchSkipInserterFedBuildings; internal static ConfigEntry LaunchVerboseScan; internal static ConfigEntry 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("Diagnostics", "DebugLog", false, "Enable verbose diagnostic logging to the BepInEx console."); GeneratorEnabled = ((BaseUnityPlugin)this).Config.Bind("Generator", "Enabled", true, "Master switch for generator fuel supply. If false this module is fully inert."); GeneratorSupplyThermal = ((BaseUnityPlugin)this).Config.Bind("Generator", "SupplyThermal", true, "Auto-refill thermal power plants (chemical fuels)."); GeneratorSupplyFusion = ((BaseUnityPlugin)this).Config.Bind("Generator", "SupplyFusion", true, "Auto-refill mini fusion power plants (deuterium fuel rods)."); GeneratorSupplyArtificialStar = ((BaseUnityPlugin)this).Config.Bind("Generator", "SupplyArtificialStar", true, "Auto-refill artificial stars (antimatter fuel rods)."); GeneratorPreferHighestFuelTier = ((BaseUnityPlugin)this).Config.Bind("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("Generator", "SupplyRadius", 0f, "Max straight-line distance from a generator to an eligible station. 0 = planetwide."); GeneratorNearestStationFirst = ((BaseUnityPlugin)this).Config.Bind("Generator", "NearestStationFirst", true, "Pull from the closest eligible station first (true) instead of station build order (false)."); GeneratorRefillIntervalTicks = ((BaseUnityPlugin)this).Config.Bind("Generator", "RefillIntervalTicks", 60, "Game ticks between refill scans. ~60 = 1s."); GeneratorRequireStationSupplyFlag = ((BaseUnityPlugin)this).Config.Bind("Generator", "RequireStationSupplyFlag", false, "If true, only pull from station slots set to Supply."); GeneratorVerboseScan = ((BaseUnityPlugin)this).Config.Bind("Generator", "VerboseScan", false, "Debug aid (needs DebugLog on): periodic scan heartbeat even when nothing moved."); GeneratorThermalFuelPriority = ((BaseUnityPlugin)this).Config.Bind("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("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("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("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("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("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("Ammo", "SupplyTurrets", true, "Auto-refill turret ammo from the planet's logistics stations."); AmmoSupplyBattleBases = ((BaseUnityPlugin)this).Config.Bind("Ammo", "SupplyBattleBases", true, "Auto-refill battle-base ammo and fighters from the planet's logistics stations."); AmmoPreferHighestAmmoTier = ((BaseUnityPlugin)this).Config.Bind("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("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("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("Ammo", "RefillIntervalTicks", 60, "Game ticks between refill scans (throttle). ~60 = 1s. Higher = cheaper, lower = more responsive."); AmmoRequireStationSupplyFlag = ((BaseUnityPlugin)this).Config.Bind("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("Ammo", "FighterItemFilter", "", "Optional: restrict which fighter/ammo items battle bases pull (empty = everything the base already accepts)."); AmmoVerboseScan = ((BaseUnityPlugin)this).Config.Bind("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("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("Production", "SupplyRadius", 0f, "Max straight-line distance from a building to an eligible station. 0 = planetwide."); ProductionNearestStationFirst = ((BaseUnityPlugin)this).Config.Bind("Production", "NearestStationFirst", true, "Pull from the closest eligible station first (true) instead of station build order (false)."); ProductionRefillIntervalTicks = ((BaseUnityPlugin)this).Config.Bind("Production", "RefillIntervalTicks", 60, "Game ticks between refill scans. ~60 = 1s."); ProductionRequireStationSupplyFlag = ((BaseUnityPlugin)this).Config.Bind("Production", "RequireStationSupplyFlag", false, "If true, only pull from station slots set to Supply."); ProductionSkipInserterFedBuildings = ((BaseUnityPlugin)this).Config.Bind("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("Production", "VerboseScan", false, "Debug aid (needs DebugLog on): periodic scan heartbeat even when nothing moved."); LaunchEnabled = ((BaseUnityPlugin)this).Config.Bind("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("Launch", "SupplyEjectors", true, "Auto-refill EM-Rail Ejectors with whatever item they're already loaded to launch."); LaunchSupplySilos = ((BaseUnityPlugin)this).Config.Bind("Launch", "SupplySilos", true, "Auto-refill Vertical Launching Silos with whatever item they're already loaded to launch."); LaunchSupplyRadius = ((BaseUnityPlugin)this).Config.Bind("Launch", "SupplyRadius", 0f, "Max straight-line distance from an ejector/silo to an eligible station. 0 = planetwide."); LaunchNearestStationFirst = ((BaseUnityPlugin)this).Config.Bind("Launch", "NearestStationFirst", true, "Pull from the closest eligible station first (true) instead of station build order (false)."); LaunchRefillIntervalTicks = ((BaseUnityPlugin)this).Config.Bind("Launch", "RefillIntervalTicks", 60, "Game ticks between refill scans. ~60 = 1s."); LaunchRequireStationSupplyFlag = ((BaseUnityPlugin)this).Config.Bind("Launch", "RequireStationSupplyFlag", false, "If true, only pull from station slots set to Supply."); LaunchSkipInserterFedBuildings = ((BaseUnityPlugin)this).Config.Bind("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("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 _scratch; private static readonly Comparison _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(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; } } } } }