using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Threading;
using BepInEx;
using BepInEx.Bootstrap;
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: AssemblyTitle("AssemblerVerticalConstruction")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("AssemblerVerticalConstruction")]
[assembly: AssemblyCopyright("Copyright lltcggie 2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("5678B572-A4A6-488A-8229-BE42EB9AEFE3")]
[assembly: AssemblyFileVersion("1.1.13.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.1.13.0")]
namespace AssemblerVerticalConstruction;
public class AssemblerComponentEx
{
public const int DefaultProductTransferStack = 9;
public const int DefaultProductBufferStack = 9;
private const int InputSlotCount = 6;
public int[][] assemblerNextIds = new int[384][];
private long[][] assemblerInputReceivedTicks = new long[384][];
private int[][] assemblerInputReceivedCounts = new int[384][];
public int assemblerCapacity = 384;
public int transfarCount = 6;
private int productTransferStack = 9;
private int productBufferStack = 9;
public int ProductTransferStack
{
get
{
return productTransferStack;
}
set
{
productTransferStack = Math.Max(1, value);
}
}
public int ProductBufferStack
{
get
{
return productBufferStack;
}
set
{
productBufferStack = Math.Max(1, value);
}
}
public void SetCargoStackLimit(int stack)
{
int val = (ProductTransferStack = Math.Max(1, stack));
ProductBufferStack = Math.Max(9, val);
}
public void SetAssemblerCapacity(int newCapacity)
{
if (newCapacity > assemblerNextIds.Length)
{
int[][] array = assemblerNextIds;
long[][] array2 = assemblerInputReceivedTicks;
int[][] array3 = assemblerInputReceivedCounts;
assemblerNextIds = new int[newCapacity][];
assemblerInputReceivedTicks = new long[newCapacity][];
assemblerInputReceivedCounts = new int[newCapacity][];
if (array != null)
{
Array.Copy(array, assemblerNextIds, array.Length);
Array.Copy(array2, assemblerInputReceivedTicks, array2.Length);
Array.Copy(array3, assemblerInputReceivedCounts, array3.Length);
}
assemblerCapacity = newCapacity;
}
}
public void EnsureAssemblerArray(int factoryIndex, int requiredCapacity)
{
EnsureFactoryIndex(factoryIndex);
int[] array = assemblerNextIds[factoryIndex];
long[] array2 = assemblerInputReceivedTicks[factoryIndex];
int[] array3 = assemblerInputReceivedCounts[factoryIndex];
if (array == null || array.Length < requiredCapacity || array2 == null || array2.Length < array.Length || array3 == null || array3.Length < array.Length * 6)
{
int val = ((array != null) ? array.Length : 0);
int num = Math.Max(Math.Max(requiredCapacity, val), 256);
int[] array4 = new int[num];
if (array != null)
{
Array.Copy(array, array4, array.Length);
}
assemblerNextIds[factoryIndex] = array4;
long[] array5 = new long[num];
if (array2 != null)
{
Array.Copy(array2, array5, array2.Length);
}
assemblerInputReceivedTicks[factoryIndex] = array5;
int[] array6 = new int[num * 6];
if (array3 != null)
{
Array.Copy(array3, array6, array3.Length);
}
assemblerInputReceivedCounts[factoryIndex] = array6;
}
}
public void ClearAssemblerArray(int factoryIndex, int requiredCapacity)
{
EnsureAssemblerArray(factoryIndex, requiredCapacity);
Array.Clear(assemblerNextIds[factoryIndex], 0, assemblerNextIds[factoryIndex].Length);
Array.Clear(assemblerInputReceivedTicks[factoryIndex], 0, assemblerInputReceivedTicks[factoryIndex].Length);
Array.Clear(assemblerInputReceivedCounts[factoryIndex], 0, assemblerInputReceivedCounts[factoryIndex].Length);
}
public int GetNextId(int index, int assemblerId)
{
if (index >= assemblerNextIds.Length)
{
return 0;
}
if (assemblerNextIds[index] == null || assemblerId >= assemblerNextIds[index].Length)
{
return 0;
}
return assemblerNextIds[index][assemblerId];
}
public int[] GetNextIds(int factoryIndex)
{
if (factoryIndex < 0 || factoryIndex >= assemblerNextIds.Length)
{
return null;
}
return assemblerNextIds[factoryIndex];
}
public static void FindRecipeIdForBuild(FactorySystem factorySystem, int assemblerId)
{
int entityId = factorySystem.assemblerPool[assemblerId].entityId;
if (entityId == 0)
{
return;
}
int num = entityId;
bool flag = default(bool);
int num2 = default(int);
int num3 = default(int);
do
{
factorySystem.factory.ReadObjectConn(num, 14, ref flag, ref num2, ref num3);
num = num2;
if (num > 0)
{
int assemblerId2 = factorySystem.factory.entityPool[num].assemblerId;
if (assemblerId2 > 0 && factorySystem.assemblerPool[assemblerId2].id == assemblerId2 && factorySystem.assemblerPool[assemblerId2].recipeId > 0)
{
((AssemblerComponent)(ref factorySystem.assemblerPool[assemblerId])).SetRecipe(factorySystem.assemblerPool[assemblerId2].recipeId, factorySystem.factory.entitySignPool);
SyncForceAccModeFromSource(factorySystem, assemblerId, assemblerId2);
return;
}
}
}
while (num != 0);
num = entityId;
do
{
factorySystem.factory.ReadObjectConn(num, 15, ref flag, ref num2, ref num3);
num = num2;
if (num > 0)
{
int assemblerId3 = factorySystem.factory.entityPool[num].assemblerId;
if (assemblerId3 > 0 && factorySystem.assemblerPool[assemblerId3].id == assemblerId3 && factorySystem.assemblerPool[assemblerId3].recipeId > 0)
{
((AssemblerComponent)(ref factorySystem.assemblerPool[assemblerId])).SetRecipe(factorySystem.assemblerPool[assemblerId3].recipeId, factorySystem.factory.entitySignPool);
SyncForceAccModeFromSource(factorySystem, assemblerId, assemblerId3);
break;
}
}
}
while (num != 0);
}
private static void SyncForceAccModeFromSource(FactorySystem factorySystem, int targetAssemblerId, int sourceAssemblerId)
{
ref AssemblerComponent reference = ref factorySystem.assemblerPool[targetAssemblerId];
ref AssemblerComponent reference2 = ref factorySystem.assemblerPool[sourceAssemblerId];
if (reference.recipeExecuteData != null && reference.recipeExecuteData.productive)
{
reference.forceAccMode = reference2.forceAccMode;
}
}
public void SetAssemblerInsertTarget(PlanetFactory __instance, int assemblerId, int nextEntityId)
{
int index = __instance.factorySystem.factory.index;
EnsureAssemblerArray(index, assemblerId + 1);
if (assemblerId != 0 && __instance.factorySystem.assemblerPool[assemblerId].id == assemblerId)
{
if (nextEntityId == 0)
{
assemblerNextIds[index][assemblerId] = 0;
return;
}
int assemblerId2 = __instance.entityPool[nextEntityId].assemblerId;
assemblerNextIds[index][assemblerId] = assemblerId2;
FindRecipeIdForBuild(__instance.factorySystem, assemblerId);
}
}
public void UnsetAssemblerInsertTarget(PlanetFactory __instance, int assemblerId, int assemblerRemoveId)
{
int index = __instance.factorySystem.factory.index;
EnsureAssemblerArray(index, Math.Max(assemblerId, assemblerRemoveId) + 1);
int[] array = assemblerNextIds[index];
if (assemblerRemoveId > 0 && assemblerRemoveId < array.Length)
{
Interlocked.Exchange(ref array[assemblerRemoveId], 0);
}
if (assemblerId > 0 && assemblerId < array.Length && array[assemblerId] == assemblerRemoveId)
{
Interlocked.CompareExchange(ref array[assemblerId], 0, assemblerRemoveId);
}
}
public void SetAssemblerNext(int index, int assemblerId, int nextId)
{
EnsureAssemblerArray(index, assemblerId + 1);
assemblerNextIds[index][assemblerId] = nextId;
}
public void RebuildAssemblerRelation(PlanetFactory factory, int assemblerId)
{
RebuildAssemblerRelation(factory, assemblerId, synchronizeRecipe: true);
}
internal void RebuildAssemblerRelation(PlanetFactory factory, int assemblerId, bool synchronizeRecipe)
{
if (factory == null || factory.factorySystem == null || assemblerId <= 0)
{
return;
}
FactorySystem factorySystem = factory.factorySystem;
AssemblerComponent[] assemblerPool = factorySystem.assemblerPool;
if (assemblerId >= assemblerPool.Length || assemblerPool[assemblerId].id != assemblerId)
{
return;
}
int entityId = assemblerPool[assemblerId].entityId;
if (entityId <= 0)
{
return;
}
int index = factory.index;
EnsureAssemblerArray(index, assemblerId + 1);
bool flag = default(bool);
int num = default(int);
int num2 = default(int);
factory.ReadObjectConn(entityId, 15, ref flag, ref num, ref num2);
int nextId = 0;
if (flag && num > 0 && num < factory.entityPool.Length)
{
int assemblerId2 = factory.entityPool[num].assemblerId;
if (assemblerId2 > 0 && assemblerId2 < assemblerPool.Length && assemblerPool[assemblerId2].id == assemblerId2)
{
nextId = assemblerId2;
}
}
SetAssemblerNext(index, assemblerId, nextId);
factory.ReadObjectConn(entityId, 14, ref flag, ref num, ref num2);
if (num > 0 && num < factory.entityPool.Length)
{
int assemblerId3 = factory.entityPool[num].assemblerId;
if (assemblerId3 > 0 && assemblerId3 < assemblerPool.Length && assemblerPool[assemblerId3].id == assemblerId3)
{
SetAssemblerNext(index, assemblerId3, assemblerId);
}
}
if (synchronizeRecipe)
{
FindRecipeIdForBuild(factorySystem, assemblerId);
}
}
public void UpdateOutputToNext(PlanetFactory factory, int planeIndex, int assemblerId, AssemblerComponent[] assemblerPool, int assemblerNextId, long transferTick, bool useMutex)
{
if (assemblerId <= 0 || assemblerNextId <= 0 || assemblerId >= assemblerPool.Length || assemblerNextId >= assemblerPool.Length)
{
ClearAssemblerNextIfMatches(planeIndex, assemblerId, assemblerNextId);
}
else if (useMutex)
{
int entityId = assemblerPool[assemblerId].entityId;
int entityId2 = assemblerPool[assemblerNextId].entityId;
if (entityId > 0 && entityId2 > 0)
{
lock (factory.entityMutexs[entityId])
{
lock (factory.entityMutexs[entityId2])
{
UpdateOutputToNextInner(factory, planeIndex, assemblerId, assemblerNextId, assemblerPool, transferTick);
return;
}
}
}
ClearAssemblerNextIfMatches(planeIndex, assemblerId, assemblerNextId);
}
else
{
UpdateOutputToNextInner(factory, planeIndex, assemblerId, assemblerNextId, assemblerPool, transferTick);
}
}
private void UpdateOutputToNextInner(PlanetFactory factory, int planeIndex, int assemblerId, int assemblerNextId, AssemblerComponent[] assemblerPool, long transferTick)
{
ref AssemblerComponent reference = ref assemblerPool[assemblerId];
ref AssemblerComponent reference2 = ref assemblerPool[assemblerNextId];
if (reference.id != assemblerId || reference2.id != assemblerNextId)
{
ClearAssemblerNextIfMatches(planeIndex, assemblerId, assemblerNextId);
return;
}
bool flag = default(bool);
int num = default(int);
int num2 = default(int);
factory.ReadObjectConn(reference.entityId, 15, ref flag, ref num, ref num2);
if (!flag || num != reference2.entityId)
{
int newNextId = 0;
if (flag && num > 0 && num < factory.entityPool.Length)
{
int assemblerId2 = factory.entityPool[num].assemblerId;
if (assemblerId2 > 0 && assemblerId2 < assemblerPool.Length && assemblerPool[assemblerId2].id == assemblerId2)
{
newNextId = assemblerId2;
}
}
ReplaceAssemblerNextIfMatches(planeIndex, assemblerId, assemblerNextId, newNextId);
}
else
{
if (reference.recipeId <= 0 || reference.recipeId != reference2.recipeId || reference.served == null || reference2.served == null || reference.recipeExecuteData == null || reference2.recipeExecuteData == null)
{
return;
}
RecipeExecuteData recipeExecuteData = reference.recipeExecuteData;
RecipeExecuteData recipeExecuteData2 = reference2.recipeExecuteData;
int timeSpend = recipeExecuteData2.timeSpend;
if (timeSpend <= 0)
{
return;
}
int num3 = Math.Max(2, reference2.speedOverride * 180 / timeSpend + 1);
int[] served = reference.served;
int[] incServed = reference.incServed;
int[] served2 = reference2.served;
int[] incServed2 = reference2.incServed;
int[] requireCounts = recipeExecuteData2.requireCounts;
long[] array = assemblerInputReceivedTicks[planeIndex];
int[] array2 = assemblerInputReceivedCounts[planeIndex];
int num4 = assemblerId * 6;
int num5 = assemblerNextId * 6;
bool flag2 = array[assemblerId] == transferTick;
bool flag3 = array[assemblerNextId] == transferTick;
bool flag4 = false;
int num6 = served.Length;
for (int i = 0; i < num6; i++)
{
int num7 = served[i];
int num8 = requireCounts[i] * num3 - served2[i];
int num9 = (flag2 ? array2[num4 + i] : 0);
int num10 = num7 - num9;
if (num8 > 0 && num10 > 0)
{
ref int reference3 = ref incServed[i];
int num11 = Math.Min(num10, num8);
if (reference3 <= 0)
{
reference3 = 0;
}
int num12 = split_inc_level(ref served[i], ref reference3, num11);
if (served[i] == 0)
{
reference3 = 0;
}
served2[i] += num11;
incServed2[i] += num11 * num12;
if (!flag3)
{
array[assemblerNextId] = transferTick;
array2[num5] = 0;
array2[num5 + 1] = 0;
array2[num5 + 2] = 0;
array2[num5 + 3] = 0;
array2[num5 + 4] = 0;
array2[num5 + 5] = 0;
flag3 = true;
}
array2[num5 + i] += num11;
flag4 = true;
}
}
if (flag4)
{
((AssemblerComponent)(ref reference)).UpdateNeeds();
((AssemblerComponent)(ref reference2)).UpdateNeeds();
}
int num13 = productTransferStack;
int num14 = productBufferStack;
int[] productCounts = recipeExecuteData.productCounts;
int[] produced = reference.produced;
int[] produced2 = reference2.produced;
int num15 = productCounts.Length;
for (int j = 0; j < num15; j++)
{
int num16 = productCounts[j];
int num17 = num16 * num14 - produced[j];
int num18 = produced2[j];
if (num17 > 0 && num18 > 0)
{
int val = num16 * num13;
int num19 = Math.Min(num17, Math.Min(val, num18));
produced[j] += num19;
produced2[j] -= num19;
}
}
}
}
private void EnsureFactoryIndex(int factoryIndex)
{
if (factoryIndex >= assemblerNextIds.Length)
{
int num = assemblerNextIds.Length;
while (factoryIndex >= num)
{
num *= 2;
}
SetAssemblerCapacity(num);
}
}
private void ClearAssemblerNextIfMatches(int index, int assemblerId, int expectedNextId)
{
ReplaceAssemblerNextIfMatches(index, assemblerId, expectedNextId, 0);
}
private void ReplaceAssemblerNextIfMatches(int index, int assemblerId, int expectedNextId, int newNextId)
{
if (index >= 0 && index < assemblerNextIds.Length)
{
int[] array = assemblerNextIds[index];
if (array != null && assemblerId > 0 && assemblerId < array.Length && array[assemblerId] == expectedNextId)
{
Interlocked.CompareExchange(ref array[assemblerId], newNextId, expectedNextId);
}
}
}
private int split_inc_level(ref int n, ref int m, int p)
{
if (n <= 0)
{
return 0;
}
int num = m / n;
int num2 = m - num * n;
n -= p;
int num3 = num2 - n;
m -= ((num3 > 0) ? (num * p + num3) : (num * p));
return num;
}
}
[BepInPlugin("lltcggie.DSP.plugin.AssemblerVerticalConstruction", "AssemblerVerticalConstruction", "1.1.13")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[ModSaveSettings(/*Could not decode attribute arguments.*/)]
public class AssemblerVerticalConstruction : BaseUnityPlugin, IModCanSave
{
public static readonly int CurrentSavedataVersion = 4;
private const string FractionateEverythingGuid = "com.menglei.dsp.fe";
private static readonly Version FractionateEverythingStackingVersion = new Version(2, 3, 0);
private const int FractionateEverythingStackLimit = 20;
private const string StackLimitNotice = " This is only an upper limit; the actual height is also restricted by the game's construction range, so tall buildings may stop below this value. Requires restart. / 此值仅为上限,实际高度还受游戏建造范围限制,高层建筑可能达不到该层数;需要重启。";
private static ManualLogSource _logger;
public static ManualLogSource Logger => _logger;
private AssemblerVerticalConstruction()
{
_logger = ((BaseUnityPlugin)this).Logger;
}
public void Awake()
{
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Expected O, but got Unknown
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Expected O, but got Unknown
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Expected O, but got Unknown
//IL_009c: Unknown result type (might be due to invalid IL or missing references)
//IL_00a6: Expected O, but got Unknown
//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
//IL_00cd: Expected O, but got Unknown
AcceptableValueRange<int> val = new AcceptableValueRange<int>(2, 32);
ConfigEntry<int> obj = ((BaseUnityPlugin)this).Config.Bind<int>("Stack Limits", "AssemblerMaxStackCount", 12, new ConfigDescription("Maximum assembler stack count at the highest vertical construction technology level. This is only an upper limit; the actual height is also restricted by the game's construction range, so tall buildings may stop below this value. Requires restart. / 此值仅为上限,实际高度还受游戏建造范围限制,高层建筑可能达不到该层数;需要重启。", (AcceptableValueBase)(object)val, Array.Empty<object>()));
ConfigEntry<int> val2 = ((BaseUnityPlugin)this).Config.Bind<int>("Stack Limits", "SmelterMaxStackCount", 14, new ConfigDescription("Maximum smelter stack count at the highest vertical construction technology level. This is only an upper limit; the actual height is also restricted by the game's construction range, so tall buildings may stop below this value. Requires restart. / 此值仅为上限,实际高度还受游戏建造范围限制,高层建筑可能达不到该层数;需要重启。", (AcceptableValueBase)(object)val, Array.Empty<object>()));
ConfigEntry<int> val3 = ((BaseUnityPlugin)this).Config.Bind<int>("Stack Limits", "ChemicalPlantMaxStackCount", 9, new ConfigDescription("Maximum chemical plant stack count at the highest vertical construction technology level. This is only an upper limit; the actual height is also restricted by the game's construction range, so tall buildings may stop below this value. Requires restart. / 此值仅为上限,实际高度还受游戏建造范围限制,高层建筑可能达不到该层数;需要重启。", (AcceptableValueBase)(object)val, Array.Empty<object>()));
ConfigEntry<int> val4 = ((BaseUnityPlugin)this).Config.Bind<int>("Stack Limits", "OilRefineryMaxStackCount", 5, new ConfigDescription("Maximum oil refinery stack count at the highest vertical construction technology level. This is only an upper limit; the actual height is also restricted by the game's construction range, so tall buildings may stop below this value. Requires restart. / 此值仅为上限,实际高度还受游戏建造范围限制,高层建筑可能达不到该层数;需要重启。", (AcceptableValueBase)(object)val, Array.Empty<object>()));
ConfigEntry<int> val5 = ((BaseUnityPlugin)this).Config.Bind<int>("Stack Limits", "ParticleColliderMaxStackCount", 4, new ConfigDescription("Maximum miniature particle collider stack count at the highest vertical construction technology level. This is only an upper limit; the actual height is also restricted by the game's construction range, so tall buildings may stop below this value. Requires restart. / 此值仅为上限,实际高度还受游戏建造范围限制,高层建筑可能达不到该层数;需要重启。", (AcceptableValueBase)(object)val, Array.Empty<object>()));
RemoveLegacyResetConfig();
AssemblerPatches.ApplyMaxStackCounts(obj.Value, val2.Value, val3.Value, val4.Value, val5.Value);
ApplyKnownModCompatibility();
Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), (string)null);
}
private void RemoveLegacyResetConfig()
{
string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath;
if (!File.Exists(configFilePath) || File.ReadAllText(configFilePath).IndexOf("IsResetNextIds", StringComparison.Ordinal) < 0)
{
return;
}
bool saveOnConfigSet = ((BaseUnityPlugin)this).Config.SaveOnConfigSet;
try
{
((BaseUnityPlugin)this).Config.SaveOnConfigSet = false;
ConfigEntry<bool> val = ((BaseUnityPlugin)this).Config.Bind<bool>("config", "IsResetNextIds", false, "Obsolete internal repair option.");
((BaseUnityPlugin)this).Config.Remove(((ConfigEntryBase)val).Definition);
((BaseUnityPlugin)this).Config.Save();
}
finally
{
((BaseUnityPlugin)this).Config.SaveOnConfigSet = saveOnConfigSet;
}
}
public void Import(BinaryReader binaryReader)
{
if ((Object)(object)DSPGame.Game == (Object)null)
{
return;
}
int num = binaryReader.ReadInt32() * -1;
if (num < CurrentSavedataVersion)
{
Logger.LogInfo((object)$"Old save data version: read {num} current {CurrentSavedataVersion}");
Logger.LogInfo((object)"ResetNextIds");
AssemblerPatches.ResetNextIds();
return;
}
if (num != CurrentSavedataVersion)
{
Logger.LogWarning((object)$"Invalid save data version: read {num} current {CurrentSavedataVersion}");
Logger.LogInfo((object)"ResetNextIds");
AssemblerPatches.ResetNextIds();
return;
}
int num2 = binaryReader.ReadInt32();
if (num2 > AssemblerPatches.assemblerComponentEx.assemblerCapacity)
{
AssemblerPatches.assemblerComponentEx.SetAssemblerCapacity(num2);
}
for (int i = 0; i < num2; i++)
{
int num3 = binaryReader.ReadInt32();
for (int j = 0; j < num3; j++)
{
int nextId = binaryReader.ReadInt32();
AssemblerPatches.assemblerComponentEx.SetAssemblerNext(i, j, nextId);
}
}
}
public void Export(BinaryWriter binaryWriter)
{
if ((Object)(object)DSPGame.Game == (Object)null)
{
return;
}
binaryWriter.Write(CurrentSavedataVersion * -1);
binaryWriter.Write(AssemblerPatches.assemblerComponentEx.assemblerCapacity);
for (int i = 0; i < AssemblerPatches.assemblerComponentEx.assemblerCapacity; i++)
{
if (AssemblerPatches.assemblerComponentEx.assemblerNextIds[i] != null)
{
binaryWriter.Write(AssemblerPatches.assemblerComponentEx.assemblerNextIds[i].Length);
for (int j = 0; j < AssemblerPatches.assemblerComponentEx.assemblerNextIds[i].Length; j++)
{
binaryWriter.Write(AssemblerPatches.assemblerComponentEx.assemblerNextIds[i][j]);
}
}
else
{
binaryWriter.Write(0);
}
}
}
public void IntoOtherSave()
{
if (!((Object)(object)DSPGame.Game == (Object)null) && !DSPGame.IsMenuDemo)
{
Logger.LogInfo((object)"ResetNextIds");
AssemblerPatches.ResetNextIds();
}
}
private static void ApplyKnownModCompatibility()
{
if (Chainloader.PluginInfos.TryGetValue("com.menglei.dsp.fe", out var value))
{
Version version = value.Metadata.Version;
if (!(version == null) && !(version < FractionateEverythingStackingVersion))
{
AssemblerVerticalConstructionCompat.SetCargoStackLimit(20);
Logger.LogInfo((object)$"Detected FractionateEverything {version}; set stacked product transfer/buffer stack limit to {20}.");
}
}
}
}
public static class AssemblerVerticalConstructionCompat
{
public static int ProductTransferStack
{
get
{
return AssemblerPatches.assemblerComponentEx.ProductTransferStack;
}
set
{
AssemblerPatches.assemblerComponentEx.ProductTransferStack = value;
}
}
public static int ProductBufferStack
{
get
{
return AssemblerPatches.assemblerComponentEx.ProductBufferStack;
}
set
{
AssemblerPatches.assemblerComponentEx.ProductBufferStack = value;
}
}
public static void SetCargoStackLimit(int stack)
{
AssemblerPatches.assemblerComponentEx.SetCargoStackLimit(stack);
}
public static void RebuildAssemblerRelation(PlanetFactory factory, int assemblerId)
{
AssemblerPatches.RebuildAssemblerRelation(factory, assemblerId);
}
public static void RebuildFactoryRelations(PlanetFactory factory)
{
AssemblerPatches.RebuildFactoryRelations(factory);
}
public static void RebuildAllRelations()
{
AssemblerPatches.ResetNextIds();
}
}
[HarmonyPatch]
internal class AssemblerPatches
{
private class ModelSetting
{
public bool multiLevelAllowPortsOrSlots;
public List<int> multiLevelAlternativeIds;
public List<bool> multiLevelAlternativeYawTransposes;
public Vector3 lapJoint;
public int[] multiLevelMaxBuildCount;
public ModelSetting(bool multiLevelAllowPortsOrSlots, List<int> multiLevelAlternativeIds, List<bool> multiLevelAlternativeYawTransposes, Vector3 lapJoint, int[] multiLevelMaxBuildCount)
{
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
this.multiLevelAllowPortsOrSlots = multiLevelAllowPortsOrSlots;
this.multiLevelAlternativeIds = multiLevelAlternativeIds;
this.multiLevelAlternativeYawTransposes = multiLevelAlternativeYawTransposes;
this.lapJoint = lapJoint;
this.multiLevelMaxBuildCount = multiLevelMaxBuildCount;
}
}
private static readonly ModelSetting AssemblerSetting = new ModelSetting(multiLevelAllowPortsOrSlots: false, new List<int> { 2303, 2304, 2305, 2318 }, new List<bool> { false, false, false, false }, new Vector3(0f, 5.05f, 0f), new int[7] { 2, 4, 6, 8, 10, 11, 12 });
private static readonly ModelSetting SmelterSetting = new ModelSetting(multiLevelAllowPortsOrSlots: false, new List<int> { 2302, 2315, 2319, 6230 }, new List<bool> { false, false, false, false }, new Vector3(0f, 4.3f, 0f), new int[7] { 2, 4, 6, 8, 10, 12, 14 });
private static readonly ModelSetting ChemicalPlantSetting = new ModelSetting(multiLevelAllowPortsOrSlots: false, new List<int> { 2309, 2317 }, new List<bool> { false, false }, new Vector3(0f, 6.85f, 0f), new int[7] { 2, 4, 5, 6, 7, 8, 9 });
private static readonly ModelSetting OilRefinerySetting = new ModelSetting(multiLevelAllowPortsOrSlots: false, new List<int> { 2308 }, new List<bool> { false }, new Vector3(0f, 11.8f, 0f), new int[7] { 1, 2, 2, 3, 3, 4, 5 });
private static readonly ModelSetting MiniatureParticleColliderSetting = new ModelSetting(multiLevelAllowPortsOrSlots: false, new List<int> { 2310 }, new List<bool> { false }, new Vector3(0f, 15.2f, 0f), new int[7] { 1, 2, 2, 3, 3, 3, 4 });
private static readonly Dictionary<int, ModelSetting> ModelSettingDict = new Dictionary<int, ModelSetting>
{
{ 2303, AssemblerSetting },
{ 2304, AssemblerSetting },
{ 2305, AssemblerSetting },
{ 2318, AssemblerSetting },
{ 2302, SmelterSetting },
{ 2315, SmelterSetting },
{ 2319, SmelterSetting },
{ 6230, SmelterSetting },
{ 2309, ChemicalPlantSetting },
{ 2317, ChemicalPlantSetting },
{ 2308, OilRefinerySetting },
{ 2310, MiniatureParticleColliderSetting }
};
public static AssemblerComponentEx assemblerComponentEx = new AssemblerComponentEx();
public static void ApplyMaxStackCounts(int assembler, int smelter, int chemicalPlant, int oilRefinery, int particleCollider)
{
ApplyMaxStackCount(AssemblerSetting, assembler);
ApplyMaxStackCount(SmelterSetting, smelter);
ApplyMaxStackCount(ChemicalPlantSetting, chemicalPlant);
ApplyMaxStackCount(OilRefinerySetting, oilRefinery);
ApplyMaxStackCount(MiniatureParticleColliderSetting, particleCollider);
}
private static void ApplyMaxStackCount(ModelSetting setting, int maxStackCount)
{
int[] multiLevelMaxBuildCount = setting.multiLevelMaxBuildCount;
int num = multiLevelMaxBuildCount.Length - 1;
for (int i = 0; i < num; i++)
{
if (multiLevelMaxBuildCount[i] > maxStackCount)
{
multiLevelMaxBuildCount[i] = maxStackCount;
}
}
multiLevelMaxBuildCount[num] = maxStackCount;
}
public static void RebuildAssemblerRelation(PlanetFactory factory, int assemblerId)
{
assemblerComponentEx.RebuildAssemblerRelation(factory, assemblerId);
}
public static void RebuildFactoryRelations(PlanetFactory factory)
{
if (factory == null || factory.factorySystem == null)
{
return;
}
FactorySystem factorySystem = factory.factorySystem;
AssemblerComponent[] assemblerPool = factorySystem.assemblerPool;
int index = factory.index;
int requiredCapacity = assemblerPool.Length;
assemblerComponentEx.ClearAssemblerArray(index, requiredCapacity);
int[] array = assemblerComponentEx.assemblerNextIds[index];
int[] array2 = new int[array.Length];
int assemblerCursor = factorySystem.assemblerCursor;
bool flag = default(bool);
int num = default(int);
int num2 = default(int);
for (int i = 1; i < assemblerCursor; i++)
{
if (assemblerPool[i].id != i)
{
continue;
}
int entityId = assemblerPool[i].entityId;
if (entityId <= 0)
{
continue;
}
factory.ReadObjectConn(entityId, 15, ref flag, ref num, ref num2);
if (flag && num > 0 && num < factory.entityPool.Length)
{
int assemblerId = factory.entityPool[num].assemblerId;
if (assemblerId > 0 && assemblerId < assemblerPool.Length && assemblerPool[assemblerId].id == assemblerId)
{
array[i] = assemblerId;
array2[assemblerId] = i;
}
}
}
for (int j = 1; j < assemblerCursor; j++)
{
if (array2[j] == 0 && assemblerPool[j].id == j)
{
for (int num3 = array[j]; num3 != 0; num3 = array[num3])
{
AssemblerComponentEx.FindRecipeIdForBuild(factorySystem, num3);
}
}
}
}
public static void ResetNextIds()
{
for (int i = 0; i < GameMain.data.factories.Length; i++)
{
if (GameMain.data.factories[i] != null)
{
RebuildFactoryRelations(GameMain.data.factories[i]);
}
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(ItemProto), "Preload")]
private static void PreloadPatch(ItemProto __instance, int _index)
{
//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
ModelProto val = LDB.models.modelArray[__instance.ModelIndex];
if (val == null || val.prefabDesc == null || !val.prefabDesc.isAssembler || !ModelSettingDict.TryGetValue(((Proto)__instance).ID, out var value))
{
return;
}
LDB.models.modelArray[__instance.ModelIndex].prefabDesc.multiLevel = true;
LDB.models.modelArray[__instance.ModelIndex].prefabDesc.multiLevelAllowPortsOrSlots = value.multiLevelAllowPortsOrSlots;
LDB.models.modelArray[__instance.ModelIndex].prefabDesc.lapJoint = value.lapJoint;
int num = value.multiLevelAlternativeIds.FindIndex((int item) => item == ((Proto)__instance).ID);
if (num >= 0)
{
int[] array = new int[value.multiLevelAlternativeIds.Count - 1];
bool[] array2 = new bool[value.multiLevelAlternativeIds.Count - 1];
int num2 = 0;
for (int num3 = 0; num3 < value.multiLevelAlternativeIds.Count; num3++)
{
if (num3 != num)
{
array[num2] = value.multiLevelAlternativeIds[num3];
array2[num2] = value.multiLevelAlternativeYawTransposes[num3];
num2++;
}
}
LDB.models.modelArray[__instance.ModelIndex].prefabDesc.multiLevelAlternativeIds = array;
LDB.models.modelArray[__instance.ModelIndex].prefabDesc.multiLevelAlternativeYawTransposes = array2;
}
else
{
LDB.models.modelArray[__instance.ModelIndex].prefabDesc.multiLevelAlternativeIds = value.multiLevelAlternativeIds.ToArray();
LDB.models.modelArray[__instance.ModelIndex].prefabDesc.multiLevelAlternativeYawTransposes = value.multiLevelAlternativeYawTransposes.ToArray();
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(FactorySystem), "SetAssemblerCapacity")]
private static bool SetAssemblerCapacityPatch(FactorySystem __instance, int newCapacity)
{
int index = __instance.factory.index;
assemblerComponentEx.EnsureAssemblerArray(index, newCapacity);
return true;
}
[HarmonyPrefix]
[HarmonyPatch(typeof(PlanetFactory), "ApplyInsertTarget")]
public static bool ApplyInsertTargetPatch(PlanetFactory __instance, int entityId, int insertTarget, int slotId, int offset)
{
if (entityId != 0)
{
if (insertTarget < 0)
{
Assert.CannotBeReached();
insertTarget = 0;
}
else
{
bool flag = default(bool);
int num = default(int);
int num2 = default(int);
__instance.ReadObjectConn(entityId, 15, ref flag, ref num, ref num2);
if (!flag || num != insertTarget)
{
int num3 = insertTarget;
insertTarget = entityId;
entityId = num3;
}
int assemblerId = __instance.entityPool[entityId].assemblerId;
if (assemblerId > 0 && __instance.entityPool[insertTarget].assemblerId > 0)
{
assemblerComponentEx.SetAssemblerInsertTarget(__instance, assemblerId, insertTarget);
}
}
}
return true;
}
[HarmonyPrefix]
[HarmonyPatch(typeof(PlanetFactory), "ApplyEntityDisconnection")]
public static bool ApplyEntityDisconnectionPatch(PlanetFactory __instance, int otherEntityId, int removingEntityId, int otherSlotId, int removingSlotId)
{
if (otherEntityId == 0)
{
return true;
}
int assemblerId = __instance.entityPool[otherEntityId].assemblerId;
if (assemblerId > 0)
{
int assemblerId2 = __instance.entityPool[removingEntityId].assemblerId;
if (assemblerId2 > 0)
{
assemblerComponentEx.UnsetAssemblerInsertTarget(__instance, assemblerId, assemblerId2);
}
}
return true;
}
[HarmonyPostfix]
[HarmonyPatch(typeof(PlanetFactory), "CreateEntityLogicComponents")]
public static void CreateEntityLogicComponentsPatch(PlanetFactory __instance, int entityId, PrefabDesc desc, int prebuildId)
{
if (entityId != 0 && desc.isAssembler)
{
int assemblerId = __instance.entityPool[entityId].assemblerId;
assemblerComponentEx.RebuildAssemblerRelation(__instance, assemblerId);
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(GameLogic), "FactorySystemLabOutputToNext")]
public static void AssemblerOutputToNextPatch(PlanetFactory[] ___factories, int ___factoryCount, long ___timei)
{
UpdateAssemblerOutputToNext(___factories, ___factoryCount, 0, 1, ___timei + 1, useMutex: false);
}
[HarmonyPostfix]
[HarmonyPatch(typeof(GameLogic), "FactorySystemLabOutputToNext_Parallel")]
public static void AssemblerOutputToNextParallelPatch(int threadOrdinal, int threadCount, PlanetFactory[] ___factories, int ___factoryCount, long ___timei)
{
UpdateAssemblerOutputToNext(___factories, ___factoryCount, threadOrdinal, threadCount, ___timei + 1, useMutex: true);
}
private static void UpdateAssemblerOutputToNext(PlanetFactory[] factories, int factoryCount, int threadOrdinal, int threadCount, long transferTick, bool useMutex)
{
if (factoryCount <= 0 || threadCount <= 0)
{
return;
}
for (int i = 0; i < factoryCount; i++)
{
PlanetFactory val = factories[i];
FactorySystem factorySystem = val.factorySystem;
AssemblerComponent[] assemblerPool = factorySystem.assemblerPool;
int assemblerCursor = factorySystem.assemblerCursor;
int index = val.index;
int[] nextIds = assemblerComponentEx.GetNextIds(index);
if (nextIds == null)
{
continue;
}
int num = assemblerCursor - 1;
int num2 = 1 + num * threadOrdinal / threadCount;
int num3 = 1 + num * (threadOrdinal + 1) / threadCount;
if (num3 > nextIds.Length)
{
num3 = nextIds.Length;
}
for (int j = num2; j < num3; j++)
{
int num4 = nextIds[j];
if (num4 > 0)
{
assemblerComponentEx.UpdateOutputToNext(val, index, j, assemblerPool, num4, transferTick, useMutex);
}
}
}
}
public static void SyncAssemblerFunctions(FactorySystem factorySystem, Player player, int assemblerId)
{
int entityId = factorySystem.assemblerPool[assemblerId].entityId;
if (entityId == 0)
{
return;
}
int num = entityId;
bool flag = default(bool);
int num2 = default(int);
int num3 = default(int);
do
{
factorySystem.factory.ReadObjectConn(num, 14, ref flag, ref num2, ref num3);
num = num2;
if (num <= 0)
{
continue;
}
int assemblerId2 = factorySystem.factory.entityPool[num].assemblerId;
if (assemblerId2 <= 0 || factorySystem.assemblerPool[assemblerId2].id != assemblerId2)
{
continue;
}
if (factorySystem.assemblerPool[assemblerId].recipeId > 0)
{
if (factorySystem.assemblerPool[assemblerId2].recipeId != factorySystem.assemblerPool[assemblerId].recipeId)
{
factorySystem.TakeBackItems_Assembler(player, assemblerId2);
((AssemblerComponent)(ref factorySystem.assemblerPool[assemblerId2])).SetRecipe(factorySystem.assemblerPool[assemblerId].recipeId, factorySystem.factory.entitySignPool);
}
}
else if (factorySystem.assemblerPool[assemblerId2].recipeId != 0)
{
factorySystem.TakeBackItems_Assembler(player, assemblerId2);
((AssemblerComponent)(ref factorySystem.assemblerPool[assemblerId2])).SetRecipe(0, factorySystem.factory.entitySignPool);
}
}
while (num != 0);
num = entityId;
bool flag2 = default(bool);
int num4 = default(int);
int num5 = default(int);
do
{
factorySystem.factory.ReadObjectConn(num, 15, ref flag2, ref num4, ref num5);
num = num4;
if (num <= 0)
{
continue;
}
int assemblerId3 = factorySystem.factory.entityPool[num].assemblerId;
if (assemblerId3 <= 0 || factorySystem.assemblerPool[assemblerId3].id != assemblerId3)
{
continue;
}
if (factorySystem.assemblerPool[assemblerId].recipeId > 0)
{
if (factorySystem.assemblerPool[assemblerId3].recipeId != factorySystem.assemblerPool[assemblerId].recipeId)
{
factorySystem.TakeBackItems_Assembler(factorySystem.factory.gameData.mainPlayer, assemblerId3);
((AssemblerComponent)(ref factorySystem.assemblerPool[assemblerId3])).SetRecipe(factorySystem.assemblerPool[assemblerId].recipeId, factorySystem.factory.entitySignPool);
}
}
else if (factorySystem.assemblerPool[assemblerId3].recipeId != 0)
{
factorySystem.TakeBackItems_Assembler(factorySystem.factory.gameData.mainPlayer, assemblerId3);
((AssemblerComponent)(ref factorySystem.assemblerPool[assemblerId3])).SetRecipe(0, factorySystem.factory.entitySignPool);
}
}
while (num != 0);
}
[HarmonyPostfix]
[HarmonyPatch(typeof(UIAssemblerWindow), "OnRecipeResetClick")]
public static void OnRecipeResetClickPatch(UIAssemblerWindow __instance)
{
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
if (__instance.assemblerId != 0 && __instance.factory != null && __instance.factorySystem.assemblerPool[__instance.assemblerId].id == __instance.assemblerId)
{
SyncAssemblerFunctions(__instance.factorySystem, __instance.player, __instance.assemblerId);
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(UIAssemblerWindow), "OnRecipePickerReturn")]
public static void OnRecipePickerReturnPatch(UIAssemblerWindow __instance)
{
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
if (__instance.assemblerId != 0 && __instance.factory != null && __instance.factorySystem.assemblerPool[__instance.assemblerId].id == __instance.assemblerId)
{
SyncAssemblerFunctions(__instance.factorySystem, __instance.player, __instance.assemblerId);
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(UIAssemblerWindow), "OnIncSwitchClick")]
public static void OnIncSwitchClickPatch(UIAssemblerWindow __instance)
{
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
if (__instance.assemblerId != 0 && __instance.factory != null && __instance.factorySystem.assemblerPool[__instance.assemblerId].id == __instance.assemblerId)
{
SyncForceAccMode(__instance.factorySystem, __instance.assemblerId);
}
}
public static void SyncForceAccMode(FactorySystem factorySystem, int assemblerId)
{
int entityId = factorySystem.assemblerPool[assemblerId].entityId;
if (entityId == 0)
{
return;
}
bool forceAccMode = factorySystem.assemblerPool[assemblerId].forceAccMode;
int num = entityId;
bool flag = default(bool);
int num2 = default(int);
int num3 = default(int);
do
{
factorySystem.factory.ReadObjectConn(num, 14, ref flag, ref num2, ref num3);
num = num2;
if (num <= 0)
{
continue;
}
int assemblerId2 = factorySystem.factory.entityPool[num].assemblerId;
if (assemblerId2 > 0 && factorySystem.assemblerPool[assemblerId2].id == assemblerId2)
{
RecipeExecuteData recipeExecuteData = factorySystem.assemblerPool[assemblerId2].recipeExecuteData;
if (recipeExecuteData != null && recipeExecuteData.productive)
{
factorySystem.assemblerPool[assemblerId2].forceAccMode = forceAccMode;
}
}
}
while (num != 0);
num = entityId;
bool flag2 = default(bool);
int num4 = default(int);
int num5 = default(int);
do
{
factorySystem.factory.ReadObjectConn(num, 15, ref flag2, ref num4, ref num5);
num = num4;
if (num <= 0)
{
continue;
}
int assemblerId3 = factorySystem.factory.entityPool[num].assemblerId;
if (assemblerId3 > 0 && factorySystem.assemblerPool[assemblerId3].id == assemblerId3)
{
RecipeExecuteData recipeExecuteData2 = factorySystem.assemblerPool[assemblerId3].recipeExecuteData;
if (recipeExecuteData2 != null && recipeExecuteData2.productive)
{
factorySystem.assemblerPool[assemblerId3].forceAccMode = forceAccMode;
}
}
}
while (num != 0);
}
[HarmonyPostfix]
[HarmonyPatch(typeof(BuildingParameters), "PasteToFactoryObject")]
public static void PasteToFactoryObjectPatch(BuildingParameters __instance, int objectId, PlanetFactory factory, bool __result)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Invalid comparison between Unknown and I4
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
if (__result && objectId > 0 && (int)__instance.type == 5)
{
int assemblerId = factory.entityPool[objectId].assemblerId;
if (assemblerId > 0 && factory.factorySystem.assemblerPool[assemblerId].id == assemblerId && factory.factorySystem.assemblerPool[assemblerId].recipeId == __instance.recipeId)
{
SyncAssemblerFunctions(factory.factorySystem, factory.gameData.mainPlayer, assemblerId);
SyncForceAccMode(factory.factorySystem, assemblerId);
assemblerComponentEx.RebuildAssemblerRelation(factory, assemblerId, synchronizeRecipe: false);
}
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(BuildTool_Click), "CheckBuildConditions")]
public static void CheckBuildConditionsPatch(BuildTool_Click __instance, ref bool __result)
{
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_013b: Unknown result type (might be due to invalid IL or missing references)
//IL_0142: Invalid comparison between Unknown and I4
//IL_0108: Unknown result type (might be due to invalid IL or missing references)
if (((BuildTool)__instance).buildPreviews.Count == 0)
{
return;
}
GameHistoryData history = ((BuildTool)__instance).actionBuild.history;
bool flag = true;
bool flag2 = default(bool);
int num5 = default(int);
int num6 = default(int);
for (int i = 0; i < ((BuildTool)__instance).buildPreviews.Count; i++)
{
BuildPreview val = ((BuildTool)__instance).buildPreviews[i];
if ((int)val.condition != 0 || !val.desc.isAssembler || !val.desc.multiLevel)
{
continue;
}
int iD = ((Proto)val.item).ID;
if (!ModelSettingDict.TryGetValue(iD, out var value))
{
continue;
}
int num = history.storageLevel - 2;
if (num >= value.multiLevelMaxBuildCount.Length)
{
continue;
}
int num2 = value.multiLevelMaxBuildCount[num];
int num3 = value.multiLevelMaxBuildCount[6];
int num4 = 0;
if (val.inputObjId != 0)
{
((BuildTool)__instance).factory.ReadObjectConn(val.inputObjId, 14, ref flag2, ref num5, ref num6);
while (num5 != 0)
{
num4++;
((BuildTool)__instance).factory.ReadObjectConn(num5, 14, ref flag2, ref num5, ref num6);
}
}
if (num2 >= 2 && num4 >= num2 - 1)
{
flag = num2 >= num3;
val.condition = (EBuildCondition)40;
}
}
for (int j = 0; j < ((BuildTool)__instance).buildPreviews.Count; j++)
{
BuildPreview val2 = ((BuildTool)__instance).buildPreviews[j];
if ((int)val2.condition == 40)
{
((BuildTool)__instance).actionBuild.model.cursorState = -1;
((BuildTool)__instance).actionBuild.model.cursorText = val2.conditionText;
if (!flag)
{
BuildModel model = ((BuildTool)__instance).actionBuild.model;
model.cursorText += Localization.Translate("垂直建造可升级");
}
if (!VFInput.onGUI)
{
UICursor.SetCursor((ECursor)6);
}
__result = false;
break;
}
}
}
}