using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
using crecheng.DSPModSave;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace CondensedProduction;
public static class BeltStack
{
public static int MaxStack
{
get
{
int num = ((Plugin.BeltStackMaxEntry == null) ? 255 : Plugin.BeltStackMaxEntry.Value);
if (num < 1)
{
return 1;
}
if (num <= 255)
{
return num;
}
return 255;
}
}
public static bool Enabled
{
get
{
if (Plugin.BeltStackEnabledEntry != null)
{
return Plugin.BeltStackEnabledEntry.Value;
}
return true;
}
}
}
public static class InserterStackPatch
{
[HarmonyPrefix]
[HarmonyPatch(typeof(InserterComponent), "InternalUpdate")]
[HarmonyPatch(typeof(InserterComponent), "InternalUpdate_Bidirectional")]
[HarmonyPatch(typeof(InserterComponent), "InternalUpdateNoAnim")]
private static void Prefix(ref InserterComponent __instance)
{
if (BeltStack.Enabled && __instance.canStack)
{
if (__instance.stackInput != 1)
{
__instance.stackInput = 1;
}
int maxStack = BeltStack.MaxStack;
if (__instance.stackOutput != (byte)maxStack)
{
__instance.stackOutput = (byte)maxStack;
}
}
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(InserterComponent), "InternalUpdate")]
[HarmonyPatch(typeof(InserterComponent), "InternalUpdate_Bidirectional")]
[HarmonyPatch(typeof(InserterComponent), "InternalUpdateNoAnim")]
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
int max = BeltStack.MaxStack;
List<CodeInstruction> list = new List<CodeInstruction>(instructions);
for (int i = 0; i < list.Count; i++)
{
if (list[i].opcode == OpCodes.Ldc_I4_4 && i + 1 < list.Count && list[i + 1].opcode == OpCodes.Div)
{
yield return new CodeInstruction(OpCodes.Ldc_I4, (object)max);
}
else
{
yield return list[i];
}
}
}
}
public static class StationOutputPatch
{
[HarmonyPatch(typeof(StationComponent), "UpdateOutputSlots")]
[HarmonyPrefix]
private static void Prefix(StationComponent __instance)
{
if (BeltStack.Enabled && __instance.planetId > 0)
{
int maxStack = BeltStack.MaxStack;
if (maxStack > 4 && __instance.pilerCount != maxStack)
{
__instance.pilerCount = maxStack;
}
}
}
}
public static class PilerStackPatch
{
[HarmonyPatch(typeof(PilerComponent), "InternalUpdate")]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
int max = BeltStack.MaxStack;
foreach (CodeInstruction instruction in instructions)
{
if (instruction.opcode == OpCodes.Ldc_I4_4)
{
yield return new CodeInstruction(OpCodes.Ldc_I4, (object)max);
}
else if (instruction.opcode == OpCodes.Ldc_R4 && instruction.operand is float num && num == 4f)
{
yield return new CodeInstruction(OpCodes.Ldc_R4, (object)(float)max);
}
else
{
yield return instruction;
}
}
}
}
public static class CargoVisualClampPatch
{
private static readonly List<int> stash = new List<int>(2048);
[HarmonyPatch(typeof(CargoContainer), "Draw")]
[HarmonyPrefix]
private static void PreDraw(CargoContainer __instance)
{
if (Plugin.KeepVisualStackEntry == null || !Plugin.KeepVisualStackEntry.Value)
{
return;
}
Cargo[] cargoPool = __instance.cargoPool;
if (cargoPool == null)
{
return;
}
int num = Math.Min(__instance.cursor, cargoPool.Length);
stash.Clear();
for (int i = 0; i < num; i++)
{
if (cargoPool[i].stack > 4)
{
stash.Add(i);
stash.Add(cargoPool[i].stack);
cargoPool[i].stack = 4;
}
}
}
[HarmonyPatch(typeof(CargoContainer), "Draw")]
[HarmonyPostfix]
private static void PostDraw(CargoContainer __instance)
{
if (stash.Count == 0)
{
return;
}
Cargo[] cargoPool = __instance.cargoPool;
if (cargoPool != null)
{
int num = cargoPool.Length;
for (int i = 0; i + 1 < stash.Count; i += 2)
{
int num2 = stash[i];
if (num2 >= 0 && num2 < num)
{
cargoPool[num2].stack = (byte)stash[i + 1];
}
}
}
stash.Clear();
}
}
[HarmonyPatch]
public static class BuildingGrabPatch
{
public static void Grab(ref int slot, ref byte stackOut)
{
int maxStack = BeltStack.MaxStack;
int num = ((slot < maxStack) ? slot : maxStack);
slot -= num;
stackOut = (byte)num;
}
private static IEnumerable<MethodBase> TargetMethods()
{
Type byrefByte = typeof(byte).MakeByRefType();
yield return AccessTools.Method(typeof(PlanetFactory), "PickFrom", new Type[6]
{
typeof(int),
typeof(int),
typeof(int),
typeof(int[]),
byrefByte,
byrefByte
}, (Type[])null);
yield return AccessTools.Method(typeof(PlanetFactory), "PickFrom", new Type[6]
{
typeof(uint),
typeof(int),
typeof(int),
typeof(int[]),
byrefByte,
byrefByte
}, (Type[])null);
}
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase original)
{
//IL_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_0192: Unknown result type (might be due to invalid IL or missing references)
//IL_019c: Expected O, but got Unknown
//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
//IL_01ae: Expected O, but got Unknown
//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
//IL_01c0: Expected O, but got Unknown
//IL_0376: Unknown result type (might be due to invalid IL or missing references)
//IL_0380: Expected O, but got Unknown
//IL_038b: Unknown result type (might be due to invalid IL or missing references)
//IL_0395: Expected O, but got Unknown
//IL_03a0: Unknown result type (might be due to invalid IL or missing references)
//IL_03aa: Expected O, but got Unknown
//IL_03b5: Unknown result type (might be due to invalid IL or missing references)
//IL_03bf: Expected O, but got Unknown
//IL_0150: Unknown result type (might be due to invalid IL or missing references)
//IL_015a: Expected O, but got Unknown
//IL_0241: Unknown result type (might be due to invalid IL or missing references)
//IL_024b: Expected O, but got Unknown
//IL_0264: Unknown result type (might be due to invalid IL or missing references)
//IL_026e: Expected O, but got Unknown
List<CodeInstruction> list = new List<CodeInstruction>(instructions);
MethodInfo methodInfo = AccessTools.Method(typeof(BuildingGrabPatch), "Grab", (Type[])null, (Type[])null);
MethodInfo cache = null;
ParameterInfo parameterInfo = null;
ParameterInfo[] parameters = original.GetParameters();
foreach (ParameterInfo parameterInfo2 in parameters)
{
if (parameterInfo2.Name == "stack")
{
parameterInfo = parameterInfo2;
}
}
int num = ((parameterInfo == null) ? (-1) : (parameterInfo.Position + ((!original.IsStatic) ? 1 : 0)));
CodeInstruction val = ((num < 0) ? ((CodeInstruction)null) : new CodeInstruction(OpCodes.Ldarg_S, (object)num));
for (int j = 0; j < list.Count; j++)
{
if (!IsTakeItemCall(list[j], ref cache))
{
continue;
}
LocalBuilder localBuilder = null;
bool flag = false;
int num2 = j - 1;
while (num2 >= 0 && num2 >= j - 8)
{
LocalBuilder localBuilder2 = GetLocalBuilder(list[num2], OpCodes.Ldloca_S, OpCodes.Ldloca);
if (localBuilder2 != null)
{
if (flag)
{
localBuilder = localBuilder2;
break;
}
flag = true;
}
num2--;
}
if (localBuilder == null)
{
continue;
}
int num3 = j - 1;
while (num3 >= 0 && num3 >= j - 30)
{
if (list[num3].opcode == OpCodes.Ldc_I4_1 && num3 + 1 < list.Count && IsStoreOf(list[num3 + 1], localBuilder))
{
list[num3] = new CodeInstruction(OpCodes.Ldc_I4, (object)255);
break;
}
num3--;
}
List<CodeInstruction> list2 = new List<CodeInstruction>();
if (val != null)
{
list2.Add(val.Clone());
list2.Add(new CodeInstruction(OpCodes.Ldloc_S, (object)localBuilder));
list2.Add(new CodeInstruction(OpCodes.Conv_U1, (object)null));
list2.Add(new CodeInstruction(OpCodes.Stind_I1, (object)null));
}
list.InsertRange(j + 1, list2);
j += list2.Count;
for (int k = j + 1; k < list.Count && k <= j + 10; k++)
{
if (IsLoadOf(list[k], localBuilder) && k + 2 < list.Count && list[k + 1].opcode == OpCodes.Ldc_I4_1 && list[k + 2].opcode == OpCodes.Bne_Un)
{
list[k + 1] = new CodeInstruction(OpCodes.Ldc_I4_0, (object)null);
list[k + 2] = new CodeInstruction(OpCodes.Beq, list[k + 2].operand);
break;
}
}
}
for (int l = 0; l + 5 < list.Count; l++)
{
if (list[l].opcode == OpCodes.Ldelema && list[l + 1].opcode == OpCodes.Dup && list[l + 2].opcode == OpCodes.Ldind_I4 && list[l + 3].opcode == OpCodes.Ldc_I4_1 && list[l + 4].opcode == OpCodes.Sub && list[l + 5].opcode == OpCodes.Stind_I4 && val != null)
{
list[l + 1] = val.Clone();
list[l + 2] = new CodeInstruction(OpCodes.Call, (object)methodInfo);
list[l + 3] = new CodeInstruction(OpCodes.Nop, (object)null);
list[l + 4] = new CodeInstruction(OpCodes.Nop, (object)null);
list[l + 5] = new CodeInstruction(OpCodes.Nop, (object)null);
l += 5;
}
}
return list;
}
private static LocalBuilder GetLocalBuilder(CodeInstruction ci, OpCode shortForm, OpCode longForm)
{
if (ci.opcode != shortForm && ci.opcode != longForm)
{
return null;
}
return ci.operand as LocalBuilder;
}
private static bool IsStoreOf(CodeInstruction ci, LocalBuilder lb)
{
if ((ci.opcode == OpCodes.Stloc_S || ci.opcode == OpCodes.Stloc) && ci.operand is LocalBuilder localBuilder)
{
return localBuilder.LocalIndex == lb.LocalIndex;
}
return false;
}
private static bool IsLoadOf(CodeInstruction ci, LocalBuilder lb)
{
if ((ci.opcode == OpCodes.Ldloc_S || ci.opcode == OpCodes.Ldloc) && ci.operand is LocalBuilder localBuilder)
{
return localBuilder.LocalIndex == lb.LocalIndex;
}
return false;
}
private static bool IsTakeItemCall(CodeInstruction ci, ref MethodInfo cache)
{
if (ci.opcode != OpCodes.Callvirt)
{
return false;
}
MethodInfo methodInfo = ci.operand as MethodInfo;
if (methodInfo == null || methodInfo.DeclaringType != typeof(StationComponent))
{
return false;
}
if (methodInfo.Name != "TakeItem")
{
return false;
}
cache = methodInfo;
return true;
}
}
public static class GlobalSupply
{
private static long lastTick = long.MinValue;
private static readonly HashSet<int> errLogged = new HashSet<int>();
private static readonly HashSet<int> diagLogged = new HashSet<int>();
public static void Tick()
{
if ((Plugin.GlobalSupplyEnabledEntry != null && !Plugin.GlobalSupplyEnabledEntry.Value) || GameMain.data == null)
{
return;
}
PlanetFactory[] factories = GameMain.data.factories;
if (factories == null)
{
return;
}
long gameTick = GameMain.gameTick;
int num = ((Plugin.GlobalSupplyIntervalEntry == null) ? 30 : Plugin.GlobalSupplyIntervalEntry.Value);
if (num < 1)
{
num = 1;
}
if (gameTick < lastTick)
{
lastTick = long.MinValue;
diagLogged.Clear();
}
if (lastTick != long.MinValue && gameTick - lastTick < num)
{
return;
}
lastTick = gameTick;
bool collect = Plugin.GlobalSupplyCollectEntry == null || Plugin.GlobalSupplyCollectEntry.Value;
for (int i = 0; i < factories.Length; i++)
{
PlanetFactory val = factories[i];
if (val == null || val.factorySystem == null || val.transport == null || !MultStore.PlanetHasWireless(val.planetId))
{
continue;
}
try
{
ProcessFactory(val, collect);
}
catch (Exception arg)
{
if (MultStore.Log != null && errLogged.Add(i))
{
MultStore.Log.LogError((object)$"[CP] wireless supply error planet={val.planetId}: {arg}");
}
}
}
}
private static void ProcessFactory(PlanetFactory factory, bool collect)
{
FactorySystem factorySystem = factory.factorySystem;
PlanetTransport transport = factory.transport;
StationComponent[] stationPool = transport.stationPool;
int stationCount = 0;
if (stationPool != null)
{
stationCount = Math.Min(Math.Max(transport.stationCount, transport.stationCursor), stationPool.Length);
}
AssemblerComponent[] assemblerPool = factorySystem.assemblerPool;
if (assemblerPool != null)
{
int num = Math.Min(factorySystem.assemblerCursor, assemblerPool.Length);
for (int i = 1; i < num; i++)
{
if (assemblerPool[i].entityId != 0)
{
ProcessAssembler(factory.planetId, ref assemblerPool[i], stationPool, stationCount, collect);
}
}
}
LabComponent[] labPool = factorySystem.labPool;
if (labPool == null)
{
return;
}
int num2 = Math.Min(factorySystem.labCursor, labPool.Length);
for (int j = 1; j < num2; j++)
{
if (labPool[j].entityId != 0)
{
if (labPool[j].researchMode)
{
ProcessResearchLab(factory, ref labPool[j], stationPool, stationCount);
}
else
{
ProcessLab(factory.planetId, ref labPool[j], stationPool, stationCount, collect);
}
}
}
}
private static void ProcessResearchLab(PlanetFactory factory, ref LabComponent c, StationComponent[] stations, int stationCount)
{
int planetId = factory.planetId;
if (!MultStore.GetWireless(planetId, c.entityId) || c.matrixServed == null)
{
return;
}
int num = MultStore.GetSet(planetId, c.entityId);
if (num < 1)
{
num = 1;
}
long num2 = 36000L * (long)num;
int[] matrixIds = LabComponent.matrixIds;
int num3 = Math.Min(c.matrixServed.Length, (matrixIds == null) ? 6 : matrixIds.Length);
if (num3 > 6)
{
num3 = 6;
}
byte b = default(byte);
for (int i = 0; i < num3; i++)
{
int num4 = ((matrixIds != null) ? matrixIds[i] : (6001 + i));
if (num4 <= 0)
{
continue;
}
long num5 = (num2 - c.matrixServed[i]) / 3600;
if (num5 <= 0)
{
continue;
}
if (num5 > 200000)
{
num5 = 200000L;
}
int num6 = (int)num5;
while (num6 > 0)
{
int want = ((num6 > 255) ? 255 : num6);
TakeFromStations(stations, stationCount, num4, want, out var taken, out var incPts);
if (taken <= 0)
{
break;
}
int num7 = incPts / taken;
if (num7 < 0)
{
num7 = 0;
}
if (num7 > 4)
{
num7 = 4;
}
int num8 = factory.InsertInto(c.entityId, -1, num4, (byte)taken, (byte)num7, ref b);
if (num8 <= 0)
{
AddToStations(stations, stationCount, num4, taken, incPts);
break;
}
num6 -= num8;
if (num8 < taken)
{
AddToStations(stations, stationCount, num4, taken - num8, incPts * (taken - num8) / taken);
}
}
}
if (MultStore.Log == null || !diagLogged.Add(c.entityId))
{
return;
}
int num9 = 0;
if (stations != null)
{
for (int j = 0; j < stationCount; j++)
{
if (stations[j] != null && stations[j].storage != null)
{
num9++;
}
}
}
MultStore.Log.LogInfo((object)$"[CP] research-lab wireless planet={planetId} entity={c.entityId} kSet={num} matrix0={((c.matrixServed.Length != 0) ? c.matrixServed[0] : (-1))} stationCount={stationCount} withStorage={num9}");
}
private static void ProcessAssembler(int planetId, ref AssemblerComponent c, StationComponent[] stations, int stationCount, bool collect)
{
if (!MultStore.GetWireless(planetId, c.entityId))
{
return;
}
int set = MultStore.GetSet(planetId, c.entityId);
RecipeExecuteData recipeExecuteData = c.recipeExecuteData;
if (recipeExecuteData == null || recipeExecuteData.requires == null || recipeExecuteData.requireCounts == null || recipeExecuteData.timeSpend <= 0 || c.served == null || c.incServed == null)
{
return;
}
int num = c.speedOverride * 180 / recipeExecuteData.timeSpend + 1;
if (num < 2)
{
num = 2;
}
long num2 = (long)set * (long)BufferFactor() * num;
int num3 = Math.Min(recipeExecuteData.requires.Length, Math.Min(recipeExecuteData.requireCounts.Length, c.served.Length));
for (int i = 0; i < num3; i++)
{
int num4 = recipeExecuteData.requires[i];
int num5 = recipeExecuteData.requireCounts[i];
if (num4 <= 0 || num5 <= 0)
{
continue;
}
long num6 = num5 * num2;
int num7 = (int)((num6 > int.MaxValue) ? int.MaxValue : num6) - c.served[i];
if (num7 > 0)
{
TakeFromStations(stations, stationCount, num4, num7, out var taken, out var incPts);
if (taken > 0)
{
c.served[i] += taken;
c.incServed[i] += incPts;
}
}
}
if (collect)
{
CollectProducts(stations, stationCount, ref c);
}
}
private static void ProcessLab(int planetId, ref LabComponent c, StationComponent[] stations, int stationCount, bool collect)
{
if (!MultStore.GetWireless(planetId, c.entityId))
{
return;
}
int set = MultStore.GetSet(planetId, c.entityId);
RecipeExecuteData recipeExecuteData = c.recipeExecuteData;
if (recipeExecuteData == null || recipeExecuteData.requires == null || recipeExecuteData.requireCounts == null || recipeExecuteData.timeSpend <= 0 || c.served == null || c.incServed == null)
{
return;
}
long num = (long)set * (long)BufferFactor();
int num2 = Math.Min(recipeExecuteData.requires.Length, Math.Min(recipeExecuteData.requireCounts.Length, c.served.Length));
for (int i = 0; i < num2; i++)
{
int num3 = recipeExecuteData.requires[i];
int num4 = recipeExecuteData.requireCounts[i];
if (num3 <= 0 || num4 <= 0)
{
continue;
}
long num5 = num4 * num;
int num6 = (int)((num5 > int.MaxValue) ? int.MaxValue : num5) - c.served[i];
if (num6 > 0)
{
TakeFromStations(stations, stationCount, num3, num6, out var taken, out var incPts);
if (taken > 0)
{
c.served[i] += taken;
c.incServed[i] += incPts;
}
}
}
if (collect)
{
CollectLabProducts(stations, stationCount, ref c);
}
}
private static void CollectProducts(StationComponent[] stations, int stationCount, ref AssemblerComponent c)
{
RecipeExecuteData recipeExecuteData = c.recipeExecuteData;
if (recipeExecuteData == null || recipeExecuteData.products == null || recipeExecuteData.productCounts == null || c.produced == null)
{
return;
}
int num = Math.Min(recipeExecuteData.products.Length, c.produced.Length);
if (num == 0)
{
return;
}
int num2 = AvgIncLevel(c.incUsed, c.served, c.incServed);
for (int i = 0; i < num; i++)
{
int num3 = recipeExecuteData.products[i];
int num4 = c.produced[i];
if (num3 > 0 && num4 > 0)
{
int num5 = AddToStations(stations, stationCount, num3, num4, num2 * num4);
if (num5 > 0)
{
c.produced[i] -= num5;
}
}
}
}
private static void CollectLabProducts(StationComponent[] stations, int stationCount, ref LabComponent c)
{
RecipeExecuteData recipeExecuteData = c.recipeExecuteData;
if (recipeExecuteData == null || recipeExecuteData.products == null || recipeExecuteData.productCounts == null || c.produced == null)
{
return;
}
int num = Math.Min(recipeExecuteData.products.Length, c.produced.Length);
if (num == 0)
{
return;
}
int num2 = AvgIncLevel(c.incUsed, c.served, c.incServed);
for (int i = 0; i < num; i++)
{
int num3 = recipeExecuteData.products[i];
int num4 = c.produced[i];
if (num3 > 0 && num4 > 0)
{
int num5 = AddToStations(stations, stationCount, num3, num4, num2 * num4);
if (num5 > 0)
{
c.produced[i] -= num5;
}
}
}
}
private static int AvgIncLevel(bool incUsed, int[] served, int[] incServed)
{
if (!incUsed || served == null || incServed == null)
{
return 0;
}
int num = 0;
int num2 = 0;
int num3 = Math.Min(served.Length, incServed.Length);
for (int i = 0; i < num3; i++)
{
if (served[i] > 0 && incServed[i] > 0)
{
num += served[i];
num2 += incServed[i];
}
}
if (num <= 0)
{
return 0;
}
int num4 = num2 / num;
if (num4 >= 0)
{
if (num4 <= 4)
{
return num4;
}
return 4;
}
return 0;
}
private static void TakeFromStations(StationComponent[] stations, int stationCount, int itemId, int want, out int taken, out int incPts)
{
taken = 0;
incPts = 0;
if (stations == null)
{
return;
}
int num3 = default(int);
for (int i = 0; i < stationCount; i++)
{
if (taken >= want)
{
break;
}
StationComponent val = stations[i];
if (val == null || val.storage == null)
{
continue;
}
while (taken < want)
{
int num = itemId;
int num2 = want - taken;
val.TakeItem(ref num, ref num2, ref num3);
if (num2 <= 0 || num != itemId)
{
break;
}
taken += num2;
incPts += num3 * num2;
}
}
if (taken > want)
{
taken = want;
}
}
private static int AddToStations(StationComponent[] stations, int stationCount, int itemId, int count, int incPts)
{
if (stations == null || count <= 0)
{
return 0;
}
int num = count;
int num2 = 0;
for (int i = 0; i < stationCount; i++)
{
if (num <= 0)
{
break;
}
StationComponent val = stations[i];
if (val == null || val.storage == null)
{
continue;
}
StationStore[] storage = val.storage;
for (int j = 0; j < storage.Length; j++)
{
if (num <= 0)
{
break;
}
if (storage[j].itemId == itemId && storage[j].max > 0)
{
int num3 = storage[j].max - storage[j].count;
if (num3 > 0)
{
int num4 = ((num < num3) ? num : num3);
int num5 = (int)((long)incPts * (long)num4 / count);
storage[j].count += num4;
storage[j].inc += num5;
num -= num4;
num2 += num4;
}
}
}
}
return num2;
}
private static int BufferFactor()
{
int num = ((Plugin.InputBufferMultiplierEntry == null) ? 3 : Plugin.InputBufferMultiplierEntry.Value);
if (num >= 1)
{
return num;
}
return 1;
}
}
public static class GlobalSupplyPatch
{
[HarmonyPatch(typeof(GameLogic), "LogicFrame")]
[HarmonyPostfix]
private static void PostLogicFrame()
{
GlobalSupply.Tick();
StorageCapPatch.Maintain();
}
}
public static class MultiplierUI
{
private const int WinIdAssembler = 93101;
private const int WinIdLab = 93102;
private const float PanelW = 230f;
private const float PanelH = 178f;
private static Texture2D whiteTex;
private static string inputText = "";
private static int editingKey = -1;
private static FieldInfo labFactoryField;
private static FieldInfo labFactorySystemField;
private static readonly Dictionary<int, Vector2> userOffset = new Dictionary<int, Vector2>();
private static readonly Vector3[] cornersBuf = (Vector3[])(object)new Vector3[4];
private static Rect lastPanelRect;
public static bool PanelShowing { get; private set; }
public static void Init()
{
labFactoryField = typeof(UILabWindow).GetField("factory", BindingFlags.Instance | BindingFlags.NonPublic);
labFactorySystemField = typeof(UILabWindow).GetField("factorySystem", BindingFlags.Instance | BindingFlags.NonPublic);
}
public static bool IsMouseOverPanel()
{
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: 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)
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
if (!PanelShowing)
{
return false;
}
Vector3 mousePosition = Input.mousePosition;
if (mousePosition.x >= ((Rect)(ref lastPanelRect)).x && mousePosition.x <= ((Rect)(ref lastPanelRect)).x + ((Rect)(ref lastPanelRect)).width && mousePosition.y >= (float)Screen.height - ((Rect)(ref lastPanelRect)).y - ((Rect)(ref lastPanelRect)).height)
{
return mousePosition.y <= (float)Screen.height - ((Rect)(ref lastPanelRect)).y;
}
return false;
}
public static void Draw()
{
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_0120: 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_0134: Unknown result type (might be due to invalid IL or missing references)
PanelShowing = false;
if ((Object)(object)GameMain.instance == (Object)null || GameMain.isPaused)
{
return;
}
UIGame val = (((Object)(object)UIRoot.instance != (Object)null) ? UIRoot.instance.uiGame : null);
if ((Object)(object)val == (Object)null)
{
return;
}
UIAssemblerWindow assemblerWindow = val.assemblerWindow;
if ((Object)(object)assemblerWindow != (Object)null && ((ManualBehaviour)assemblerWindow).active && assemblerWindow.assemblerId != 0 && assemblerWindow.factorySystem != null)
{
AssemblerComponent val2 = assemblerWindow.factorySystem.assemblerPool[assemblerWindow.assemblerId];
DrawPanel(93101, assemblerWindow.windowTrans, assemblerWindow.factorySystem.factory, val2.entityId);
return;
}
UILabWindow labWindow = val.labWindow;
if ((Object)(object)labWindow != (Object)null && ((ManualBehaviour)labWindow).active && labWindow.labId != 0)
{
PlanetFactory val3 = (PlanetFactory)((labFactoryField != null) ? /*isinst with value type is only supported in some contexts*/: null);
FactorySystem val4 = (FactorySystem)((labFactorySystemField != null) ? /*isinst with value type is only supported in some contexts*/: null);
if (val3 != null && val4 != null)
{
LabComponent val5 = val4.labPool[labWindow.labId];
DrawPanel(93102, labWindow.windowTrans, val3, val5.entityId);
}
}
}
private static Vector2 ComputeDock(RectTransform anchor)
{
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: 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_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//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_009b: Unknown result type (might be due to invalid IL or missing references)
//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
Vector2 result = default(Vector2);
((Vector2)(ref result))..ctor((float)Screen.width - 230f - 20f, (float)Screen.height * 0.3f);
if ((Object)(object)anchor == (Object)null)
{
return result;
}
anchor.GetWorldCorners(cornersBuf);
Vector3 val = cornersBuf[2] - cornersBuf[0];
if (((Vector3)(ref val)).sqrMagnitude < 1f)
{
return result;
}
Camera val2 = null;
Canvas componentInParent = ((Component)anchor).GetComponentInParent<Canvas>();
if ((Object)(object)componentInParent != (Object)null && (int)componentInParent.renderMode != 0)
{
val2 = componentInParent.worldCamera;
}
Vector2 val3 = RectTransformUtility.WorldToScreenPoint(val2, cornersBuf[2]);
float num = Mathf.Clamp(val3.x + 8f, 0f, (float)Screen.width - 230f);
float num2 = Mathf.Clamp((float)Screen.height - val3.y, 0f, (float)Screen.height - 178f);
return new Vector2(num, num2);
}
private static void DrawPanel(int winId, RectTransform anchor, PlanetFactory factory, int entityId)
{
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: Unknown result type (might be due to invalid IL or missing references)
//IL_00a2: 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_00bf: Unknown result type (might be due to invalid IL or missing references)
//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
//IL_00d7: Expected O, but got Unknown
//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
//IL_00fb: 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_0107: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
if (factory == null || entityId == 0)
{
return;
}
int planetId = factory.planetId;
int num = planetId * 1000000 + entityId;
if (editingKey != num)
{
editingKey = num;
inputText = MultStore.GetSet(planetId, entityId).ToString();
}
Vector2 val = ComputeDock(anchor);
if (!userOffset.TryGetValue(winId, out var value))
{
value = Vector2.zero;
}
Rect val2 = default(Rect);
((Rect)(ref val2))..ctor(val.x + value.x, val.y + value.y, 230f, 178f);
Rect val3 = GUI.Window(winId, val2, (WindowFunction)delegate
{
//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
GUILayout.Label("设定倍率上限:", Array.Empty<GUILayoutOption>());
GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
if (GUILayout.Button("-10", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(40f) }))
{
Apply(factory, entityId, MultStore.GetSet(planetId, entityId) - 10);
}
if (GUILayout.Button("-1", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(35f) }))
{
Apply(factory, entityId, MultStore.GetSet(planetId, entityId) - 1);
}
inputText = GUILayout.TextField(inputText, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(60f) });
if (GUILayout.Button("+1", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(35f) }))
{
Apply(factory, entityId, MultStore.GetSet(planetId, entityId) + 1);
}
if (GUILayout.Button("+10", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(40f) }))
{
Apply(factory, entityId, MultStore.GetSet(planetId, entityId) + 10);
}
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
if (GUILayout.Button("1", Array.Empty<GUILayoutOption>()))
{
Apply(factory, entityId, 1);
}
if (GUILayout.Button("5", Array.Empty<GUILayoutOption>()))
{
Apply(factory, entityId, 5);
}
if (GUILayout.Button("10", Array.Empty<GUILayoutOption>()))
{
Apply(factory, entityId, 10);
}
if (GUILayout.Button("100", Array.Empty<GUILayoutOption>()))
{
Apply(factory, entityId, 100);
}
if (GUILayout.Button("1000", Array.Empty<GUILayoutOption>()))
{
Apply(factory, entityId, 1000);
}
if (GUILayout.Button("应用输入", Array.Empty<GUILayoutOption>()) && int.TryParse(inputText, out var result))
{
Apply(factory, entityId, result);
}
GUILayout.EndHorizontal();
bool wireless = MultStore.GetWireless(planetId, entityId);
if (GUILayout.Button(wireless ? "无线:开" : "无线:关", Array.Empty<GUILayoutOption>()))
{
MultStore.SetWireless(planetId, entityId, !wireless);
}
int set = MultStore.GetSet(planetId, entityId);
int eff = MultStore.GetEff(planetId, entityId);
GUILayout.Label($"设定 x{set} / 实际 x{eff}", Array.Empty<GUILayoutOption>());
DrawEnergyBar(planetId, entityId);
GUI.DragWindow(new Rect(0f, 0f, 230f, 20f));
}, "浓缩生产");
userOffset[winId] = new Vector2(((Rect)(ref val3)).x - val.x, ((Rect)(ref val3)).y - val.y);
lastPanelRect = val3;
PanelShowing = true;
}
private static void DrawEnergyBar(int planetId, int entityId)
{
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
//IL_0084: Expected O, but got Unknown
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: 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_00eb: 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_010d: Unknown result type (might be due to invalid IL or missing references)
//IL_0163: Unknown result type (might be due to invalid IL or missing references)
//IL_0172: Unknown result type (might be due to invalid IL or missing references)
//IL_0186: Unknown result type (might be due to invalid IL or missing references)
//IL_018b: Unknown result type (might be due to invalid IL or missing references)
//IL_0192: Unknown result type (might be due to invalid IL or missing references)
//IL_019c: Expected O, but got Unknown
//IL_019c: Unknown result type (might be due to invalid IL or missing references)
if (!MultStore.GetBufferInfo(planetId, entityId, out var cur, out var cap))
{
int set = MultStore.GetSet(planetId, entityId);
int num = ((Plugin.EnergyBufferSecondsEntry == null) ? 10 : Plugin.EnergyBufferSecondsEntry.Value);
if (set <= 1 || num <= 0)
{
return;
}
cap = (long)set * 40000000L * num * 60;
if (cap <= 0)
{
return;
}
MultStore.SetBufferCap(planetId, entityId, cap);
MultStore.ChargeBuffer(planetId, entityId, cap, cap);
cur = cap;
}
if (cap > 0)
{
if ((Object)(object)whiteTex == (Object)null)
{
whiteTex = new Texture2D(1, 1);
whiteTex.SetPixel(0, 0, Color.white);
whiteTex.Apply();
}
float num2 = (float)((double)cur / (double)cap);
if (num2 < 0f)
{
num2 = 0f;
}
if (num2 > 1f)
{
num2 = 1f;
}
Rect rect = GUILayoutUtility.GetRect(206f, 16f);
GUI.color = new Color(0.15f, 0.15f, 0.15f);
GUI.DrawTexture(rect, (Texture)(object)whiteTex);
GUI.color = ((num2 > 0.3f) ? new Color(0.25f, 0.75f, 1f) : new Color(1f, 0.55f, 0.15f));
GUI.DrawTexture(new Rect(((Rect)(ref rect)).x + 1f, ((Rect)(ref rect)).y + 1f, (((Rect)(ref rect)).width - 2f) * num2, ((Rect)(ref rect)).height - 2f), (Texture)(object)whiteTex);
GUI.color = Color.white;
GUIStyle val = new GUIStyle(GUI.skin.label)
{
alignment = (TextAnchor)4,
fontSize = 11
};
GUI.Label(rect, $"储能 {num2 * 100f:0}%", val);
}
}
private static void Apply(PlanetFactory factory, int entityId, int k)
{
if (k < 1)
{
k = 1;
}
MultStore.SetMult(factory.planetId, entityId, k);
PropagateToStack(factory, entityId, k);
inputText = MultStore.GetSet(factory.planetId, entityId).ToString();
}
private static void PropagateToStack(PlanetFactory factory, int entityId, int k)
{
FactorySystem val = factory?.factorySystem;
if (val == null || val.labPool == null)
{
return;
}
LabComponent[] labPool = val.labPool;
int num = Math.Min(val.labCursor, labPool.Length);
if (num <= 1)
{
return;
}
int num2 = -1;
for (int i = 1; i < num; i++)
{
if (labPool[i].entityId == entityId && labPool[i].id != 0)
{
num2 = labPool[i].id;
break;
}
}
if (num2 <= 0)
{
return;
}
HashSet<int> hashSet = new HashSet<int>();
int num3 = num2;
int num4 = 0;
while (num3 > 0 && num3 < num && num4++ < 64 && hashSet.Add(num3))
{
num3 = labPool[num3].nextLabId;
}
for (int j = 1; j < num; j++)
{
if (labPool[j].id == 0 || hashSet.Contains(labPool[j].id))
{
continue;
}
int nextLabId = labPool[j].nextLabId;
int num5 = 0;
while (nextLabId > 0 && nextLabId < num && num5++ < 64)
{
if (hashSet.Contains(nextLabId))
{
hashSet.Add(labPool[j].id);
break;
}
nextLabId = labPool[nextLabId].nextLabId;
}
}
foreach (int item in hashSet)
{
if (item > 0 && item < num && labPool[item].entityId != 0)
{
MultStore.SetMult(factory.planetId, labPool[item].entityId, k);
}
}
}
}
public static class VFInputGuardPatch
{
[HarmonyPatch(typeof(VFInput), "UpdateGameStates")]
[HarmonyPostfix]
private static void Postfix()
{
if (MultiplierUI.IsMouseOverPanel())
{
VFInput.onGUI = true;
VFInput.onGUIOperate = true;
}
}
}
public static class MultStore
{
public const int SaveVersion = 3;
private static readonly Dictionary<int, Dictionary<int, int>> setMap = new Dictionary<int, Dictionary<int, int>>();
private static readonly HashSet<int> wirelessMap = new HashSet<int>();
private static readonly ConcurrentDictionary<long, int> effMap = new ConcurrentDictionary<long, int>();
private static readonly ConcurrentDictionary<long, int> energyMap = new ConcurrentDictionary<long, int>();
private static readonly ConcurrentDictionary<long, float> satMap = new ConcurrentDictionary<long, float>();
private static readonly ConcurrentDictionary<long, long> bufferMap = new ConcurrentDictionary<long, long>();
private static readonly ConcurrentDictionary<long, int> energyCapMap = new ConcurrentDictionary<long, int>();
private static readonly ConcurrentDictionary<long, long> bufCapMap = new ConcurrentDictionary<long, long>();
private static readonly ConcurrentDictionary<long, int> healthyCountMap = new ConcurrentDictionary<long, int>();
[ThreadStatic]
public static int CurrentPlanetId = -1;
public static ManualLogSource Log;
public static int ClipboardK = 1;
public static bool ClipboardWireless;
public static int AmbientPlanetId = -1;
private static readonly Dictionary<long, long> energyFrame = new Dictionary<long, long>();
private static readonly Dictionary<int, int> capMap = new Dictionary<int, int>();
public static int EffectivePlanetId
{
get
{
if (CurrentPlanetId < 0)
{
return AmbientPlanetId;
}
return CurrentPlanetId;
}
}
public static int MaxMultiplier
{
get
{
int num = ((Plugin.MaxMultiplierEntry == null) ? 100 : Plugin.MaxMultiplierEntry.Value);
if (num > 0)
{
return num;
}
return int.MaxValue;
}
}
public static void SamplePower(int planetId, int entityId, float power)
{
if (planetId >= 0)
{
if (power < 0f)
{
power = 0f;
}
if (power > 1f)
{
power = 1f;
}
satMap[EffKey(planetId, entityId)] = power;
}
}
public static float GetSat(int planetId, int entityId)
{
if (!satMap.TryGetValue(EffKey(planetId, entityId), out var value))
{
return 1f;
}
return value;
}
public static long ChargeBuffer(int planetId, int entityId, long delta, long cap)
{
long key = EffKey(planetId, entityId);
bufferMap.TryGetValue(key, out var value);
value += delta;
if (value < 0)
{
value = 0L;
}
if (value > cap)
{
value = cap;
}
bufferMap[key] = value;
return value;
}
public static void TickHealthyCount(int planetId, int entityId)
{
if (planetId >= 0)
{
long key = EffKey(planetId, entityId);
healthyCountMap.AddOrUpdate(key, 1, (long k, int v) => (v >= 9999) ? v : (v + 1));
}
}
public static void ResetHealthyCount(int planetId, int entityId)
{
if (planetId >= 0)
{
healthyCountMap[EffKey(planetId, entityId)] = 0;
}
}
public static int GetHealthyCount(int planetId, int entityId)
{
if (!healthyCountMap.TryGetValue(EffKey(planetId, entityId), out var value))
{
return 0;
}
return value;
}
public static void SetBufferCap(int planetId, int entityId, long cap)
{
if (planetId >= 0)
{
bufCapMap[EffKey(planetId, entityId)] = cap;
}
}
public static bool GetBufferInfo(int planetId, int entityId, out long cur, out long cap)
{
long key = EffKey(planetId, entityId);
bufferMap.TryGetValue(key, out cur);
return bufCapMap.TryGetValue(key, out cap);
}
public static int GetEnergyCapK(int planetId, int entityId)
{
if (!energyCapMap.TryGetValue(EffKey(planetId, entityId), out var value))
{
return int.MaxValue;
}
return value;
}
public static void SetEnergyCapK(int planetId, int entityId, int k)
{
if (planetId >= 0)
{
energyCapMap[EffKey(planetId, entityId)] = k;
}
}
private static long EffKey(int planetId, int entityId)
{
return (long)(planetId + 2) * 1000000L + entityId;
}
public static int GetSet(int planetId, int entityId)
{
if (setMap.TryGetValue(planetId, out var value) && value.TryGetValue(entityId, out var value2))
{
return value2;
}
return 1;
}
public static void SetMult(int planetId, int entityId, int k)
{
int maxMultiplier = MaxMultiplier;
if (k > maxMultiplier)
{
k = maxMultiplier;
}
Dictionary<int, int> value;
if (k <= 1)
{
if (setMap.TryGetValue(planetId, out value))
{
value.Remove(entityId);
if (value.Count == 0)
{
setMap.Remove(planetId);
}
}
SetEff(planetId, entityId, 1);
capMap.Remove(entityId);
}
else
{
if (!setMap.TryGetValue(planetId, out value))
{
value = new Dictionary<int, int>();
setMap[planetId] = value;
}
value[entityId] = k;
capMap[entityId] = k;
}
}
public static bool PlanetHasSets(int planetId)
{
return setMap.ContainsKey(planetId);
}
public static bool GetWireless(int planetId, int entityId)
{
return wirelessMap.Contains(planetId);
}
public static void SetWireless(int planetId, int entityId, bool on)
{
if (planetId >= 0)
{
if (on)
{
wirelessMap.Add(planetId);
}
else
{
wirelessMap.Remove(planetId);
}
}
}
public static bool PlanetHasWireless(int planetId)
{
return wirelessMap.Contains(planetId);
}
public static bool TryMarkEnergy(int planetId, int entityId, long frame)
{
long key = (long)planetId * 1000000L + entityId;
if (energyFrame.TryGetValue(key, out var value) && value == frame)
{
return false;
}
energyFrame[key] = frame;
return true;
}
public static int GetCapK(int entityId)
{
if (!capMap.TryGetValue(entityId, out var value))
{
return 1;
}
return value;
}
public static int GetEff(int planetId, int entityId)
{
if (!effMap.TryGetValue(EffKey(planetId, entityId), out var value))
{
return 1;
}
return value;
}
public static void SetEff(int planetId, int entityId, int k)
{
if (planetId < 0)
{
return;
}
long key = EffKey(planetId, entityId);
effMap[key] = k;
if (!energyMap.TryGetValue(key, out var value))
{
energyMap[key] = k;
return;
}
int num = k - value;
if (num != 0)
{
int num2 = num / 4;
if (num2 == 0)
{
num2 = ((num > 0) ? 1 : (-1));
}
energyMap[key] = value + num2;
}
}
public static int GetEnergyK(int planetId, int entityId)
{
if (!energyMap.TryGetValue(EffKey(planetId, entityId), out var value))
{
return 1;
}
return value;
}
public static void ClearAll()
{
setMap.Clear();
effMap.Clear();
energyMap.Clear();
satMap.Clear();
bufferMap.Clear();
bufCapMap.Clear();
energyCapMap.Clear();
healthyCountMap.Clear();
capMap.Clear();
energyFrame.Clear();
wirelessMap.Clear();
}
public static void Export(BinaryWriter w)
{
w.Write(3);
w.Write(setMap.Count);
foreach (KeyValuePair<int, Dictionary<int, int>> item in setMap)
{
w.Write(item.Key);
w.Write(item.Value.Count);
foreach (KeyValuePair<int, int> item2 in item.Value)
{
w.Write(item2.Key);
w.Write(item2.Value);
}
}
w.Write(wirelessMap.Count);
foreach (int item3 in wirelessMap)
{
w.Write(item3);
}
}
public static void Import(BinaryReader r)
{
ClearAll();
int num = r.ReadInt32();
int num2 = r.ReadInt32();
for (int i = 0; i < num2; i++)
{
int key = r.ReadInt32();
int num3 = r.ReadInt32();
Dictionary<int, int> dictionary = new Dictionary<int, int>(num3);
for (int j = 0; j < num3; j++)
{
int key2 = r.ReadInt32();
int num4 = r.ReadInt32();
if (num4 > 1)
{
dictionary[key2] = num4;
capMap[key2] = num4;
}
}
if (dictionary.Count > 0)
{
setMap[key] = dictionary;
}
}
if (num >= 3)
{
int num5 = r.ReadInt32();
for (int k = 0; k < num5; k++)
{
wirelessMap.Add(r.ReadInt32());
}
}
else
{
if (num < 2)
{
return;
}
int num6 = r.ReadInt32();
for (int l = 0; l < num6; l++)
{
int item = r.ReadInt32();
int num7 = r.ReadInt32();
for (int m = 0; m < num7; m++)
{
r.ReadInt32();
}
wirelessMap.Add(item);
}
}
}
}
[BepInPlugin("com.mandao.CondensedProduction", "CondensedProduction", "1.4.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BaseUnityPlugin, IModCanSave
{
public const string GUID = "com.mandao.CondensedProduction";
public const string NAME = "CondensedProduction";
public const string VERSION = "1.4.0";
public static ConfigEntry<int> MaxMultiplierEntry;
public static ConfigEntry<bool> ScaleOutputStorageEntry;
public static ConfigEntry<int> InputBufferMultiplierEntry;
public static ConfigEntry<int> EnergyBufferSecondsEntry;
public static ConfigEntry<int> ContainerMultiplierEntry;
public static ConfigEntry<bool> GlobalSupplyEnabledEntry;
public static ConfigEntry<int> GlobalSupplyIntervalEntry;
public static ConfigEntry<bool> GlobalSupplyCollectEntry;
public static ConfigEntry<bool> BeltStackEnabledEntry;
public static ConfigEntry<int> BeltStackMaxEntry;
public static ConfigEntry<bool> KeepVisualStackEntry;
private void Awake()
{
//IL_0068: Unknown result type (might be due to invalid IL or missing references)
//IL_0072: Expected O, but got Unknown
//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
//IL_0207: Unknown result type (might be due to invalid IL or missing references)
//IL_0217: Unknown result type (might be due to invalid IL or missing references)
//IL_0227: Unknown result type (might be due to invalid IL or missing references)
//IL_0237: Unknown result type (might be due to invalid IL or missing references)
//IL_0247: Unknown result type (might be due to invalid IL or missing references)
//IL_0257: Unknown result type (might be due to invalid IL or missing references)
//IL_0267: Unknown result type (might be due to invalid IL or missing references)
//IL_0277: Unknown result type (might be due to invalid IL or missing references)
//IL_0287: Unknown result type (might be due to invalid IL or missing references)
//IL_0297: Unknown result type (might be due to invalid IL or missing references)
//IL_02a7: Unknown result type (might be due to invalid IL or missing references)
//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
MaxMultiplierEntry = ((BaseUnityPlugin)this).Config.Bind<int>("通用", "MaxMultiplier", 1000, "单个建筑可设定的倍率上限(1~100000,0 表示不限制)。实际运行倍率始终受输入物品量与引擎速度上限自适应。");
ScaleOutputStorageEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("通用", "ScaleOutputStorage", true, "是否按设定倍率放大熔炉/装配机的产物缓存上限(熔炉100→100×N等)。");
EnergyBufferSecondsEntry = ((BaseUnityPlugin)this).Config.Bind<int>("电力", "EnergyBufferSeconds", 10, new ConfigDescription("每栋倍率建筑的内部储能时长(秒,按满倍率功耗计)。电网按平均功率平稳充电,瞬时消耗从储能扣除;电网不足时靠储能维持运行并逐步降速,而不是功率瞬间跳变。0 = 关闭储能", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 120), Array.Empty<object>()));
InputBufferMultiplierEntry = ((BaseUnityPlugin)this).Config.Bind<int>("通用", "InputBufferMultiplier", 3, "原料缓存系数:缓存上限 = 原版上限 × 设定倍率 × 该值。越大越能囤料,供料波动时不易停机。");
ContainerMultiplierEntry = ((BaseUnityPlugin)this).Config.Bind<int>("通用", "ContainerMultiplier", 100, "容器每格上限倍数:物流站、储物箱、罐体、玩家背包的每格容量 = 原版 × 该值。");
GlobalSupplyEnabledEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("无线供料", "Enabled", true, "启用无线供料:开启了「无线」的生产建筑,由本行星的原版行星物流站/星际物流站直接供料,无需分拣器。");
GlobalSupplyIntervalEntry = ((BaseUnityPlugin)this).Config.Bind<int>("无线供料", "IntervalTicks", 30, "无线供料执行间隔(游戏刻)。越小补料越及时,CPU 开销越大。");
GlobalSupplyCollectEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("无线供料", "Collect", true, "是否把开启了「无线」的建筑的产出直接回收到本行星物流站库存。");
BeltStackEnabledEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("传送带堆叠", "Enabled", true, "启用传送带堆叠扩容(堆叠器、白爪、物流站出口)。");
BeltStackMaxEntry = ((BaseUnityPlugin)this).Config.Bind<int>("传送带堆叠", "MaxStack", 255, "堆叠上限。游戏内堆叠数存为单字节,最大 255(原版 4 层)。");
KeepVisualStackEntry = ((BaseUnityPlugin)this).Config.Bind<bool>("传送带堆叠", "KeepVisualStack", true, "保持原版渲染:绘制时把堆叠临时压回 4 层,画面与原版一致(仅影响显示)。");
ConfigEntry<bool> val = ((BaseUnityPlugin)this).Config.Bind<bool>("兼容", "MultiplierMigrated", false, "内部使用:记录已将旧的 100 倍上限迁移为 1000。");
if (!val.Value)
{
if (MaxMultiplierEntry.Value > 0 && MaxMultiplierEntry.Value <= 100)
{
MaxMultiplierEntry.Value = 1000;
}
val.Value = true;
((BaseUnityPlugin)this).Config.Save();
}
Harmony val2 = new Harmony("com.mandao.CondensedProduction");
val2.PatchAll(typeof(ParallelTickPatch));
val2.PatchAll(typeof(FactoryContextPatch));
val2.PatchAll(typeof(AssemblerBatchPatch));
val2.PatchAll(typeof(LabBatchPatch));
val2.PatchAll(typeof(LabResearchPatch));
val2.PatchAll(typeof(ResearchNeedsPatch));
val2.PatchAll(typeof(NeedsBufferPatch));
val2.PatchAll(typeof(PowerSamplePatch));
val2.PatchAll(typeof(CopySettingPatch));
val2.PatchAll(typeof(VFInputGuardPatch));
val2.PatchAll(typeof(StorageCapPatch));
val2.PatchAll(typeof(StationLimitPatch));
val2.PatchAll(typeof(BuildingGrabPatch));
val2.PatchAll(typeof(GlobalSupplyPatch));
val2.PatchAll(typeof(PilerStackPatch));
val2.PatchAll(typeof(InserterStackPatch));
val2.PatchAll(typeof(StationOutputPatch));
val2.PatchAll(typeof(CargoVisualClampPatch));
MultiplierUI.Init();
MultStore.Log = ((BaseUnityPlugin)this).Logger;
((BaseUnityPlugin)this).Logger.LogInfo((object)"CondensedProduction 1.4.0 loaded.");
}
private void OnGUI()
{
MultiplierUI.Draw();
}
public void Export(BinaryWriter w)
{
MultStore.Export(w);
}
public void Import(BinaryReader r)
{
MultStore.Import(r);
}
public void IntoOtherSave()
{
MultStore.ClearAll();
}
}
public static class MultEngine
{
private static readonly ConcurrentDictionary<int, int> fallbackEff = new ConcurrentDictionary<int, int>();
[ThreadStatic]
private static long tlsFrame = long.MinValue;
[ThreadStatic]
private static Dictionary<long, int> tlsK;
private static int GetAsmKConsume(ref AssemblerComponent c)
{
int currentPlanetId = MultStore.CurrentPlanetId;
int num = ((currentPlanetId >= 0) ? MultStore.GetSet(currentPlanetId, c.entityId) : MultStore.GetCapK(c.entityId));
if (num <= 1)
{
return 1;
}
return ResolveDyn(currentPlanetId, c.entityId, num, c.recipeExecuteData.requireCounts, c.served);
}
private static int GetLabKConsume(ref LabComponent c)
{
int currentPlanetId = MultStore.CurrentPlanetId;
int num = ((currentPlanetId >= 0) ? MultStore.GetSet(currentPlanetId, c.entityId) : MultStore.GetCapK(c.entityId));
if (num <= 1)
{
return 1;
}
return ResolveDyn(currentPlanetId, c.entityId, num, c.recipeExecuteData.requireCounts, c.served);
}
private static int GetAsmKProduce(ref AssemblerComponent c)
{
int currentPlanetId = MultStore.CurrentPlanetId;
int num = ((currentPlanetId >= 0) ? MultStore.GetSet(currentPlanetId, c.entityId) : MultStore.GetCapK(c.entityId));
if (num <= 1)
{
return 1;
}
return ProduceK(currentPlanetId, c.entityId, num);
}
private static int GetLabKProduce(ref LabComponent c)
{
int currentPlanetId = MultStore.CurrentPlanetId;
int num = ((currentPlanetId >= 0) ? MultStore.GetSet(currentPlanetId, c.entityId) : MultStore.GetCapK(c.entityId));
if (num <= 1)
{
return 1;
}
return ProduceK(currentPlanetId, c.entityId, num);
}
private static int ProduceK(int planet, int entityId, int kSet)
{
int value = 0;
if (planet >= 0)
{
value = MultStore.GetEff(planet, entityId);
}
else
{
fallbackEff.TryGetValue(entityId, out value);
}
if (value < 1)
{
value = kSet;
}
if (value < 1)
{
value = 1;
}
return value;
}
private static int ResolveDyn(int planet, int entityId, int kSet, int[] require, int[] served)
{
long gameTick = GameMain.gameTick;
if (gameTick != tlsFrame || tlsK == null)
{
tlsFrame = gameTick;
if (tlsK == null)
{
tlsK = new Dictionary<long, int>();
}
else
{
tlsK.Clear();
}
}
long key = (long)(planet + 2) * 1000000L + entityId;
if (tlsK.TryGetValue(key, out var value))
{
return value;
}
int num = kSet;
if (require != null && served != null)
{
int num2 = ((require.Length < served.Length) ? require.Length : served.Length);
for (int i = 0; i < num2; i++)
{
int num3 = require[i];
if (num3 > 0)
{
int num4 = served[i] / num3;
if (num4 < num)
{
num = num4;
}
}
}
}
int energyCapK = MultStore.GetEnergyCapK(planet, entityId);
if (num > energyCapK)
{
num = energyCapK;
}
if (num < 1)
{
num = 1;
}
if (num > kSet)
{
num = kSet;
}
int num5 = ((planet >= 0) ? MultStore.GetEff(planet, entityId) : 0);
if (num5 > 0)
{
int num6 = kSet / 20;
if (num6 < 1)
{
num6 = 1;
}
int num7 = num - num5;
if (num7 > num6)
{
num = num5 + num6;
}
else if (num7 < -num6)
{
num = num5 - num6;
}
if (num < 1)
{
num = 1;
}
if (num > kSet)
{
num = kSet;
}
}
tlsK[key] = num;
MultStore.SetEff(planet, entityId, num);
fallbackEff[entityId] = num;
return num;
}
private static int GetAsmKNeeds(ref AssemblerComponent c)
{
int num = KFor(c.entityId);
if (num <= 1)
{
return 1;
}
return (int)Math.Min(2147483647L, (long)num * (long)BufferFactor());
}
private static int GetLabKNeeds(ref LabComponent c)
{
int num = KFor(c.entityId);
if (num <= 1)
{
return 1;
}
return (int)Math.Min(2147483647L, (long)num * (long)BufferFactor());
}
private static int GetLabKSet(ref LabComponent c)
{
int currentPlanetId = MultStore.CurrentPlanetId;
int num = ((currentPlanetId < 0) ? 1 : MultStore.GetSet(currentPlanetId, c.entityId));
if (num >= 1)
{
return num;
}
return 1;
}
private static int BufferFactor()
{
int num = ((Plugin.InputBufferMultiplierEntry == null) ? 3 : Plugin.InputBufferMultiplierEntry.Value);
if (num >= 1)
{
return num;
}
return 1;
}
internal static int KFor(int entityId)
{
int currentPlanetId = MultStore.CurrentPlanetId;
if (currentPlanetId < 0)
{
return MultStore.GetCapK(entityId);
}
return MultStore.GetSet(currentPlanetId, entityId);
}
internal static void EnergyPost(FactorySystem fs)
{
if (fs == null || fs.factory == null)
{
return;
}
int planetId = fs.factory.planetId;
if (!MultStore.PlanetHasSets(planetId))
{
return;
}
PowerConsumerComponent[] array = ((fs.factory.powerSystem != null) ? fs.factory.powerSystem.consumerPool : null);
if (array == null)
{
return;
}
long gameTick = GameMain.gameTick;
AssemblerComponent[] assemblerPool = fs.assemblerPool;
if (assemblerPool != null)
{
int num = Math.Min(fs.assemblerCursor, assemblerPool.Length);
for (int i = 1; i < num; i++)
{
if (assemblerPool[i].entityId == 0 || !assemblerPool[i].replicating)
{
continue;
}
int energyK = MultStore.GetEnergyK(planetId, assemblerPool[i].entityId);
if (energyK > 1)
{
int pcId = assemblerPool[i].pcId;
if (pcId > 0 && pcId < array.Length && MultStore.TryMarkEnergy(planetId, assemblerPool[i].entityId, gameTick))
{
AccountEnergy(planetId, assemblerPool[i].entityId, array, pcId, energyK);
array[pcId].requiredEnergy *= energyK;
}
}
}
}
LabComponent[] labPool = fs.labPool;
if (labPool == null)
{
return;
}
int num2 = Math.Min(fs.labCursor, labPool.Length);
for (int j = 1; j < num2; j++)
{
if (labPool[j].entityId == 0 || !labPool[j].replicating)
{
continue;
}
int num3 = (labPool[j].researchMode ? MultStore.GetSet(planetId, labPool[j].entityId) : MultStore.GetEnergyK(planetId, labPool[j].entityId));
if (num3 <= 1)
{
continue;
}
int pcId2 = labPool[j].pcId;
if (pcId2 > 0 && pcId2 < array.Length && MultStore.TryMarkEnergy(planetId, labPool[j].entityId, gameTick))
{
if (!labPool[j].researchMode)
{
AccountEnergy(planetId, labPool[j].entityId, array, pcId2, num3);
}
array[pcId2].requiredEnergy *= num3;
}
}
}
internal static void EnergyPostAll()
{
if (GameMain.data == null)
{
return;
}
PlanetFactory[] factories = GameMain.data.factories;
if (factories == null)
{
return;
}
foreach (PlanetFactory val in factories)
{
if (val == null || val.factorySystem == null)
{
continue;
}
try
{
EnergyPost(val.factorySystem);
}
catch (Exception ex)
{
if (MultStore.Log != null)
{
MultStore.Log.LogError((object)("[CP] energy sweep error: " + ex));
}
}
}
}
private static int BufferSeconds()
{
int num = ((Plugin.EnergyBufferSecondsEntry == null) ? 10 : Plugin.EnergyBufferSecondsEntry.Value);
if (num >= 0)
{
return num;
}
return 0;
}
private static void AccountEnergy(int planet, int entityId, PowerConsumerComponent[] consumers, int pcId, int kSmooth)
{
long num = consumers[pcId].requiredEnergy;
if (num <= 0)
{
num = consumers[pcId].workEnergyPerTick;
}
if (num <= 0)
{
return;
}
int num2 = BufferSeconds() * 60;
float num3 = MultStore.GetSat(planet, entityId);
if (num3 > 1f)
{
num3 = 1f;
}
long num4 = (long)((double)num * (double)kSmooth * (double)num3);
long num5 = MultStore.GetEff(planet, entityId) * num;
int set = MultStore.GetSet(planet, entityId);
long num6 = set * num * num2;
long num7 = MultStore.ChargeBuffer(planet, entityId, num4 - num5, num6);
MultStore.SetBufferCap(planet, entityId, num6);
int num9;
if (num3 < 0.95f && num2 > 0)
{
long num8 = num7 / (num2 * num);
num9 = kSmooth + (int)num8;
if (num9 < 1)
{
num9 = 1;
}
if (num9 > set)
{
num9 = set;
}
MultStore.ResetHealthyCount(planet, entityId);
}
else
{
MultStore.TickHealthyCount(planet, entityId);
int energyCapK = MultStore.GetEnergyCapK(planet, entityId);
if (energyCapK == int.MaxValue)
{
num9 = int.MaxValue;
}
else if (MultStore.GetHealthyCount(planet, entityId) < 30 || (num2 > 0 && num6 > 0 && (double)num7 / (double)num6 < 0.2))
{
num9 = energyCapK;
}
else
{
int num10 = set / 360 + 1;
num9 = energyCapK + num10;
if (num9 >= set)
{
num9 = int.MaxValue;
}
}
}
MultStore.SetEnergyCapK(planet, entityId, num9);
}
}
public static class PowerSamplePatch
{
[HarmonyPatch(typeof(AssemblerComponent), "InternalUpdate")]
[HarmonyPrefix]
private static void PreAsm(ref AssemblerComponent __instance, float power)
{
int currentPlanetId = MultStore.CurrentPlanetId;
if (currentPlanetId >= 0 && MultStore.GetSet(currentPlanetId, __instance.entityId) > 1)
{
MultStore.SamplePower(currentPlanetId, __instance.entityId, power);
}
}
[HarmonyPatch(typeof(LabComponent), "InternalUpdateAssemble")]
[HarmonyPrefix]
private static void PreLab(ref LabComponent __instance, float power)
{
int currentPlanetId = MultStore.CurrentPlanetId;
if (currentPlanetId >= 0 && MultStore.GetSet(currentPlanetId, __instance.entityId) > 1)
{
MultStore.SamplePower(currentPlanetId, __instance.entityId, power);
}
}
}
public static class CountMultiplyTranspiler
{
internal static IEnumerable<CodeInstruction> Apply(IEnumerable<CodeInstruction> instructions, MethodInfo getKConsume, MethodInfo getKProduce)
{
List<CodeInstruction> list = new List<CodeInstruction>(instructions);
Dictionary<int, MethodInfo> tracked = new Dictionary<int, MethodInfo>();
for (int i = 0; i + 2 < list.Count; i++)
{
if (!IsLdfld(list[i], "recipeExecuteData"))
{
continue;
}
MethodInfo methodInfo = CountFieldGetter(list[i + 1], getKConsume, getKProduce);
if (methodInfo != null)
{
int storeLocalIndex = GetStoreLocalIndex(list[i + 2]);
if (storeLocalIndex >= 0)
{
tracked[storeLocalIndex] = methodInfo;
}
}
}
for (int j = 0; j < list.Count; j++)
{
int loadLocalIndex = GetLoadLocalIndex(list[j]);
if (loadLocalIndex >= 0 && tracked.TryGetValue(loadLocalIndex, out var getK))
{
int k = j + 1;
bool flag = false;
for (; k < list.Count && k <= j + 4; k++)
{
if (list[k].opcode == OpCodes.Ldelem_I4)
{
flag = true;
break;
}
if (!IsIndexPush(list[k]))
{
break;
}
}
if (flag)
{
for (int t = j; t <= k; t++)
{
yield return list[t];
}
yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null);
yield return new CodeInstruction(OpCodes.Call, (object)getK);
yield return new CodeInstruction(OpCodes.Mul, (object)null);
j = k;
continue;
}
}
yield return list[j];
getK = null;
}
}
private static bool IsLdfld(CodeInstruction ci, string name)
{
if (ci.opcode == OpCodes.Ldfld && ci.operand is FieldInfo fieldInfo)
{
return fieldInfo.Name == name;
}
return false;
}
private static MethodInfo CountFieldGetter(CodeInstruction ci, MethodInfo consume, MethodInfo produce)
{
if (ci.opcode == OpCodes.Ldfld && ci.operand is FieldInfo fieldInfo && fieldInfo.DeclaringType != null && fieldInfo.DeclaringType.Name == "RecipeExecuteData")
{
if (fieldInfo.Name == "requireCounts")
{
return consume;
}
if (fieldInfo.Name == "productCounts")
{
return produce;
}
}
return null;
}
private static bool IsIndexPush(CodeInstruction ci)
{
if (!(ci.opcode == OpCodes.Ldc_I4) && !(ci.opcode == OpCodes.Ldc_I4_S) && !(ci.opcode == OpCodes.Ldc_I4_0) && !(ci.opcode == OpCodes.Ldc_I4_1) && !(ci.opcode == OpCodes.Ldc_I4_2) && !(ci.opcode == OpCodes.Ldc_I4_3))
{
return GetLoadLocalIndex(ci) >= 0;
}
return true;
}
internal static int GetStoreLocalIndex(CodeInstruction ci)
{
if (ci.opcode == OpCodes.Stloc_0)
{
return 0;
}
if (ci.opcode == OpCodes.Stloc_1)
{
return 1;
}
if (ci.opcode == OpCodes.Stloc_2)
{
return 2;
}
if (ci.opcode == OpCodes.Stloc_3)
{
return 3;
}
if (ci.opcode == OpCodes.Stloc_S || ci.opcode == OpCodes.Stloc)
{
return LocalIndex(ci.operand);
}
return -1;
}
internal static int GetLoadLocalIndex(CodeInstruction ci)
{
if (ci.opcode == OpCodes.Ldloc_0)
{
return 0;
}
if (ci.opcode == OpCodes.Ldloc_1)
{
return 1;
}
if (ci.opcode == OpCodes.Ldloc_2)
{
return 2;
}
if (ci.opcode == OpCodes.Ldloc_3)
{
return 3;
}
if (ci.opcode == OpCodes.Ldloc_S || ci.opcode == OpCodes.Ldloc)
{
return LocalIndex(ci.operand);
}
return -1;
}
private static int LocalIndex(object operand)
{
if (operand is LocalBuilder localBuilder)
{
return localBuilder.LocalIndex;
}
if (operand is int)
{
return (int)operand;
}
if (operand is short)
{
return (short)operand;
}
if (operand is byte)
{
return (byte)operand;
}
return -1;
}
internal static CodeInstruction LoadLocal(int index)
{
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Expected O, but got Unknown
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Expected O, but got Unknown
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_003c: Expected O, but got Unknown
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Expected O, but got Unknown
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Expected O, but got Unknown
return (CodeInstruction)(index switch
{
0 => (object)new CodeInstruction(OpCodes.Ldloc_0, (object)null),
1 => (object)new CodeInstruction(OpCodes.Ldloc_1, (object)null),
2 => (object)new CodeInstruction(OpCodes.Ldloc_2, (object)null),
3 => (object)new CodeInstruction(OpCodes.Ldloc_3, (object)null),
_ => (object)new CodeInstruction(OpCodes.Ldloc_S, (object)index),
});
}
}
public static class AssemblerBatchPatch
{
private static readonly MethodInfo GetKConsume = typeof(MultEngine).GetMethod("GetAsmKConsume", BindingFlags.Static | BindingFlags.NonPublic);
private static readonly MethodInfo GetKProduce = typeof(MultEngine).GetMethod("GetAsmKProduce", BindingFlags.Static | BindingFlags.NonPublic);
[HarmonyPatch(typeof(AssemblerComponent), "InternalUpdate")]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
foreach (CodeInstruction item in CountMultiplyTranspiler.Apply(instructions, GetKConsume, GetKProduce))
{
if (item.opcode == OpCodes.Ldc_I4_S && item.operand is sbyte b && b == 100)
{
yield return item;
yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null);
yield return new CodeInstruction(OpCodes.Call, (object)GetKProduce);
yield return new CodeInstruction(OpCodes.Mul, (object)null);
}
else
{
yield return item;
}
}
}
}
public static class NeedsBufferPatch
{
private static readonly MethodInfo GetAsmK = typeof(MultEngine).GetMethod("GetAsmKNeeds", BindingFlags.Static | BindingFlags.NonPublic);
private static readonly MethodInfo GetLabK = typeof(MultEngine).GetMethod("GetLabKNeeds", BindingFlags.Static | BindingFlags.NonPublic);
[HarmonyPatch(typeof(AssemblerComponent), "UpdateNeeds")]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> AsmNeeds(IEnumerable<CodeInstruction> instructions)
{
return CountMultiplyTranspiler.Apply(instructions, GetAsmK, GetAsmK);
}
[HarmonyPatch(typeof(LabComponent), "UpdateNeedsAssemble")]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> LabNeeds(IEnumerable<CodeInstruction> instructions)
{
return CountMultiplyTranspiler.Apply(instructions, GetLabK, GetLabK);
}
}
public static class LabBatchPatch
{
private static readonly MethodInfo GetKConsume = typeof(MultEngine).GetMethod("GetLabKConsume", BindingFlags.Static | BindingFlags.NonPublic);
private static readonly MethodInfo GetKProduce = typeof(MultEngine).GetMethod("GetLabKProduce", BindingFlags.Static | BindingFlags.NonPublic);
[HarmonyPatch(typeof(LabComponent), "InternalUpdateAssemble")]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
List<CodeInstruction> list = new List<CodeInstruction>(CountMultiplyTranspiler.Apply(instructions, GetKConsume, GetKProduce));
for (int i = 0; i < list.Count; i++)
{
yield return list[i];
if (list[i].opcode == OpCodes.Ldc_I4_S && list[i].operand is sbyte b && b == 10 && i + 2 < list.Count && list[i + 1].opcode == OpCodes.Ldarg_0 && list[i + 2].opcode == OpCodes.Ldfld && list[i + 2].operand is FieldInfo { Name: "speedOverride" })
{
yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null);
yield return new CodeInstruction(OpCodes.Call, (object)GetKProduce);
yield return new CodeInstruction(OpCodes.Mul, (object)null);
}
}
}
}
public static class LabResearchPatch
{
[ThreadStatic]
private static bool inLoop;
[HarmonyPatch(typeof(LabComponent), "InternalUpdateResearch")]
[HarmonyPrefix]
private static bool Prefix(ref LabComponent __instance, float power, float research_speed, int[] consumeRegister, ref TechState ts, ref int techHashedThisFrame, ref long uMatrixPoint, ref long hashRegister, ref uint __result)
{
if (inLoop)
{
return true;
}
int currentPlanetId = MultStore.CurrentPlanetId;
int num = ((currentPlanetId < 0) ? 1 : MultStore.GetSet(currentPlanetId, __instance.entityId));
if (num <= 1)
{
return true;
}
inLoop = true;
try
{
__result = ((LabComponent)(ref __instance)).InternalUpdateResearch(power, research_speed, consumeRegister, ref ts, ref techHashedThisFrame, ref uMatrixPoint, ref hashRegister);
for (int i = 1; i < num; i++)
{
if (!__instance.replicating)
{
break;
}
((LabComponent)(ref __instance)).InternalUpdateResearch(power, research_speed, consumeRegister, ref ts, ref techHashedThisFrame, ref uMatrixPoint, ref hashRegister);
}
}
finally
{
inLoop = false;
}
return false;
}
}
public static class ResearchNeedsPatch
{
private static readonly MethodInfo GetK = typeof(MultEngine).GetMethod("GetLabKSet", BindingFlags.Static | BindingFlags.NonPublic);
[HarmonyPatch(typeof(LabComponent), "UpdateNeedsResearch")]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
foreach (CodeInstruction ci in instructions)
{
yield return ci;
if (ci.opcode == OpCodes.Ldc_I4 && ci.operand is int v && v == 36000)
{
yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null);
yield return new CodeInstruction(OpCodes.Call, (object)GetK);
yield return new CodeInstruction(OpCodes.Mul, (object)null);
}
}
}
}
public static class ParallelContextTranspiler
{
private static readonly MethodInfo SetCtx = typeof(ParallelContextTranspiler).GetMethod("SetContext", BindingFlags.Static | BindingFlags.NonPublic);
private static void SetContext(PlanetFactory factory)
{
MultStore.CurrentPlanetId = ((factory != null) ? factory.planetId : (-1));
}
internal static IEnumerable<CodeInstruction> Apply(IEnumerable<CodeInstruction> instructions)
{
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
//IL_00b2: Expected O, but got Unknown
//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: Expected O, but got Unknown
List<CodeInstruction> list = new List<CodeInstruction>(instructions);
for (int i = 0; i + 2 < list.Count; i++)
{
if (!(list[i].opcode == OpCodes.Ldfld) || !(list[i].operand is FieldInfo { Name: "factories" } fieldInfo) || !(fieldInfo.DeclaringType.Name == "GameLogic"))
{
continue;
}
for (int j = i + 1; j < list.Count && j <= i + 12; j++)
{
if (list[j].opcode == OpCodes.Ldelem_Ref && CountMultiplyTranspiler.GetStoreLocalIndex(list[j + 1]) >= 0)
{
List<CodeInstruction> collection = new List<CodeInstruction>
{
new CodeInstruction(OpCodes.Dup, (object)null),
new CodeInstruction(OpCodes.Call, (object)SetCtx)
};
list.InsertRange(j + 1, collection);
return list;
}
}
}
return list;
}
}
public static class ParallelTickPatch
{
[HarmonyPatch(typeof(GameLogic), "_assembler_parallel")]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> AsmTranspiler(IEnumerable<CodeInstruction> instructions)
{
return ParallelContextTranspiler.Apply(instructions);
}
[HarmonyPatch(typeof(GameLogic), "_lab_produce_parallel")]
[HarmonyTranspiler]
private static IEnumerable<CodeInstruction> LabTranspiler(IEnumerable<CodeInstruction> instructions)
{
return ParallelContextTranspiler.Apply(instructions);
}
[HarmonyPatch(typeof(GameLogic), "_assembler_parallel")]
[HarmonyPostfix]
private static void PostAsm(int threadOrdinal)
{
MultStore.CurrentPlanetId = -1;
if (threadOrdinal == 0)
{
MultEngine.EnergyPostAll();
}
}
[HarmonyPatch(typeof(GameLogic), "_lab_produce_parallel")]
[HarmonyPostfix]
private static void PostLab(int threadOrdinal)
{
MultStore.CurrentPlanetId = -1;
}
}
public static class FactoryContextPatch
{
[HarmonyPrefix]
[HarmonyPatch(typeof(FactorySystem), "GameTick")]
private static void PreGameTick(FactorySystem __instance)
{
MultStore.CurrentPlanetId = ((__instance.factory != null) ? __instance.factory.planetId : (-1));
}
[HarmonyPostfix]
[HarmonyPatch(typeof(FactorySystem), "GameTick")]
private static void PostGameTick(FactorySystem __instance)
{
MultEngine.EnergyPost(__instance);
MultStore.CurrentPlanetId = -1;
}
[HarmonyPrefix]
[HarmonyPatch(typeof(FactorySystem), "GameTickLabProduceMode")]
private static void PreLabProduce(FactorySystem __instance)
{
MultStore.CurrentPlanetId = ((__instance.factory != null) ? __instance.factory.planetId : (-1));
}
[HarmonyPostfix]
[HarmonyPatch(typeof(FactorySystem), "GameTickLabProduceMode")]
private static void PostLabProduce()
{
MultStore.CurrentPlanetId = -1;
}
[HarmonyPrefix]
[HarmonyPatch(typeof(FactorySystem), "GameTickLabResearchMode")]
private static void PreLabResearch(FactorySystem __instance)
{
MultStore.CurrentPlanetId = ((__instance.factory != null) ? __instance.factory.planetId : (-1));
}
[HarmonyPostfix]
[HarmonyPatch(typeof(FactorySystem), "GameTickLabResearchMode")]
private static void PostLabResearch()
{
MultStore.CurrentPlanetId = -1;
}
}
public static class CopySettingPatch
{
[HarmonyPatch(typeof(BuildingParameters), "CopyFromFactoryObject")]
[HarmonyPostfix]
private static void BpCopy(int objectId, PlanetFactory factory)
{
if (factory != null && objectId > 0)
{
MultStore.ClipboardK = MultStore.GetSet(factory.planetId, objectId);
MultStore.ClipboardWireless = MultStore.GetWireless(factory.planetId, objectId);
}
}
[HarmonyPatch(typeof(BuildingParameters), "ApplyPrebuildParametersToEntity")]
[HarmonyPostfix]
private static void BpPaste(int entityId, PlanetFactory factory)
{
if (factory != null && entityId > 0)
{
MultStore.SetMult(factory.planetId, entityId, MultStore.ClipboardK);
MultStore.SetWireless(factory.planetId, entityId, MultStore.ClipboardWireless);
}
}
[HarmonyPatch(typeof(PlanetFactory), "OnCopyBuildingSetting")]
[HarmonyPostfix]
private static void OnCopy(PlanetFactory __instance, int entityId)
{
MultStore.ClipboardK = MultStore.GetSet(__instance.planetId, entityId);
MultStore.ClipboardWireless = MultStore.GetWireless(__instance.planetId, entityId);
}
[HarmonyPatch(typeof(PlanetFactory), "OnPasteBuildingSetting")]
[HarmonyPostfix]
private static void OnPaste(PlanetFactory __instance, int entityId)
{
MultStore.SetMult(__instance.planetId, entityId, MultStore.ClipboardK);
MultStore.SetWireless(__instance.planetId, entityId, MultStore.ClipboardWireless);
}
}
public static class StorageCapPatch
{
private static bool tableScaled;
private static bool prefabScaled;
private static long lastMaintain = long.MinValue;
private static int Factor
{
get
{
int num = ((Plugin.ContainerMultiplierEntry == null) ? 100 : Plugin.ContainerMultiplierEntry.Value);
if (num >= 1)
{
return num;
}
return 1;
}
}
public static void Maintain()
{
if (Factor > 1)
{
long gameTick = GameMain.gameTick;
if (gameTick < lastMaintain)
{
lastMaintain = long.MinValue;
}
if (lastMaintain == long.MinValue || gameTick - lastMaintain >= 30)
{
lastMaintain = gameTick;
EnsureStackTable();
EnsureStationPrefabs();
}
}
}
private static void EnsureStationPrefabs()
{
if (prefabScaled || (Object)(object)LDB.items == (Object)null || ((ProtoSet<ItemProto>)(object)LDB.items).dataArray == null)
{
return;
}
int factor = Factor;
HashSet<PrefabDesc> seen = new HashSet<PrefabDesc>();
ItemProto[] dataArray = ((ProtoSet<ItemProto>)(object)LDB.items).dataArray;
for (int i = 0; i < dataArray.Length; i++)
{
ScaleStationMax(dataArray[i].prefabDesc, factor, seen);
}
if ((Object)(object)LDB.models != (Object)null && ((ProtoSet<ModelProto>)(object)LDB.models).dataArray != null)
{
ModelProto[] dataArray2 = ((ProtoSet<ModelProto>)(object)LDB.models).dataArray;
for (int j = 0; j < dataArray2.Length; j++)
{
ScaleStationMax(dataArray2[j].prefabDesc, factor, seen);
}
}
prefabScaled = true;
}
private static void ScaleStationMax(PrefabDesc pd, int f, HashSet<PrefabDesc> seen)
{
if (pd != null && pd.stationMaxItemCount > 0 && seen.Add(pd))
{
long val = (long)pd.stationMaxItemCount * (long)f;
pd.stationMaxItemCount = (int)Math.Min(2147483647L, val);
}
}
private static void EnsureStackTable()
{
if (tableScaled || !StorageComponent.staticLoaded)
{
return;
}
int[] itemStackCount = StorageComponent.itemStackCount;
if (itemStackCount != null)
{
int factor = Factor;
for (int i = 0; i < itemStackCount.Length; i++)
{
long val = (long)itemStackCount[i] * (long)factor;
itemStackCount[i] = (int)Math.Min(2147483647L, val);
}
tableScaled = true;
}
}
[HarmonyPatch(typeof(StationComponent), "Init")]
[HarmonyPrefix]
private static void StationInitPrefix()
{
EnsureStationPrefabs();
}
[HarmonyPatch(typeof(StorageComponent), "LoadStatic")]
[HarmonyPostfix]
private static void LoadStaticPostfix()
{
EnsureStackTable();
}
[HarmonyPatch(typeof(StorageComponent), "Import")]
[HarmonyPostfix]
private static void ImportPostfix(StorageComponent __instance)
{
if (Factor <= 1)
{
return;
}
EnsureStackTable();
GRID[] grids = __instance.grids;
int[] itemStackCount = StorageComponent.itemStackCount;
if (grids == null || itemStackCount == null)
{
return;
}
for (int i = 0; i < grids.Length; i++)
{
int filter = grids[i].filter;
if (filter > 0 && filter < itemStackCount.Length)
{
grids[i].stackSize = itemStackCount[filter];
}
}
}
}
[HarmonyPatch]
public static class StationLimitPatch
{
private static int requested;
private static int requestedItem;
[HarmonyPatch(typeof(PlanetTransport), "SetStationStorage")]
[HarmonyPrefix]
private static void PreSet(int itemId, int itemCountMax)
{
requested = itemCountMax;
requestedItem = itemId;
}
[HarmonyPatch(typeof(PlanetTransport), "SetStationStorage")]
[HarmonyPostfix]
private static void PostSet(PlanetTransport __instance, int stationId, int storageIdx, int itemId)
{
if (itemId <= 0 || itemId != requestedItem)
{
return;
}
StationComponent[] stationPool = __instance.stationPool;
if (stationPool == null)
{
return;
}
foreach (StationComponent val in stationPool)
{
if (val != null && val.id == stationId && val.storage != null)
{
if (storageIdx >= 0 && storageIdx < val.storage.Length && val.storage[storageIdx].itemId == itemId && requested > val.storage[storageIdx].max)
{
val.storage[storageIdx].max = requested;
}
break;
}
}
}
}