Decompiled source of PlanetwideSupplier v1.0.0

plugins\PlanetwideSupplier.dll

Decompiled 3 days ago
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;
				}
			}
		}
	}
}