Decompiled source of Weaver v1.1.5
Weaver.dll
Decompiled a week ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using PowerNetworkStructures; using UnityEngine; using Weaver.Benchmarking; using Weaver.Extensions; using Weaver.FatoryGraphs; using Weaver.Optimizations.LinearDataAccess; using Weaver.Optimizations.LinearDataAccess.Assemblers; using Weaver.Optimizations.LinearDataAccess.Fractionators; using Weaver.Optimizations.LinearDataAccess.Inserters; using Weaver.Optimizations.LinearDataAccess.Inserters.Types; using Weaver.Optimizations.LinearDataAccess.Labs; using Weaver.Optimizations.LinearDataAccess.Labs.Producing; using Weaver.Optimizations.LinearDataAccess.Labs.Researching; using Weaver.Optimizations.LinearDataAccess.PowerSystems; using Weaver.Optimizations.LinearDataAccess.Spraycoaters; using Weaver.Optimizations.LinearDataAccess.WorkDistributors; using Weaver.Optimizations.Statistics; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("Weaver")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.0.1.0")] [assembly: AssemblyInformationalVersion("0.0.1+0f3c743f92fcb1f820dc47586166d95aa67bbe2e")] [assembly: AssemblyProduct("Weaver")] [assembly: AssemblyTitle("Weaver")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.1.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class RequiresLocationAttribute : Attribute { } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Weaver { internal static class HarmonyConstants { public const bool EXECUTE_ORIGINAL_METHOD = true; public const bool SKIP_ORIGINAL_METHOD = false; } public struct HashCode { private static readonly uint s_seed = 5122634u; private const uint Prime1 = 2654435761u; private const uint Prime2 = 2246822519u; private const uint Prime3 = 3266489917u; private const uint Prime4 = 668265263u; private const uint Prime5 = 374761393u; private uint _v1; private uint _v2; private uint _v3; private uint _v4; private uint _queue1; private uint _queue2; private uint _queue3; private uint _length; [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void Initialize(out uint v1, out uint v2, out uint v3, out uint v4) { v1 = (uint)((int)s_seed + -1640531535 + -2048144777); v2 = s_seed + 2246822519u; v3 = s_seed; v4 = s_seed - 2654435761u; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static uint Round(uint hash, uint input) { return RotateLeft(hash + (uint)((int)input * -2048144777), 13) * 2654435761u; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static uint QueueRound(uint hash, uint queuedValue) { return RotateLeft(hash + (uint)((int)queuedValue * -1028477379), 17) * 668265263; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static uint MixState(uint v1, uint v2, uint v3, uint v4) { return RotateLeft(v1, 1) + RotateLeft(v2, 7) + RotateLeft(v3, 12) + RotateLeft(v4, 18); } private static uint MixEmptyState() { return s_seed + 374761393; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static uint MixFinal(uint hash) { hash ^= hash >> 15; hash *= 2246822519u; hash ^= hash >> 13; hash *= 3266489917u; hash ^= hash >> 16; return hash; } public void Add<T>(T value) { Add(value?.GetHashCode() ?? 0); } public void Add<T>(T value, IEqualityComparer<T> comparer) { Add((value != null) ? (comparer?.GetHashCode(value) ?? value.GetHashCode()) : 0); } private void Add(int value) { uint num = _length++; switch (num % 4) { case 0u: _queue1 = (uint)value; return; case 1u: _queue2 = (uint)value; return; case 2u: _queue3 = (uint)value; return; } if (num == 3) { Initialize(out _v1, out _v2, out _v3, out _v4); } _v1 = Round(_v1, _queue1); _v2 = Round(_v2, _queue2); _v3 = Round(_v3, _queue3); _v4 = Round(_v4, (uint)value); } public int ToHashCode() { uint length = _length; uint num = length % 4; uint num2 = ((length < 4) ? MixEmptyState() : MixState(_v1, _v2, _v3, _v4)); num2 += length * 4; if (num != 0) { num2 = QueueRound(num2, _queue1); if (num > 1) { num2 = QueueRound(num2, _queue2); if (num > 2) { num2 = QueueRound(num2, _queue3); } } } return (int)MixFinal(num2); } public static uint RotateLeft(uint value, int offset) { return (value << offset) | (value >> 32 - offset); } } public static class ReflectionExtensions { public static void RaiseActionEvent<T>(this T instance, string eventName) { Delegate[] array = (typeof(T).GetField(eventName, BindingFlags.Instance | BindingFlags.NonPublic).GetValue(instance) as MulticastDelegate)?.GetInvocationList(); if (array != null && array.Length != 0) { WeaverFixes.Logger.LogInfo((object)("Raised event " + eventName)); Delegate[] array2 = array; for (int i = 0; i < array2.Length; i++) { array2[i].DynamicInvoke(); } } } } internal static class ModInfo { public const string Guid = "Weaver"; public const string Name = "Weaver"; public const string Version = "1.1.5"; } internal static class ModDependencies { public const string SampleAndHoldSimId = "starfi5h.plugin.SampleAndHoldSim"; } [BepInPlugin("Weaver", "Weaver", "1.1.5")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class WeaverFixes : BaseUnityPlugin { internal static ManualLogSource Logger = Logger.CreateLogSource("Weaver"); private void Awake() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown Harmony val = new Harmony("Weaver"); val.PatchAll(typeof(ProductionStatisticsPatches)); val.PatchAll(typeof(KillStatisticsPatches)); val.PatchAll(typeof(TrafficStatisticsPatches)); OptimizedStarCluster.EnableOptimization(val); } } public static class MyPluginInfo { public const string PLUGIN_GUID = "Weaver"; public const string PLUGIN_NAME = "Weaver"; public const string PLUGIN_VERSION = "0.0.1"; } } namespace Weaver.Optimizations.Statistics { public class CustomChartsPatches { [HarmonyPrefix] [HarmonyPatch(typeof(CustomCharts), "GameTick")] private static bool GameTick_Parallelize(CustomCharts __instance) { if (!GameMain.multithreadSystem.multithreadSystemEnable) { return true; } new ParallelOptions().MaxDegreeOfParallelism = GameMain.multithreadSystem.usedThreadCnt; StatPlan[] buffer = __instance.statPlans.buffer; int cursor = __instance.statPlans.cursor; Parallel.For(1, cursor, delegate(int i) { if (buffer[i] != null && buffer[i].id == i) { buffer[i].GameTick(); } }); return false; } } public class KillStatisticsPatches { [HarmonyPrefix] [HarmonyPatch(typeof(KillStatistics), "PrepareTick")] private static bool PrepareTick_Parallelize(KillStatistics __instance) { if (!GameMain.multithreadSystem.multithreadSystemEnable) { return true; } ParallelOptions parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = GameMain.multithreadSystem.usedThreadCnt }; Parallel.ForEach(__instance.starKillStatPool, parallelOptions, delegate(AstroKillStat x) { if (x != null) { x.PrepareTick(); } }); Parallel.ForEach(__instance.factoryKillStatPool, parallelOptions, delegate(AstroKillStat x) { if (x != null) { x.PrepareTick(); } }); AstroKillStat mechaKillStat = __instance.mechaKillStat; if (mechaKillStat != null) { mechaKillStat.PrepareTick(); } return false; } [HarmonyPrefix] [HarmonyPatch(typeof(KillStatistics), "GameTick")] private static bool GameTick_Parallelize(KillStatistics __instance, long time) { if (!GameMain.multithreadSystem.multithreadSystemEnable) { return true; } ParallelOptions parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = GameMain.multithreadSystem.usedThreadCnt }; Parallel.ForEach(__instance.starKillStatPool, parallelOptions, delegate(AstroKillStat x) { if (x != null) { x.GameTick(time); } }); Parallel.ForEach(__instance.factoryKillStatPool, parallelOptions, delegate(AstroKillStat x) { if (x != null) { x.GameTick(time); } }); AstroKillStat mechaKillStat = __instance.mechaKillStat; if (mechaKillStat != null) { mechaKillStat.GameTick(time); } return false; } [HarmonyPrefix] [HarmonyPatch(typeof(KillStatistics), "AfterTick")] private static bool AfterTick_Parallelize(KillStatistics __instance) { if (!GameMain.multithreadSystem.multithreadSystemEnable) { return true; } ParallelOptions parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = GameMain.multithreadSystem.usedThreadCnt }; Parallel.ForEach(__instance.starKillStatPool, parallelOptions, delegate(AstroKillStat x) { if (x != null) { x.AfterTick(); } }); Parallel.ForEach(__instance.factoryKillStatPool, parallelOptions, delegate(AstroKillStat x) { if (x != null) { x.AfterTick(); } }); AstroKillStat mechaKillStat = __instance.mechaKillStat; if (mechaKillStat != null) { mechaKillStat.AfterTick(); } return false; } } public class ProductionStatisticsPatches { [HarmonyPrefix] [HarmonyPatch(typeof(ProductionStatistics), "PrepareTick")] private static bool PrepareTick_Parallelize(ProductionStatistics __instance) { if (!GameMain.multithreadSystem.multithreadSystemEnable) { return true; } ParallelOptions parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = GameMain.multithreadSystem.usedThreadCnt }; Parallel.For(0, __instance.gameData.factoryCount, parallelOptions, delegate(int i) { FactorySystem factorySystem = GameMain.data.factories[i].factorySystem; if (factorySystem == null || factorySystem.labCursor > 1 || factorySystem.assemblerCursor > 1 || factorySystem.minerCursor > 1 || factorySystem.fractionatorCursor > 1 || factorySystem.ejectorCursor > 1 || factorySystem.siloCursor > 1) { __instance.factoryStatPool[i].PrepareTick(); } }); return false; } [HarmonyPrefix] [HarmonyPatch(typeof(ProductionStatistics), "GameTick")] private static bool GameTick_Parallelize(ProductionStatistics __instance, long time) { if (!GameMain.multithreadSystem.multithreadSystemEnable) { return true; } new ParallelOptions().MaxDegreeOfParallelism = GameMain.multithreadSystem.usedThreadCnt; Parallel.For(0, __instance.gameData.factoryCount, delegate(int i) { FactorySystem factorySystem = GameMain.data.factories[i].factorySystem; if (factorySystem == null || factorySystem.labCursor > 1 || factorySystem.assemblerCursor > 1 || factorySystem.minerCursor > 1 || factorySystem.fractionatorCursor > 1 || factorySystem.ejectorCursor > 1 || factorySystem.siloCursor > 1) { __instance.factoryStatPool[i].GameTick(time); if (__instance.factoryStatPool[i].itemChanged) { try { __instance.RaiseActionEvent<ProductionStatistics>("onItemChange"); } catch (Exception ex) { WeaverFixes.Logger.LogError((object)ex); } } } }); __instance.extraInfoCalculator.GameTick(); return false; } } public sealed class TrafficStatisticsPatches { private static bool[] _isStarUpdated; private static bool[] _isPlanetUpdated; [HarmonyPrefix] [HarmonyPatch(typeof(TrafficStatistics), "PrepareTick")] public static void PrepareTick(TrafficStatistics __instance, long time) { if (_isStarUpdated == null || __instance.starTrafficPool.Length != _isStarUpdated.Length) { _isStarUpdated = new bool[__instance.starTrafficPool.Length]; } if (_isPlanetUpdated == null || __instance.factoryTrafficPool.Length != _isPlanetUpdated.Length) { _isPlanetUpdated = new bool[__instance.factoryTrafficPool.Length]; } } [HarmonyPrefix] [HarmonyPatch(typeof(TrafficStatistics), "GameTick")] private static bool GameTick_Parallelize(TrafficStatistics __instance, long time) { if (!GameMain.multithreadSystem.multithreadSystemEnable) { return true; } ParallelOptions parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = GameMain.multithreadSystem.usedThreadCnt }; Parallel.For(0, __instance.starTrafficPool.Length, parallelOptions, delegate(int i) { AstroTrafficStat val2 = __instance.starTrafficPool[i]; if (val2 != null) { val2.GameTick(time); if (val2.itemChanged) { try { __instance.RaiseActionEvent<TrafficStatistics>("onItemChange"); } catch (Exception ex2) { WeaverFixes.Logger.LogError((object)ex2); } } } }); Parallel.For(0, __instance.factoryTrafficPool.Length, parallelOptions, delegate(int i) { AstroTrafficStat val = __instance.factoryTrafficPool[i]; if (val != null) { val.GameTick(time); if (val.itemChanged) { try { __instance.RaiseActionEvent<TrafficStatistics>("onItemChange"); } catch (Exception ex) { WeaverFixes.Logger.LogError((object)ex); } } } }); return false; } } } namespace Weaver.Optimizations.ObjectPools { public class ShrinkPools { private delegate TReturn PassStructAsRefFunc<TArgument, TReturn>(ArrayStructRef<TArgument> item) where TArgument : struct; private struct ArrayStructRef<T> where T : struct { private readonly T[] _array; private readonly int _index; public readonly ref T Value => ref _array[_index]; public ArrayStructRef(T[] array, int index) { _array = array; _index = index; } } private static int HasCalculatedData; private static bool HasOptimizedPools; [HarmonyPrefix] [HarmonyPatch(typeof(GameData), "GameTick")] private static void GameTick_DetectPoolHoles(GameData __instance) { if (DSPGame.IsMenuDemo || HasCalculatedData > 1) { return; } HasCalculatedData++; int totalSlots = 0; int usedSlots = 0; int unusedSlots = 0; int holes = 0; PlanetFactory[] factories = __instance.factories; foreach (PlanetFactory val in factories) { if (val == null) { continue; } if (val.factorySystem != null) { GatherPoolData<MinerComponent>(val.factorySystem.minerPool, (Func<MinerComponent, int>)((MinerComponent x) => x.id), ref totalSlots, ref usedSlots, ref unusedSlots, ref holes); GatherPoolData<InserterComponent>(val.factorySystem.inserterPool, (Func<InserterComponent, int>)((InserterComponent x) => x.id), ref totalSlots, ref usedSlots, ref unusedSlots, ref holes); GatherPoolData<AssemblerComponent>(val.factorySystem.assemblerPool, (Func<AssemblerComponent, int>)((AssemblerComponent x) => x.id), ref totalSlots, ref usedSlots, ref unusedSlots, ref holes); GatherPoolData<FractionatorComponent>(val.factorySystem.fractionatorPool, (Func<FractionatorComponent, int>)((FractionatorComponent x) => x.id), ref totalSlots, ref usedSlots, ref unusedSlots, ref holes); GatherPoolData<EjectorComponent>(val.factorySystem.ejectorPool, (Func<EjectorComponent, int>)((EjectorComponent x) => x.id), ref totalSlots, ref usedSlots, ref unusedSlots, ref holes); GatherPoolData<SiloComponent>(val.factorySystem.siloPool, (Func<SiloComponent, int>)((SiloComponent x) => x.id), ref totalSlots, ref usedSlots, ref unusedSlots, ref holes); GatherPoolData<LabComponent>(val.factorySystem.labPool, (Func<LabComponent, int>)((LabComponent x) => x.id), ref totalSlots, ref usedSlots, ref unusedSlots, ref holes); } if (val.factoryStorage != null) { GatherPoolDataForClass(val.factoryStorage.storagePool, (StorageComponent x) => x.id, ref totalSlots, ref usedSlots, ref unusedSlots, ref holes); GatherPoolData<TankComponent>(val.factoryStorage.tankPool, (Func<TankComponent, int>)((TankComponent x) => x.id), ref totalSlots, ref usedSlots, ref unusedSlots, ref holes); } if (val.cargoTraffic != null) { GatherPoolDataForClass(val.cargoTraffic.pathPool, (CargoPath x) => x.id, ref totalSlots, ref usedSlots, ref unusedSlots, ref holes); GatherPoolData<BeltComponent>(val.cargoTraffic.beltPool, (Func<BeltComponent, int>)((BeltComponent x) => x.id), ref totalSlots, ref usedSlots, ref unusedSlots, ref holes); GatherPoolData<SplitterComponent>(val.cargoTraffic.splitterPool, (Func<SplitterComponent, int>)((SplitterComponent x) => x.id), ref totalSlots, ref usedSlots, ref unusedSlots, ref holes); GatherPoolData<MonitorComponent>(val.cargoTraffic.monitorPool, (Func<MonitorComponent, int>)((MonitorComponent x) => x.id), ref totalSlots, ref usedSlots, ref unusedSlots, ref holes); GatherPoolData<SpraycoaterComponent>(val.cargoTraffic.spraycoaterPool, (Func<SpraycoaterComponent, int>)((SpraycoaterComponent x) => x.id), ref totalSlots, ref usedSlots, ref unusedSlots, ref holes); GatherPoolData<PilerComponent>(val.cargoTraffic.pilerPool, (Func<PilerComponent, int>)((PilerComponent x) => x.id), ref totalSlots, ref usedSlots, ref unusedSlots, ref holes); } if (val.transport != null) { GatherPoolDataForClass(val.transport.stationPool, (StationComponent x) => x.id, ref totalSlots, ref usedSlots, ref unusedSlots, ref holes); GatherPoolDataForClass(val.transport.dispenserPool, (DispenserComponent x) => x.id, ref totalSlots, ref usedSlots, ref unusedSlots, ref holes); } if (val.powerSystem != null) { GatherPoolData<PowerGeneratorComponent>(val.powerSystem.genPool, (Func<PowerGeneratorComponent, int>)((PowerGeneratorComponent x) => x.id), ref totalSlots, ref usedSlots, ref unusedSlots, ref holes); GatherPoolData<PowerNodeComponent>(val.powerSystem.nodePool, (Func<PowerNodeComponent, int>)((PowerNodeComponent x) => x.id), ref totalSlots, ref usedSlots, ref unusedSlots, ref holes); GatherPoolData<PowerConsumerComponent>(val.powerSystem.consumerPool, (Func<PowerConsumerComponent, int>)((PowerConsumerComponent x) => x.id), ref totalSlots, ref usedSlots, ref unusedSlots, ref holes); GatherPoolData<PowerAccumulatorComponent>(val.powerSystem.accPool, (Func<PowerAccumulatorComponent, int>)((PowerAccumulatorComponent x) => x.id), ref totalSlots, ref usedSlots, ref unusedSlots, ref holes); GatherPoolData<PowerExchangerComponent>(val.powerSystem.excPool, (Func<PowerExchangerComponent, int>)((PowerExchangerComponent x) => x.id), ref totalSlots, ref usedSlots, ref unusedSlots, ref holes); GatherPoolDataForClass(val.powerSystem.netPool, (PowerNetwork x) => x.id, ref totalSlots, ref usedSlots, ref unusedSlots, ref holes); } } WeaverFixes.Logger.LogInfo((object)$"Total: {totalSlots:N0}"); WeaverFixes.Logger.LogInfo((object)$"Used: {usedSlots:N0}"); WeaverFixes.Logger.LogInfo((object)$"Unused: {unusedSlots:N0}"); WeaverFixes.Logger.LogInfo((object)$"Holes: {holes:N0}"); WeaverFixes.Logger.LogInfo((object)$"Used Ratio: {(float)usedSlots / (float)totalSlots * 100f:N2}%"); } [HarmonyPostfix] [HarmonyPatch(typeof(GameData), "GameTick")] private static void GameTick_OptimizePools(GameData __instance) { if (DSPGame.IsMenuDemo || HasOptimizedPools) { return; } HasOptimizedPools = true; PlanetFactory[] factories = __instance.factories; foreach (PlanetFactory val in factories) { if (val == null) { continue; } if (val.factorySystem != null) { ResizePool<MinerComponent>(ref val.factorySystem.minerPool, (PassStructAsRefFunc<MinerComponent, int>)((ArrayStructRef<MinerComponent> x) => x.Value.id), (Action<int>)val.factorySystem.SetMinerCapacity, ref val.factorySystem.minerCursor, ref val.factorySystem.minerCapacity, ref val.factorySystem.minerRecycle, ref val.factorySystem.minerRecycleCursor); ResizePool<InserterComponent>(ref val.factorySystem.inserterPool, (PassStructAsRefFunc<InserterComponent, int>)((ArrayStructRef<InserterComponent> x) => x.Value.id), (Action<int>)val.factorySystem.SetInserterCapacity, ref val.factorySystem.inserterCursor, ref val.factorySystem.inserterCapacity, ref val.factorySystem.inserterRecycle, ref val.factorySystem.inserterRecycleCursor); ResizePool<AssemblerComponent>(ref val.factorySystem.assemblerPool, (PassStructAsRefFunc<AssemblerComponent, int>)((ArrayStructRef<AssemblerComponent> x) => x.Value.id), (Action<int>)val.factorySystem.SetAssemblerCapacity, ref val.factorySystem.assemblerCursor, ref val.factorySystem.assemblerCapacity, ref val.factorySystem.assemblerRecycle, ref val.factorySystem.assemblerRecycleCursor); ResizePool<FractionatorComponent>(ref val.factorySystem.fractionatorPool, (PassStructAsRefFunc<FractionatorComponent, int>)((ArrayStructRef<FractionatorComponent> x) => x.Value.id), (Action<int>)val.factorySystem.SetFractionatorCapacity, ref val.factorySystem.fractionatorCursor, ref val.factorySystem.fractionatorCapacity, ref val.factorySystem.fractionatorRecycle, ref val.factorySystem.fractionatorRecycleCursor); ResizePool<EjectorComponent>(ref val.factorySystem.ejectorPool, (PassStructAsRefFunc<EjectorComponent, int>)((ArrayStructRef<EjectorComponent> x) => x.Value.id), (Action<int>)val.factorySystem.SetEjectorCapacity, ref val.factorySystem.ejectorCursor, ref val.factorySystem.ejectorCapacity, ref val.factorySystem.ejectorRecycle, ref val.factorySystem.ejectorRecycleCursor); ResizePool<SiloComponent>(ref val.factorySystem.siloPool, (PassStructAsRefFunc<SiloComponent, int>)((ArrayStructRef<SiloComponent> x) => x.Value.id), (Action<int>)val.factorySystem.SetSiloCapacity, ref val.factorySystem.siloCursor, ref val.factorySystem.siloCapacity, ref val.factorySystem.siloRecycle, ref val.factorySystem.siloRecycleCursor); ResizePool<LabComponent>(ref val.factorySystem.labPool, (PassStructAsRefFunc<LabComponent, int>)((ArrayStructRef<LabComponent> x) => x.Value.id), (Action<int>)val.factorySystem.SetLabCapacity, ref val.factorySystem.labCursor, ref val.factorySystem.labCapacity, ref val.factorySystem.labRecycle, ref val.factorySystem.labRecycleCursor); } if (val.factoryStorage != null) { ResizePoolForClass(ref val.factoryStorage.storagePool, (Func<StorageComponent, int>)((StorageComponent x) => x.id), (Action<int>)val.factoryStorage.SetStorageCapacity, ref val.factoryStorage.storageCursor, ref val.factoryStorage.storageCapacity, ref val.factoryStorage.storageRecycle, ref val.factoryStorage.storageRecycleCursor); ResizePool<TankComponent>(ref val.factoryStorage.tankPool, (PassStructAsRefFunc<TankComponent, int>)((ArrayStructRef<TankComponent> x) => x.Value.id), (Action<int>)val.factoryStorage.SetTankCapacity, ref val.factoryStorage.tankCursor, ref val.factoryStorage.tankCapacity, ref val.factoryStorage.tankRecycle, ref val.factoryStorage.tankRecycleCursor); } if (val.cargoTraffic != null) { ResizePoolForClass(ref val.cargoTraffic.pathPool, (Func<CargoPath, int>)((CargoPath x) => x.id), (Action<int>)val.cargoTraffic.SetPathCapacity, ref val.cargoTraffic.pathCursor, ref val.cargoTraffic.pathCapacity, ref val.cargoTraffic.pathRecycle, ref val.cargoTraffic.pathRecycleCursor); ResizePool<BeltComponent>(ref val.cargoTraffic.beltPool, (PassStructAsRefFunc<BeltComponent, int>)((ArrayStructRef<BeltComponent> x) => x.Value.id), (Action<int>)val.cargoTraffic.SetBeltCapacity, ref val.cargoTraffic.beltCursor, ref val.cargoTraffic.beltCapacity, ref val.cargoTraffic.beltRecycle, ref val.cargoTraffic.beltRecycleCursor); ResizePool<SplitterComponent>(ref val.cargoTraffic.splitterPool, (PassStructAsRefFunc<SplitterComponent, int>)((ArrayStructRef<SplitterComponent> x) => x.Value.id), (Action<int>)val.cargoTraffic.SetSplitterCapacity, ref val.cargoTraffic.splitterCursor, ref val.cargoTraffic.splitterCapacity, ref val.cargoTraffic.splitterRecycle, ref val.cargoTraffic.splitterRecycleCursor); ResizePool<MonitorComponent>(ref val.cargoTraffic.monitorPool, (PassStructAsRefFunc<MonitorComponent, int>)((ArrayStructRef<MonitorComponent> x) => x.Value.id), (Action<int>)val.cargoTraffic.SetMonitorCapacity, ref val.cargoTraffic.monitorCursor, ref val.cargoTraffic.monitorCapacity, ref val.cargoTraffic.monitorRecycle, ref val.cargoTraffic.monitorRecycleCursor); ResizePool<SpraycoaterComponent>(ref val.cargoTraffic.spraycoaterPool, (PassStructAsRefFunc<SpraycoaterComponent, int>)((ArrayStructRef<SpraycoaterComponent> x) => x.Value.id), (Action<int>)val.cargoTraffic.SetSpraycoaterCapacity, ref val.cargoTraffic.spraycoaterCursor, ref val.cargoTraffic.spraycoaterCapacity, ref val.cargoTraffic.spraycoaterRecycle, ref val.cargoTraffic.spraycoaterRecycleCursor); ResizePool<PilerComponent>(ref val.cargoTraffic.pilerPool, (PassStructAsRefFunc<PilerComponent, int>)((ArrayStructRef<PilerComponent> x) => x.Value.id), (Action<int>)val.cargoTraffic.SetPilerCapacity, ref val.cargoTraffic.pilerCursor, ref val.cargoTraffic.pilerCapacity, ref val.cargoTraffic.pilerRecycle, ref val.cargoTraffic.pilerRecycleCursor); } if (val.transport != null) { ResizePoolForClass(ref val.transport.stationPool, (Func<StationComponent, int>)((StationComponent x) => x.id), (Action<int>)val.transport.SetStationCapacity, ref val.transport.stationCursor, ref val.transport.stationCapacity, ref val.transport.stationRecycle, ref val.transport.stationRecycleCursor); ResizePoolForClass(ref val.transport.dispenserPool, (Func<DispenserComponent, int>)((DispenserComponent x) => x.id), (Action<int>)val.transport.SetDispenserCapacity, ref val.transport.dispenserCursor, ref val.transport.dispenserCapacity, ref val.transport.dispenserRecycle, ref val.transport.dispenserRecycleCursor); } if (val.powerSystem != null) { ResizePool<PowerGeneratorComponent>(ref val.powerSystem.genPool, (PassStructAsRefFunc<PowerGeneratorComponent, int>)((ArrayStructRef<PowerGeneratorComponent> x) => x.Value.id), (Action<int>)val.powerSystem.SetGeneratorCapacity, ref val.powerSystem.genCursor, ref val.powerSystem.genCapacity, ref val.powerSystem.genRecycle, ref val.powerSystem.genRecycleCursor); ResizePool<PowerNodeComponent>(ref val.powerSystem.nodePool, (PassStructAsRefFunc<PowerNodeComponent, int>)((ArrayStructRef<PowerNodeComponent> x) => x.Value.id), (Action<int>)val.powerSystem.SetNodeCapacity, ref val.powerSystem.nodeCursor, ref val.powerSystem.nodeCapacity, ref val.powerSystem.nodeRecycle, ref val.powerSystem.nodeRecycleCursor); ResizePool<PowerConsumerComponent>(ref val.powerSystem.consumerPool, (PassStructAsRefFunc<PowerConsumerComponent, int>)((ArrayStructRef<PowerConsumerComponent> x) => x.Value.id), (Action<int>)val.powerSystem.SetConsumerCapacity, ref val.powerSystem.consumerCursor, ref val.powerSystem.consumerCapacity, ref val.powerSystem.consumerRecycle, ref val.powerSystem.consumerRecycleCursor); ResizePool<PowerAccumulatorComponent>(ref val.powerSystem.accPool, (PassStructAsRefFunc<PowerAccumulatorComponent, int>)((ArrayStructRef<PowerAccumulatorComponent> x) => x.Value.id), (Action<int>)val.powerSystem.SetAccumulatorCapacity, ref val.powerSystem.accCursor, ref val.powerSystem.accCapacity, ref val.powerSystem.accRecycle, ref val.powerSystem.accRecycleCursor); ResizePool<PowerExchangerComponent>(ref val.powerSystem.excPool, (PassStructAsRefFunc<PowerExchangerComponent, int>)((ArrayStructRef<PowerExchangerComponent> x) => x.Value.id), (Action<int>)val.powerSystem.SetExchangerCapacity, ref val.powerSystem.excCursor, ref val.powerSystem.excCapacity, ref val.powerSystem.excRecycle, ref val.powerSystem.excRecycleCursor); ResizePoolForClass(ref val.powerSystem.netPool, (Func<PowerNetwork, int>)((PowerNetwork x) => x.id), (Action<int>)val.powerSystem.SetNetworkCapacity, ref val.powerSystem.netCursor, ref val.powerSystem.netCapacity, ref val.powerSystem.netRecycle, ref val.powerSystem.netRecycleCursor); } } WeaverFixes.Logger.LogInfo((object)"Optimized pools"); } private static void GatherPoolData<T>(T[] pool, Func<T, int> getId, ref int totalSlots, ref int usedSlots, ref int unusedSlots, ref int holes) where T : struct { totalSlots += pool.Length; int num = 0; for (int i = 1; i < pool.Length; i++) { if (getId(pool[i]) == i) { usedSlots++; num = i; } else { unusedSlots++; } } for (int j = 1; j <= num; j++) { if (getId(pool[j]) != j) { holes++; } } } private static void GatherPoolDataForClass<T>(T[] pool, Func<T, int> getId, ref int totalSlots, ref int usedSlots, ref int unusedSlots, ref int holes) where T : class { totalSlots += pool.Length; int num = 0; for (int i = 1; i < pool.Length; i++) { if (pool[i] != null && getId(pool[i]) == i) { usedSlots++; num = i; } else { unusedSlots++; } } for (int j = 1; j <= num; j++) { if (pool[j] == null || getId(pool[j]) != j) { holes++; } } } private static void ResizePool<T>(ref T[] pool, PassStructAsRefFunc<T, int> getId, Action<int> setCapacity, ref int cursor, ref int capacity, ref int[] recycle, ref int recycleCursor) where T : struct { int num = cursor - 1; while (num >= 1 && getId(new ArrayStructRef<T>(pool, num)) != num) { num--; } cursor = num + 1; setCapacity(cursor); } private static void ResizePoolForClass<T>(ref T[] pool, Func<T, int> getId, Action<int> setCapacity, ref int cursor, ref int capacity, ref int[] recycle, ref int recycleCursor) where T : class { int num = cursor - 1; while (num >= 1 && getId(pool[num]) != num) { num--; } cursor = num + 1; setCapacity(cursor); } } } namespace Weaver.Optimizations.LoadBalance { [StructLayout(LayoutKind.Sequential, Size = 1)] internal struct InserterExecutableGraphAction : IExecutableGraphAction { public void Execute(long time, PlanetFactory factory, int[] indexes) { bool flag = factory.planet == GameMain.localPlanet; InserterComponent[] inserterPool = factory.factorySystem.inserterPool; CargoTraffic traffic = factory.factorySystem.traffic; PowerSystem powerSystem = factory.powerSystem; float[] networkServes = powerSystem.networkServes; AnimData[] entityAnimPool = factory.entityAnimPool; int[][] entityNeeds = factory.entityNeeds; PowerConsumerComponent[] consumerPool = powerSystem.consumerPool; EntityData[] entityPool = factory.entityPool; BeltComponent[] beltPool = factory.cargoTraffic.beltPool; byte b = (byte)GameMain.history.inserterStackCountObsolete; byte b2 = (byte)GameMain.history.inserterStackInput; byte stackOutput = (byte)GameMain.history.inserterStackOutput; bool inserterBidirectional = GameMain.history.inserterBidirectional; int delay = ((b > 1) ? 110000 : 0); int delay2 = ((b2 > 1) ? 40000 : 0); bool flag2 = time % 60 == 0; int[] array; if (flag) { array = indexes; foreach (int num in array) { ref InserterComponent reference = ref inserterPool[num]; if (flag2) { ((InserterComponent)(ref reference)).InternalOffsetCorrection(entityPool, traffic, beltPool); if (reference.grade == 3) { reference.delay = delay; reference.stackInput = b; reference.stackOutput = 1; reference.bidirectional = false; } else if (reference.grade == 4) { reference.delay = delay2; reference.stackInput = b2; reference.stackOutput = stackOutput; reference.bidirectional = inserterBidirectional; } else { reference.delay = 0; reference.stackInput = 1; reference.stackOutput = 1; reference.bidirectional = false; } } float num2 = networkServes[consumerPool[reference.pcId].networkId]; if (reference.bidirectional) { ((InserterComponent)(ref reference)).InternalUpdate_Bidirectional(factory, entityNeeds, entityAnimPool, num2, flag); } else { ((InserterComponent)(ref reference)).InternalUpdate(factory, entityNeeds, entityAnimPool, num2); } } return; } array = indexes; foreach (int num3 in array) { ref InserterComponent reference2 = ref inserterPool[num3]; if (flag2) { if (reference2.grade == 3) { reference2.delay = delay; reference2.stackInput = b; reference2.stackOutput = 1; reference2.bidirectional = false; } else if (reference2.grade == 4) { reference2.delay = delay2; reference2.stackInput = b2; reference2.stackOutput = stackOutput; reference2.bidirectional = inserterBidirectional; } else { reference2.delay = 0; reference2.stackInput = 1; reference2.stackOutput = 1; reference2.bidirectional = false; } } float num4 = networkServes[consumerPool[reference2.pcId].networkId]; if (reference2.bidirectional) { ((InserterComponent)(ref reference2)).InternalUpdate_Bidirectional(factory, entityNeeds, entityAnimPool, num4, flag); } else { ((InserterComponent)(ref reference2)).InternalUpdateNoAnim(factory, entityNeeds, num4); } } } } public class InserterMultithreadingOptimization { private static readonly TimeIndexedCollectionStatistic _inserterTickTimes = new TimeIndexedCollectionStatistic(200); private static readonly List<ExecutableGraph<InserterExecutableGraphAction>> _inserterExecutables = new List<ExecutableGraph<InserterExecutableGraphAction>>(); private static long? _gameTime; public static void EnableOptimization(Harmony harmony) { harmony.PatchAll(typeof(InserterMultithreadingOptimization)); } [HarmonyPriority(1)] [HarmonyPostfix] [HarmonyPatch(typeof(GameSave), "LoadCurrentGame")] private static void LoadCurrentGame_Postfix() { WeaverFixes.Logger.LogInfo((object)"Initializing InserterMultithreadingOptimization"); _inserterTickTimes.Clear(); _inserterExecutables.Clear(); for (int i = 0; i < GameMain.data.factoryCount; i++) { PlanetFactory val = GameMain.data.factories[i]; FactorySystem factorySystem = val.factorySystem; if (factorySystem == null) { continue; } List<Graph> list = Graphifier.ToInserterGraphs(factorySystem); Graphifier.SplitLargeGraphs(list); Graphifier.CombineSmallGraphs(list); foreach (Graph item2 in list) { ExecutableGraph<InserterExecutableGraphAction> item = new ExecutableGraph<InserterExecutableGraphAction>(val, item2, EntityType.Inserter, default(InserterExecutableGraphAction)); _inserterExecutables.Add(item); } } WeaverFixes.Logger.LogInfo((object)$"Created {_inserterExecutables.Count} executable graphs"); } [HarmonyPrefix] [HarmonyPatch(typeof(MultithreadSystem), "PrepareInserterData")] private static bool PrepareInserterData_Prefix(MultithreadSystem __instance, long _time) { _gameTime = _time; __instance.missionOrders |= 2u; foreach (ExecutableGraph<InserterExecutableGraphAction> inserterExecutable in _inserterExecutables) { inserterExecutable.Prepare(); } return false; } [HarmonyPrefix] [HarmonyPatch(typeof(MultithreadSystem), "Schedule")] private static bool Schedule_Prefix(MultithreadSystem __instance) { return __instance.missionOrders != 2; } [HarmonyPrefix] [HarmonyPatch(typeof(MultithreadSystem), "Complete")] private static bool Complete_Prefix(MultithreadSystem __instance) { if (__instance.missionOrders != 2) { return true; } if (!_gameTime.HasValue) { throw new InvalidOperationException("_gameTime is null."); } ParallelOptions parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = GameMain.multithreadSystem.usedThreadCnt }; _inserterTickTimes.EnsureCapacity(1); _inserterTickTimes.StartSampling(0); Parallel.ForEach(_inserterExecutables, parallelOptions, delegate(ExecutableGraph<InserterExecutableGraphAction> executableGraph) { executableGraph.Execute(_gameTime.Value); }); _inserterTickTimes.EndSampling(0); if (_gameTime.Value % 60 == 0L) { WeaverFixes.Logger.LogInfo((object)$"Inserter tick {_inserterTickTimes.GetAverageTimeInMilliseconds(0):N2}"); } __instance.isRevAllThreadCompleteSignal = true; __instance.missionOrders = 0u; return false; } } public class InserterThreadLoadBalance { private static uint _updateCounter; internal static int[]? _inserterPerThreadItemCount; internal static bool enableStatisticsLoadBalancing; public static void EnableOptimization(Harmony harmony) { harmony.PatchAll(typeof(WorkerThreadExecutorBenchmarkPatches)); harmony.PatchAll(typeof(MultithreadSystemBenchmarkDisplayPatches)); MultithreadSystemBenchmarkDisplayPatches._logResults = false; harmony.PatchAll(typeof(InserterThreadLoadBalance)); } [HarmonyPostfix] [HarmonyPatch(typeof(GameSave), "LoadCurrentGame")] private static void LoadCurrentGame_Postfix() { _updateCounter = 0u; _inserterPerThreadItemCount = null; enableStatisticsLoadBalancing = false; } [HarmonyPrefix] [HarmonyPatch(typeof(MultithreadSystem), "Schedule")] private static void Schedule_Prefix(MultithreadSystem __instance, out bool __state) { if (__instance.missionOrders != 2) { __state = false; return; } __state = true; _updateCounter++; if (_inserterPerThreadItemCount == null || _inserterPerThreadItemCount.Length != GameMain.multithreadSystem.usedThreadCnt) { _inserterPerThreadItemCount = new int[GameMain.multithreadSystem.usedThreadCnt]; enableStatisticsLoadBalancing = false; return; } if (_updateCounter % 60 == 0) { StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < _inserterPerThreadItemCount.Length; i++) { stringBuilder.Append($" {_inserterPerThreadItemCount[i],7:N0}"); } WeaverFixes.Logger.LogInfo((object)string.Format("{0} Sum: {1} Thread item counts: {2}", "MultithreadSystem", _inserterPerThreadItemCount.Sum(), stringBuilder)); MultithreadSystemBenchmarkDisplayPatches.LogComputeTimes((MissionOrderType)2, WorkerThreadExecutorBenchmarkPatches._missionComputeTimes[2u]); RebalanceInsertersPerThread(__instance); } RescaleToCurrentInserterCount(__instance); } private static void RebalanceInsertersPerThread(MultithreadSystem __instance) { TimeIndexedCollectionStatistic timeIndexedCollectionStatistic = WorkerThreadExecutorBenchmarkPatches._missionComputeTimes[2u]; if (!timeIndexedCollectionStatistic.IsFilledWithData(_inserterPerThreadItemCount.Length)) { return; } float num = 0f; for (int i = 0; i < _inserterPerThreadItemCount.Length; i++) { num += timeIndexedCollectionStatistic.GetAverageTimeInMilliseconds(i); } float num2 = num / (float)_inserterPerThreadItemCount.Length; int num3 = 0; for (int j = 0; j < _inserterPerThreadItemCount.Length; j++) { if (!(timeIndexedCollectionStatistic.GetAverageTimeInMilliseconds(j) > num2)) { num3++; } } int num4 = -1; float num5 = float.MinValue; for (int k = 0; k < _inserterPerThreadItemCount.Length; k++) { if (!(num5 >= timeIndexedCollectionStatistic.GetAverageTimeInMilliseconds(k))) { num4 = k; num5 = timeIndexedCollectionStatistic.GetAverageTimeInMilliseconds(k); } } if (num4 == -1) { return; } int num6 = -1; float num7 = float.MaxValue; for (int l = 0; l < _inserterPerThreadItemCount.Length; l++) { if (!(num7 < timeIndexedCollectionStatistic.GetAverageTimeInMilliseconds(l))) { num6 = l; num7 = timeIndexedCollectionStatistic.GetAverageTimeInMilliseconds(l); } } if (num6 != -1 && !(num5 < num2 * 1.05f)) { float averageTimeInMilliseconds = timeIndexedCollectionStatistic.GetAverageTimeInMilliseconds(num4); int num8 = (int)((float)_inserterPerThreadItemCount[num4] * ((1f - 1f / (averageTimeInMilliseconds / num2)) * 0.5f)); _inserterPerThreadItemCount[num4] -= num8; _inserterPerThreadItemCount[num6] += num8; } } private static void RescaleToCurrentInserterCount(MultithreadSystem __instance) { PlanetFactory[] inserterFactories = __instance.workerThreadExecutors[0].inserterFactories; int inserterFactoryCnt = __instance.workerThreadExecutors[0].inserterFactoryCnt; int num = 0; for (int i = 0; i < inserterFactoryCnt; i++) { num += inserterFactories[i].factorySystem.inserterCursor; } int num2 = _inserterPerThreadItemCount.Sum(); int num3 = (num - num2 + (_inserterPerThreadItemCount.Length - 1)) / _inserterPerThreadItemCount.Length; for (int j = 0; j < _inserterPerThreadItemCount.Length; j++) { _inserterPerThreadItemCount[j] += num3; } int num4 = _inserterPerThreadItemCount.Sum(); if (num4 < num) { throw new InvalidOperationException($"Rescaled inserter count is less than the total inserter count.\r\nRescaled count: {num4}\r\nExpected count: {num}"); } } [HarmonyPostfix] [HarmonyPatch(typeof(MultithreadSystem), "Schedule")] private static void Schedule_Postfix(MultithreadSystem __instance, bool __state) { if (__state) { enableStatisticsLoadBalancing = true; MultithreadSystemBenchmarkDisplayPatches._logResults = false; } } [HarmonyPostfix] [HarmonyPatch(typeof(MultithreadSystem), "PrepareInserterData")] private static void PrepareInserterData_Loadbalance(MultithreadSystem __instance) { } [HarmonyPrefix] [HarmonyPatch(/*Could not decode attribute arguments.*/)] private static bool CalculateMissionIndex_Loadbalance_Prefix(WorkerThreadExecutor __instance, ref bool __result, int _curThreadIdx, ref int _start, ref int _end) { if (!enableStatisticsLoadBalancing) { return true; } __result = _inserterPerThreadItemCount[_curThreadIdx] > 0; for (int i = 0; i < _curThreadIdx; i++) { _start += _inserterPerThreadItemCount[i]; } _end = _start + _inserterPerThreadItemCount[_curThreadIdx]; return false; } [HarmonyPostfix] [HarmonyPatch(/*Could not decode attribute arguments.*/)] private static void CalculateMissionIndex_Loadbalance_Postfix(WorkerThreadExecutor __instance, int _curThreadIdx, int _start, int _end) { if (!enableStatisticsLoadBalancing && _inserterPerThreadItemCount != null) { _inserterPerThreadItemCount[_curThreadIdx] = _end - _start; } } } public class MultithreadSystemLoadBalance { } } namespace Weaver.Optimizations.LinearDataAccess { internal static class HarmonyExtensions { public static void ReplaceCode(this CodeMatcher codeMatcher, CodeMatch[] start, bool replaceStart, CodeMatch[] end, bool replaceEnd, CodeInstruction[] replaceWith) { codeMatcher.MatchForward(!replaceStart, start).ThrowIfNotMatch("Failed to find start", Array.Empty<CodeMatch>()); int pos = codeMatcher.Pos; codeMatcher.MatchForward(replaceEnd, end).ThrowIfNotMatch("Failed to find end", Array.Empty<CodeMatch>()); int pos2 = codeMatcher.Pos; codeMatcher.Start().Advance(pos).RemoveInstructions(pos2 - pos + 1) .Insert(replaceWith); } public static void PrintRelativeRangeOfInstructions(this CodeMatcher codeMatcher, int startOffset, int length) { codeMatcher.Advance(startOffset); for (int i = 0; i < length; i++) { WeaverFixes.Logger.LogMessage((object)codeMatcher.Instruction); codeMatcher.Advance(1); } } } [Flags] internal enum LabState { Active = 0, Inactive = 8, InactiveNoAssembler = 9, InactiveNoRecipeSet = 0xA, InactiveOutputFull = 0xB, InactiveInputMissing = 0xC, ResearchMode = 0x10 } public class LinearInserterDataAccessOptimization { private record struct EntityIndexAndPowerIndex(EntityType EntityType, int EntityIndex, int PowerConsumerIndex); public static void EnableOptimization(Harmony harmony) { harmony.PatchAll(typeof(LinearInserterDataAccessOptimization)); } [HarmonyPriority(2)] [HarmonyPostfix] [HarmonyPatch(typeof(GameSave), "LoadCurrentGame")] private static void LoadCurrentGame_Postfix() { WeaverFixes.Logger.LogInfo((object)"Initializing LinearInserterDataAccessOptimization"); for (int i = 0; i < GameMain.data.factoryCount; i++) { PlanetFactory val = GameMain.data.factories[i]; FactorySystem factorySystem = val.factorySystem; PowerSystem powerSystem = val.powerSystem; CargoTraffic cargoTraffic = val.cargoTraffic; PlanetTransport transport = val.transport; DefenseSystem defenseSystem = val.defenseSystem; DigitalSystem digitalSystem = val.digitalSystem; HashSystem hashSystemStatic = val.hashSystemStatic; if (factorySystem != null && powerSystem != null && cargoTraffic != null && transport != null && defenseSystem != null && digitalSystem != null && hashSystemStatic != null) { CompactInserters(val, factorySystem); InserterLinearAccessToAssemblers(val, factorySystem); } } } private static void CompactInserters(PlanetFactory planet, FactorySystem factory) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) List<Graph> list = Graphifier.ToInserterGraphs(factory); if (list.Count == 0) { return; } Graphifier.CombineSmallGraphs(list); InserterComponent[] inserterPool = factory.inserterPool; List<InserterComponent> list2 = new List<InserterComponent>(); list2.Add(new InserterComponent { id = 0 }); foreach (Graph item in list) { foreach (Node item2 in from x in item.GetAllNodes() where x.EntityTypeIndex.EntityType == EntityType.Inserter orderby (int)x.EntityTypeIndex.EntityType, x.EntityId select x) { InserterComponent val = inserterPool[item2.EntityTypeIndex.Index]; val.id = list2.Count; planet.entityPool[val.entityId].inserterId = val.id; list2.Add(val); } } factory.SetInserterCapacity(list2.Count); list2.CopyTo(factory.inserterPool); factory.inserterCursor = factory.inserterPool.Length; factory.inserterRecycleCursor = 0; } private static void InserterLinearAccessToAssemblers(PlanetFactory planet, FactorySystem factory) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0102: 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_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) List<Graph> source = Graphifier.ToInserterGraphs(factory); AssemblerComponent[] assemblerPool = factory.assemblerPool; List<AssemblerComponent> list = new List<AssemblerComponent> { new AssemblerComponent { id = 0 } }; HashSet<int> hashSet = new HashSet<int>(); foreach (Node item in from x in source.SelectMany((Graph x) => x.GetAllNodes()) where x.EntityTypeIndex.EntityType == EntityType.Inserter orderby x.EntityTypeIndex.Index select x) { ref InserterComponent reference = ref factory.inserterPool[item.EntityTypeIndex.Index]; if (reference.pickTarget != 0) { int assemblerId = planet.entityPool[reference.pickTarget].assemblerId; if (assemblerId != 0 && hashSet.Add(reference.pickTarget)) { AssemblerComponent val = assemblerPool[assemblerId]; val.id = list.Count; planet.entityPool[reference.pickTarget].assemblerId = val.id; list.Add(val); } } if (reference.insertTarget != 0) { int assemblerId2 = planet.entityPool[reference.insertTarget].assemblerId; if (assemblerId2 != 0 && hashSet.Add(reference.insertTarget)) { AssemblerComponent val2 = assemblerPool[assemblerId2]; val2.id = list.Count; planet.entityPool[reference.insertTarget].assemblerId = val2.id; list.Add(val2); } } } for (int i = 1; i < factory.assemblerCursor; i++) { if (!hashSet.Contains(i) && assemblerPool[i].id == i) { AssemblerComponent val3 = assemblerPool[i]; val3.id = list.Count; planet.entityPool[val3.entityId].assemblerId = val3.id; list.Add(val3); } } factory.SetAssemblerCapacity(list.Count); list.CopyTo(factory.assemblerPool); factory.assemblerCursor = factory.assemblerPool.Length; factory.assemblerRecycleCursor = 0; } private static void InserterLinearAccessToAssemblerEntities(PlanetFactory planet, FactorySystem factory, PowerSystem power, HashSystem hashSystem) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0087: 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_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0115: 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_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) EntityData[] entityPool = planet.entityPool; AnimData[] entityAnimPool = planet.entityAnimPool; SignData[] entitySignPool = planet.entitySignPool; int[] oldEntityConnPool = planet.entityConnPool; Mutex[] entityMutexs = planet.entityMutexs; int[][] entityNeeds = planet.entityNeeds; List<EntityData> list = new List<EntityData>(); List<AnimData> list2 = new List<AnimData>(); List<SignData> list3 = new List<SignData>(); List<int> list4 = new List<int>(); List<Mutex> list5 = new List<Mutex>(); List<int[]> list6 = new List<int[]>(); list.Add(default(EntityData)); list2.Add(default(AnimData)); list3.Add(default(SignData)); list4.AddRange(Enumerable.Repeat(0, 16)); list5.Add(null); list6.Add(null); HashSet<int> hashSet = new HashSet<int>(); for (int i = 1; i < factory.assemblerCursor; i++) { ref AssemblerComponent reference = ref factory.assemblerPool[i]; if (reference.id == i) { hashSet.Add(reference.entityId); } } for (int j = 1; j < planet.entityCursor; j++) { if (hashSet.Contains(j)) { list.Add(default(EntityData)); list2.Add(default(AnimData)); list3.Add(default(SignData)); list4.AddRange(Enumerable.Repeat(0, 16)); list5.Add(null); list6.Add(null); continue; } list.Add(entityPool[j]); list2.Add(entityAnimPool[j]); list3.Add(entitySignPool[j]); list4.AddRange(from x in Enumerable.Range(j, 16) select oldEntityConnPool[x]); list5.Add(entityMutexs[j]); list6.Add(entityNeeds[j]); } Dictionary<int, int> dictionary = new Dictionary<int, int>(); for (int k = 1; k < planet.entityCursor; k++) { if (hashSet.Contains(k)) { EntityData val = entityPool[k]; val.id = list.Count; val.hashAddress = hashSystem.UpdateObjectHashAddress(val.hashAddress, k, val.pos, (EObjectType)0); dictionary.Add(k, val.id); list.Add(val); list2.Add(entityAnimPool[k]); list3.Add(entitySignPool[k]); list4.AddRange(from x in Enumerable.Range(k, 16) select oldEntityConnPool[x]); list5.Add(entityMutexs[k]); list6.Add(entityNeeds[k]); } } for (int l = 1; l < factory.assemblerCursor; l++) { ref AssemblerComponent reference2 = ref factory.assemblerPool[l]; if (reference2.id == l) { reference2.entityId = dictionary[reference2.entityId]; list6[reference2.entityId] = reference2.needs; } } for (int m = 1; m < factory.inserterCursor; m++) { ref InserterComponent reference3 = ref factory.inserterPool[m]; if (reference3.id != m) { continue; } if (reference3.pickTarget != 0) { if (planet.entityPool[reference3.pickTarget].assemblerId == 0) { continue; } reference3.pickTarget = dictionary[reference3.pickTarget]; } if (reference3.insertTarget != 0 && planet.entityPool[reference3.insertTarget].assemblerId != 0) { reference3.insertTarget = dictionary[reference3.insertTarget]; } } for (int n = 1; n < factory.minerCursor; n++) { ref MinerComponent reference4 = ref factory.minerPool[n]; if (reference4.id == n && dictionary.TryGetValue(reference4.insertTarget, out var value)) { reference4.insertTarget = value; } } int entityCapacity = Math.Max(planet.entityCapacity, list.Count); int count = list.Count; planet.SetEntityCapacity(entityCapacity); list.CopyTo(planet.entityPool); list2.CopyTo(planet.entityAnimPool); list3.CopyTo(planet.entitySignPool); list4.CopyTo(planet.entityConnPool); list5.CopyTo(planet.entityMutexs); list6.CopyTo(planet.entityNeeds); planet.entityCursor = count; planet.entityRecycleCursor = 0; foreach (KeyValuePair<int, int> item in dictionary) { planet.HandleObjectConnChangeWhenBuild(item.Key, item.Value); } } private static void InserterLinearAccessToPowerConsumers(PlanetFactory planet, FactorySystem factory, PowerSystem power, CargoTraffic cargoTraffic, PlanetTransport transport, DefenseSystem defenseSystem, DigitalSystem digitalSystem) { //IL_05f7: Unknown result type (might be due to invalid IL or missing references) //IL_0605: Unknown result type (might be due to invalid IL or missing references) //IL_069a: Unknown result type (might be due to invalid IL or missing references) //IL_069f: Unknown result type (might be due to invalid IL or missing references) //IL_06b4: Unknown result type (might be due to invalid IL or missing references) //IL_06c0: Unknown result type (might be due to invalid IL or missing references) //IL_06cd: Unknown result type (might be due to invalid IL or missing references) List<EntityIndexAndPowerIndex> list = new List<EntityIndexAndPowerIndex>(); for (int i = 1; i < cargoTraffic.monitorCursor; i++) { ref MonitorComponent reference = ref cargoTraffic.monitorPool[i]; if (reference.id == i && reference.pcId != 0) { list.Add(new EntityIndexAndPowerIndex(EntityType.Monitor, i, reference.pcId)); } } for (int j = 1; j < cargoTraffic.spraycoaterCursor; j++) { ref SpraycoaterComponent reference2 = ref cargoTraffic.spraycoaterPool[j]; if (reference2.id == j && reference2.pcId != 0) { list.Add(new EntityIndexAndPowerIndex(EntityType.SprayCoater, j, reference2.pcId)); } } for (int k = 1; k < cargoTraffic.pilerCursor; k++) { ref PilerComponent reference3 = ref cargoTraffic.pilerPool[k]; if (reference3.id == k && reference3.pcId != 0) { list.Add(new EntityIndexAndPowerIndex(EntityType.Piler, k, reference3.pcId)); } } for (int l = 1; l < factory.minerCursor; l++) { ref MinerComponent reference4 = ref factory.minerPool[l]; if (reference4.id == l && reference4.pcId != 0) { list.Add(new EntityIndexAndPowerIndex(EntityType.Miner, l, reference4.pcId)); } } for (int m = 1; m < factory.inserterCursor; m++) { ref InserterComponent reference5 = ref factory.inserterPool[m]; if (reference5.id == m && reference5.pcId != 0) { list.Add(new EntityIndexAndPowerIndex(EntityType.Inserter, m, reference5.pcId)); } } for (int n = 1; n < factory.assemblerCursor; n++) { ref AssemblerComponent reference6 = ref factory.assemblerPool[n]; if (reference6.id == n && reference6.pcId != 0) { list.Add(new EntityIndexAndPowerIndex(EntityType.Assembler, n, reference6.pcId)); } } for (int num = 1; num < factory.fractionatorCursor; num++) { ref FractionatorComponent reference7 = ref factory.fractionatorPool[num]; if (reference7.id == num && reference7.pcId != 0) { list.Add(new EntityIndexAndPowerIndex(EntityType.Fractionator, num, reference7.pcId)); } } for (int num2 = 1; num2 < factory.ejectorCursor; num2++) { ref EjectorComponent reference8 = ref factory.ejectorPool[num2]; if (reference8.id == num2 && reference8.pcId != 0) { list.Add(new EntityIndexAndPowerIndex(EntityType.Ejector, num2, reference8.pcId)); } } for (int num3 = 1; num3 < factory.siloCursor; num3++) { ref SiloComponent reference9 = ref factory.siloPool[num3]; if (reference9.id == num3 && reference9.pcId != 0) { list.Add(new EntityIndexAndPowerIndex(EntityType.Silo, num3, reference9.pcId)); } } for (int num4 = 1; num4 < factory.labCursor; num4++) { ref LabComponent reference10 = ref factory.labPool[num4]; if (reference10.id == num4 && reference10.pcId != 0) { list.Add(new EntityIndexAndPowerIndex(reference10.researchMode ? EntityType.ResearchingLab : EntityType.ProducingLab, num4, reference10.pcId)); } } for (int num5 = 1; num5 < transport.stationCursor; num5++) { StationComponent val = transport.stationPool[num5]; if (val != null && val.id == num5 && val.pcId != 0) { list.Add(new EntityIndexAndPowerIndex(EntityType.Station, num5, val.pcId)); } } for (int num6 = 1; num6 < transport.dispenserCursor; num6++) { DispenserComponent val2 = transport.dispenserPool[num6]; if (val2 != null && val2.id == num6 && val2.pcId != 0) { list.Add(new EntityIndexAndPowerIndex(EntityType.Dispenser, num6, val2.pcId)); } } for (int num7 = 1; num7 < digitalSystem.markers.cursor; num7++) { MarkerComponent val3 = digitalSystem.markers.buffer[num7]; if (val3 != null && val3.id == num7 && val3.pcId != 0) { list.Add(new EntityIndexAndPowerIndex(EntityType.Marker, num7, val3.pcId)); } } for (int num8 = 1; num8 < defenseSystem.turrets.cursor; num8++) { ref TurretComponent reference11 = ref defenseSystem.turrets.buffer[num8]; if (reference11.id == num8 && reference11.pcId != 0) { list.Add(new EntityIndexAndPowerIndex(EntityType.Turret, num8, reference11.pcId)); } } for (int num9 = 1; num9 < defenseSystem.fieldGenerators.cursor; num9++) { ref FieldGeneratorComponent reference12 = ref defenseSystem.fieldGenerators.buffer[num9]; if (reference12.id == num9 && reference12.pcId != 0) { list.Add(new EntityIndexAndPowerIndex(EntityType.FieldGenerator, num9, reference12.pcId)); } } for (int num10 = 1; num10 < defenseSystem.battleBases.cursor; num10++) { BattleBaseComponent val4 = defenseSystem.battleBases.buffer[num10]; if (val4 != null && val4.id == num10 && val4.pcId != 0) { list.Add(new EntityIndexAndPowerIndex(EntityType.BattleBase, num10, val4.pcId)); } } HashSet<int> hashSet = new HashSet<int>(); for (int num11 = 1; num11 < power.consumerCursor; num11++) { if (power.consumerPool[num11].id == num11) { hashSet.Add(num11); } } if (!hashSet.SetEquals(new HashSet<int>(list.Select((EntityIndexAndPowerIndex x) => x.PowerConsumerIndex)))) { throw new InvalidOperationException($"Failed to gather all power consuming entities.\r\nExpected: {hashSet.Count:N0}\r\nActual: {new HashSet<int>(list.Select((EntityIndexAndPowerIndex x) => x.PowerConsumerIndex)).Count:N0}\r\n{list.First()}"); } PowerConsumerComponent[] consumerPool = power.consumerPool; List<PowerConsumerComponent> list2 = new List<PowerConsumerComponent>(); list2.Add(new PowerConsumerComponent { id = 0 }); Dictionary<int, int> dictionary = new Dictionary<int, int>(); foreach (EntityIndexAndPowerIndex item in (from x in list group x by x.EntityType).SelectMany((IGrouping<EntityType, EntityIndexAndPowerIndex> x) => x.OrderBy((EntityIndexAndPowerIndex y) => y.EntityIndex))) { if (!dictionary.ContainsKey(item.PowerConsumerIndex)) { dictionary.Add(item.PowerConsumerIndex, list2.Count); PowerConsumerComponent val5 = consumerPool[item.PowerConsumerIndex]; val5.id = list2.Count; planet.entityPool[val5.entityId].powerConId = val5.id; list2.Add(val5); } } power.SetConsumerCapacity(list2.Count); list2.CopyTo(power.consumerPool); power.consumerCursor = power.consumerPool.Length; power.consumerRecycleCursor = 0; for (int num12 = 1; num12 < cargoTraffic.monitorCursor; num12++) { ref MonitorComponent reference13 = ref cargoTraffic.monitorPool[num12]; if (reference13.id == num12 && reference13.pcId != 0) { reference13.pcId = dictionary[reference13.pcId]; } } for (int num13 = 1; num13 < cargoTraffic.spraycoaterCursor; num13++) { ref SpraycoaterComponent reference14 = ref cargoTraffic.spraycoaterPool[num13]; if (reference14.id == num13 && reference14.pcId != 0) { reference14.pcId = dictionary[reference14.pcId]; } } for (int num14 = 1; num14 < cargoTraffic.pilerCursor; num14++) { ref PilerComponent reference15 = ref cargoTraffic.pilerPool[num14]; if (reference15.id == num14 && reference15.pcId != 0) { reference15.pcId = dictionary[reference15.pcId]; } } for (int num15 = 1; num15 < cargoTraffic.pilerCursor; num15++) { ref PilerComponent reference16 = ref cargoTraffic.pilerPool[num15]; if (reference16.id == num15 && reference16.pcId != 0) { reference16.pcId = dictionary[reference16.pcId]; } } for (int num16 = 1; num16 < factory.minerCursor; num16++) { ref MinerComponent reference17 = ref factory.minerPool[num16]; if (reference17.id == num16 && reference17.pcId != 0) { reference17.pcId = dictionary[reference17.pcId]; } } for (int num17 = 1; num17 < factory.inserterCursor; num17++) { ref InserterComponent reference18 = ref factory.inserterPool[num17]; if (reference18.id == num17 && reference18.pcId != 0) { reference18.pcId = dictionary[reference18.pcId]; } } for (int num18 = 1; num18 < factory.assemblerCursor; num18++) { ref AssemblerComponent reference19 = ref factory.assemblerPool[num18]; if (reference19.id == num18 && reference19.pcId != 0) { reference19.pcId = dictionary[reference19.pcId]; } } for (int num19 = 1; num19 < factory.fractionatorCursor; num19++) { ref FractionatorComponent reference20 = ref factory.fractionatorPool[num19]; if (reference20.id == num19 && reference20.pcId != 0) { reference20.pcId = dictionary[reference20.pcId]; } } for (int num20 = 1; num20 < factory.ejectorCursor; num20++) { ref EjectorComponent reference21 = ref factory.ejectorPool[num20]; if (reference21.id == num20 && reference21.pcId != 0) { reference21.pcId = dictionary[reference21.pcId]; } } for (int num21 = 1; num21 < factory.siloCursor; num21++) { ref SiloComponent reference22 = ref factory.siloPool[num21]; if (reference22.id == num21 && reference22.pcId != 0) { reference22.pcId = dictionary[reference22.pcId]; } } for (int num22 = 1; num22 < factory.labCursor; num22++) { ref LabComponent reference23 = ref factory.labPool[num22]; if (reference23.id == num22 && reference23.pcId != 0) { reference23.pcId = dictionary[reference23.pcId]; } } for (int num23 = 1; num23 < transport.stationCursor; num23++) { StationComponent val6 = transport.stationPool[num23]; if (val6 != null && val6.id == num23 && val6.pcId != 0) { val6.pcId = dictionary[val6.pcId]; } } for (int num24 = 1; num24 < transport.dispenserCursor; num24++) { DispenserComponent val7 = transport.dispenserPool[num24]; if (val7 != null && val7.id == num24 && val7.pcId != 0) { val7.pcId = dictionary[val7.pcId]; } } for (int num25 = 1; num25 < digitalSystem.markers.cursor; num25++) { MarkerComponent val8 = digitalSystem.markers.buffer[num25]; if (val8 != null && val8.id == num25 && val8.pcId != 0) { val8.pcId = dictionary[val8.pcId]; } } for (int num26 = 1; num26 < defenseSystem.turrets.cursor; num26++) { ref TurretComponent reference24 = ref defenseSystem.turrets.buffer[num26]; if (reference24.id == num26 && reference24.pcId != 0) { reference24.pcId = dictionary[reference24.pcId]; } } for (int num27 = 1; num27 < defenseSystem.fieldGenerators.cursor; num27++) { ref FieldGeneratorComponent reference25 = ref defenseSystem.fieldGenerators.buffer[num27]; if (reference25.id == num27 && reference25.pcId != 0) { reference25.pcId = dictionary[reference25.pcId]; } } for (int num28 = 1; num28 < defenseSystem.battleBases.cursor; num28++) { BattleBaseComponent val9 = defenseSystem.battleBases.buffer[num28]; if (val9 != null && val9.id == num28 && val9.pcId != 0) { val9.pcId = dictionary[val9.pcId]; } } for (int num29 = 1; num29 < power.netCursor; num29++) { if (power.netPool[num29] == null || power.netPool[num29].id == 0) { continue; } PowerNetwork val10 = power.netPool[num29]; foreach (Node node in val10.nodes) { for (int num30 = 0; num30 < node.consumers.Count; num30++) { if (dictionary.TryGetValue(node.consumers[num30], out var value)) { node.consumers[num30] = value; } } node.consumers.Sort(); } for (int num31 = 0; num31 < val10.consumers.Count; num31++) { if (dictionary.TryGetValue(val10.consumers[num31], out var value2)) { val10.consumers[num31] = value2; } } val10.consumers.Sort(); } } } internal struct NetworkIdAndState<T> where T : Enum { private uint _value; public int State { get { return (int)(_value >> 24); } set { _value = (_value & 0xFFFFFFu) | (uint)(value << 24); } } public readonly int Index => (int)(0xFFFFFF & _value); public NetworkIdAndState(int state, int index) { _value = (uint)((state << 24) | index); } } internal sealed class OptimizedPlanet { private readonly PlanetFactory _planet; private readonly StarClusterResearchManager _starClusterResearchManager; public InserterExecutor<OptimizedBiInserter> _optimizedBiInserterExecutor; public InserterExecutor<OptimizedInserter> _optimizedInserterExecutor; public AssemblerExecutor _assemblerExecutor; private int[] _minerNetworkIds; private int[] _ejectorNetworkIds; public ProducingLabExecutor _producingLabExecutor; public NetworkIdAndState<LabState>[] _producingLabNetworkIdAndStates; public OptimizedProducingLab[] _optimizedProducingLabs; public ProducingLabRecipe[] _producingLabRecipes; public Dictionary<int, int> _producingLabIdToOptimizedIndex; public ResearchingLabExecutor _researchingLabExecutor; public NetworkIdAndState<LabState>[] _researchingLabNetworkIdAndStates; public OptimizedResearchingLab[] _optimizedResearchingLabs; public Dictionary<int, int> _researchingLabIdToOptimizedIndex; public SpraycoaterExecutor _spraycoaterExecutor; public FractionatorExecutor _fractionatorExecutor; public OptimizedPowerSystem _optimizedPowerSystem; private WorkTracker[] _workTrackers; private int _workTrackersParallelism; public OptimizedPlanetStatus Status { get; private set; } = OptimizedPlanetStatus.Stopped; public int OptimizeDelayInTicks { get; set; } public OptimizedPlanet(PlanetFactory planet, StarClusterResearchManager starClusterResearchManager) { _planet = planet; _starClusterResearchManager = starClusterResearchManager; } public void Save() { _optimizedBiInserterExecutor.Save(_planet); _optimizedInserterExecutor.Save(_planet); _assemblerExecutor.Save(_planet); _producingLabExecutor.Save(_planet); _researchingLabExecutor.Save(_planet); _spraycoaterExecutor.Save(_planet); _fractionatorExecutor.Save(_planet); Status = OptimizedPlanetStatus.Stopped; _workTrackers = null; _workTrackersParallelism = -1; } public void Initialize() { OptimizedPowerSystemBuilder optimizedPowerSystemBuilder = new OptimizedPowerSystemBuilder(_planet.powerSystem); InitializeAssemblers(_planet, optimizedPowerSystemBuilder); InitializeMiners(_planet); InitializeEjectors(_planet); InitializeLabAssemblers(_planet, optimizedPowerSystemBuilder); InitializeResearchingLabs(_planet, optimizedPowerSystemBuilder); InitializeInserters(_planet, optimizedPowerSystemBuilder); InitializeSpraycoaters(_planet, optimizedPowerSystemBuilder); InitializeFractionators(_planet, optimizedPowerSystemBuilder); _optimizedPowerSystem = optimizedPowerSystemBuilder.Build(); Status = OptimizedPlanetStatus.Running; _workTrackers = null; _workTrackersParallelism = -1; } private void InitializeInserters(PlanetFactory planet, OptimizedPowerSystemBuilder optimizedPowerSystemBuilder) { _optimizedBiInserterExecutor = new InserterExecutor<OptimizedBiInserter>(_assemblerExecutor._assemblerNetworkIdAndStates, _producingLabNetworkIdAndStates, _researchingLabNetworkIdAndStates); _optimizedBiInserterExecutor.Initialize(planet, this, (InserterComponent x) => x.bidirectional, optimizedPowerSystemBuilder.CreateBiInserterBuilder()); _optimizedInserterExecutor = new InserterExecutor<OptimizedInserter>(_assemblerExecutor._assemblerNetworkIdAndStates, _producingLabNetworkIdAndStates, _researchingLabNetworkIdAndStates); _optimizedInserterExecutor.Initialize(planet, this, (InserterComponent x) => !x.bidirectional, optimizedPowerSystemBuilder.CreateInserterBuilder()); } private void InitializeAssemblers(PlanetFactory planet, OptimizedPowerSystemBuilder optimizedPowerSystemBuilder) { _assemblerExecutor = new AssemblerExecutor(); _assemblerExecutor.InitializeAssemblers(planet, optimizedPowerSystemBuilder); } private void InitializeMiners(PlanetFactory planet) { int[] array = new int[planet.factorySystem.minerCursor]; for (int i = 0; i < planet.factorySystem.minerCursor; i++) { ref MinerComponent reference = ref planet.factorySystem.minerPool[i]; if (reference.id == i) { array[i] = planet.powerSystem.consumerPool[reference.pcId].networkId; } } _minerNetworkIds = array; } private void InitializeEjectors(PlanetFactory planet) { int[] array = new int[planet.factorySystem.ejectorCursor]; for (int i = 0; i < planet.factorySystem.ejectorCursor; i++) { ref EjectorComponent reference = ref planet.factorySystem.ejectorPool[i]; if (reference.id == i) { array[i] = planet.powerSystem.consumerPool[reference.pcId].networkId; ref int[] needs = ref reference.needs; if (needs == null) { needs = new int[6]; } planet.entityNeeds[reference.entityId] = reference.needs; } } _ejectorNetworkIds = array; } private void InitializeLabAssemblers(PlanetFactory planet, OptimizedPowerSystemBuilder optimizedPowerSystemBuilder) { _producingLabExecutor = new ProducingLabExecutor(); _producingLabExecutor.Initialize(planet, optimizedPowerSystemBuilder); _producingLabNetworkIdAndStates = _producingLabExecutor._networkIdAndStates; _optimizedProducingLabs = _producingLabExecutor._optimizedLabs; _producingLabRecipes = _producingLabExecutor._producingLabRecipes; _producingLabIdToOptimizedIndex = _producingLabExecutor._labIdToOptimizedLabIndex; } private void InitializeResearchingLabs(PlanetFactory planet, OptimizedPowerSystemBuilder optimizedPowerSystemBuilder) { _researchingLabExecutor = new ResearchingLabExecutor(_starClusterResearchManager); _researchingLabExecutor.Initialize(planet, optimizedPowerSystemBuilder); _researchingLabNetworkIdAndStates = _researchingLabExecutor._networkIdAndStates; _optimizedResearchingLabs = _researchingLabExecutor._optimizedLabs; _researchingLabIdToOptimizedIndex = _researchingLabExecutor._labIdToOptimizedLabIndex; } private void InitializeSpraycoaters(PlanetFactory planet, OptimizedPowerSystemBuilder optimizedPowerSystemBuilder) { _spraycoaterExecutor = new SpraycoaterExecutor(); _spraycoaterExecutor.Initialize(planet, optimizedPowerSystemBuilder); } private void InitializeFractionators(PlanetFactory planet, OptimizedPowerSystemBuilder optimizedPowerSystemBuilder) { _fractionatorExecutor = new FractionatorExecutor(); _fractionatorExecutor.Initialize(planet, optimizedPowerSystemBuilder); } public void GameTick(PlanetFactory planet, long time, int _usedThreadCnt, int _curThreadIdx, int _minimumMissionCnt) { //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Invalid comparison between Unknown and I4 GameHistoryData history = GameMain.history; FactoryProductionStat obj = GameMain.statistics.production.factoryStatPool[planet.index]; int[] productRegister = obj.productRegister; int[] consumeRegister = obj.consumeRegister; PowerSystem powerSystem = planet.powerSystem; float[] networkServes = powerSystem.networkServes; _ = planet.entityPool; VeinData[] veinPool = planet.veinPool; AnimData[] entityAnimPool = planet.entityAnimPool; SignData[] entitySignPool = planet.entitySignPool; int[][] entityNeeds = planet.entityNeeds; FactorySystem factorySystem = planet.factorySystem; PowerConsumerComponent[] consumerPool = powerSystem.consumerPool; AstroData[] array = null; int num = default(int); int num2 = default(int); if (WorkerThreadExecutor.CalculateMissionIndex(1, factorySystem.minerCursor - 1, _usedThreadCnt, _curThreadIdx, _minimumMissionCnt, ref num, ref num2)) { float num3; float num4 = (num3 = planet.gameData.gameDesc.resourceMultiplier); if (num3 < 5f / 12f) { num3 = 5f / 12f; } float num5 = history.miningCostRate; float miningSpeedScale = history.miningSpeedScale; float num6 = history.miningCostRate * 0.40111667f / num3; if (num4 > 99.5f) { num5 = 0f; num6 = 0f; } int[] minerNetworkIds = _minerNetworkIds; MinerComponent.InsufficientWarningThresAmount(num4, num5); for (int i = num; i < num2; i++) { if (factorySystem.minerPool[i].id == i) { float num7 = networkServes[minerNetworkIds[i]]; ((MinerComponent)(ref factorySystem.minerPool[i])).InternalUpdate(planet, veinPool, num7, ((int)factorySystem.minerPool[i].type == 3) ? num6 : num5, miningSpeedScale, productRegister); } } } _assemblerExecutor.GameTick(planet, time, _usedThreadCnt, _curThreadIdx, _minimumMissionCnt); _fractionatorExecutor.GameTick(planet, time, _usedThreadCnt, _curThreadIdx, _minimumMissionCnt); lock (factorySystem.ejectorPool) { if (factorySystem.ejectorCursor - factorySystem.ejectorRecycleCursor > 1) { array = factorySystem.planet.galaxy.astrosData; } } DysonSwarm val = null; if (factorySystem.factory.dysonSphere != null) { val = factorySystem.factory.dysonSphere.swarm; } if (WorkerThreadExecutor.CalculateMissionIndex(1, factorySystem.ejectorCursor - 1, _usedThreadCnt, _curThreadIdx, _minimumMissionCnt, ref num, ref num2)) { int[] ejectorNetworkIds = _ejectorNetworkIds; for (int j = num; j < num2; j++) { if (factorySystem.ejectorPool[j].id == j) { float num8 = networkServes[ejectorNetworkIds[j]]; ((EjectorComponent)(ref factorySystem.ejectorPool[j])).InternalUpdate(num8, time, val, array, entityAnimPool, consumeRegister); } } } lock (factorySystem.siloPool) { if (factorySystem.siloCursor - factorySystem.siloRecycleCursor > 1) { array = factorySystem.planet.galaxy.astrosData; } } DysonSphere dysonSphere = factorySystem.factory.dysonSphere; bool flag = dysonSphere != null && dysonSphere.autoNodeCount > 0; if (!WorkerThreadExecutor.CalculateMissionIndex(1, factorySystem.siloCursor - 1, _usedThreadCnt, _curThreadIdx, _minimumMissionCnt, ref num, ref num2)) { return; } for (int k = num; k < num2; k++) { if (factorySystem.siloPool[k].id == k) { int entityId = factorySystem.siloPool[k].entityId; uint num9 = 0u; float num10 = networkServes[consumerPool[factorySystem.siloPool[k].pcId].networkId]; num9 = ((SiloComponent)(ref factorySystem.siloPool[k])).InternalUpdate(num10, dysonSphere, entityAnimPool, consumeRegister); entityAnimPool[entityId].state = num9; entityNeeds[entityId] = factorySystem.siloPool[k].needs; if (entitySignPool[entityId].signType == 0 || entitySignPool[entityId].signType > 3) { entitySignPool[entityId].signType = ((!flag) ? 9u : 0u); } } } } public TypedObjectIndex GetAsGranularTypedObjectIndex(int index, PlanetFactory planet) { ref EntityData reference = ref planet.entityPool[index]; if (reference.beltId != 0) { return new TypedObjectIndex(EntityType.Belt, reference.beltId); } if (reference.assemblerId != 0) { if (_assemblerExecutor._assemblerIdToOptimizedIndex.TryGetValue(reference.assemblerId, out var value)) { return new TypedObjectIndex(EntityType.Assembler, value); } if (_assemblerExecutor._unOptimizedAssemblerIds.Contains(reference.assemblerId)) { return TypedObjectIndex.Invalid; } throw new InvalidOperationException("Failed to convert assembler id into optimized assembler id."); } if (reference.ejectorId != 0) { return new TypedObjectIndex(EntityType.Ejector, reference.ejectorId); } if (reference.siloId != 0) { return new TypedObjectIndex(EntityType.Silo, reference.siloId); } if (reference.labId != 0) { if (planet.factorySystem.labPool[reference.labId].researchMode) { if (_researchingLabIdToOptimizedIndex.TryGetValue(reference.labId, out var value2)) { return new TypedObjectIndex(EntityType.ResearchingLab, value2); } if (_researchingLabExecutor._unOptimizedLabIds.Contains(reference.labId)) { return TypedObjectIndex.Invalid; } throw new InvalidOperationException("Failed to convert researching lab id into optimized lab id."); } if (_producingLabIdToOptimizedIndex.TryGetValue(reference.labId, out var value3)) { return new TypedObjectIndex(EntityType.ProducingLab, value3); } if (_producingLabExecutor._unOptimizedLabIds.Contains(reference.labId)) { return TypedObjectIndex.Invalid; } throw new InvalidOperationException("Failed to convert producing lab id into optimized lab id."); } if (reference.storageId != 0) { return new TypedObjectIndex(EntityType.Storage, reference.storageId); } if (reference.stationId != 0) { return new TypedObjectIndex(EntityType.Station, reference.stationId); } if (reference.powerGenId != 0) { return new TypedObjectIndex(EntityType.PowerGenerator, reference.powerGenId); } if (reference.splitterId != 0) { return new TypedObjectIndex(EntityType.Splitter, reference.splitterId); } if (reference.inserterId != 0) { return new TypedObjectIndex(EntityType.Inserter, reference.inserterId); } throw new InvalidOperationException("Unknown entity type."); } public static int[]? GetEntityNeeds(PlanetFactory planet, int entityIndex) { ref EntityData reference = ref planet.entityPool[entityIndex]; if (reference.beltId != 0) { return null; } if (reference.assemblerId != 0) { return planet.factorySystem.assemblerPool[reference.assemblerId].needs ?? throw new InvalidOperationException("Need must not be null for assembler."); } if (reference.ejectorId != 0) { ref EjectorComponent reference2 = ref planet.factorySystem.ejectorPool[reference.ejectorId]; int[] needs = reference2.needs; if (needs == null) { reference2.needs = new int[6]; planet.entityNeeds[reference2.entityId] = reference2.needs; needs = reference2.needs; } return needs; } if (reference.siloId != 0) { ref SiloComponent reference3 = ref planet.factorySystem.siloPool[reference.siloId]; int[] needs2 = reference3.needs; if (needs2 == null) { reference3.needs = new int[6]; planet.entityNeeds[reference3.entityId] = reference3.needs; needs2 = reference3.needs; } return needs2; } if (reference.labId != 0) { return planet.factorySystem.labPool[reference.labId].needs ?? throw new InvalidOperationException("Need must not be null for lab."); } if (reference.storageId != 0) { return null; } if (reference.stationId != 0) { return planet.transport.stationPool[reference.stationId].needs ?? throw new InvalidOperationException("Need must not be null for station."); } if (reference.powerGenId != 0) { return null; } if (reference.splitterId != 0) { return null; } if (reference.inserterId != 0) { return null; } throw new InvalidOperationException("Unknown entity type."); } public WorkTracker[] GetMultithreadedWork(int maxParallelism) { if (_workTrackersParallelism != maxParallelism) { _workTrackers = CreateMultithreadedWork(maxParallelism); _workTrackersParallelism = maxParallelism; } return _workTrackers; } private WorkTracker[] CreateMultithreadedWork(int maxParallelism) { List<WorkTracker> list = new List<WorkTracker>(); int minerCursor = _planet.factorySystem.minerCursor; int num = ((Status == OptimizedPlanetStatus.Running) ? _assemblerExecutor.AssemblerCount : _planet.factorySystem.assemblerCursor); int num2 = ((Status == OptimizedPlanetStatus.Running) ? _fractionatorExecutor.FractionatorCount : _planet.factorySystem.fractionatorCursor); int ejectorCursor = _planet.factorySystem.ejectorCursor; int siloCursor = _planet.factorySystem.siloCursor; int monitorCursor = _planet.cargoTraffic.monitorCursor; int num3 = ((Status == OptimizedPlanetStatus.Running) ? _spraycoaterExecutor.SpraycoaterCount : _planet.cargoTraffic.spraycoaterCursor); int pilerCursor = _planet.cargoTraffic.pilerCursor; int splitterCursor = _planet.cargoTraffic.splitterCursor; int pathCursor = _planet.cargoTraffic.pathCursor; int stationCursor = _planet.transport.stationCursor; int dispenserCursor = _planet.transport.dispenserCursor; int num4 = stationCursor + dispenserCursor; int cursor = _planet.defenseSystem.turrets.cursor; int cursor2 = _planet.defenseSystem.fieldGenerators.cursor; int cursor3 = _planet.defenseSystem.battleBases.cursor; int cursor4 = _planet.digitalSystem.markers.cursor; int num5 = ((Status == OptimizedPlanetStatus.Running) ? (_optimizedBiInserterExecutor.InserterCount + _optimizedInserterExecutor.InserterCount) : _planet.factorySystem.inserterCursor); int num6 = ((Status == OptimizedPlanetStatus.Running) ? _producingLabExecutor.ProducingLabCount : _planet.factorySystem.labCursor); int num7 = ((Status == OptimizedPlanetStatus.Running) ? _researchingLabExecutor.ResearchingLabCount : _planet.factorySystem.labCursor); int num8 = ((Status == OptimizedPlanetStatus.Running) ? (num6 + num7) : _planet.factorySystem.labCursor); int storageCursor = _planet.factoryStorage.storageCursor; int tankCursor = _planet.factoryStorage.tankCursor; int val = (minerCursor + num + num2 + ejectorCursor + siloCursor + monitorCursor + num3 + pilerCursor + stationCursor + dispenserCursor + cursor + cursor2 + cursor3 + cursor4 + 4999) / 5000; val = Math.Min(val, maxParallelism); if (val > 0) { list.Add(new WorkTracker(WorkType.BeforePower, val)); } if (_planet.powerSystem.netCursor > 0) { list.Add(new WorkTracker(WorkType.Power, 1)); } list.Add(new WorkTracker(WorkType.Construction, 1)); list.Add(new WorkTracker(WorkType.CheckBefore, 1)); int val2 = (minerCursor + num + num2 + ejectorCursor + siloCursor + num6 + 4999) / 5000; val2 = Math.Min(val2, maxParallelism); if (val2 > 0) { list.Add(new WorkTracker(WorkType.Assembler, val2)); } if (num7 > 0) { list.Add(new WorkTracker(WorkType.LabResearchMode, 1)); } int val3 = (num8 + 4999) / 5000; val3 = Math.Min(val3, maxParallelism); if (val3 > 0) { list.Add(new WorkTracker(WorkType.LabOutput2NextData, val3)); } if (num4 > 0) { list.Add(new WorkTracker(WorkType.TransportData, 1)); } if (stationCursor > 0) { list.Add(new WorkTracker(WorkType.InputFromBelt, 1)); } int val4 = (num5 + 4999) / 5000; val4 = Math.Min(val4, maxParallelism); if (val4 > 0) { list.Add(new WorkTracker(WorkType.InserterData, val4)); } if (storageCursor + tankCursor > 0) { list.Add(new WorkTracker(WorkType.Storage, 1)); } int val5 = (pathCursor + 4999) / 5000; val5 = Math.Min(val5, maxParallelism); if (val5 > 0) { list.Add(new WorkTracker(WorkType.CargoPathsData, val5)); } if (splitterCursor > 0) { list.Add(new WorkTracker(WorkType.Splitter, 1)); } if (monitorCursor > 0) { list.Add(new WorkTracker(WorkType.Monitor, 1)); } if (num3 > 0) { list.Add(new WorkTracker(WorkType.Spraycoater, 1)); } if (pilerCursor > 0) { list.Add(new WorkTracker(WorkType.Piler, 1)); } if (stationCursor > 0) { list.Add(new WorkTracker(WorkType.OutputToBelt, 1)); } int val6 = (num4 + 4999) / 5000; val6 = Math.Min(val6, maxParallelism); if (GameMain.sandboxToolsEnabled && val6 > 0) { list.Add(new WorkTracker(WorkType.SandboxMode, val6)); } int val7 = (pathCursor + 4999) / 5000; val7 = Math.Min(val7, maxParallelism); if (Status == OptimizedPlanetStatus.Stopped && val7 > 0) { list.Add(new WorkTracker(WorkType.PresentCargoPathsData, val7)); } if (cursor4 > 0) { list.Add(new WorkTracker(WorkType.Digital, 1)); } return list.ToArray(); } } internal enum OptimizedPlanetStatus { Running, Stopped } internal static class OptimizedStarCluster { private static readonly Dictionary<PlanetFactory, OptimizedPlanet> _planetToOptimizedPlanet = new Dictionary<PlanetFactory, OptimizedPlanet>(); private static readonly Queue<PlanetFactory> _newPlanets = new Queue<PlanetFactory>(); private static readonly Queue<PlanetFactory> _planetsToReOptimize = new Queue<PlanetFactory>(); public static readonly StarClusterResearchManager _starClusterResearchManager = new StarClusterResearchManager(); private static readonly WorkStealingMultiThreadedFactorySimulation _workStealingMultiThreadedFactorySimulation = new WorkStealingMultiThreadedFactorySimulation(_starClusterResearchManager); private static bool _clearOptimizedPlanetsOnNextTick = false; public static void EnableOptimization(Harmony harmony) { harmony.PatchAll(typeof(OptimizedStarCluster)); } public static OptimizedPlanet GetOptimizedPlanet(PlanetFactory planet) { return _planetToOptimizedPlanet[planet]; } [HarmonyPrefix] [HarmonyPatch(typeof(GameMain), "End")] public static void End() { WeaverFixes.Logger.LogInfo((object)"Marking optimized planets to be cleared."); _clearOptimizedPlanetsOnNextTick = true; } [HarmonyPriority(1)] [HarmonyPostfix] [HarmonyPatch(typeof(GameSave), "LoadCurrentGame")] private static void LoadCurrentGame_Postfix() { WeaverFixes.Logger.LogInfo((object)"Initializing OptimizedPlanet"); _planetToOptimizedPlanet.Clear(); _workStealingMultiThreadedFactorySimulation.Clear(); _clearOptimizedPlanetsOnNextTick = false; for (int i = 0; i < GameMain.data.factoryCount; i++) { PlanetFactory val = GameMain.data.factories[i]; if (val.factorySystem != null) { _planetToOptimizedPlanet.Add(val, new OptimizedPlanet(val, _starClusterResearchManager)); } } } [HarmonyPrefix] [HarmonyPatch(typeof(GameSave), "SaveCurrentGame")] private static void SaveCurrentGame_Prefix() { WeaverFixes.Logger.LogInfo((object)"Saving optimized planets"); foreach (KeyValuePair<PlanetFactory, OptimizedPlanet> item in _planetToOptimizedPlanet) { if (item.Value.Status == OptimizedPlanetStatus.Running) { WeaverFixes.Logger.LogInfo((object)("Saving planet: " + item.Key.planet.displayName)); item.Value.Save(); } } } [HarmonyPrefix] [HarmonyPatch(typeof(GameData), "GameTick")] public static void GameData_GameTick() { if (_clearOptimizedPlanetsOnNextTick) { _clearOptimizedPlanetsOnNextTick = false; _planetToOptimizedPlanet.Clear(); _workStealingMultiThreadedFactorySimulation.Clear(); } lock (_newPlanets) { while (_newPlanets.Count > 0) { PlanetFactory val = _newPlanets.Dequeue(); WeaverFixes.Logger.LogInfo((object)("Adding planet: " + val.planet.displayName)); _planetToOptimizedPlanet.Add(val, new OptimizedPlanet(val, _starClusterResearchManager)); } } foreach (KeyValuePair<PlanetFactory, OptimizedPlanet> item in _planetToOptimizedPlanet) { if (GameMain.localPlanet?.factory != item.Key) { if (item.Value.Status == OptimizedPlanetStatus.Stopped && (item.Value.OptimizeDelayInTicks <= 0 || item.Value.OptimizeDelayInTicks-- <= 0)) { WeaverFixes.Logger.LogInfo((object)("Optimizing planet: " + item.Key.planet.displayName)); item.Value.Initialize(); } } else if (item.Value.Status != OptimizedPlanetStatus.Stopped) { WeaverFixes.Logger.LogInfo((object)("DeOptimizing planet: " + item.Key.planet.displayName)); item.Value.Save(); } } if (_planetsToReOptimize.Count > 0) { PlanetFactory val2 = _planetsToReOptimize.Dequeue(); OptimizedPlanet optimizedPlanet = _planetToOptimizedPlanet[val2]; if (optimizedPlanet.Status != OptimizedPlanetStatus.Stopped) { WeaverFixes.Logger.LogInfo((object)("DeOptimizing planet: " + val2.planet.displayName)); optimizedPlanet.Save(); } } } [HarmonyPostfix] [HarmonyPatch(typeof(PlanetFactory), "Init")] public static void PlanetFactory_Init(PlanetFactory __instance) { lock (_newPlanets) { _newPlanets.Enqueue(__instance); } } [HarmonyPrefix] [HarmonyPatch(typeof(PlanetFactory), "AddEntityDataWithComponents")] public static void PlanetFactory_AddEntityDataWithComponents(PlanetFactory __instance) { DeOptimizeDueToNonPlayerAction(__instance); } [HarmonyPrefix] [HarmonyPatch(typeof(PlanetFactory), "RemoveEntityWithComponents")] public static void PlanetFactory_RemoveEntityWithComponents(PlanetFactory __instance) { DeOptimizeDueToNonPlayerAction(__instance); } [HarmonyPrefix] [HarmonyPatch(typeof(PlanetFactory), "UpgradeEntityWithComponents")] public static void PlanetFactory_UpgradeEntityWithComponents(PlanetFactory __instance) { DeOptimizeDueToNonPlayerAction(__instance); } [HarmonyPostfix] [HarmonyPatch(typeof(PlanetFactory), "GameTick", new Type[] { typeof(long) })] public static void PlanetFactory_SingleThreadedGameTick() { _starClusterResearchManager.UIThreadUnlockResearchedTechnologies(GameMain.history); } [HarmonyPrefix] [HarmonyPatch(typeof(FactorySystem), "GameTick", new Type[] { typeof(long), typeof(bool), typeof(int), typeof(int), typeof(int) })] public static bool FactorySystem_ParallelGameTick(FactorySystem __instance, long time, bool isActive, int _usedThreadCnt, int _curThreadIdx, int _minimumMissionCnt) { OptimizedPlanet optimizedPlanet = _planetToOptimizedPlanet[__instance.factory]; if (optimizedPlanet.Status != 0) { return true; } optimizedPlanet.GameTick(__instance.factory, time, _usedThreadCnt, _curThreadIdx, _minimumMissionCnt); return false; } [HarmonyPrefix] [HarmonyPatch(typeof(FactorySystem), "GameTickLabProduceMode", new Type[] { typeof(long), typeof(bool), typeof(int), typeof(int), typeof(int) })] public static bool FactorySystem_GameTickLabProduceMode(FactorySystem __instance, long time, bool isActive, int _usedThreadCnt, int _curThreadIdx, int _minimumMissionCnt) { OptimizedPlanet optimizedPlanet = _planetToOptimizedPlanet[__instance.factory]; if (optimizedPlanet.Status != 0) { return true; } optimizedPlanet._producingLabExecutor.GameTickLabProduceMode(__instance.factory, time, _usedThreadCnt, _curThreadIdx, _minimumMissionCnt); return false; } [HarmonyPrefix] [HarmonyPatch(typeof(FactorySystem), "GameTickBeforePower")] public static bool FactorySystem_SingleThreadedGameTickBeforePower(FactorySystem __instance, long time, bool isActive) { return FactorySystem_ParallelGameTickBeforePower(__instance, time, isActive, 1, 0, 4); } [HarmonyPrefix] [HarmonyPatch(typeof(FactorySystem), "ParallelGameTickBeforePower")] public static bool FactorySystem_ParallelGameTickBeforePower(FactorySystem __instance, long time, bool isActive, int _usedThreadCnt, int _curThreadIdx, int _minimumMissionCnt) { OptimizedPlanet optimizedPlanet = _planetToOptimizedPlanet[__instance.factory]; if (optimizedPlanet.Status != 0) { return true; } optimizedPlanet._optimizedPowerSystem.FactorySystem_ParallelGameTickBeforePower(__instance.factory, optimizedPlanet, time, isActive, _usedThreadCnt, _curThreadIdx, _minimumMissionCnt); return false; } [HarmonyPrefix] [HarmonyPatch(typeof(CargoTraffic), "GameTickBeforePower")] public static bool CargoTraffic_SingleThreadedGameTickBeforePower(CargoTraffic __instance, long time, bool isActive) { return CargoTraffic_ParallelGameTickBeforePower(__instance, time, isActive, 1, 0, 4); } [HarmonyPrefix] [HarmonyPatch(typeof(CargoTraffic), "ParallelGameTickBeforePower")] public static bool CargoTraffic_ParallelGameTickBeforePower(CargoTraffic __instance, long time, bool isActive, int _usedThreadCnt, int _curThreadIdx, int _minimumMissionCnt) { OptimizedPlanet optimizedPlanet = _planetToOptimizedPlanet[__instance.factory]; if (optimizedPlanet.Status != 0) { return true; } optimizedPlanet._optimizedPowerSystem.CargoTraffic_ParallelGameTickBeforePower(__instance.factory, optimizedPlanet, time, isActive, _usedThreadCnt, _curThreadIdx, _minimumMissionCnt); return false; } [HarmonyPrefix] [HarmonyPatch(typeof(PowerSystem), "GameTick")] public static bool GameTick(PowerSystem __instance, long time, bool isActive, bool isMultithreadMode = false) { OptimizedPlanet optimizedPlanet = _planetToOptimizedPlanet[__instance.factory]; if (optimizedPlanet.Status != 0) { return true; } optimizedPlanet._optimizedPowerSystem.GameTick(__instance.factory, time, isActive, isMultithreadMode); return false; } [HarmonyPrefix] [HarmonyPatch(typeof(FactorySystem), "GameTickLabResearchMode")] public static bool GameTickLabResearchMode(FactorySystem __instance, long time, bool isActive) { OptimizedPlanet optimizedPlanet = _planetToOptimizedPlanet[__instance.factory]; if (optimizedPlanet.Status != 0) { return true; } optimizedPlanet._researchingLabExecutor.GameTickLabResearchMode(__instance.factory, time); return false; } [HarmonyTranspiler] [HarmonyPatch(typeof(FactorySystem), "GameTickLabResearchMode")] private static IEnumerable<CodeInstruction> DeferResearchUnlockToStarClusterResearchManager(IEnumerable<CodeInstruction> instructions, ILGenerator generator) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Expected O, but got Unknown //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Expected O, but got Unknown //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Expected O, but got Unknown //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Expected O, but got Unknown //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Expected O, but got Unknown //IL_0161: Unknown re