Decompiled source of StackingPlus v0.1.0

plugins\StackingPlus.dll

Decompiled a day 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.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("StackingPlus")]
[assembly: AssemblyDescription("Dyson Sphere Program BepInEx mod.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("StackingPlus")]
[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 StackingPlus;

internal static class ModSettings
{
	public static bool EnableSorterOutput = true;

	public static int SorterOutputCap = 8;

	public static bool EnableSorterInput = true;

	public static int SorterInputCap = 8;

	public static bool EnableStationPiler = true;

	public static int StationPilerCap = 8;

	public static bool EnableDeliveryPackage = true;

	public static int DeliveryPackageCap = 8;

	public static bool TechGated = true;

	public static int VanillaCeilingOutput = 4;

	public static int VanillaCeilingInput = 4;

	public static int VanillaCeilingPiler = 4;

	public static int VanillaCeilingPackage = 4;

	public static bool BeltSpeedEnable = false;

	public static float BeltSpeedMultiplier = 2f;

	public const int HardStackCeiling = 255;

	public static int ClampStack(int v)
	{
		if (v < 2)
		{
			return 2;
		}
		if (v > 255)
		{
			return 255;
		}
		return v;
	}
}
internal static class BeltSpeedPatch
{
	private static readonly Dictionary<int, int> _origBeltSpeed = new Dictionary<int, int>();

	private static readonly Dictionary<int, int> _scaledToOrig = new Dictionary<int, int>();

	private static bool _snapshotTaken;

	private static float _appliedMult = float.NaN;

	private static FieldRef<CargoPath, int> _chunkCountRef = AccessTools.FieldRefAccess<CargoPath, int>("chunkCount");

	internal static void EnsureProtoScaled()
	{
		try
		{
			if (!ModSettings.BeltSpeedEnable || (_snapshotTaken && _appliedMult == ModSettings.BeltSpeedMultiplier))
			{
				return;
			}
			ItemProtoSet items = LDB.items;
			if ((Object)(object)items == (Object)null || ((ProtoSet<ItemProto>)(object)items).dataArray == null)
			{
				return;
			}
			float beltSpeedMultiplier = ModSettings.BeltSpeedMultiplier;
			int num = 0;
			ItemProto[] dataArray = ((ProtoSet<ItemProto>)(object)items).dataArray;
			foreach (ItemProto val in dataArray)
			{
				if (val == null)
				{
					continue;
				}
				PrefabDesc prefabDesc = val.prefabDesc;
				if (prefabDesc != null && prefabDesc.isBelt && prefabDesc.beltSpeed > 0)
				{
					if (!_origBeltSpeed.TryGetValue(((Proto)val).ID, out var value))
					{
						value = prefabDesc.beltSpeed;
						_origBeltSpeed[((Proto)val).ID] = value;
					}
					int num2 = ScaleSpeed(value, beltSpeedMultiplier);
					StackingPlusLog.Info("[belt] proto " + ((Proto)val).ID + " (" + ((Proto)val).name + ") orig=" + value + " current=" + prefabDesc.beltSpeed + " -> target=" + num2 + " (x" + beltSpeedMultiplier + ")");
					if (prefabDesc.beltSpeed != num2)
					{
						prefabDesc.beltSpeed = num2;
						num++;
					}
					_scaledToOrig[num2] = value;
				}
			}
			_snapshotTaken = true;
			_appliedMult = beltSpeedMultiplier;
			if (num > 0)
			{
				StackingPlusLog.Info("[belt] scaled " + num + " belt proto(s) x" + beltSpeedMultiplier);
			}
		}
		catch (Exception ex)
		{
			StackingPlusLog.Warn("EnsureProtoScaled failed: " + ex.Message);
		}
	}

	private static int ScaledSpeedForProto(int protoId)
	{
		if (_origBeltSpeed.TryGetValue(protoId, out var value))
		{
			return ScaleSpeed(value, ModSettings.BeltSpeedMultiplier);
		}
		ItemProto val = ((ProtoSet<ItemProto>)(object)LDB.items).Select(protoId);
		if (val != null && val.prefabDesc != null && val.prefabDesc.isBelt)
		{
			return val.prefabDesc.beltSpeed;
		}
		return 0;
	}

	internal static int OriginalSpeedForProto(int protoId)
	{
		if (_origBeltSpeed.TryGetValue(protoId, out var value))
		{
			return value;
		}
		ItemProto val = ((ProtoSet<ItemProto>)(object)LDB.items).Select(protoId);
		if (val != null && val.prefabDesc != null && val.prefabDesc.isBelt)
		{
			float beltSpeedMultiplier = ModSettings.BeltSpeedMultiplier;
			int beltSpeed = val.prefabDesc.beltSpeed;
			if (!(beltSpeedMultiplier > 1f))
			{
				return beltSpeed;
			}
			return Math.Max(1, (int)Math.Round((float)beltSpeed / beltSpeedMultiplier));
		}
		return -1;
	}

	internal static void BeforeSetBeltState(CargoTraffic __instance, int beltId, ref int state)
	{
		try
		{
			if (!ModSettings.BeltSpeedEnable)
			{
				return;
			}
			if (_scaledToOrig.TryGetValue(state, out var value) && value != state)
			{
				StackingPlusLog.Info("[belt][visual] SetBeltState belt#" + beltId + " tread-state " + state + " -> " + value + " (value-based; visual identity preserved).");
				state = value;
			}
			else
			{
				if (__instance == null || __instance.factory == null || __instance.factory.entityPool == null || __instance.beltPool == null || beltId <= 0 || beltId >= __instance.beltPool.Length)
				{
					return;
				}
				int entityId = __instance.beltPool[beltId].entityId;
				if (entityId > 0 && entityId < __instance.factory.entityPool.Length)
				{
					int protoId = __instance.factory.entityPool[entityId].protoId;
					int num = OriginalSpeedForProto(protoId);
					if (num > 0 && state != num)
					{
						StackingPlusLog.Info("[belt][visual] SetBeltState belt#" + beltId + " proto=" + protoId + " tread-state " + state + " -> " + num + " (entity-based fallback).");
						state = num;
					}
				}
			}
		}
		catch (Exception ex)
		{
			StackingPlusLog.Warn("BeforeSetBeltState failed: " + ex.Message);
		}
	}

	internal static void AfterHeadOrRearSpeed(ref int __result)
	{
		try
		{
			if (ModSettings.BeltSpeedEnable && _scaledToOrig.TryGetValue(__result, out var value) && value != __result)
			{
				__result = value;
			}
		}
		catch (Exception ex)
		{
			StackingPlusLog.Warn("AfterHeadOrRearSpeed failed: " + ex.Message);
		}
	}

	internal static void BeforeAlterBeltRenderer(CargoTraffic __instance, int beltId, out int __state)
	{
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_003b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0060: Unknown result type (might be due to invalid IL or missing references)
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
		__state = -1;
		try
		{
			if (!ModSettings.BeltSpeedEnable || __instance == null || __instance.beltPool == null || beltId <= 0 || beltId >= __instance.beltPool.Length)
			{
				return;
			}
			BeltComponent val = __instance.beltPool[beltId];
			if (val.id != beltId || __instance.factory == null || __instance.factory.entityPool == null)
			{
				return;
			}
			int entityId = val.entityId;
			if (entityId > 0 && entityId < __instance.factory.entityPool.Length)
			{
				int num = OriginalSpeedForProto(__instance.factory.entityPool[entityId].protoId);
				if (num > 0 && num != val.speed)
				{
					__state = val.speed;
					__instance.beltPool[beltId].speed = num;
				}
			}
		}
		catch (Exception ex)
		{
			StackingPlusLog.Warn("BeforeAlterBeltRenderer failed: " + ex.Message);
		}
	}

	internal static void AfterAlterBeltRenderer(CargoTraffic __instance, int beltId, int __state)
	{
		try
		{
			if (__state >= 0 && __instance != null && __instance.beltPool != null && beltId > 0 && beltId < __instance.beltPool.Length)
			{
				__instance.beltPool[beltId].speed = __state;
			}
		}
		catch (Exception ex)
		{
			StackingPlusLog.Warn("AfterAlterBeltRenderer failed: " + ex.Message);
		}
	}

	private static int ReadChunkSpeed(CargoPath path, int index)
	{
		try
		{
			if (path == null || path.chunks == null || _chunkCountRef == null)
			{
				return -1;
			}
			int num = _chunkCountRef.Invoke(path);
			for (int i = 0; i < num; i++)
			{
				int num2 = path.chunks[i * 3];
				int num3 = path.chunks[i * 3 + 1];
				if (index >= num2 && index < num2 + num3)
				{
					return path.chunks[i * 3 + 2];
				}
			}
		}
		catch
		{
		}
		return -1;
	}

	private static int ScaleSpeed(int orig, float m)
	{
		if (m <= 1f)
		{
			return orig;
		}
		int num = (int)Math.Round((float)orig * m);
		if (num < 1)
		{
			num = 1;
		}
		if (num > 255)
		{
			num = 255;
		}
		return num;
	}

	internal static void AfterCargoTrafficImport(CargoTraffic __instance)
	{
		//IL_016e: Unknown result type (might be due to invalid IL or missing references)
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_0063: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_011d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0129: Unknown result type (might be due to invalid IL or missing references)
		//IL_0130: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if (!ModSettings.BeltSpeedEnable)
			{
				return;
			}
			EnsureProtoScaled();
			PlanetFactory factory = __instance.factory;
			if (factory == null || factory.entityPool == null || __instance.beltPool == null || __instance.pathPool == null)
			{
				return;
			}
			int num = 0;
			int num2 = 0;
			for (int i = 1; i < __instance.beltCursor; i++)
			{
				BeltComponent val = __instance.beltPool[i];
				if (val.id != i)
				{
					continue;
				}
				int entityId = val.entityId;
				if (entityId <= 0 || entityId >= factory.entityPool.Length)
				{
					continue;
				}
				int protoId = factory.entityPool[entityId].protoId;
				int num3 = ScaledSpeedForProto(protoId);
				if (num3 <= 0)
				{
					continue;
				}
				int segPathId = val.segPathId;
				CargoPath val2 = ((segPathId > 0 && segPathId < __instance.pathPool.Length) ? __instance.pathPool[segPathId] : null);
				bool flag = num2 < 3;
				int num4 = -1;
				if (flag && val2 != null)
				{
					num4 = ReadChunkSpeed(val2, val.segIndex);
				}
				if (__instance.beltPool[i].speed != num3)
				{
					__instance.beltPool[i].speed = num3;
				}
				if (val2 != null && val.segLength > 0)
				{
					val2.InsertChunk(val.segIndex, val.segLength, num3);
					num++;
				}
				int num5 = OriginalSpeedForProto(protoId);
				if (num5 > 0)
				{
					try
					{
						__instance.SetBeltState(i, num5);
					}
					catch
					{
					}
				}
				if (flag && val2 != null)
				{
					int num6 = ReadChunkSpeed(val2, val.segIndex);
					StackingPlusLog.Info("[belt] sample belt#" + i + " proto=" + protoId + " segIdx=" + val.segIndex + " segLen=" + val.segLength + " target=" + num3 + " chunkSpeed " + num4 + " -> " + num6 + " beltPoolSpeed=" + __instance.beltPool[i].speed);
					num2++;
				}
			}
			if (num > 0)
			{
				string text = ((factory.planet != null) ? factory.planet.displayName : "?");
				StackingPlusLog.Info("[belt] rewrote " + num + " existing belt segment(s) on " + text + " (multiplier x" + ModSettings.BeltSpeedMultiplier + ").");
			}
		}
		catch (Exception ex)
		{
			StackingPlusLog.Error("AfterCargoTrafficImport failed: " + ex);
		}
	}
}
internal static class StackingPatch
{
	private static FieldRef<GameHistoryData, int> _outputRef;

	private static FieldRef<GameHistoryData, int> _inputRef;

	private static FieldRef<GameHistoryData, int> _pilerRef;

	private static bool _outputOk;

	private static bool _inputOk;

	private static bool _pilerOk;

	private static bool _pendingRefresh;

	internal static void Init()
	{
		_outputRef = TryFieldRef("inserterStackOutput", out _outputOk);
		_inputRef = TryFieldRef("inserterStackInput", out _inputOk);
		_pilerRef = TryFieldRef("stationPilerLevel", out _pilerOk);
	}

	private static FieldRef<GameHistoryData, int> TryFieldRef(string name, out bool ok)
	{
		try
		{
			FieldRef<GameHistoryData, int> val = AccessTools.FieldRefAccess<GameHistoryData, int>(name);
			ok = val != null;
			if (!ok)
			{
				StackingPlusLog.Warn("[compat] GameHistoryData." + name + " not found; that dimension is disabled.");
			}
			return val;
		}
		catch (Exception ex)
		{
			ok = false;
			StackingPlusLog.Warn("[compat] GameHistoryData." + name + " not found; that dimension is disabled: " + ex.Message);
			return null;
		}
	}

	internal static void AfterUnlockTech(GameHistoryData __instance)
	{
		Enforce(__instance, refreshInserters: true);
	}

	internal static void AfterImport(GameHistoryData __instance)
	{
		Enforce(__instance, refreshInserters: false);
	}

	internal static void AfterSetForNewGame(GameHistoryData __instance)
	{
		Enforce(__instance, refreshInserters: true);
	}

	internal static void OnGameBegin()
	{
		BeltSpeedPatch.EnsureProtoScaled();
		if (_pendingRefresh)
		{
			SafeRefresh(GameMain.history);
		}
	}

	internal static void EnforceCurrent()
	{
		try
		{
			if ((Object)(object)GameMain.instance != (Object)null && GameMain.history != null)
			{
				Enforce(GameMain.history, refreshInserters: true);
			}
		}
		catch (Exception ex)
		{
			StackingPlusLog.Warn("EnforceCurrent failed: " + ex.Message);
		}
	}

	internal static void Enforce(GameHistoryData history, bool refreshInserters)
	{
		if (history == null)
		{
			return;
		}
		try
		{
			bool flag = false;
			if (ModSettings.EnableSorterOutput && _outputOk)
			{
				flag |= Apply(_outputRef, history, "SorterOutput", ModSettings.SorterOutputCap, ModSettings.VanillaCeilingOutput);
			}
			if (ModSettings.EnableSorterInput && _inputOk)
			{
				flag |= Apply(_inputRef, history, "SorterInput", ModSettings.SorterInputCap, ModSettings.VanillaCeilingInput);
			}
			if (ModSettings.EnableStationPiler && _pilerOk)
			{
				Apply(_pilerRef, history, "StationPiler", ModSettings.StationPilerCap, ModSettings.VanillaCeilingPiler);
			}
			if (ModSettings.EnableDeliveryPackage)
			{
				ApplyDelivery();
			}
			if (flag)
			{
				if (refreshInserters)
				{
					SafeRefresh(history);
				}
				else
				{
					_pendingRefresh = true;
				}
			}
		}
		catch (Exception ex)
		{
			StackingPlusLog.Error("Enforce failed: " + ex);
		}
	}

	private static void SafeRefresh(GameHistoryData history)
	{
		try
		{
			if (history != null && history.gameData != null)
			{
				history.gameData.OnInserterTechChange();
				_pendingRefresh = false;
				StackingPlusLog.Info("[stack] refreshed existing sorters.");
			}
		}
		catch (Exception ex)
		{
			_pendingRefresh = true;
			StackingPlusLog.Info("[stack] sorter refresh deferred (game not ready): " + ex.Message);
		}
	}

	private static bool Apply(FieldRef<GameHistoryData, int> fieldRef, GameHistoryData history, string label, int cap, int ceiling)
	{
		int num = ModSettings.ClampStack(cap);
		int num2 = fieldRef.Invoke(history);
		if (ModSettings.TechGated && num2 < ceiling)
		{
			return false;
		}
		if (num <= num2)
		{
			return false;
		}
		fieldRef.Invoke(history) = num;
		StackingPlusLog.Info("[stack] " + label + ": " + num2 + " -> " + num + " (gated=" + ModSettings.TechGated + ", ceiling=" + ceiling + ")");
		return true;
	}

	private static void ApplyDelivery()
	{
		try
		{
			Player mainPlayer = GameMain.mainPlayer;
			if (mainPlayer == null)
			{
				return;
			}
			DeliveryPackage deliveryPackage = mainPlayer.deliveryPackage;
			if (deliveryPackage != null)
			{
				int num = ModSettings.ClampStack(ModSettings.DeliveryPackageCap);
				int stackSizeMultiplier = deliveryPackage.stackSizeMultiplier;
				if ((!ModSettings.TechGated || stackSizeMultiplier >= ModSettings.VanillaCeilingPackage) && num > stackSizeMultiplier)
				{
					deliveryPackage.stackSizeMultiplier = num;
					StackingPlusLog.Info("[stack] DeliveryPackage: " + stackSizeMultiplier + " -> " + num + " (gated=" + ModSettings.TechGated + ", ceiling=" + ModSettings.VanillaCeilingPackage + ")");
				}
			}
		}
		catch (Exception ex)
		{
			StackingPlusLog.Warn("ApplyDelivery failed: " + ex.Message);
		}
	}
}
[BepInPlugin("com.zicarius.StackingPlus", "StackingPlus", "0.1.0")]
public sealed class Plugin : BaseUnityPlugin
{
	public const string PluginGuid = "com.zicarius.StackingPlus";

	public const string PluginName = "StackingPlus";

	public const string PluginVersion = "0.1.0";

	private Harmony harmony;

	private ConfigEntry<bool> cfgDebugLog;

	private ConfigEntry<bool> cfgEnableOutput;

	private ConfigEntry<int> cfgOutputCap;

	private ConfigEntry<bool> cfgEnableInput;

	private ConfigEntry<int> cfgInputCap;

	private ConfigEntry<bool> cfgEnablePiler;

	private ConfigEntry<int> cfgPilerCap;

	private ConfigEntry<bool> cfgEnablePackage;

	private ConfigEntry<int> cfgPackageCap;

	private ConfigEntry<bool> cfgTechGated;

	private ConfigEntry<int> cfgCeilingOutput;

	private ConfigEntry<int> cfgCeilingInput;

	private ConfigEntry<int> cfgCeilingPiler;

	private ConfigEntry<int> cfgCeilingPackage;

	private ConfigEntry<bool> cfgBeltEnable;

	private ConfigEntry<float> cfgBeltMultiplier;

	private void Awake()
	{
		//IL_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: Expected O, but got Unknown
		BindConfig();
		StackingPlusLog.Init(((BaseUnityPlugin)this).Logger, cfgDebugLog);
		PushConfigToSettings();
		WireLiveConfig();
		StackingPatch.Init();
		harmony = new Harmony("com.zicarius.StackingPlus");
		ApplyPatches();
		DumpTargetMethodSignatures();
		LogResolvedConfig();
		StackingPlusLog.Info("StackingPlus 0.1.0 loaded.");
	}

	private void Start()
	{
		StackingPatch.EnforceCurrent();
	}

	private void OnDestroy()
	{
		if (harmony != null)
		{
			harmony.UnpatchSelf();
			harmony = null;
		}
		StackingPlusLog.Info("StackingPlus unloaded.");
	}

	private void BindConfig()
	{
		//IL_0069: Unknown result type (might be due to invalid IL or missing references)
		//IL_0073: Expected O, but got Unknown
		//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Expected O, but got Unknown
		//IL_0117: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Expected O, but got Unknown
		//IL_016e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0178: Expected O, but got Unknown
		//IL_0272: Unknown result type (might be due to invalid IL or missing references)
		//IL_027c: Expected O, but got Unknown
		cfgDebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "DebugLog", false, "Enable verbose diagnostic logging to the BepInEx console.");
		cfgEnableOutput = ((BaseUnityPlugin)this).Config.Bind<bool>("Stacking", "EnableSorterOutput", true, "Raise Pile Sorter -> belt output stacking (the belt cargo cap). This is the core throughput fix.");
		cfgOutputCap = ((BaseUnityPlugin)this).Config.Bind<int>("Stacking", "SorterOutputCap", 8, new ConfigDescription("Target sorter output stack size (vanilla 4). Cargo.stack is a byte so 255 is the hard ceiling.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 255), Array.Empty<object>()));
		cfgEnableInput = ((BaseUnityPlugin)this).Config.Bind<bool>("Stacking", "EnableSorterInput", true, "Raise Pile Sorter pickup (input) stacking.");
		cfgInputCap = ((BaseUnityPlugin)this).Config.Bind<int>("Stacking", "SorterInputCap", 8, new ConfigDescription("Target sorter input stack size (vanilla 4).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 255), Array.Empty<object>()));
		cfgEnablePiler = ((BaseUnityPlugin)this).Config.Bind<bool>("Stacking", "EnableStationPiler", true, "Raise the logistics station output piler level.");
		cfgPilerCap = ((BaseUnityPlugin)this).Config.Bind<int>("Stacking", "StationPilerCap", 8, new ConfigDescription("Target station piler level (vanilla 4).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 255), Array.Empty<object>()));
		cfgEnablePackage = ((BaseUnityPlugin)this).Config.Bind<bool>("Stacking", "EnableDeliveryPackage", true, "Raise the delivery package stack-size multiplier.");
		cfgPackageCap = ((BaseUnityPlugin)this).Config.Bind<int>("Stacking", "DeliveryPackageCap", 8, new ConfigDescription("Target delivery package multiplier (vanilla 4).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 255), Array.Empty<object>()));
		cfgTechGated = ((BaseUnityPlugin)this).Config.Bind<bool>("Stacking", "TechGated", true, "If true, each boost applies only once its vanilla ceiling is researched (early game stays vanilla). If false, caps are forced immediately.");
		cfgCeilingOutput = ((BaseUnityPlugin)this).Config.Bind<int>("Advanced", "VanillaCeilingOutput", 4, "Vanilla max used for tech-gating sorter output. Override if a DSP update changes it.");
		cfgCeilingInput = ((BaseUnityPlugin)this).Config.Bind<int>("Advanced", "VanillaCeilingInput", 4, "Vanilla max used for tech-gating sorter input.");
		cfgCeilingPiler = ((BaseUnityPlugin)this).Config.Bind<int>("Advanced", "VanillaCeilingPiler", 4, "Vanilla max used for tech-gating station piler.");
		cfgCeilingPackage = ((BaseUnityPlugin)this).Config.Bind<int>("Advanced", "VanillaCeilingPackage", 4, "Vanilla max used for tech-gating delivery package.");
		cfgBeltEnable = ((BaseUnityPlugin)this).Config.Bind<bool>("BeltSpeed", "Enable", false, "EXPERIMENTAL: multiply belt speed. Default OFF - stacking alone fixes throughput; belt speed needs in-game verification.");
		cfgBeltMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("BeltSpeed", "Multiplier", 2f, new ConfigDescription("Belt speed multiplier applied to belts as they are created/rebuilt.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>()));
	}

	private void PushConfigToSettings()
	{
		ModSettings.EnableSorterOutput = cfgEnableOutput.Value;
		ModSettings.SorterOutputCap = cfgOutputCap.Value;
		ModSettings.EnableSorterInput = cfgEnableInput.Value;
		ModSettings.SorterInputCap = cfgInputCap.Value;
		ModSettings.EnableStationPiler = cfgEnablePiler.Value;
		ModSettings.StationPilerCap = cfgPilerCap.Value;
		ModSettings.EnableDeliveryPackage = cfgEnablePackage.Value;
		ModSettings.DeliveryPackageCap = cfgPackageCap.Value;
		ModSettings.TechGated = cfgTechGated.Value;
		ModSettings.VanillaCeilingOutput = cfgCeilingOutput.Value;
		ModSettings.VanillaCeilingInput = cfgCeilingInput.Value;
		ModSettings.VanillaCeilingPiler = cfgCeilingPiler.Value;
		ModSettings.VanillaCeilingPackage = cfgCeilingPackage.Value;
		ModSettings.BeltSpeedEnable = cfgBeltEnable.Value;
		ModSettings.BeltSpeedMultiplier = cfgBeltMultiplier.Value;
	}

	private void WireLiveConfig()
	{
		((BaseUnityPlugin)this).Config.SettingChanged += delegate
		{
			PushConfigToSettings();
			StackingPlusLog.Info("[config] changed; re-enforcing.");
			StackingPatch.EnforceCurrent();
		};
	}

	private void ApplyPatches()
	{
		TryPatch(typeof(GameHistoryData), "UnlockTechFunction", null, HM(typeof(StackingPatch), "AfterUnlockTech"));
		TryPatch(typeof(GameHistoryData), "Import", null, HM(typeof(StackingPatch), "AfterImport"));
		TryPatch(typeof(GameHistoryData), "SetForNewGame", null, HM(typeof(StackingPatch), "AfterSetForNewGame"));
		TryPatch(typeof(GameMain), "Begin", null, HM(typeof(StackingPatch), "OnGameBegin"));
		if (ModSettings.BeltSpeedEnable)
		{
			TryPatch(typeof(CargoTraffic), "Import", null, HM(typeof(BeltSpeedPatch), "AfterCargoTrafficImport"));
			TryPatch(typeof(CargoTraffic), "SetBeltState", HM(typeof(BeltSpeedPatch), "BeforeSetBeltState"));
			TryPatch(typeof(CargoTraffic), "AlterBeltRenderer", HM(typeof(BeltSpeedPatch), "BeforeAlterBeltRenderer"), HM(typeof(BeltSpeedPatch), "AfterAlterBeltRenderer"));
			HarmonyMethod postfix = HM(typeof(BeltSpeedPatch), "AfterHeadOrRearSpeed");
			TryPatchProperty(typeof(CargoPath), "headSpeed", postfix);
			TryPatchProperty(typeof(CargoPath), "rearSpeed", postfix);
		}
	}

	private static HarmonyMethod HM(Type type, string method)
	{
		//IL_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Expected O, but got Unknown
		return new HarmonyMethod(type.GetMethod(method, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic));
	}

	private void TryPatchProperty(Type type, string propertyName, HarmonyMethod postfix)
	{
		try
		{
			MethodInfo methodInfo = AccessTools.PropertyGetter(type, propertyName);
			if (methodInfo == null)
			{
				StackingPlusLog.Warn("[compat] property getter not found: " + type.Name + "." + propertyName + " - patch skipped.");
			}
			else
			{
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, postfix, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				StackingPlusLog.Info("[patch] patched " + type.Name + "." + propertyName + " (getter)");
			}
		}
		catch (Exception ex)
		{
			StackingPlusLog.Error("[patch] failed to patch " + type.Name + "." + propertyName + " getter: " + ex);
		}
	}

	private void TryPatch(Type type, string method, HarmonyMethod prefix = null, HarmonyMethod postfix = null)
	{
		try
		{
			MethodInfo methodInfo = AccessTools.Method(type, method, (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				StackingPlusLog.Warn("[compat] target not found: " + type.Name + "." + method + " - patch skipped.");
			}
			else
			{
				harmony.Patch((MethodBase)methodInfo, prefix, postfix, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				StackingPlusLog.Info("[patch] patched " + type.Name + "." + method);
			}
		}
		catch (Exception ex)
		{
			StackingPlusLog.Error("[patch] failed to patch " + type.Name + "." + method + ": " + ex);
		}
	}

	private void LogResolvedConfig()
	{
		StackingPlusLog.Info("[config] gated=" + ModSettings.TechGated + " output=" + ModSettings.EnableSorterOutput + "/" + ModSettings.SorterOutputCap + "(v" + ModSettings.VanillaCeilingOutput + ") input=" + ModSettings.EnableSorterInput + "/" + ModSettings.SorterInputCap + "(v" + ModSettings.VanillaCeilingInput + ") piler=" + ModSettings.EnableStationPiler + "/" + ModSettings.StationPilerCap + "(v" + ModSettings.VanillaCeilingPiler + ") package=" + ModSettings.EnableDeliveryPackage + "/" + ModSettings.DeliveryPackageCap + "(v" + ModSettings.VanillaCeilingPackage + ") belt=" + ModSettings.BeltSpeedEnable + "/x" + ModSettings.BeltSpeedMultiplier);
	}

	private void DumpTargetMethodSignatures()
	{
		string[][] array = new string[8][]
		{
			new string[2] { "GameHistoryData", "UnlockTechFunction" },
			new string[2] { "GameHistoryData", "Import" },
			new string[2] { "GameHistoryData", "SetForNewGame" },
			new string[2] { "GameData", "OnInserterTechChange" },
			new string[2] { "GameMain", "Begin" },
			new string[2] { "CargoTraffic", "Import" },
			new string[2] { "CargoTraffic", "SetBeltState" },
			new string[2] { "CargoTraffic", "AlterBeltRenderer" }
		};
		foreach (string[] array2 in array)
		{
			try
			{
				Type type = AccessTools.TypeByName(array2[0]);
				if (type == null)
				{
					StackingPlusLog.Warn("[diag] Type not found: " + array2[0]);
					continue;
				}
				MethodInfo methodInfo = AccessTools.Method(type, array2[1], (Type[])null, (Type[])null);
				if (methodInfo == null)
				{
					StackingPlusLog.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(")");
				StackingPlusLog.Info(stringBuilder.ToString());
			}
			catch (Exception ex)
			{
				StackingPlusLog.Error("[diag] Failed to inspect " + array2[0] + "." + array2[1] + ": " + ex.Message);
			}
		}
	}
}
internal static class StackingPlusLog
{
	private static ManualLogSource logger;

	private static bool debugEnabled;

	public static void Init(ManualLogSource src, ConfigEntry<bool> debug)
	{
		logger = src;
		debugEnabled = debug.Value;
		debug.SettingChanged += delegate
		{
			debugEnabled = debug.Value;
		};
	}

	public static void Info(string msg)
	{
		if (debugEnabled && logger != null)
		{
			logger.LogInfo((object)("[StackingPlus] " + msg));
		}
	}

	public static void Warn(string msg)
	{
		if (logger != null)
		{
			logger.LogWarning((object)("[StackingPlus] " + msg));
		}
	}

	public static void Error(string msg)
	{
		if (logger != null)
		{
			logger.LogError((object)("[StackingPlus] " + msg));
		}
	}
}