using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; 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 UnityEngine.UI; using Weaver.Extensions; using Weaver.FatoryGraphs; using Weaver.Optimizations; using Weaver.Optimizations.Assemblers; using Weaver.Optimizations.Belts; using Weaver.Optimizations.Ejectors; using Weaver.Optimizations.Fractionators; using Weaver.Optimizations.Inserters; using Weaver.Optimizations.Inserters.Types; using Weaver.Optimizations.Labs; using Weaver.Optimizations.Labs.Producing; using Weaver.Optimizations.Labs.Researching; using Weaver.Optimizations.Miners; using Weaver.Optimizations.Monitors; using Weaver.Optimizations.NeedsSystem; using Weaver.Optimizations.Pilers; using Weaver.Optimizations.PowerSystems; using Weaver.Optimizations.PowerSystems.Generators; using Weaver.Optimizations.Silos; using Weaver.Optimizations.Splitters; using Weaver.Optimizations.Spraycoaters; using Weaver.Optimizations.StaticData; using Weaver.Optimizations.Stations; using Weaver.Optimizations.Statistics; using Weaver.Optimizations.Storages; using Weaver.Optimizations.Tanks; using Weaver.Optimizations.Turrets; using Weaver.Optimizations.WorkDistributors; using Weaver.Optimizations.WorkDistributors.WorkChunks; [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+fcd59f70e26862d41d69aa6ea8e6c331d683651d")] [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] internal sealed class IsUnmanagedAttribute : 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 System.Diagnostics.CodeAnalysis { [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] internal sealed class MemberNotNullWhenAttribute : Attribute { public bool ReturnValue { get; } public string[] Members { get; } public MemberNotNullWhenAttribute(bool returnValue, string member) { ReturnValue = returnValue; Members = new string[1] { member }; } public MemberNotNullWhenAttribute(bool returnValue, params string[] members) { ReturnValue = returnValue; Members = members; } } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] internal sealed class NotNullWhenAttribute : Attribute { public bool ReturnValue { get; } public NotNullWhenAttribute(bool returnValue) { ReturnValue = returnValue; } } } 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; public static int Combine(T value1) { HashCode hashCode = default(HashCode); hashCode.Add(value1); return hashCode.GetHashCode(); } public static int Combine(T1 value1, T2 value2) { HashCode hashCode = default(HashCode); hashCode.Add(value1); hashCode.Add(value2); return hashCode.GetHashCode(); } public static int Combine(T1 value1, T2 value2, T3 value3) { HashCode hashCode = default(HashCode); hashCode.Add(value1); hashCode.Add(value2); hashCode.Add(value3); return hashCode.GetHashCode(); } public static int Combine(T1 value1, T2 value2, T3 value3, T4 value4) { HashCode hashCode = default(HashCode); hashCode.Add(value1); hashCode.Add(value2); hashCode.Add(value3); hashCode.Add(value4); return hashCode.GetHashCode(); } public static int Combine(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5) { HashCode hashCode = default(HashCode); hashCode.Add(value1); hashCode.Add(value2); hashCode.Add(value3); hashCode.Add(value4); hashCode.Add(value5); return hashCode.GetHashCode(); } public static int Combine(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6) { HashCode hashCode = default(HashCode); hashCode.Add(value1); hashCode.Add(value2); hashCode.Add(value3); hashCode.Add(value4); hashCode.Add(value5); hashCode.Add(value6); return hashCode.GetHashCode(); } public static int Combine(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6, T7 value7) { HashCode hashCode = default(HashCode); hashCode.Add(value1); hashCode.Add(value2); hashCode.Add(value3); hashCode.Add(value4); hashCode.Add(value5); hashCode.Add(value6); hashCode.Add(value7); return hashCode.GetHashCode(); } [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 value) { Add(value?.GetHashCode() ?? 0); } public void Add(T value, IEqualityComparer 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 readonly 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(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 = "2.4.1"; } [BepInPlugin("Weaver", "Weaver", "2.4.1")] public class WeaverFixes : BaseUnityPlugin { private record struct ModIncompatibility(string ModName, string ModGuid, IncompatibilityDegree IncompatibilityDegree, string? IncompatibilityDescription, string TechnicalIncompatibilityDescription); private enum IncompatibilityDegree { PartiallyCompatible, CompletelyIncompatible } internal static ManualLogSource Logger = Logger.CreateLogSource("Weaver"); private const string _ModCompatibilityConfigName = "WarnAboutModIncompatibility"; private static readonly bool _enableDebugOptions = false; private bool _firstUpdate = true; private bool _warnAbountModIncompatibility; private static readonly ModIncompatibility[] _incompatibleMods = new ModIncompatibility[7] { new ModIncompatibility("GenesisBook", "org.LoShin.GenesisBook", IncompatibilityDegree.CompletelyIncompatible, null, "Patches base game code which Weaver never calls."), new ModIncompatibility("Multfuntion mod", "cn.blacksnipe.dsp.Multfuntion_mod", IncompatibilityDegree.PartiallyCompatible, "Some functionality may not work.", "Most patches are for logic that weaver never calls."), new ModIncompatibility("MoreMegaStructure", "Gnimaerd.DSP.plugin.MoreMegaStructure", IncompatibilityDegree.PartiallyCompatible, "Mega structures do not work unless player is present on planet.", "Patches base game code which Weaver never calls."), new ModIncompatibility("VeinityProject", "eirshy.dsp.VeinityProject", IncompatibilityDegree.CompletelyIncompatible, null, "Patches base game code which Weaver never calls."), new ModIncompatibility("PlanetMiner", "crecheng.PlanetMiner", IncompatibilityDegree.CompletelyIncompatible, null, "It depends on the research lab update which weaver never calls for optimized planets."), new ModIncompatibility("SmartTank", "GniMaerd.DSP.plugin.SmartTank", IncompatibilityDegree.PartiallyCompatible, "Well presumably most people will only use it on their first planet? If true then there is no issue.", "Patches base game code which Weaver never calls."), new ModIncompatibility("PlanetwideSpray", "starfi5h.plugin.PlanetwideSpray", IncompatibilityDegree.CompletelyIncompatible, null, "Patches base game code which Weaver never calls.") }; private void Awake() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown _warnAbountModIncompatibility = ((BaseUnityPlugin)this).Config.Bind("Weaver", "WarnAboutModIncompatibility", true, "Displays incompatible mods, if any, on game launch.").Value; Harmony val = new Harmony("Weaver"); val.PatchAll(typeof(KillStatisticsPatches)); val.PatchAll(typeof(TrafficStatisticsPatches)); OptimizedStarCluster.EnableOptimization(val); UniverseStaticDataBuilder.EnableStatistics(); } public void Update() { if (_firstUpdate) { _firstUpdate = false; if (_warnAbountModIncompatibility) { CheckForAndWarnAboutIncompatibleMods(); } } } private static void CheckForAndWarnAboutIncompatibleMods() { //IL_0178: Unknown result type (might be due to invalid IL or missing references) ModIncompatibility[] array = _incompatibleMods.Where((ModIncompatibility x) => Chainloader.PluginInfos.ContainsKey(x.ModGuid)).ToArray(); if (array.Length == 0) { return; } StringBuilder stringBuilder = new StringBuilder(); ModIncompatibility[] array2 = array.Where((ModIncompatibility x) => x.IncompatibilityDegree == IncompatibilityDegree.CompletelyIncompatible).ToArray(); if (array2.Length != 0) { stringBuilder.AppendLine("The following mods are not compatible with Weaver:"); ModIncompatibility[] array3 = array2; foreach (ModIncompatibility modIncompatibility in array3) { stringBuilder.AppendLine("\t" + modIncompatibility.ModName); } } ModIncompatibility[] array4 = array.Where((ModIncompatibility x) => x.IncompatibilityDegree == IncompatibilityDegree.PartiallyCompatible).ToArray(); if (array4.Length != 0) { if (array2.Length != 0) { stringBuilder.AppendLine(); } stringBuilder.AppendLine("The following mods are partially incompatible. Some functionality will not work with Weaver."); ModIncompatibility[] array3 = array4; foreach (ModIncompatibility modIncompatibility2 in array3) { stringBuilder.AppendLine("\t" + modIncompatibility2.ModName); } } stringBuilder.AppendLine(); stringBuilder.AppendLine("This warning can be disabled by setting the Weaver"); stringBuilder.AppendLine("config WarnAboutModIncompatibility to false."); ((Graphic)UIMessageBox.Show("Incompatible mods", stringBuilder.ToString(), "Close", 0).m_MessageText).rectTransform.sizeDelta = new Vector2((float)Screen.width, (float)Screen.height); } } 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 { internal sealed class DysonSphereManager { private readonly Queue _createDysonSpheresFor = new Queue(); public void AddDysonDysonSphere(PlanetFactory planet) { lock (_createDysonSpheresFor) { _createDysonSpheresFor.Enqueue(planet); } } public void UIThreadCreateDysonSpheres() { try { foreach (PlanetFactory item in _createDysonSpheresFor) { item.CheckOrCreateDysonSphere(); } } finally { _createDysonSpheresFor.Clear(); } } } internal sealed class DysonSphereStatisticsManager { private readonly HashSet _dysonSphereProductionRegisters = new HashSet(); private const int _sailItemId = 11901; private const int _structureNodeItemId = 11902; private const int _cellItemId = 11903; private static readonly int[] _dysonItemIds = new int[3] { 11901, 11902, 11903 }; public bool IsDysonSphereStatistics(FactoryProductionStat factoryStats) { return _dysonSphereProductionRegisters.Contains(factoryStats.productRegister); } public void FindAllDysonSphereProductRegisters() { for (int i = 0; i < GameMain.data.dysonSpheres.Length; i++) { DysonSphere val = GameMain.data.dysonSpheres[i]; if (val != null) { int[] productRegister = val.productRegister; if (productRegister != null) { _dysonSphereProductionRegisters.Add(productRegister); } } } } public void ClearDysonSphereProductRegisters() { _dysonSphereProductionRegisters.Clear(); } public static void DysonSphereGameTick(FactoryProductionStat factoryStats, long time) { ProductionHelper.PartialProductionStatisticsGameTick(factoryStats, time, _dysonItemIds); } public static void DysonSphereClearRegisters(FactoryProductionStat factoryStats) { int[] dysonItemIds = _dysonItemIds; for (int i = 0; i < dysonItemIds.Length; i++) { factoryStats.productRegister[dysonItemIds[i]] = 0; factoryStats.consumeRegister[dysonItemIds[i]] = 0; } } } 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()); int pos = codeMatcher.Pos; codeMatcher.MatchForward(replaceEnd, end).ThrowIfNotMatch("Failed to find end", Array.Empty()); 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); } } } internal interface IOptimizedPlanet { OptimizedPlanetStatus Status { get; } int OptimizeDelayInTicks { get; set; } void Save(); void Initialize(UniverseStaticDataBuilder universeStaticDataBuilder); void TransportGameTick(int workerIndex, long time, Vector3 playerPos); IWorkNode GetMultithreadedWork(int maxParallelism); } internal sealed class OptimizedDysonSphere { private static readonly Dictionary _dysonSphereToOptimizedDysonSphere = new Dictionary(); private static readonly Dictionary _dysonSwarmToOptimizedDysonSphere = new Dictionary(); private readonly DysonSphere _dysonSphere; private readonly long[] _dysonSphereLayersPowerGenerated; private bool _needToRecalculatePower; public OptimizedDysonSphere(DysonSphere dysonSphere) { _dysonSphere = dysonSphere; _dysonSphereLayersPowerGenerated = new long[dysonSphere.layersSorted.Length]; _needToRecalculatePower = true; } public static void Reset() { _dysonSphereToOptimizedDysonSphere.Clear(); _dysonSwarmToOptimizedDysonSphere.Clear(); if (GameMain.data.dysonSpheres == null) { return; } DysonSphere[] dysonSpheres = GameMain.data.dysonSpheres; foreach (DysonSphere val in dysonSpheres) { if (val != null) { OptimizedDysonSphere value = new OptimizedDysonSphere(val); _dysonSphereToOptimizedDysonSphere.Add(val, value); if (val.swarm != null) { _dysonSwarmToOptimizedDysonSphere.Add(val.swarm, value); } } } } [HarmonyPostfix] [HarmonyPatch(typeof(DysonSphere), "Init")] public static void DysonSphere_Init(DysonSphere __instance) { OptimizedDysonSphere value = new OptimizedDysonSphere(__instance); _dysonSphereToOptimizedDysonSphere.Add(__instance, value); _dysonSwarmToOptimizedDysonSphere.Add(__instance.swarm, value); } [HarmonyPrefix] [HarmonyPatch(typeof(DysonSphere), "ConstructSp")] public static bool DysonSphere_ConstructSp(DysonSphere __instance, DysonNode node) { OptimizedDysonSphere optimizedDysonSphere = GetOptimizedDysonSphere(__instance); object obj = node.ConstructSp(); if (obj == null) { return false; } DysonNode val = (DysonNode)((obj is DysonNode) ? obj : null); if (val != null) { __instance.UpdateProgress(val); optimizedDysonSphere.AddDysonNodeToPowerGenerated(val.layerId - 1); } else { DysonFrame val2 = (DysonFrame)((obj is DysonFrame) ? obj : null); if (val2 != null) { __instance.UpdateProgress(val2); optimizedDysonSphere.AddDysonFrameToPowerGenerated(val2.layerId - 1); } } int[] productRegister = __instance.productRegister; if (productRegister != null) { lock (productRegister) { productRegister[11902]++; } } return false; } [HarmonyPrefix] [HarmonyPatch(typeof(DysonShell), "Construct")] public static void DysonShell_Construct(DysonShell __instance) { GetOptimizedDysonSphere(__instance.dysonSphere).AddDysonShellToPowerGenerated(__instance.layerId - 1); } public static OptimizedDysonSphere GetOptimizedDysonSphere(DysonSphere dysonSphere) { return _dysonSphereToOptimizedDysonSphere[dysonSphere]; } public static OptimizedDysonSphere GetOptimizedDysonSphere(DysonSwarm dysonSwarm) { return _dysonSwarmToOptimizedDysonSphere[dysonSwarm]; } [HarmonyPrefix] [HarmonyPatch(typeof(DysonSphere), "BeforeGameTick")] public static bool DysonSphere_BeforeGameTick_Prefix(DysonSphere __instance) { OptimizedDysonSphere optimizedDysonSphere = GetOptimizedDysonSphere(__instance); if (optimizedDysonSphere.ShouldRecalculatePower()) { return true; } optimizedDysonSphere.OptimizedBeforeGameTick(); return false; } [HarmonyPostfix] [HarmonyPatch(typeof(DysonSphere), "BeforeGameTick")] public static void DysonSphere_BeforeGameTick_Postfix(DysonSphere __instance) { OptimizedDysonSphere optimizedDysonSphere = GetOptimizedDysonSphere(__instance); if (optimizedDysonSphere.ShouldRecalculatePower()) { optimizedDysonSphere.ResetPowerGenerated(); } } public void OptimizedBeforeGameTick() { _dysonSphere.energyReqCurrentTick = 0L; _dysonSphere.energyGenCurrentTick = 0L; _dysonSphere.energyGenOriginalCurrentTick = 0L; _dysonSphere.swarm.energyGenCurrentTick = _dysonSphere.swarm.sailCount * _dysonSphere.energyGenPerSail; DysonSphere dysonSphere = _dysonSphere; dysonSphere.energyGenCurrentTick += _dysonSphere.swarm.energyGenCurrentTick; _dysonSphere.grossRadius = _dysonSphere.swarm.grossRadius; DeepProfiler.BeginSample((DPEntry)55, -1, -1L); long[] dysonSphereLayersPowerGenerated = _dysonSphereLayersPowerGenerated; for (int i = 0; i < dysonSphereLayersPowerGenerated.Length; i++) { DysonSphereLayer val = _dysonSphere.layersSorted[i]; if (val != null) { if (val.grossRadius > _dysonSphere.grossRadius) { _dysonSphere.grossRadius = val.grossRadius; } val.energyGenCurrentTick = dysonSphereLayersPowerGenerated[i]; DysonSphere dysonSphere2 = _dysonSphere; dysonSphere2.energyGenCurrentTick += dysonSphereLayersPowerGenerated[i]; } } DeepProfiler.EndSample((DPEntry)55, -1); _dysonSphere.energyGenOriginalCurrentTick = _dysonSphere.energyGenCurrentTick; _dysonSphere.energyGenCurrentTick = (long)((double)_dysonSphere.energyGenCurrentTick * _dysonSphere.energyDFHivesDebuffCoef); } public void AddDysonNodeToPowerGenerated(int layerIndex) { Interlocked.Add(ref _dysonSphereLayersPowerGenerated[layerIndex], _dysonSphere.energyGenPerNode); } public void AddDysonFrameToPowerGenerated(int layerIndex) { Interlocked.Add(ref _dysonSphereLayersPowerGenerated[layerIndex], _dysonSphere.energyGenPerFrame); } public void AddDysonShellToPowerGenerated(int layerIndex) { Interlocked.Add(ref _dysonSphereLayersPowerGenerated[layerIndex], _dysonSphere.energyGenPerShell); } public void ResetPowerGenerated() { for (int i = 0; i < _dysonSphere.layersSorted.Length; i++) { DysonSphereLayer val = _dysonSphere.layersSorted[i]; if (val == null) { _dysonSphereLayersPowerGenerated[i] = 0L; } else { _dysonSphereLayersPowerGenerated[i] = val.energyGenCurrentTick; } } _needToRecalculatePower = false; } internal void MarkNeedToRecalculatePower() { if (!_needToRecalculatePower) { _needToRecalculatePower = true; } } internal bool ShouldRecalculatePower() { return _needToRecalculatePower; } [HarmonyPrefix] [HarmonyPatch(typeof(DysonSphere), "RemoveLayer", new Type[] { typeof(DysonSphereLayer) })] public static void DysonSphere_RemoveLayerDysonSphereLayer(DysonSphere __instance) { GetOptimizedDysonSphere(__instance).MarkNeedToRecalculatePower(); } [HarmonyPrefix] [HarmonyPatch(typeof(DysonSphere), "RemoveLayer", new Type[] { typeof(int) })] public static void DysonSphere_RemoveLayerId(DysonSphere __instance) { GetOptimizedDysonSphere(__instance).MarkNeedToRecalculatePower(); } [HarmonyPrefix] [HarmonyPatch(typeof(DysonSphere), "AddDysonNodeRData")] public static void DysonSphere_AddDysonNodeRData(DysonSphere __instance) { GetOptimizedDysonSphere(__instance).MarkNeedToRecalculatePower(); } [HarmonyPrefix] [HarmonyPatch(typeof(DysonSphere), "RemoveDysonNodeRData")] public static void DysonSphere_RemoveDysonNodeRData(DysonSphere __instance) { GetOptimizedDysonSphere(__instance).MarkNeedToRecalculatePower(); } [HarmonyPrefix] [HarmonyPatch(typeof(DysonSphere), "AutoConstruct")] public static void DysonSphere_AutoConstruct(DysonSphere __instance) { GetOptimizedDysonSphere(__instance).MarkNeedToRecalculatePower(); } [HarmonyPrefix] [HarmonyPatch(typeof(DysonSwarm), "AutoConstruct")] public static void DysonSwarm_AutoConstruct(DysonSwarm __instance) { GetOptimizedDysonSphere(__instance).MarkNeedToRecalculatePower(); } [HarmonyPrefix] [HarmonyPatch(typeof(DysonSwarm), "RemoveSailsByOrbit")] public static void DysonSwarm_RemoveSailsByOrbit(DysonSwarm __instance) { GetOptimizedDysonSphere(__instance).MarkNeedToRecalculatePower(); } } internal sealed class OptimizedGasPlanet : IOptimizedPlanet { private readonly PlanetFactory _planet; private GasPlanetWideStationExecutor _planetWideStationExecutor; private OptimizedPlanetWideProductionStatistics _optimizedPlanetWideProductionStatistics; private IWorkNode? _workNodes; private int _workStepsParallelism; public OptimizedPlanetStatus Status { get; private set; } = OptimizedPlanetStatus.Stopped; public int OptimizeDelayInTicks { get; set; } public OptimizedGasPlanet(PlanetFactory planet) { _planet = planet; } public static bool IsGasPlanet(PlanetFactory planet) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 return (int)planet.planet.type == 5; } public void Initialize(UniverseStaticDataBuilder universeStaticDataBuilder) { _planetWideStationExecutor = new GasPlanetWideStationExecutor(); _planetWideStationExecutor.Initialize(_planet); PlanetWideProductionRegisterBuilder planetWideProductionRegisterBuilder = new PlanetWideProductionRegisterBuilder(_planet); for (int i = 0; i < _planet.planet.gasItems.Length; i++) { planetWideProductionRegisterBuilder.AdditionalProductItemsIdToWatch(_planet.planet.gasItems[i]); } _optimizedPlanetWideProductionStatistics = planetWideProductionRegisterBuilder.Build(universeStaticDataBuilder); Status = OptimizedPlanetStatus.Running; _workNodes = null; _workStepsParallelism = -1; } public void Save() { _workNodes = null; _workStepsParallelism = -1; Status = OptimizedPlanetStatus.Stopped; } public void TransportGameTick(int workerIndex, long time, Vector3 playerPos) { MiningFlags miningFlags = new MiningFlags(); if (_planetWideStationExecutor.Count > 0) { DeepProfiler.BeginSample((DPEntry)36, workerIndex, (long)_planet.planetId); DeepProfiler.BeginMajorSample((DPEntry)37, workerIndex, -1L); _planetWideStationExecutor.StationGameTick(_planet, time, ref miningFlags); DeepProfiler.EndMajorSample((DPEntry)37, workerIndex); DeepProfiler.EndSample((DPEntry)36, workerIndex); } PlanetFactory planet = _planet; planet._miningFlag |= miningFlags.MiningFlag; PlanetFactory planet2 = _planet; planet2._veinMiningFlag |= miningFlags.VeinMiningFlag; DeepProfiler.BeginSample((DPEntry)75, workerIndex, -1L); FactoryProductionStat obj = GameMain.statistics.production.factoryStatPool[_planet.index]; int[] productRegister = obj.productRegister; int[] consumeRegister = obj.consumeRegister; _optimizedPlanetWideProductionStatistics.UpdateStatistics(time, productRegister, consumeRegister); DeepProfiler.EndSample((DPEntry)75, workerIndex); } public IWorkNode GetMultithreadedWork(int maxParallelism) { if (_workNodes == null || _workStepsParallelism != maxParallelism) { _workNodes = CreateMultithreadedWork(maxParallelism); _workStepsParallelism = maxParallelism; } return _workNodes; } private IWorkNode CreateMultithreadedWork(int maxParallelism) { if (Status == OptimizedPlanetStatus.Stopped) { return CreateParallelWorkForNonRunningOptimizedPlanet(maxParallelism); } if (_planetWideStationExecutor.Count > 0) { return new SingleWorkLeaf(new PlanetWideTransport(this)); } return new NoWorkNode(); } private IWorkNode CreateParallelWorkForNonRunningOptimizedPlanet(int maxParallelism) { if (_planet.transport.stationCursor > 0) { return UnOptimizedPlanetWorkChunk.CreateDuplicateChunksInWorkLeafs(_planet, WorkType.TransportData, 1)[0]; } return new NoWorkNode(); } } internal enum OptimizedPlanetStatus { Running, Stopped } internal static class OptimizedStarCluster { private static readonly Dictionary _planetToOptimizedPlanet = new Dictionary(); private static readonly Dictionary _planetProductionStatisticsToOptimizedPlanet = new Dictionary(); private static readonly Queue _newPlanets = new Queue(); private static readonly Queue _planetsToReOptimize = new Queue(); public static readonly StarClusterResearchManager _starClusterResearchManager = new StarClusterResearchManager(); public static readonly DysonSphereManager _dysonSphereManager = new DysonSphereManager(); private static readonly DysonSphereStatisticsManager _dysonSphereStatisticsManager = new DysonSphereStatisticsManager(); private static readonly UniverseStaticDataBuilder _universeStaticDataBuilder = new UniverseStaticDataBuilder(); private static readonly WorkStealingMultiThreadedFactorySimulation _workStealingMultiThreadedFactorySimulation = new WorkStealingMultiThreadedFactorySimulation(_starClusterResearchManager, _dysonSphereManager, _universeStaticDataBuilder); private static bool _clearOptimizedPlanetsOnNextTick = false; private static bool _firstUpdate = true; private static bool _programShutdown = false; private static readonly Random random = new Random(); private static bool _debugEnableHeavyReOptimization = false; private static bool _enableStatistics = false; public static bool ForceOptimizeLocalPlanet { get; set; } = false; public static void EnableOptimization(Harmony harmony) { harmony.PatchAll(typeof(OptimizedStarCluster)); harmony.PatchAll(typeof(OptimizedDysonSphere)); } public static void DebugEnableHeavyReOptimization() { _debugEnableHeavyReOptimization = true; } public static void EnableStatistics() { _enableStatistics = true; } public static IOptimizedPlanet GetOptimizedPlanet(PlanetFactory planet) { return _planetToOptimizedPlanet[planet]; } public static bool TryGetOptimizedPlanet(PlanetFactory planet, [NotNullWhen(true)] out IOptimizedPlanet? optimizedPlanet) { return _planetToOptimizedPlanet.TryGetValue(planet, out optimizedPlanet); } public static bool TryGetOptimizedPlanet(FactoryProductionStat productionStatistics, [NotNullWhen(true)] out IOptimizedPlanet? optimizedPlanet) { return _planetProductionStatisticsToOptimizedPlanet.TryGetValue(productionStatistics, out optimizedPlanet); } public static IEnumerable GetAllOptimizedPlanets() { return _planetToOptimizedPlanet.Values; } [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 OptimizedStarCluster"); PrepareOptimizedStarClusterForGame(); for (int i = 0; i < GameMain.data.factoryCount; i++) { TryAddNewPlanet(GameMain.data.factories[i]); } OptimizedDysonSphere.Reset(); _dysonSphereStatisticsManager.FindAllDysonSphereProductRegisters(); } [HarmonyPrefix] [HarmonyPatch(typeof(DSPGame), "ExitProgram")] private static void DSPGame_ExitProgram() { WeaverFixes.Logger.LogInfo((object)"Stopping simulation threads."); _workStealingMultiThreadedFactorySimulation.Dispose(); _programShutdown = true; } private static void PrepareOptimizedStarClusterForGame() { _clearOptimizedPlanetsOnNextTick = false; _firstUpdate = true; _planetToOptimizedPlanet.Clear(); _planetProductionStatisticsToOptimizedPlanet.Clear(); _dysonSphereStatisticsManager.ClearDysonSphereProductRegisters(); _universeStaticDataBuilder.Clear(); _workStealingMultiThreadedFactorySimulation.Clear(); KillStatisticsPatches.Clear(); TrafficStatisticsPatches.Clear(); } private static void TryAddNewPlanet(PlanetFactory planet) { if (planet.factorySystem != null) { if (OptimizedGasPlanet.IsGasPlanet(planet)) { OptimizedGasPlanet value = new OptimizedGasPlanet(planet); _planetToOptimizedPlanet.Add(planet, value); _planetProductionStatisticsToOptimizedPlanet.Add(GameMain.statistics.production.factoryStatPool[planet.index], value); } else { OptimizedTerrestrialPlanet value2 = new OptimizedTerrestrialPlanet(planet, _starClusterResearchManager); _planetToOptimizedPlanet.Add(planet, value2); _planetProductionStatisticsToOptimizedPlanet.Add(GameMain.statistics.production.factoryStatPool[planet.index], value2); } } } [HarmonyPrefix] [HarmonyPatch(typeof(GameSave), "SaveCurrentGame")] private static void SaveCurrentGame_Prefix() { WeaverFixes.Logger.LogInfo((object)"Saving optimized planets"); foreach (KeyValuePair 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(GameThreadController), "LogicFrame")] public static bool GameThreadController_LogicFrame(GameThreadController __instance) { if (_programShutdown) { return true; } if (_clearOptimizedPlanetsOnNextTick) { PrepareOptimizedStarClusterForGame(); } lock (_newPlanets) { if (_newPlanets.Count > 0) { while (_newPlanets.Count > 0) { PlanetFactory val = _newPlanets.Dequeue(); WeaverFixes.Logger.LogInfo((object)("Adding planet: " + val.planet.displayName)); TryAddNewPlanet(val); } _dysonSphereStatisticsManager.FindAllDysonSphereProductRegisters(); } } foreach (KeyValuePair item in _planetToOptimizedPlanet) { if (GameMain.localPlanet?.factory != item.Key || ForceOptimizeLocalPlanet) { if (item.Value.Status == OptimizedPlanetStatus.Stopped) { if (item.Value.OptimizeDelayInTicks > 0 && item.Value.OptimizeDelayInTicks-- > 0) { continue; } WeaverFixes.Logger.LogInfo((object)("Optimizing planet: " + item.Key.planet.displayName)); item.Value.Initialize(_universeStaticDataBuilder); } if (ForceOptimizeLocalPlanet && GameMain.localPlanet?.factory == item.Key) { item.Value.Save(); } } else if (item.Value.Status != OptimizedPlanetStatus.Stopped) { WeaverFixes.Logger.LogInfo((object)("DeOptimizing planet: " + item.Key.planet.displayName)); item.Value.Save(); } } if (_firstUpdate) { _firstUpdate = false; if (_enableStatistics) { _workStealingMultiThreadedFactorySimulation.PrintWorkStatistics(); } } if (_planetsToReOptimize.Count > 0) { PlanetFactory val2 = _planetsToReOptimize.Dequeue(); IOptimizedPlanet optimizedPlanet = _planetToOptimizedPlanet[val2]; if (optimizedPlanet.Status == OptimizedPlanetStatus.Running) { WeaverFixes.Logger.LogInfo((object)("DeOptimizing planet: " + val2.planet.displayName)); optimizedPlanet.Save(); if (_debugEnableHeavyReOptimization) { optimizedPlanet.OptimizeDelayInTicks = 50; } } } if (_debugEnableHeavyReOptimization && GameMain.gameTick % 10 == 0L) { PlanetFactory[] array = _planetToOptimizedPlanet.Keys.ToArray(); int num = random.Next(0, array.Length); _planetsToReOptimize.Enqueue(array[num]); } DeepProfiler.BeginSample((DPEntry)82, -1, 2L); __instance.EnsureThreadCount(); __instance.threadManager.samplePerformanceCounters = DeepProfiler.watchEnabled; DeepProfiler.EndSample(-1, -2L); ExecuteSimulation(__instance.gameLogic, GameMain.data.factories); return false; } [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), "KillEntityFinally")] public static void PlanetFactory_KillEntityFinally(PlanetFactory __instance) { DeOptimizeDueToNonPlayerAction(__instance); } [HarmonyPrefix] [HarmonyPatch(typeof(PlanetFactory), "UpgradeEntityWithComponents")] public static void PlanetFactory_UpgradeEntityWithComponents(PlanetFactory __instance) { DeOptimizeDueToNonPlayerAction(__instance); } [HarmonyPrefix] [HarmonyPatch(typeof(GameLogic), "FactorySystemLabResearchGameTick")] public static bool GameLogic_FactorySystemLabResearchGameTick(GameLogic __instance) { DeepProfiler.BeginSample((DPEntry)24, -1, 2L); for (int i = 0; i < __instance.factoryCount; i++) { PlanetFactory val = __instance.factories[i]; bool isActive = __instance.localLoadedFactory == val; ThreadSafeGameTickLabResearchMode(val, __instance.timei, isActive); } DeepProfiler.EndSample(-1, -2L); return false; } public static void ThreadSafeGameTickLabResearchMode(PlanetFactory planetFactory, long time, bool isActive) { lock (_starClusterResearchManager) { planetFactory.factorySystem.GameTickLabResearchMode(time, isActive); } } [HarmonyTranspiler] [HarmonyPatch(typeof(FactorySystem), "GameTickLabResearchMode")] private static IEnumerable DeferResearchUnlockToStarClusterResearchManager(IEnumerable 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 result type (might be due to invalid IL or missing references) //IL_0167: Expected O, but got Unknown //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Expected O, but got Unknown //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Expected O, but got Unknown //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Expected O, but got Unknown //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Expected O, but got Unknown CodeMatcher val = new CodeMatcher(instructions, generator); CodeMatch[] start = (CodeMatch[])(object)new CodeMatch[6] { new CodeMatch((OpCode?)OpCodes.Ldloc_1, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldfld, (object)AccessTools.Field(typeof(GameHistoryData), "techStates"), (string)null), new CodeMatch((OpCode?)OpCodes.Ldarg_0, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Ldfld, (object)AccessTools.Field(typeof(FactorySystem), "researchTechId"), (string)null), new CodeMatch((OpCode?)OpCodes.Ldloc_S, (object)null, (string)null), new CodeMatch((OpCode?)OpCodes.Callvirt, (object)AccessTools.PropertySetter(typeof(Dictionary), "Item"), (string)null) }; CodeMatch[] end = (CodeMatch[])(object)new CodeMatch[1] { new CodeMatch((OpCode?)OpCodes.Callvirt, (object)AccessTools.Method(typeof(GameHistoryData), "NotifyTechUnlock", (Type[])null, (Type[])null), (string)null) }; CodeInstruction[] replaceWith = (CodeInstruction[])(object)new CodeInstruction[8] { new CodeInstruction(OpCodes.Callvirt, (object)AccessTools.PropertySetter(typeof(Dictionary), "Item")), new CodeInstruction(OpCodes.Ldsfld, (object)AccessTools.Field(typeof(OptimizedStarCluster), "_starClusterResearchManager")), new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldfld, (object)AccessTools.Field(typeof(FactorySystem), "researchTechId")), new CodeInstruction(OpCodes.Ldloc_S, (object)34), new CodeInstruction(OpCodes.Ldloc_S, (object)13), new CodeInstruction(OpCodes.Ldloc_S, (object)12), new CodeInstruction(OpCodes.Callvirt, (object)AccessTools.Method(typeof(StarClusterResearchManager), "AddResearchedTech", (Type[])null, (Type[])null)) }; val.ReplaceCode(start, replaceStart: false, end, replaceEnd: false, replaceWith); val.ReplaceCode(start, replaceStart: false, end, replaceEnd: false, replaceWith); return val.InstructionEnumeration(); } [HarmonyPrefix] [HarmonyPatch(typeof(ProductionStatistics), "RefreshPowerGenerationCapacitesWithFactory")] public static bool ProductionStatistics_RefreshPowerGenerationCapacitesWithFactory(ProductionStatistics __instance, PlanetFactory factory) { if (factory == null) { return true; } IOptimizedPlanet optimizedPlanet = GetOptimizedPlanet(factory); if (optimizedPlanet.Status == OptimizedPlanetStatus.Stopped) { return true; } if (!(optimizedPlanet is OptimizedTerrestrialPlanet optimizedTerrestrialPlanet)) { return true; } optimizedTerrestrialPlanet.RefreshPowerGenerationCapacites(__instance, factory); return false; } [HarmonyPrefix] [HarmonyPatch(typeof(ProductionStatistics), "RefreshPowerConsumptionDemandsWithFactory")] public static bool ProductionStatistics_RefreshPowerConsumptionDemandsWithFactory(ProductionStatistics __instance, PlanetFactory factory) { if (factory == null) { return true; } IOptimizedPlanet optimizedPlanet = GetOptimizedPlanet(factory); if (optimizedPlanet.Status == OptimizedPlanetStatus.Stopped) { return true; } if (!(optimizedPlanet is OptimizedTerrestrialPlanet optimizedTerrestrialPlanet)) { return true; } optimizedTerrestrialPlanet.RefreshPowerConsumptionDemands(__instance, factory); return false; } [HarmonyPrefix] [HarmonyPatch(typeof(FactoryProductionStat), "GameTick")] public static bool FactoryProductionStat_GameTick(FactoryProductionStat __instance, long time) { if (_dysonSphereStatisticsManager.IsDysonSphereStatistics(__instance)) { DysonSphereStatisticsManager.DysonSphereGameTick(__instance, time); } if (!TryGetOptimizedPlanet(__instance, out IOptimizedPlanet optimizedPlanet)) { return true; } if (optimizedPlanet.Status == OptimizedPlanetStatus.Stopped) { return true; } return false; } [HarmonyPrefix] [HarmonyPatch(typeof(FactoryProductionStat), "ClearRegisters")] public static bool FactoryProductionStat_ClearRegisters(FactoryProductionStat __instance) { if (_dysonSphereStatisticsManager.IsDysonSphereStatistics(__instance)) { DysonSphereStatisticsManager.DysonSphereClearRegisters(__instance); } if (!TryGetOptimizedPlanet(__instance, out IOptimizedPlanet optimizedPlanet)) { return true; } if (optimizedPlanet.Status == OptimizedPlanetStatus.Stopped) { return true; } __instance.powerGenRegister = 0L; __instance.powerConRegister = 0L; __instance.powerDisRegister = 0L; __instance.powerChaRegister = 0L; __instance.hashRegister = 0L; return false; } [HarmonyPrefix] [HarmonyPatch(typeof(DeepProfiler), "BeginSample")] public static void DeepProfiler_BeginSample(DPEntry entry, ref int thread, long detail) { UpdateThreadIndexIfRequired(ref thread); } [HarmonyPrefix] [HarmonyPatch(typeof(DeepProfiler), "EndSample", new Type[] { typeof(int), typeof(long) })] public static void DeepProfiler_EndSampleNonTyped(ref int thread, long detail) { UpdateThreadIndexIfRequired(ref thread); } [HarmonyPrefix] [HarmonyPatch(typeof(DeepProfiler), "EndSample", new Type[] { typeof(DPEntry), typeof(int) })] public static void DeepProfiler_EndSampleTyped(DPEntry entry, ref int thread) { UpdateThreadIndexIfRequired(ref thread); } [HarmonyPrefix] [HarmonyPatch(typeof(TurretComponent), "BeltUpdate")] public static bool TurretComponent_BeltUpdate(ref TurretComponent __instance, CargoTraffic cargoTraffic) { if (!OptimizedTurret.NeedToCheckBelt(ref __instance)) { return false; } if (!TryGetOptimizedPlanet(cargoTraffic.factory, out IOptimizedPlanet optimizedPlanet) || optimizedPlanet.Status == OptimizedPlanetStatus.Stopped || !(optimizedPlanet is OptimizedTerrestrialPlanet optimizedTerrestrialPlanet)) { return true; } optimizedTerrestrialPlanet.TurretBeltUpdate(ref __instance); return false; } public static void ReOptimizeAllPlanets() { lock (_planetsToReOptimize) { foreach (PlanetFactory item in from x in _planetToOptimizedPlanet where x.Value.Status == OptimizedPlanetStatus.Running select x.Key) { _planetsToReOptimize.Enqueue(item); } } } private static void ExecuteSimulation(GameLogic gameLogic, PlanetFactory?[] planets) { DeepProfiler.BeginSample((DPEntry)82, -1, 1L); gameLogic.timef = gameLogic.main.timef; gameLogic.timei = gameLogic.main.timei; gameLogic.timef_once = gameLogic.main.timef_once; gameLogic.timei_once = gameLogic.main.timei_once; gameLogic.deltaTime = 1f / 60f; gameLogic.deltaTime_lf = 1.0 / 60.0; gameLogic.sandbox_tool_enabled = GameMain.sandboxToolsEnabled; gameLogic.isPrologue = gameLogic.timei == 0; EnemyUnitComponent.gameTick = gameLogic.timei; gameLogic.CollectCombatSettings(); gameLogic.factories = gameLogic.data.factories; gameLogic.factoryCount = gameLogic.data.factoryCount; gameLogic.localLoadedFactory = gameLogic.data.localLoadedPlanetFactory; DeepProfiler.EndSample((DPEntry)82, -1); _workStealingMultiThreadedFactorySimulation.Simulate(gameLogic, planets); } private static void DeOptimizeDueToNonPlayerAction(PlanetFactory planet) { IOptimizedPlanet optimizedPlanet = _planetToOptimizedPlanet[planet]; if (optimizedPlanet.Status == OptimizedPlanetStatus.Running) { WeaverFixes.Logger.LogInfo((object)("DeOptimizing planet: " + planet.planet.displayName)); optimizedPlanet.Save(); } optimizedPlanet.OptimizeDelayInTicks = 200; } private static void UpdateThreadIndexIfRequired(ref int thread) { if (thread == -1) { int? value = ThreadLocalData.ThreadIndex.Value; if (value.HasValue) { thread = value.Value; } } } } internal sealed class OptimizedSubFactory { private readonly PlanetFactory _planet; private readonly OptimizedTerrestrialPlanet _optimizedPlanet; private readonly StarClusterResearchManager _starClusterResearchManager; private readonly UniverseStaticData _universeStaticData; private OptimizedProductionStatistics _optimizedProductionStatistics; private SubFactoryNeeds _subFactoryNeeds; public InserterExecutor _optimizedBiInserterExecutor; public InserterExecutor _optimizedInserterExecutor; public AssemblerExecutor _assemblerExecutor; public VeinMinerExecutor _beltVeinMinerExecutor; public VeinMinerExecutor _stationVeinMinerExecutor; public OilMinerExecutor _oilMinerExecutor; public WaterMinerExecutor _waterMinerExecutor; public EjectorExecutor _ejectorExecutor; public SiloExecutor _siloExecutor; public ProducingLabExecutor _producingLabExecutor; public OptimizedProducingLab[] _optimizedProducingLabs; public Dictionary _producingLabIdToOptimizedIndex; public ResearchingLabExecutor _researchingLabExecutor; public OptimizedResearchingLab[] _optimizedResearchingLabs; public Dictionary _researchingLabIdToOptimizedIndex; public MonitorExecutor _monitorExecutor; public SpraycoaterExecutor _spraycoaterExecutor; public PilerExecutor _pilerExecutor; public FractionatorExecutor _fractionatorExecutor; public StationExecutor _stationExecutor; public TankExecutor _tankExecutor; public BeltExecutor _beltExecutor; public SplitterExecutor _splitterExecutor; public bool HasCalculatedPowerConsumption; public OptimizedSubFactory(PlanetFactory planet, OptimizedTerrestrialPlanet optimizedTerrestrialPlanet, StarClusterResearchManager starClusterResearchManager, UniverseStaticData universeStaticData) { _planet = planet; _optimizedPlanet = optimizedTerrestrialPlanet; _starClusterResearchManager = starClusterResearchManager; _universeStaticData = universeStaticData; } public void Save(CargoContainer cargoContainer) { _beltExecutor.Save(cargoContainer); _beltVeinMinerExecutor.Save(_planet); _stationVeinMinerExecutor.Save(_planet); _oilMinerExecutor.Save(_planet); _waterMinerExecutor.Save(_planet); _optimizedBiInserterExecutor.Save(_planet); _optimizedInserterExecutor.Save(_planet); _assemblerExecutor.Save(_planet, _subFactoryNeeds); _producingLabExecutor.Save(_planet, _subFactoryNeeds); _researchingLabExecutor.Save(_planet, _subFactoryNeeds); _spraycoaterExecutor.Save(_planet); _fractionatorExecutor.Save(_planet); _tankExecutor.Save(_planet); _siloExecutor.Save(_planet, _subFactoryNeeds); _ejectorExecutor.Save(_planet, _subFactoryNeeds); } public void Initialize(Graph subFactoryGraph, OptimizedPowerSystemBuilder optimizedPowerSystemBuilder, PlanetWideBeltExecutor planetWideBeltExecutor, TurretExecutorBuilder turretExecutorBuilder, PlanetWideProductionRegisterBuilder planetWideProductionRegisterBuilder, SubFactoryProductionRegisterBuilder subFactoryProductionRegisterBuilder, OptimizedItemId[]?[]? fuelNeeds, UniverseStaticDataBuilder universeStaticDataBuilder) { SubFactoryPowerSystemBuilder subFactoryPowerSystemBuilder = optimizedPowerSystemBuilder.AddSubFactory(this); SubFactoryNeedsBuilder subFactoryNeedsBuilder = new SubFactoryNeedsBuilder(); InitializeBelts(subFactoryGraph, planetWideBeltExecutor, universeStaticDataBuilder); InitializeAssemblers(subFactoryGraph, subFactoryPowerSystemBuilder, subFactoryProductionRegisterBuilder, subFactoryNeedsBuilder, universeStaticDataBuilder); InitializeMiners(subFactoryGraph, subFactoryPowerSystemBuilder, subFactoryProductionRegisterBuilder, _beltExecutor, universeStaticDataBuilder); InitializeStations(subFactoryGraph, _beltExecutor, _stationVeinMinerExecutor, universeStaticDataBuilder); InitializeEjectors(subFactoryGraph, subFactoryPowerSystemBuilder, subFactoryProductionRegisterBuilder, subFactoryNeedsBuilder, universeStaticDataBuilder); InitializeSilos(subFactoryGraph, subFactoryPowerSystemBuilder, subFactoryProductionRegisterBuilder, subFactoryNeedsBuilder, universeStaticDataBuilder); InitializeLabAssemblers(subFactoryGraph, subFactoryPowerSystemBuilder, subFactoryProductionRegisterBuilder, subFactoryNeedsBuilder, universeStaticDataBuilder); InitializeResearchingLabs(subFactoryGraph, subFactoryPowerSystemBuilder, subFactoryProductionRegisterBuilder, subFactoryNeedsBuilder, universeStaticDataBuilder); _subFactoryNeeds = subFactoryNeedsBuilder.Build(); InitializeInserters(subFactoryGraph, subFactoryPowerSystemBuilder, _beltExecutor, fuelNeeds, _subFactoryNeeds, universeStaticDataBuilder); InitializeMonitors(subFactoryGraph, subFactoryPowerSystemBuilder, _beltExecutor, universeStaticDataBuilder); InitializeSpraycoaters(subFactoryGraph, subFactoryPowerSystemBuilder, subFactoryProductionRegisterBuilder, _beltExecutor, universeStaticDataBuilder); InitializePilers(subFactoryGraph, subFactoryPowerSystemBuilder, _beltExecutor, universeStaticDataBuilder); InitializeFractionators(subFactoryGraph, subFactoryPowerSystemBuilder, subFactoryProductionRegisterBuilder, _beltExecutor, universeStaticDataBuilder); InitializeTanks(subFactoryGraph, _beltExecutor); InitializeSplitters(subFactoryGraph, _beltExecutor); turretExecutorBuilder.Initialize(_planet, subFactoryGraph, planetWideProductionRegisterBuilder, _beltExecutor); _optimizedProductionStatistics = subFactoryProductionRegisterBuilder.Build(universeStaticDataBuilder); HasCalculatedPowerConsumption = false; } private void InitializeInserters(Graph subFactoryGraph, SubFactoryPowerSystemBuilder subFactoryPowerSystemBuilder, BeltExecutor beltExecutor, OptimizedItemId[]?[]? fuelNeeds, SubFactoryNeeds subFactoryNeeds, UniverseStaticDataBuilder universeStaticDataBuilder) { _optimizedBiInserterExecutor = new InserterExecutor(_assemblerExecutor._assemblerStates, _producingLabExecutor._labStates, _researchingLabExecutor._labStates, subFactoryPowerSystemBuilder.FuelGeneratorSegments, fuelNeeds, subFactoryNeeds, _assemblerExecutor._producedSize, _assemblerExecutor._served, _assemblerExecutor._incServed, _assemblerExecutor._produced, _assemblerExecutor._assemblerRecipeIndexes, _assemblerExecutor._needToUpdateNeeds, _producingLabExecutor._producedSize, _producingLabExecutor._served, _producingLabExecutor._incServed, _producingLabExecutor._produced, _producingLabExecutor._labRecipeIndexes, _producingLabExecutor._needToUpdateNeeds, _researchingLabExecutor._matrixServed, _researchingLabExecutor._matrixIncServed, _siloExecutor._siloIndexes, _ejectorExecutor._ejectorBulletDatas, universeStaticDataBuilder.UniverseStaticData); _optimizedBiInserterExecutor.Initialize(_planet, this, subFactoryGraph, (InserterComponent x) => x.bidirectional, subFactoryPowerSystemBuilder.CreateBiInserterBuilder(), beltExecutor, universeStaticDataBuilder, universeStaticDataBuilder.BiInserterGrades); _optimizedInserterExecutor = new InserterExecutor(_assemblerExecutor._assemblerStates, _producingLabExecutor._labStates, _researchingLabExecutor._labStates, subFactoryPowerSystemBuilder.FuelGeneratorSegments, fuelNeeds, subFactoryNeeds, _assemblerExecutor._producedSize, _assemblerExecutor._served, _assemblerExecutor._incServed, _assemblerExecutor._produced, _assemblerExecutor._assemblerRecipeIndexes, _assemblerExecutor._needToUpdateNeeds, _producingLabExecutor._producedSize, _producingLabExecutor._served, _producingLabExecutor._incServed, _producingLabExecutor._produced, _producingLabExecutor._labRecipeIndexes, _producingLabExecutor._needToUpdateNeeds, _researchingLabExecutor._matrixServed, _researchingLabExecutor._matrixIncServed, _siloExecutor._siloIndexes, _ejectorExecutor._ejectorBulletDatas, universeStaticDataBuilder.UniverseStaticData); _optimizedInserterExecutor.Initialize(_planet, this, subFactoryGraph, (InserterComponent x) => !x.bidirectional, subFactoryPowerSystemBuilder.CreateInserterBuilder(), beltExecutor, universeStaticDataBuilder, universeStaticDataBuilder.InserterGrades); } private void InitializeAssemblers(Graph subFactoryGraph, SubFactoryPowerSystemBuilder subFactoryPowerSystemBuilder, SubFactoryProductionRegisterBuilder subFactoryProductionRegisterBuilder, SubFactoryNeedsBuilder subFactoryNeedsBuilder, UniverseStaticDataBuilder universeStaticDataBuilder) { _assemblerExecutor = new AssemblerExecutor(); _assemblerExecutor.InitializeAssemblers(_planet, subFactoryGraph, subFactoryPowerSystemBuilder, subFactoryProductionRegisterBuilder, subFactoryNeedsBuilder, universeStaticDataBuilder); } private void InitializeMiners(Graph subFactoryGraph, SubFactoryPowerSystemBuilder subFactoryPowerSystemBuilder, SubFactoryProductionRegisterBuilder subFactoryProductionRegisterBuilder, BeltExecutor beltExecutor, UniverseStaticDataBuilder universeStaticDataBuilder) { _beltVeinMinerExecutor = new VeinMinerExecutor(); _beltVeinMinerExecutor.Initialize(_planet, subFactoryGraph, subFactoryPowerSystemBuilder.CreateBeltVeinMinerBuilder(), subFactoryProductionRegisterBuilder, beltExecutor, universeStaticDataBuilder); _stationVeinMinerExecutor = new VeinMinerExecutor(); _stationVeinMinerExecutor.Initialize(_planet, subFactoryGraph, subFactoryPowerSystemBuilder.CreateStationVeinMinerBuilder(), subFactoryProductionRegisterBuilder, beltExecutor, universeStaticDataBuilder); _oilMinerExecutor = new OilMinerExecutor(); _oilMinerExecutor.Initialize(_planet, subFactoryGraph, subFactoryPowerSystemBuilder, subFactoryProductionRegisterBuilder, beltExecutor, universeStaticDataBuilder); _waterMinerExecutor = new WaterMinerExecutor(); _waterMinerExecutor.Initialize(_planet, subFactoryGraph, subFactoryPowerSystemBuilder, subFactoryProductionRegisterBuilder, beltExecutor, universeStaticDataBuilder); } private void InitializeEjectors(Graph subFactoryGraph, SubFactoryPowerSystemBuilder subFactoryPowerSystemBuilder, SubFactoryProductionRegisterBuilder subFactoryProductionRegisterBuilder, SubFactoryNeedsBuilder subFactoryNeedsBuilder, UniverseStaticDataBuilder universeStaticDataBuilder) { _ejectorExecutor = new EjectorExecutor(); _ejectorExecutor.Initialize(_planet, subFactoryGraph, subFactoryPowerSystemBuilder, subFactoryProductionRegisterBuilder, subFactoryNeedsBuilder, universeStaticDataBuilder); } private void InitializeSilos(Graph subFactoryGraph, SubFactoryPowerSystemBuilder subFactoryPowerSystemBuilder, SubFactoryProductionRegisterBuilder subFactoryProductionRegisterBuilder, SubFactoryNeedsBuilder subFactoryNeedsBuilder, UniverseStaticDataBuilder universeStaticDataBuilder) { _siloExecutor = new SiloExecutor(); _siloExecutor.Initialize(_planet, subFactoryGraph, subFactoryPowerSystemBuilder, subFactoryProductionRegisterBuilder, subFactoryNeedsBuilder, universeStaticDataBuilder); } private void InitializeLabAssemblers(Graph subFactoryGraph, SubFactoryPowerSystemBuilder subFactoryPowerSystemBuilder, SubFactoryProductionRegisterBuilder subFactoryProductionRegisterBuilder, SubFactoryNeedsBuilder subFactoryNeedsBuilder, UniverseStaticDataBuilder universeStaticDataBuilder) { _producingLabExecutor = new ProducingLabExecutor(); _producingLabExecutor.Initialize(_planet, subFactoryGraph, subFactoryPowerSystemBuilder, subFactoryProductionRegisterBuilder, subFactoryNeedsBuilder, universeStaticDataBuilder); _optimizedProducingLabs = _producingLabExecutor._optimizedLabs; _producingLabIdToOptimizedIndex = _producingLabExecutor._labIdToOptimizedLabIndex; } private void InitializeResearchingLabs(Graph subFactoryGraph, SubFactoryPowerSystemBuilder subFactoryPowerSystemBuilder, SubFactoryProductionRegisterBuilder subFactoryProductionRegisterBuilder, SubFactoryNeedsBuilder subFactoryNeedsBuilder, UniverseStaticDataBuilder universeStaticDataBuilder) { _researchingLabExecutor = new ResearchingLabExecutor(_starClusterResearchManager); _researchingLabExecutor.Initialize(_planet, subFactoryGraph, subFactoryPowerSystemBuilder, subFactoryProductionRegisterBuilder, subFactoryNeedsBuilder, universeStaticDataBuilder); _optimizedResearchingLabs = _researchingLabExecutor._optimizedLabs; _researchingLabIdToOptimizedIndex = _researchingLabExecutor._labIdToOptimizedLabIndex; } private void InitializeMonitors(Graph subFactoryGraph, SubFactoryPowerSystemBuilder subFactoryPowerSystemBuilder, BeltExecutor beltExecutor, UniverseStaticDataBuilder universeStaticDataBuilder) { _monitorExecutor = new MonitorExecutor(); _monitorExecutor.Initialize(_planet, subFactoryGraph, subFactoryPowerSystemBuilder, beltExecutor, universeStaticDataBuilder); } private void InitializeSpraycoaters(Graph subFactoryGraph, SubFactoryPowerSystemBuilder subFactoryPowerSystemBuilder, SubFactoryProductionRegisterBuilder subFactoryProductionRegisterBuilder, BeltExecutor beltExecutor, UniverseStaticDataBuilder universeStaticDataBuilder) { _spraycoaterExecutor = new SpraycoaterExecutor(); _spraycoaterExecutor.Initialize(_planet, subFactoryGraph, subFactoryPowerSystemBuilder, subFactoryProductionRegisterBuilder, beltExecutor, universeStaticDataBuilder); } private void InitializePilers(Graph subFactoryGraph, SubFactoryPowerSystemBuilder subFactoryPowerSystemBuilder, BeltExecutor beltExecutor, UniverseStaticDataBuilder universeStaticDataBuilder) { _pilerExecutor = new PilerExecutor(); _pilerExecutor.Initialize(_planet, subFactoryGraph, subFactoryPowerSystemBuilder, beltExecutor, universeStaticDataBuilder); } private void InitializeFractionators(Graph subFactoryGraph, SubFactoryPowerSystemBuilder subFactoryPowerSystemBuilder, SubFactoryProductionRegisterBuilder subFactoryProductionRegisterBuilder, BeltExecutor beltExecutor, UniverseStaticDataBuilder universeStaticDataBuilder) { _fractionatorExecutor = new FractionatorExecutor(); _fractionatorExecutor.Initialize(_planet, subFactoryGraph, subFactoryPowerSystemBuilder, subFactoryProductionRegisterBuilder, beltExecutor, universeStaticDataBuilder); } private void InitializeStations(Graph subFactoryGraph, BeltExecutor beltExecutor, VeinMinerExecutor stationVeinMinerExecutor, UniverseStaticDataBuilder universeStaticDataBuilder) { _stationExecutor = new StationExecutor(); _stationExecutor.Initialize(_planet, subFactoryGraph, beltExecutor, stationVeinMinerExecutor, universeStaticDataBuilder); } private void InitializeTanks(Graph subFactoryGraph, BeltExecutor beltExecutor) { _tankExecutor = new TankExecutor(); _tankExecutor.Initialize(_planet, subFactoryGraph, beltExecutor); } private void InitializeBelts(Graph subFactoryGraph, PlanetWideBeltExecutor planetWideBeltExecutor, UniverseStaticDataBuilder universeStaticDataBuilder) { _beltExecutor = new BeltExecutor(); _beltExecutor.Initialize(_planet, subFactoryGraph, universeStaticDataBuilder); planetWideBeltExecutor.AddBeltExecutor(_beltExecutor); } private void InitializeSplitters(Graph subFactoryGraph, BeltExecutor beltExecutor) { _splitterExecutor = new SplitterExecutor(); _splitterExecutor.Initialize(_planet, subFactoryGraph, beltExecutor); } public void GameTick(int workerIndex, long time, SubFactoryPowerConsumption powerSystem) { MiningFlags miningFlags = new MiningFlags(); long[] networksPowerConsumption = powerSystem.NetworksPowerConsumption; Array.Clear(networksPowerConsumption, 0, networksPowerConsumption.Length); int[] productRegister = _optimizedProductionStatistics.ProductRegister; int[] consumeRegister = _optimizedProductionStatistics.ConsumeRegister; ReadonlyArray powerConsumerTypes = _universeStaticData.PowerConsumerTypes; if (_beltVeinMinerExecutor.Count + _stationVeinMinerExecutor.Count + _oilMinerExecutor.Count + _waterMinerExecutor.Count > 0) { DeepProfiler.BeginSample((DPEntry)19, workerIndex, -1L); _beltVeinMinerExecutor.GameTick(_planet, powerSystem.BeltVeinMinerPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption, productRegister, ref miningFlags, _beltExecutor.OptimizedCargoPaths); _stationVeinMinerExecutor.GameTick(_planet, powerSystem.StationVeinMinerPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption, productRegister, ref miningFlags, _beltExecutor.OptimizedCargoPaths); _oilMinerExecutor.GameTick(_planet, powerSystem.OilMinerPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption, productRegister, _beltExecutor.OptimizedCargoPaths); _waterMinerExecutor.GameTick(_planet, powerSystem.WaterMinerPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption, productRegister, _beltExecutor.OptimizedCargoPaths); DeepProfiler.EndSample((DPEntry)19, workerIndex); } if (_assemblerExecutor.Count > 0) { DeepProfiler.BeginSample((DPEntry)20, workerIndex, -1L); _assemblerExecutor.GameTick(_planet, powerSystem.AssemblerPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption, productRegister, consumeRegister, _subFactoryNeeds, _universeStaticData); DeepProfiler.EndSample((DPEntry)20, workerIndex); } if (_fractionatorExecutor.Count > 0) { DeepProfiler.BeginSample((DPEntry)21, workerIndex, -1L); _fractionatorExecutor.GameTick(_planet, powerSystem.FractionatorPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption, productRegister, consumeRegister, _beltExecutor.OptimizedCargoPaths, _universeStaticData); DeepProfiler.EndSample((DPEntry)21, workerIndex); } if (_ejectorExecutor.Count > 0) { DeepProfiler.BeginSample((DPEntry)22, workerIndex, -1L); _ejectorExecutor.GameTick(_planet, time, powerSystem.EjectorPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption, consumeRegister, _subFactoryNeeds); DeepProfiler.EndSample((DPEntry)22, workerIndex); } if (_siloExecutor.Count > 0) { DeepProfiler.BeginSample((DPEntry)23, workerIndex, -1L); _siloExecutor.GameTick(_planet, powerSystem.SiloPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption, consumeRegister, _subFactoryNeeds); DeepProfiler.EndSample((DPEntry)23, workerIndex); } if (_producingLabExecutor.Count + _researchingLabExecutor.Count > 0) { DeepProfiler.BeginMajorSample((DPEntry)24, workerIndex, -1L); if (_producingLabExecutor.Count > 0) { _producingLabExecutor.GameTickLabProduceMode(_planet, powerSystem.ProducingLabPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption, productRegister, consumeRegister, _subFactoryNeeds, _universeStaticData); _producingLabExecutor.GameTickLabOutputToNext(time, _subFactoryNeeds, _universeStaticData); } if (_researchingLabExecutor.Count > 0) { _researchingLabExecutor.GameTickLabResearchMode(_planet, powerSystem.ResearchingLabPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption, consumeRegister, _subFactoryNeeds); _researchingLabExecutor.GameTickLabOutputToNext(time, _subFactoryNeeds); } DeepProfiler.EndMajorSample((DPEntry)24, workerIndex); } if (_stationExecutor.Count > 0) { DeepProfiler.BeginSample((DPEntry)36, workerIndex, (long)_planet.planetId); DeepProfiler.BeginMajorSample((DPEntry)37, workerIndex, -1L); _stationExecutor.StationGameTick(_planet, time, _stationVeinMinerExecutor, ref miningFlags); DeepProfiler.EndMajorSample((DPEntry)37, workerIndex); DeepProfiler.EndSample((DPEntry)36, workerIndex); } if (_stationExecutor.Count > 0) { DeepProfiler.BeginMajorSample((DPEntry)37, workerIndex, -1L); _stationExecutor.InputFromBelt(_beltExecutor.OptimizedCargoPaths); DeepProfiler.EndMajorSample((DPEntry)37, workerIndex); } if (_optimizedBiInserterExecutor.Count + _optimizedInserterExecutor.Count > 0) { DeepProfiler.BeginMajorSample((DPEntry)25, workerIndex, -1L); _optimizedBiInserterExecutor.GameTickInserters(_planet, powerSystem.InserterBiPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption, _beltExecutor.OptimizedCargoPaths, _universeStaticData); _optimizedInserterExecutor.GameTickInserters(_planet, powerSystem.InserterPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption, _beltExecutor.OptimizedCargoPaths, _universeStaticData); DeepProfiler.EndMajorSample((DPEntry)25, workerIndex); } if (_tankExecutor.Count > 0) { DeepProfiler.BeginMajorSample((DPEntry)26, workerIndex, -1L); _tankExecutor.GameTick(_beltExecutor.OptimizedCargoPaths); DeepProfiler.EndMajorSample((DPEntry)26, workerIndex); } if (_beltExecutor.Count > 0) { DeepProfiler.BeginMajorSample((DPEntry)28, workerIndex, -1L); _beltExecutor.GameTick(); DeepProfiler.EndMajorSample((DPEntry)28, workerIndex); } if (_splitterExecutor.Count > 0) { DeepProfiler.BeginMajorSample((DPEntry)29, workerIndex, -1L); _splitterExecutor.GameTick(this, _beltExecutor.OptimizedCargoPaths); DeepProfiler.EndMajorSample((DPEntry)29, workerIndex); } if (_monitorExecutor.Count > 0) { DeepProfiler.BeginMajorSample((DPEntry)30, workerIndex, -1L); _monitorExecutor.GameTick(_planet, powerSystem.MonitorPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption, _beltExecutor.OptimizedCargoPaths); DeepProfiler.EndMajorSample((DPEntry)30, workerIndex); } if (_spraycoaterExecutor.Count > 0) { DeepProfiler.BeginMajorSample((DPEntry)31, workerIndex, -1L); _spraycoaterExecutor.GameTick(powerSystem.SpraycoaterPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption, consumeRegister, _beltExecutor.OptimizedCargoPaths); DeepProfiler.EndMajorSample((DPEntry)31, workerIndex); } if (_pilerExecutor.Count > 0) { DeepProfiler.BeginMajorSample((DPEntry)32, workerIndex, -1L); _pilerExecutor.GameTick(_planet, powerSystem.PilerPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption, _beltExecutor.OptimizedCargoPaths); DeepProfiler.EndMajorSample((DPEntry)32, workerIndex); } if (_stationExecutor.Count > 0) { DeepProfiler.BeginMajorSample((DPEntry)37, workerIndex, -1L); _stationExecutor.OutputToBelt(_beltExecutor.OptimizedCargoPaths); DeepProfiler.EndMajorSample((DPEntry)37, workerIndex); } _optimizedPlanet.AddMiningFlags(miningFlags); HasCalculatedPowerConsumption = true; } public void RefreshPowerConsumptionDemands(ProductionStatistics statistics, SubFactoryPowerConsumption powerSystem) { ReadonlyArray powerConsumerTypes = _universeStaticData.PowerConsumerTypes; RefreshPowerConsumptionDemands(statistics, _beltVeinMinerExecutor.UpdatePowerConsumptionPerPrototype(powerSystem.BeltVeinMinerPowerConsumerTypeIndexes, powerConsumerTypes)); RefreshPowerConsumptionDemands(statistics, _stationVeinMinerExecutor.UpdatePowerConsumptionPerPrototype(powerSystem.StationVeinMinerPowerConsumerTypeIndexes, powerConsumerTypes)); RefreshPowerConsumptionDemands(statistics, _oilMinerExecutor.UpdatePowerConsumptionPerPrototype(powerSystem.OilMinerPowerConsumerTypeIndexes, powerConsumerTypes)); RefreshPowerConsumptionDemands(statistics, _waterMinerExecutor.UpdatePowerConsumptionPerPrototype(powerSystem.WaterMinerPowerConsumerTypeIndexes, powerConsumerTypes)); RefreshPowerConsumptionDemands(statistics, _assemblerExecutor.UpdatePowerConsumptionPerPrototype(powerSystem.AssemblerPowerConsumerTypeIndexes, powerConsumerTypes)); RefreshPowerConsumptionDemands(statistics, _fractionatorExecutor.UpdatePowerConsumptionPerPrototype(powerSystem.FractionatorPowerConsumerTypeIndexes, powerConsumerTypes)); RefreshPowerConsumptionDemands(statistics, _ejectorExecutor.UpdatePowerConsumptionPerPrototype(powerSystem.EjectorPowerConsumerTypeIndexes, powerConsumerTypes)); RefreshPowerConsumptionDemands(statistics, _siloExecutor.UpdatePowerConsumptionPerPrototype(_planet, powerSystem.SiloPowerConsumerTypeIndexes, powerConsumerTypes)); RefreshPowerConsumptionDemands(statistics, _producingLabExecutor.UpdatePowerConsumptionPerPrototype(powerSystem.ProducingLabPowerConsumerTypeIndexes, powerConsumerTypes)); RefreshPowerConsumptionDemands(statistics, _researchingLabExecutor.UpdatePowerConsumptionPerPrototype(powerSystem.ResearchingLabPowerConsumerTypeIndexes, powerConsumerTypes)); RefreshPowerConsumptionDemands(statistics, _optimizedBiInserterExecutor.UpdatePowerConsumptionPerPrototype(powerSystem.InserterBiPowerConsumerTypeIndexes, powerConsumerTypes)); RefreshPowerConsumptionDemands(statistics, _optimizedInserterExecutor.UpdatePowerConsumptionPerPrototype(powerSystem.InserterPowerConsumerTypeIndexes, powerConsumerTypes)); RefreshPowerConsumptionDemands(statistics, _monitorExecutor.UpdatePowerConsumptionPerPrototype(powerSystem.MonitorPowerConsumerTypeIndexes, powerConsumerTypes)); RefreshPowerConsumptionDemands(statistics, _spraycoaterExecutor.UpdatePowerConsumptionPerPrototype(powerSystem.SpraycoaterPowerConsumerTypeIndexes, powerConsumerTypes)); RefreshPowerConsumptionDemands(statistics, _pilerExecutor.UpdatePowerConsumptionPerPrototype(powerSystem.PilerPowerConsumerTypeIndexes, powerConsumerTypes)); } 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, _ejectorExecutor.GetOptimizedEjectorIndex(reference.ejectorId)); } if (reference.siloId != 0) { return new TypedObjectIndex(EntityType.Silo, _siloExecutor.GetOptimizedSiloIndex(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) { ref PowerGeneratorComponent reference2 = ref planet.powerSystem.genPool[reference.powerGenId]; return new TypedObjectIndex((!reference2.wind && !reference2.photovoltaic && !reference2.gamma && !reference2.geothermal) ? EntityType.FuelPowerGenerator : 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 bool InsertCargoIntoStorage(int entityId, OptimizedCargo cargo, bool useBan = true) { int storageId = _planet.entityPool[entityId].storageId; if (storageId > 0) { for (StorageComponent val = _planet.factoryStorage.storagePool[storageId]; val != null; val = val.nextStorage) { if (!useBan || val.lastFullItem != cargo.Item) { if (AddCargo(val, cargo, useBan)) { return true; } if (val.nextStorage == null) { return false; } } } } return false; } public int PickFromStorageFiltered(int entityId, ref int filter, int count, out int inc) { inc = 0; int num = count; int storageId = _planet.entityPool[entityId].storageId; if (storageId > 0) { StorageComponent val = _planet.factoryStorage.storagePool[storageId]; StorageComponent val2 = val; if (val != null) { int num4 = default(int); for (val = val.topStorage; val != null; val = val.previousStorage) { if (val.lastEmptyItem != 0 && val.lastEmptyItem != filter) { int num2 = filter; int num3 = count; val.TakeTailItemsFiltered(ref num2, ref num3, ref num4, _planet.entityPool[val.entityId].battleBaseId > 0); count -= num3; inc += num4; if (num2 > 0) { filter = num2; } if (count == 0) { val.lastEmptyItem = -1; return num; } if (filter >= 0) { val.lastEmptyItem = filter; } } if (val == val2) { break; } } } } return num - count; } private static bool AddCargo(StorageComponent storage, OptimizedCargo cargo, bool useBan = false) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Invalid comparison between Unknown and I4 //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Invalid comparison between Unknown and I4 //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Invalid comparison between Unknown and I4 //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Invalid comparison between Unknown and I4 //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Invalid comparison between Unknown and I4 //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Invalid comparison between Unknown and I4 if (cargo.Item <= 0 || cargo.Stack == 0 || cargo.Item >= 12000) { return false; } bool flag = (int)storage.type > 0; if (flag) { if ((int)storage.type == 1 && !StorageComponent.itemIsFuel[cargo.Item]) { return false; } if ((int)storage.type == 2 && (!StorageComponent.itemIsAmmo[cargo.Item] || StorageComponent.itemIsBomb[cargo.Item])) { return false; } if ((int)storage.type == 3 && !StorageComponent.itemIsBomb[cargo.Item]) { return false; } if ((int)storage.type == 4 && !StorageComponent.itemIsFighter[cargo.Item]) { return false; } } bool result = false; bool flag2 = false; int num = 0; int num2 = (useBan ? (storage.size - storage.bans) : storage.size); ref byte stack = ref cargo.Stack; for (int i = 0; i < num2; i++) { if (storage.grids[i].itemId == 0) { if (flag && ((int)storage.type == 8 || storage.grids[i].filter > 0) && cargo.Item != storage.grids[i].filter) { continue; } if (num == 0) { num = StorageComponent.itemStackCount[cargo.Item]; } storage.grids[i].itemId = cargo.Item; if (storage.grids[i].filter == 0) { storage.grids[i].stackSize = num; } } if (storage.grids[i].itemId == cargo.Item) { if (num == 0) { num = storage.grids[i].stackSize; } int num3 = num - storage.grids[i].count; if (stack <= num3) { storage.grids[i].count += stack; storage.grids[i].inc += cargo.Inc; result = true; flag2 = true; break; } storage.grids[i].count = num; storage.grids[i].inc += storage.split_inc(ref stack, ref cargo.Inc, (byte)num3); flag2 = true; } } if (flag2) { storage.searchStart = 0; storage.lastEmptyItem = -1; storage.NotifyStorageChange(); } return result; } private static void RefreshPowerConsumptionDemands(ProductionStatistics statistics, PrototypePowerConsumptions prototypePowerConsumptions) { int[] powerConId2Index = ItemProto.powerConId2Index; for (int i = 0; i < prototypePowerConsumptions.PrototypeIds.Length; i++) { int num = powerConId2Index[prototypePowerConsumptions.PrototypeIds[i]]; statistics.conDemands[num] += prototypePowerConsumptions.PrototypeIdPowerConsumption[i]; statistics.conCount[num] += prototypePowerConsumptions.PrototypeIdCounts[i]; statistics.totalConDemand += prototypePowerConsumptions.PrototypeIdPowerConsumption[i]; } } } internal sealed class OptimizedTerrestrialPlanet : IOptimizedPlanet { public static bool ViewBeltsOnLocalOptimizedPlanet; private readonly PlanetFactory _planet; private readonly StarClusterResearchManager _starClusterResearchManager; private OptimizedSubFactory[] _subFactories; private OptimizedPowerSystem _optimizedPowerSystem; private TurretExecutor _turretExecutor; private OptimizedPlanetWideProductionStatistics _optimizedPlanetWideProductionStatistics; private IWorkNode? _workNodes; private int _workStepsParallelism; private UnOptimizedWorkChunkCounts? _workNodesWorkChunkCounts; public OptimizedPlanetStatus Status { get; private set; } = OptimizedPlanetStatus.Stopped; public int OptimizeDelayInTicks { get; set; } public OptimizedTerrestrialPlanet(PlanetFactory planet, StarClusterResearchManager starClusterResearchManager) { _planet = planet; _starClusterResearchManager = starClusterResearchManager; } public void Save() { CargoContainer container = _planet.cargoTraffic.container; container.recycleBegin = 0; container.recycleEnd = 0; container.cursor = 0; OptimizedSubFactory[] subFactories = _subFactories; for (int i = 0; i < subFactories.Length; i++) { subFactories[i].Save(container); } _optimizedPowerSystem.Save(_planet); if (ViewBeltsOnLocalOptimizedPlanet) { _planet.cargoTraffic.PresentCargoPathsSync(); return; } Status = OptimizedPlanetStatus.Stopped; _workNodes = null; _workStepsParallelism = -1; _workNodesWorkChunkCounts = null; } public void Initialize(UniverseStaticDataBuilder universeStaticDataBuilder) { List list = Graphifier.ToGraphs(_planet); Graphifier.CombineSmallGraphs(list); PlanetWideProductionRegisterBuilder planetWideProductionRegisterBuilder = new PlanetWideProductionRegisterBuilder(_planet); OptimizedItemId[][] fuelNeeds; OptimizedPowerSystemBuilder optimizedPowerSystemBuilder = OptimizedPowerSystemBuilder.Create(_planet, planetWideProductionRegisterBuilder.GetSubFactoryBuilder(), universeStaticDataBuilder, out fuelNeeds); PlanetWideBeltExecutor planetWideBeltExecutor = new PlanetWideBeltExecutor(); TurretExecutorBuilder turretExecutorBuilder = new TurretExecutorBuilder(); _subFactories = new OptimizedSubFactory[list.Count]; for (int i = 0; i < _subFactories.Length; i++) { _subFactories[i] = new OptimizedSubFactory(_planet, this, _starClusterResearchManager, universeStaticDataBuilder.UniverseStaticData); _subFactories[i].Initialize(list[i], optimizedPowerSystemBuilder, planetWideBeltExecutor, turretExecutorBuilder, planetWideProductionRegisterBuilder, planetWideProductionRegisterBuilder.GetSubFactoryBuilder(), fuelNeeds, universeStaticDataBuilder); } _optimizedPowerSystem = optimizedPowerSystemBuilder.Build(planetWideBeltExecutor); _turretExecutor = turretExecutorBuilder.Build(); _optimizedPlanetWideProductionStatistics = planetWideProductionRegisterBuilder.Build(universeStaticDataBuilder); Status = OptimizedPlanetStatus.Running; _workNodes = null; _workStepsParallelism = -1; _workNodesWorkChunkCounts = null; } public IWorkNode GetMultithreadedWork(int maxParallelism) { if (HasWorkChanged(maxParallelism, out var unOptimizedWorkChunkCounts)) { _workNodes = CreateMultithreadedWork(maxParallelism, ref unOptimizedWorkChunkCounts); _workStepsParallelism = maxParallelism; } return _workNodes; } [MemberNotNullWhen(false, "_workNodes")] private bool HasWorkChanged(int maxParallelism, out UnOptimizedWorkChunkCounts unOptimizedWorkChunkCounts) { if (Status == OptimizedPlanetStatus.Stopped) { unOptimizedWorkChunkCounts = UnOptimizedWorkChunkCounts.ComputeWorkChunkCounts(_planet, maxParallelism); if (_workNodesWorkChunkCounts.HasValue && _workStepsParallelism == maxParallelism) { return !unOptimizedWorkChunkCounts.Equals(_workNodesWorkChunkCounts); } return true; } if (_workNodes == null) { unOptimizedWorkChunkCounts = default(UnOptimizedWorkChunkCounts); return true; } if (_workStepsParallelism != maxParallelism) { unOptimizedWorkChunkCounts = default(UnOptimizedWorkChunkCounts); return true; } unOptimizedWorkChunkCounts = default(UnOptimizedWorkChunkCounts); return false; } private IWorkNode CreateMultithreadedWork(int maxParallelism, ref UnOptimizedWorkChunkCounts unOptimizedWorkChunkCounts) { if (Status == OptimizedPlanetStatus.Stopped) { _workNodesWorkChunkCounts = unOptimizedWorkChunkCounts; return unOptimizedWorkChunkCounts.CreateWorkNode(); } if (_subFactories.Length == 0) { return new NoWorkNode(); } if (_subFactories.Length == 1) { OptimizedSubFactory subFactory = _subFactories[0]; return new SingleWorkLeaf(new EntirePlanet(this, subFactory, _optimizedPowerSystem.GetSubFactoryPowerConsumption(subFactory))); } List list = new List(); list.Add(new IWorkNode[1] { new SingleWorkLeaf(new PlanetWidePower(this)) }); List list2 = new List(); OptimizedSubFactory[] subFactories = _subFactories; foreach (OptimizedSubFactory subFactory2 in subFactories) { list2.Add(new SubFactoryGameTick(subFactory2, _optimizedPowerSystem.GetSubFactoryPowerConsumption(subFactory2))); } list.Add(new IWorkNode[1] { new WorkLeaf(list2.ToArray()) }); list.Add(new IWorkNode[1] { new SingleWorkLeaf(new PostSubFactoryStep(this)) }); return new WorkNode(list.ToArray()); } public void RequestDysonSpherePower(int workerIndex) { if (Status == OptimizedPlanetStatus.Running) { _optimizedPowerSystem.RequestDysonSpherePower(_planet, workerIndex); } else { UnoptimizedRequestDysonSpherePower(); } } public void BeforePowerStep(long time) { _planet.defenseSystem.GameTickBeforePower(time); _planet.digitalSystem.GameTickBeforePower(time); } public void PowerStep(long time, int workerIndex) { _optimizedPowerSystem.GameTick(_planet, time, workerIndex); } public void TransportGameTick(int workerIndex, long time, Vector3 playerPos) { //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) PlanetTransport transport = _planet.transport; if (transport.dispenserCount == 0) { return; } DeepProfiler.BeginSample((DPEntry)36, workerIndex, (long)_planet.planetId); DeepProfiler.BeginSample((DPEntry)38, workerIndex, -1L); DispenserGameTick_SandboxMode(workerIndex, transport); GameHistoryData history = GameMain.history; float[] networkServes = transport.powerSystem.networkServes; PowerConsumerComponent[] consumerPool = transport.powerSystem.consumerPool; double num = Math.Cos((double)history.dispenserDeliveryMaxAngle * Math.PI / 180.0); if (num < -0.999) { num = -1.0; } playerPos += ((Vector3)(ref playerPos)).normalized * 2.66666f; bool playerDeliveryEnabled = transport.playerDeliveryEnabled; transport.DeterminePlayerDeliveryEnabled(transport.factory); if (playerDeliveryEnabled != transport.playerDeliveryEnabled) { transport.RefreshDispenserTraffic(-10000); } for (int i = 1; i < transport.dispenserCursor; i++) { if (transport.dispenserPool[i] != null && transport.dispenserPool[i].id == i) { float num2 = networkServes[consumerPool[transport.dispenserPool[i].pcId].networkId]; transport.dispenserPool[i].InternalTick(transport.factory, transport.factory.entityPool, transport.dispenserPool, playerPos, time, num2, history.logisticCourierSpeedModified, history.logisticCourierCarries, num); transport.dispenserPool[i].SetPCState(consumerPool); } } DeepProfiler.EndSample((DPEntry)38, workerIndex); DeepProfiler.EndSample((DPEntry)36, workerIndex); } private static void DispenserGameTick_SandboxMode(int workerIndex, PlanetTransport transport) { if (!GameMain.sandboxToolsEnabled) { return; } for (int i = 1; i < transport.dispenserCursor; i++) { if (transport.dispenserPool[i] != null && transport.dispenserPool[i].id == i) { transport.dispenserPool[i].UpdateKeepMode(); } } } public void DigitalSystemStep(int workerIndex) { DeepProfiler.BeginMajorSample((DPEntry)39, workerIndex, -1L); _planet.digitalSystem.GameTick(false); DeepProfiler.EndMajorSample((DPEntry)39, workerIndex); } public void AggregateSubFactoryDataStep(int workerIndex, long time) { DeepProfiler.BeginSample((DPEntry)75, workerIndex, -1L); FactoryProductionStat obj = GameMain.statistics.production.factoryStatPool[_planet.index]; int[] productRegister = obj.productRegister; int[] consumeRegister = obj.consumeRegister; _optimizedPlanetWideProductionStatistics.UpdateStatistics(time, productRegister, consumeRegister); DeepProfiler.EndSample((DPEntry)75, workerIndex); } public void TurretBeltUpdate(ref TurretComponent turret) { _turretExecutor.TurretBeltUpdate(ref turret); } public void AddMiningFlags(MiningFlags miningFlags) { if (miningFlags.MiningFlag == 0 && miningFlags.VeinMiningFlag == 0) { return; } lock (this) { PlanetFactory planet = _planet; planet._miningFlag |= miningFlags.MiningFlag; PlanetFactory planet2 = _planet; planet2._veinMiningFlag |= miningFlags.VeinMiningFlag; } } public void RefreshPowerGenerationCapacites(ProductionStatistics statistics, PlanetFactory planet) { _optimizedPowerSystem.RefreshPowerGenerationCapacites(statistics, planet); } public void RefreshPowerConsumptionDemands(ProductionStatistics statistics, PlanetFactory planet) { OptimizedSubFactory[] subFactories = _subFactories; foreach (OptimizedSubFactory optimizedSubFactory in subFactories) { optimizedSubFactory.RefreshPowerConsumptionDemands(statistics, _optimizedPowerSystem.GetSubFactoryPowerConsumption(optimizedSubFactory)); } _optimizedPowerSystem.RefreshPowerConsumptionDemands(statistics, planet); } private void UnoptimizedRequestDysonSpherePower() { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) DysonSphere dysonSphere = _planet.dysonSphere; float num = 1f - GameMain.history.solarEnergyLossRate; float num2 = ((dysonSphere != null) ? ((float)((double)dysonSphere.grossRadius / ((double)_planet.planet.sunDistance * 40000.0))) : 0f); Vector3 normalized = ((Vector3)(ref _planet.planet.runtimeLocalSunDirection)).normalized; long num3 = 0L; for (int i = 1; i < _planet.powerSystem.genCursor; i++) { if (_planet.powerSystem.genPool[i].gamma) { num3 += ((PowerGeneratorComponent)(ref _planet.powerSystem.genPool[i])).EnergyCap_Gamma_Req(normalized.x, normalized.y, normalized.z, num2, num); } } if (dysonSphere != null) { Interlocked.Add(ref dysonSphere.energyReqCurrentTick, num3); } } } internal static class ProductionHelper { public static void PartialProductionStatisticsGameTick(FactoryProductionStat factoryStats, long time, int[] itemsIdsToCheck) { if (time % 1 != 0L) { return; } int num = 0; int num2 = 6; int num3 = 6 + num; int num4 = 7 + num; int num5 = 13; int num6 = 4200; int num7 = itemsIdsToCheck.Length; for (int i = 0; i < num7; i++) { int num8 = itemsIdsToCheck[i]; int num9 = num8; int num10 = factoryStats.productRegister[num8]; int num11 = factoryStats.consumeRegister[num8]; int num12 = factoryStats.productIndices[num9]; if (num12 <= 0) { if (num10 <= 0 && num11 <= 0) { continue; } int productCursor = factoryStats.productCursor; factoryStats.CreateProductStat(num9); factoryStats.productIndices[num9] = productCursor; num12 = productCursor; } ProductStat obj = factoryStats.productPool[num12]; int[] count = obj.count; int[] cursor = obj.cursor; long[] total = obj.total; int num13 = cursor[num]; int num14 = num10 - count[num13]; count[num13] = num10; total[num] += num14; total[num2] += num10; cursor[num]++; if (cursor[num] >= 600) { cursor[num] -= 600; } int num15 = cursor[num3]; int num16 = num11 - count[num15]; count[num15] = num11; total[num4] += num16; total[num5] += num11; cursor[num3]++; if (cursor[num3] >= num6) { cursor[num3] -= 600; } } } } internal readonly struct TypedObjectIndex : IEquatable { private const int IndexBitCount = 24; private const uint IndexBitMask = 16777215u; private const uint EntityTypeMask = 255u; private readonly uint _value; public static readonly TypedObjectIndex Invalid = new TypedObjectIndex(EntityType.None, 16777215); public EntityType EntityType => (EntityType)(_value >> 24); public int Index => (int)(0xFFFFFF & _value); public TypedObjectIndex(EntityType entityType, int index) { if ((int)entityType < 0 || (long)(int)entityType > 255L) { throw new ArgumentOutOfRangeException("index", $"{entityType} was outside the range {0} to {255u:N0}"); } if (index < 0 || (long)index > 16777215L) { throw new ArgumentOutOfRangeException("index", $"{index} was outside the range {0} to {16777215u:N0}"); } _value = ((uint)entityType << 24) | (0xFFFFFFu & (uint)index); } public static bool operator ==(TypedObjectIndex left, TypedObjectIndex right) { return left._value == right._value; } public static bool operator !=(TypedObjectIndex left, TypedObjectIndex right) { return left._value != right._value; } public bool Equals(TypedObjectIndex other) { return _value == other._value; } public override bool Equals(object obj) { if (obj is TypedObjectIndex other) { return Equals(other); } return false; } public override int GetHashCode() { uint value = _value; return value.GetHashCode(); } public override string ToString() { return string.Format("TypedObjectIndex\r\n\\t{0}: {1}\r\n\\t{2}: {3:N0}", "EntityType", Enum.GetName(typeof(EntityType), EntityType), "Index", Index); } } } namespace Weaver.Optimizations.WorkDistributors { internal interface IWorkNode : IDisposable { bool IsLeaf { get; } (bool isNodeComplete, bool didAnyWork) TryDoWork(bool waitForWork, bool searchAllWork, int workerIndex, object singleThreadedCodeLock, PlanetData localPlanet, long time, Vector3 playerPosition); IEnumerable GetAllWorkChunks(); void Reset(); int GetWorkChunkCount(); void DeepDispose(); } internal sealed class NoWorkNode : IWorkNode, IDisposable { public bool IsLeaf { get { throw new NotImplementedException(); } } public int GetWorkChunkCount() { throw new NotImplementedException(); } public void Reset() { throw new NotImplementedException(); } public (bool isNodeComplete, bool didAnyWork) TryDoWork(bool waitForWork, bool searchAllWork, int workerIndex, object singleThreadedCodeLock, PlanetData localPlanet, long time, Vector3 playerPosition) { throw new NotImplementedException(); } public IEnumerable GetAllWorkChunks() { throw new NotImplementedException(); } public void DeepDispose() { } public void Dispose() { } } internal sealed class DummyWorkDoneImmediatelyNode : IWorkNode, IDisposable { public bool IsLeaf => true; public int GetWorkChunkCount() { return 0; } public void Reset() { } public (bool isNodeComplete, bool didAnyWork) TryDoWork(bool waitForWork, bool searchAllWork, int workerIndex, object singleThreadedCodeLock, PlanetData localPlanet, long time, Vector3 playerPosition) { return (true, true); } public IEnumerable GetAllWorkChunks() { return Array.Empty(); } public void DeepDispose() { } public void Dispose() { } } internal sealed class PlanetWorkManager { private PlanetFactory _planet; private readonly IOptimizedPlanet _optimizedPlanet; private readonly SingleWorkLeaf _prePlanetFactoryWorkNode; private SingleWorkLeaf[]? _enemyGroundCombatWorkNodes; private IWorkNode? _factoryWorkNode; private IWorkNode? _planetWorkNode; public IOptimizedPlanet OptimizedPlanet => _optimizedPlanet; public PlanetWorkManager(GameLogic gameLogic, PlanetFactory planet, IOptimizedPlanet optimizedPlanet) { _planet = planet; _optimizedPlanet = optimizedPlanet; _prePlanetFactoryWorkNode = new SingleWorkLeaf(new PrePlanetFactorySteps(gameLogic, planet)); } public bool UpdatePlanetWork(int parallelism) { bool flag = false; int parallelCount = EnemyGroundCombatWorkChunk.GetParallelCount(_planet, parallelism); if (parallelCount > 0 && (_enemyGroundCombatWorkNodes == null || _enemyGroundCombatWorkNodes.Length != parallelCount)) { if (_enemyGroundCombatWorkNodes != null) { for (int i = 0; i < _enemyGroundCombatWorkNodes.Length; i++) { _enemyGroundCombatWorkNodes[i].Dispose(); } } _enemyGroundCombatWorkNodes = new SingleWorkLeaf[parallelCount]; for (int j = 0; j < _enemyGroundCombatWorkNodes.Length; j++) { _enemyGroundCombatWorkNodes[j] = new SingleWorkLeaf(new EnemyGroundCombatWorkChunk(_planet, j, parallelCount)); } flag = true; } else if (_enemyGroundCombatWorkNodes != null && parallelCount == 0) { for (int k = 0; k < _enemyGroundCombatWorkNodes.Length; k++) { _enemyGroundCombatWorkNodes[k].Dispose(); } _enemyGroundCombatWorkNodes = null; flag = true; } IWorkNode multithreadedWork = _optimizedPlanet.GetMultithreadedWork(parallelism); if (_factoryWorkNode != multithreadedWork) { _factoryWorkNode?.Dispose(); _factoryWorkNode = multithreadedWork; flag = true; } if (flag) { _planetWorkNode?.Dispose(); if (multithreadedWork is NoWorkNode && _enemyGroundCombatWorkNodes == null) { _planetWorkNode = _prePlanetFactoryWorkNode; } else if (multithreadedWork is NoWorkNode && _enemyGroundCombatWorkNodes != null) { IWorkNode[][] obj = new IWorkNode[2][] { new IWorkNode[1] { _prePlanetFactoryWorkNode }, null }; IWorkNode[] enemyGroundCombatWorkNodes = _enemyGroundCombatWorkNodes; obj[1] = enemyGroundCombatWorkNodes; _planetWorkNode = new WorkNode(obj); } else if (_enemyGroundCombatWorkNodes == null) { _planetWorkNode = new WorkNode(new IWorkNode[2][] { new IWorkNode[1] { _prePlanetFactoryWorkNode }, new IWorkNode[1] { _factoryWorkNode } }); } else { IWorkNode[][] obj2 = new IWorkNode[3][] { new IWorkNode[1] { _prePlanetFactoryWorkNode }, null, null }; IWorkNode[] enemyGroundCombatWorkNodes = _enemyGroundCombatWorkNodes; obj2[1] = enemyGroundCombatWorkNodes; obj2[2] = new IWorkNode[1] { _factoryWorkNode }; _planetWorkNode = new WorkNode(obj2); } } return flag; } public bool TryGetPlanetWork([NotNullWhen(true)] out IWorkNode? planetWorkNode) { if (_planetWorkNode == null) { planetWorkNode = null; return false; } if (_planetWorkNode is NoWorkNode) { planetWorkNode = null; return false; } planetWorkNode = _planetWorkNode; return true; } public PlanetWorkStatistics? GetPlanetWorkStatistics() { if (_planetWorkNode == null) { return null; } if (_planetWorkNode is NoWorkNode) { return null; } int workChunkCount = _planetWorkNode.GetWorkChunkCount(); return new PlanetWorkStatistics(-1, workChunkCount); } } internal record struct PlanetWorkPlan(PlanetWorkManager PlanetWorkManager, IWorkChunk WorkChunk); internal record struct PlanetWorkStatistics(int WorkStepsCount, int TotalWorkChunkCount); internal sealed class RootWorkNode : IDisposable { private readonly IWorkNode _workNode; private volatile bool _isWorkDone; public RootWorkNode(IWorkNode workNode) { _workNode = workNode; } public void Execute(int workerIndex, object singleThreadedCodeLock, PlanetData localPlanet, long time, Vector3 playerPosition) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) if (_isWorkDone) { return; } if (_workNode.TryDoWork(waitForWork: false, searchAllWork: false, workerIndex, singleThreadedCodeLock, localPlanet, time, playerPosition).isNodeComplete) { _isWorkDone = true; return; } while (!_isWorkDone) { bool flag; bool flag2; (flag, flag2) = _workNode.TryDoWork(waitForWork: false, searchAllWork: true, workerIndex, singleThreadedCodeLock, localPlanet, time, playerPosition); if (flag) { _isWorkDone = true; break; } if (!flag2) { (flag, flag2) = _workNode.TryDoWork(waitForWork: true, searchAllWork: true, workerIndex, singleThreadedCodeLock, localPlanet, time, playerPosition); if (flag) { _isWorkDone = true; break; } if (!flag2) { break; } } } } public IEnumerable GetAllWorkChunks() { return _workNode.GetAllWorkChunks(); } public void Reset() { _workNode.Reset(); _isWorkDone = false; } public void DeepDispose() { _workNode?.DeepDispose(); } public void Dispose() { _workNode?.Dispose(); } } internal sealed class SolarSystemWorkManager { [CompilerGenerated] private sealed class d__10 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private PlanetWorkStatistics <>2__current; private int <>l__initialThreadId; public SolarSystemWorkManager <>4__this; private List.Enumerator <>7__wrap1; PlanetWorkStatistics IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__10(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>7__wrap1 = default(List.Enumerator); <>1__state = -2; } private bool MoveNext() { try { int num = <>1__state; SolarSystemWorkManager solarSystemWorkManager = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>7__wrap1 = solarSystemWorkManager._planetWorkManager.GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; } while (<>7__wrap1.MoveNext()) { PlanetWorkStatistics? planetWorkStatistics = <>7__wrap1.Current.GetPlanetWorkStatistics(); if (planetWorkStatistics.HasValue) { <>2__current = planetWorkStatistics.Value; <>1__state = 1; return true; } } <>m__Finally1(); <>7__wrap1 = default(List.Enumerator); return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; ((IDisposable)<>7__wrap1).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__10 result; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; result = this; } else { result = new d__10(0) { <>4__this = <>4__this }; } return result; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } private readonly List _planetWorkManager = new List(); private readonly List _planetWorkNodes = new List(); private readonly List _planetRayReceiverEnergyRequests = new List(); private IWorkNode? _dysonWorkNode; private IWorkNode? _planetRayReceiverEnergyRequestsWorkNode; private IWorkNode? _solarSystemWorkNode; public void AddPlanet(PlanetWorkManager planetWorkManager) { _planetWorkManager.Add(planetWorkManager); _solarSystemWorkNode?.Dispose(); _solarSystemWorkNode = null; } public void AddDysonSphere(DysonSphere dysonSphere) { if (_dysonWorkNode != null) { throw new InvalidOperationException("Attempted to add dyson sphere but solar system already has a dyson sphere."); } _dysonWorkNode = new SingleWorkLeaf(new SolarSystemDysonSphereWorkChunk(dysonSphere)); _solarSystemWorkNode?.Dispose(); _solarSystemWorkNode = null; } public bool UpdateSolarSystemWork(int parallelism) { for (int i = 0; i < _planetWorkManager.Count; i++) { if (_planetWorkManager[i].UpdatePlanetWork(parallelism)) { _solarSystemWorkNode?.Dispose(); _solarSystemWorkNode = null; } } if (_solarSystemWorkNode == null) { _planetWorkNodes.Clear(); _planetRayReceiverEnergyRequests.Clear(); for (int j = 0; j < _planetWorkManager.Count; j++) { if (_planetWorkManager[j].TryGetPlanetWork(out IWorkNode planetWorkNode)) { _planetWorkNodes.Add(planetWorkNode); if (_planetWorkManager[j].OptimizedPlanet is OptimizedTerrestrialPlanet optimizedPlanet) { _planetRayReceiverEnergyRequests.Add(new DysonSpherePowerRequest(optimizedPlanet)); } } } } if (_solarSystemWorkNode == null) { List list = new List(); if (_dysonWorkNode != null) { list.Add(new IWorkNode[1] { _dysonWorkNode }); } if (_planetRayReceiverEnergyRequests.Count > 0) { _planetRayReceiverEnergyRequestsWorkNode?.Dispose(); _planetRayReceiverEnergyRequestsWorkNode = new WorkLeaf(_planetRayReceiverEnergyRequests.ToArray()); list.Add(new IWorkNode[1] { _planetRayReceiverEnergyRequestsWorkNode }); } if (_planetWorkNodes.Count > 0) { list.Add(_planetWorkNodes.ToArray()); } if (list.Count == 0) { _solarSystemWorkNode = new NoWorkNode(); } else { _solarSystemWorkNode = new WorkNode(list.ToArray()); } return true; } return false; } public bool TryGetSolarSystemWork([NotNullWhen(true)] out IWorkNode? solarSystemWorkNode) { if (_solarSystemWorkNode == null) { solarSystemWorkNode = null; return false; } if (_solarSystemWorkNode is NoWorkNode) { solarSystemWorkNode = null; return false; } solarSystemWorkNode = _solarSystemWorkNode; return true; } [IteratorStateMachine(typeof(d__10))] public IEnumerable GetPlanetWorkStatistics() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__10(-2) { <>4__this = this }; } } internal sealed class StarClusterWorkManager : IDisposable { [CompilerGenerated] private sealed class d__20 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private IWorkChunk <>2__current; private int <>l__initialThreadId; private DysonSphere dysonSphere; public DysonSphere <>3__dysonSphere; private int maxParallelism; public int <>3__maxParallelism; private int 5__2; private int 5__3; IWorkChunk IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__20(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__2 = (Math.Max(dysonSphere.swarm.bulletCursor, dysonSphere.rocketCursor) + 1999) / 2000; 5__2 = Math.Min(5__2, maxParallelism); 5__2 = Math.Max(5__2, 1); 5__3 = 0; break; case 1: <>1__state = -1; 5__3++; break; } if (5__3 < 5__2) { <>2__current = new DysonSphereAttach(dysonSphere, 5__3, 5__2); <>1__state = 1; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__20 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__20(0); } d__.dysonSphere = <>3__dysonSphere; d__.maxParallelism = <>3__maxParallelism; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } private readonly HashSet _assignedSpheres = new HashSet(); private readonly Dictionary _planetToWorkManagers = new Dictionary(); private readonly List _solarSystemWorkManagers = new List(); private readonly Dictionary _starToWorkManagers = new Dictionary(); private readonly List _solarSystemWorkNodes = new List(); private RootWorkNode? _factorySimulationRootWorkNode; private RootWorkNode? _defenseSystemTurretRootWorkNode; private RootWorkNode? _dysonSphereAttachRootWorkNode; public int Parallelism { get; private set; } = -1; public void UpdateListOfPlanets(GameLogic gameLogic, PlanetFactory?[] allPlanets, DysonSphere[] dysonSpheres, int parallelism) { Parallelism = parallelism; foreach (PlanetFactory val in allPlanets) { if (val != null && !_planetToWorkManagers.ContainsKey(val)) { IOptimizedPlanet optimizedPlanet = OptimizedStarCluster.GetOptimizedPlanet(val); PlanetWorkManager planetWorkManager = new PlanetWorkManager(gameLogic, val, optimizedPlanet); _planetToWorkManagers.Add(val, planetWorkManager); if (!_starToWorkManagers.TryGetValue(val.planet.star, out SolarSystemWorkManager value)) { value = new SolarSystemWorkManager(); _solarSystemWorkManagers.Add(value); _starToWorkManagers.Add(val.planet.star, value); } value.AddPlanet(planetWorkManager); _factorySimulationRootWorkNode?.Dispose(); _factorySimulationRootWorkNode = null; _defenseSystemTurretRootWorkNode?.Dispose(); _defenseSystemTurretRootWorkNode = null; } } for (int j = 0; j < _solarSystemWorkManagers.Count; j++) { if (_solarSystemWorkManagers[j].UpdateSolarSystemWork(parallelism)) { _factorySimulationRootWorkNode?.Dispose(); _factorySimulationRootWorkNode = null; } } foreach (DysonSphere val2 in dysonSpheres) { if (val2 != null && _assignedSpheres.Add(val2)) { if (!_starToWorkManagers.TryGetValue(val2.starData, out SolarSystemWorkManager value2)) { value2 = new SolarSystemWorkManager(); _solarSystemWorkManagers.Add(value2); _starToWorkManagers.Add(val2.starData, value2); } _assignedSpheres.Add(val2); value2.AddDysonSphere(val2); _factorySimulationRootWorkNode?.Dispose(); _factorySimulationRootWorkNode = null; _dysonSphereAttachRootWorkNode?.Dispose(); _dysonSphereAttachRootWorkNode = null; } } if (GameMain.gameTick % 240 == 0L) { _dysonSphereAttachRootWorkNode?.Dispose(); _dysonSphereAttachRootWorkNode = null; } if (_factorySimulationRootWorkNode == null) { _solarSystemWorkNodes.Clear(); for (int l = 0; l < _solarSystemWorkManagers.Count; l++) { if (_solarSystemWorkManagers[l].TryGetSolarSystemWork(out IWorkNode solarSystemWorkNode)) { _solarSystemWorkNodes.Add(solarSystemWorkNode); } } if (_solarSystemWorkNodes.Count == 0) { _factorySimulationRootWorkNode = new RootWorkNode(new DummyWorkDoneImmediatelyNode()); } else { WeaverFixes.Logger.LogMessage((object)$"Star cluster size: {_solarSystemWorkNodes.Count}"); _factorySimulationRootWorkNode = new RootWorkNode(new WorkNode(new IWorkNode[1][] { _solarSystemWorkNodes.ToArray() })); } } if (_defenseSystemTurretRootWorkNode == null) { List list = new List(); foreach (PlanetFactory val3 in allPlanets) { if (val3 == null) { continue; } int cursor = val3.defenseSystem.turrets.cursor; int componentWorkChunkCount = UnOptimizedWorkChunkCounts.GetComponentWorkChunkCount(parallelism, 20, cursor); if (componentWorkChunkCount > 0) { for (int n = 0; n < componentWorkChunkCount; n++) { list.Add(new DefenseSystemTurret(val3, n, componentWorkChunkCount)); } } } IWorkChunk[] workNodes = list.ToArray(); _defenseSystemTurretRootWorkNode = new RootWorkNode(new WorkLeaf(workNodes)); } if (_dysonSphereAttachRootWorkNode == null) { IWorkChunk[] array = _assignedSpheres.SelectMany((DysonSphere x) => GetWorkChunksForDysonSphereAttach(x, parallelism)).ToArray(); if (array.Length == 0) { _dysonSphereAttachRootWorkNode = new RootWorkNode(new DummyWorkDoneImmediatelyNode()); } else { _dysonSphereAttachRootWorkNode = new RootWorkNode(new WorkLeaf(array)); } } } public RootWorkNode GetFactorySimulationRootWorkNode() { if (_factorySimulationRootWorkNode == null) { throw new InvalidOperationException(); } return _factorySimulationRootWorkNode; } public RootWorkNode GetDefenseSystemTurretRootWorkNode() { if (_defenseSystemTurretRootWorkNode == null) { throw new InvalidOperationException(); } return _defenseSystemTurretRootWorkNode; } public RootWorkNode GetDysonSphereAttachRootWorkNode() { if (_dysonSphereAttachRootWorkNode == null) { throw new InvalidOperationException(); } return _dysonSphereAttachRootWorkNode; } public void Reset() { if (_factorySimulationRootWorkNode == null) { throw new InvalidOperationException(); } _factorySimulationRootWorkNode.Reset(); if (_defenseSystemTurretRootWorkNode == null) { throw new InvalidOperationException(); } _defenseSystemTurretRootWorkNode.Reset(); if (_dysonSphereAttachRootWorkNode == null) { throw new InvalidOperationException(); } _dysonSphereAttachRootWorkNode.Reset(); } public StarClusterWorkStatistics GetStarClusterStatistics() { List list = new List(); foreach (SolarSystemWorkManager solarSystemWorkManager in _solarSystemWorkManagers) { list.AddRange(solarSystemWorkManager.GetPlanetWorkStatistics()); } return new StarClusterWorkStatistics(list.ToArray()); } public IEnumerable GetAllWorkChunks() { if (_factorySimulationRootWorkNode == null) { throw new InvalidOperationException(); } return _factorySimulationRootWorkNode.GetAllWorkChunks(); } public void Dispose() { } [IteratorStateMachine(typeof(d__20))] private static IEnumerable GetWorkChunksForDysonSphereAttach(DysonSphere dysonSphere, int maxParallelism) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__20(-2) { <>3__dysonSphere = dysonSphere, <>3__maxParallelism = maxParallelism }; } } internal record struct StarClusterWorkStatistics(PlanetWorkStatistics[] PlanetWorkStatistics); internal sealed class WorkExecutor { private readonly StarClusterWorkManager _starClusterWorkManager; private readonly int _workerIndex; private readonly object _singleThreadedCodeLock; public int WorkerIndex => _workerIndex; public WorkExecutor(StarClusterWorkManager starClusterWorkManager, int workerIndex, object singleThreadedCodeLock) { _starClusterWorkManager = starClusterWorkManager; _workerIndex = workerIndex; _singleThreadedCodeLock = singleThreadedCodeLock; } public void ExecuteFactorySimulation(PlanetData localPlanet, long time, Vector3 playerPosition) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) try { _starClusterWorkManager.GetFactorySimulationRootWorkNode().Execute(_workerIndex, _singleThreadedCodeLock, localPlanet, time, playerPosition); } catch (Exception ex) { WeaverFixes.Logger.LogError((object)ex.Message); WeaverFixes.Logger.LogError((object)ex.StackTrace); throw; } } public void ExecuteDefenseSystemTurret(PlanetData localPlanet, long time, Vector3 playerPosition) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) try { _starClusterWorkManager.GetDefenseSystemTurretRootWorkNode().Execute(_workerIndex, _singleThreadedCodeLock, localPlanet, time, playerPosition); } catch (Exception ex) { WeaverFixes.Logger.LogError((object)ex.Message); WeaverFixes.Logger.LogError((object)ex.StackTrace); throw; } } public void ExecuteDysonSphereAttachUpdate(PlanetData localPlanet, long time, Vector3 playerPosition) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) try { _starClusterWorkManager.GetDysonSphereAttachRootWorkNode().Execute(_workerIndex, _singleThreadedCodeLock, localPlanet, time, playerPosition); } catch (Exception ex) { WeaverFixes.Logger.LogError((object)ex.Message); WeaverFixes.Logger.LogError((object)ex.StackTrace); throw; } } } internal sealed class WorkLeaf : IWorkNode, IDisposable { private readonly IWorkChunk[] _workNodes; private int _completedCount; private int _scheduledCount; public bool IsLeaf => true; public WorkLeaf(IWorkChunk[] workNodes) { if (workNodes.Length == 0) { throw new ArgumentOutOfRangeException("workNodes", workNodes, "There was 0 work chunks in the array of work."); } _workNodes = workNodes; } public (bool isNodeComplete, bool didAnyWork) TryDoWork(bool waitForWork, bool searchAllWork, int workerIndex, object singleThreadedCodeLock, PlanetData localPlanet, long time, Vector3 playerPosition) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) if (_scheduledCount >= _workNodes.Length) { return (false, false); } int num = Interlocked.Increment(ref _scheduledCount) - 1; if (num >= _workNodes.Length) { return (false, false); } _workNodes[num].Execute(workerIndex, singleThreadedCodeLock, localPlanet, time, playerPosition); return (Interlocked.Increment(ref _completedCount) == _workNodes.Length, true); } public IEnumerable GetAllWorkChunks() { return _workNodes; } public void Reset() { _completedCount = 0; _scheduledCount = 0; } public int GetWorkChunkCount() { return _workNodes.Length; } public void DeepDispose() { } public void Dispose() { } } internal sealed class SingleWorkLeaf : IWorkNode, IDisposable { [CompilerGenerated] private sealed class d__6 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private IWorkChunk <>2__current; private int <>l__initialThreadId; public SingleWorkLeaf <>4__this; IWorkChunk IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__6(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; SingleWorkLeaf singleWorkLeaf = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>2__current = singleWorkLeaf._workNode; <>1__state = 1; return true; case 1: <>1__state = -1; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__6 result; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; result = this; } else { result = new d__6(0) { <>4__this = <>4__this }; } return result; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } private readonly IWorkChunk _workNode; private int _scheduledCount; public bool IsLeaf => true; public SingleWorkLeaf(IWorkChunk workNode) { _workNode = workNode; } public (bool isNodeComplete, bool didAnyWork) TryDoWork(bool waitForWork, bool searchAllWork, int workerIndex, object singleThreadedCodeLock, PlanetData localPlanet, long time, Vector3 playerPosition) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) if (_scheduledCount > 0) { return (false, false); } if (Interlocked.Increment(ref _scheduledCount) - 1 >= 1) { return (false, false); } _workNode.Execute(workerIndex, singleThreadedCodeLock, localPlanet, time, playerPosition); return (true, true); } [IteratorStateMachine(typeof(d__6))] public IEnumerable GetAllWorkChunks() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__6(-2) { <>4__this = this }; } public void Reset() { _scheduledCount = 0; } public int GetWorkChunkCount() { return 1; } public void DeepDispose() { } public void Dispose() { } } internal sealed class WorkNode : IWorkNode, IDisposable { private readonly IWorkNode[][] _preservedWorkNodes; private readonly IWorkNode?[][] _actualWorkNodes; private readonly ManualResetEvent[] _workNodeBarriers; private readonly int[] _scheduledWorkIndex; private readonly int[] _completedWorkIndex; private int _workStepIndex; public bool IsLeaf => false; public WorkNode(IWorkNode[][] workNodes) { if (workNodes.Any((IWorkNode[] x) => x.Length == 0)) { throw new InvalidOperationException(""); } if (workNodes.Length == 0) { throw new ArgumentOutOfRangeException("workNodes", workNodes, "There must be at least 1 work for the work to be valid."); } _preservedWorkNodes = workNodes; _actualWorkNodes = _preservedWorkNodes.Select((IWorkNode[] x) => x.ToArray()).ToArray(); _workNodeBarriers = _actualWorkNodes.Select((IWorkNode[] _) => new ManualResetEvent(initialState: false)).ToArray(); _scheduledWorkIndex = new int[workNodes.Length]; _completedWorkIndex = new int[workNodes.Length]; _workStepIndex = 0; } public (bool isNodeComplete, bool didAnyWork) TryDoWork(bool waitForWork, bool searchAllWork, int workerIndex, object singleThreadedCodeLock, PlanetData localPlanet, long time, Vector3 playerPosition) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) bool flag = false; int workStepIndex; do { workStepIndex = _workStepIndex; if (workStepIndex == _actualWorkNodes.Length) { return (false, false); } int num = _scheduledWorkIndex[workStepIndex]; int num2 = _actualWorkNodes[workStepIndex].Length; if (num < num2 && !searchAllWork) { num = Interlocked.Increment(ref _scheduledWorkIndex[workStepIndex]) - 1; if (num >= num2) { num = 0; } } else { num = 0; } if (waitForWork && !searchAllWork) { var (item, flag2) = TryFindWorkToWaitFor(waitForWork, searchAllWork, workerIndex, singleThreadedCodeLock, localPlanet, time, playerPosition, workStepIndex, justWaitForWork: false); if (flag2) { return (item, flag2); } } bool flag3 = false; for (int i = num; i < num2; i++) { IWorkNode workNode = _actualWorkNodes[workStepIndex][i]; if (workNode != null) { var (flag4, flag5) = TryDoWorkInNode(waitForWork, searchAllWork, workerIndex, singleThreadedCodeLock, localPlanet, time, playerPosition, workStepIndex, i, workNode); if (flag4) { return (true, true); } flag = flag || flag5; flag3 = flag3 || flag5; } } if (waitForWork && searchAllWork && !flag3) { var (item2, flag6) = TryFindWorkToWaitFor(waitForWork, searchAllWork, workerIndex, singleThreadedCodeLock, localPlanet, time, playerPosition, workStepIndex, justWaitForWork: true); if (flag6) { return (item2, flag6); } } } while (workStepIndex != _workStepIndex); return (false, flag); } private (bool isNodeComplete, bool didAnyWork) TryFindWorkToWaitFor(bool waitForWork, bool searchAllWork, int workerIndex, object singleThreadedCodeLock, PlanetData localPlanet, long time, Vector3 playerPosition, int workStepIndex, bool justWaitForWork) { //IL_00e6: Unknown result type (might be due to invalid IL or missing references) if (_scheduledWorkIndex[workStepIndex] < _actualWorkNodes[workStepIndex].Length && !justWaitForWork) { return (false, false); } int num = workStepIndex + 1; while (num < _actualWorkNodes.Length) { if (!_preservedWorkNodes[num][0].IsLeaf) { if (waitForWork) { num++; continue; } return (false, false); } if (_scheduledWorkIndex[num] > _actualWorkNodes[num].Length) { if (waitForWork) { num++; continue; } return (false, false); } int num2 = Interlocked.Increment(ref _scheduledWorkIndex[num]) - 1; int num3 = _actualWorkNodes[num].Length; if (num2 >= num3) { if (waitForWork) { num++; continue; } return (false, false); } IWorkNode workNode = _actualWorkNodes[num][num2]; if (workNode == null) { if (waitForWork) { num++; continue; } return (false, false); } _workNodeBarriers[num - 1].WaitOne(); return TryDoWorkInNode(waitForWork, searchAllWork, workerIndex, singleThreadedCodeLock, localPlanet, time, playerPosition, num, num2, workNode); } return (false, false); } private (bool isNodeComplete, bool didAnyWork) TryDoWorkInNode(bool waitForWork, bool searchAllWork, int workerIndex, object singleThreadedCodeLock, PlanetData localPlanet, long time, Vector3 playerPosition, int workStepIndex, int nodeIndex, IWorkNode workNode) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) var (flag, item) = workNode.TryDoWork(waitForWork, searchAllWork, workerIndex, singleThreadedCodeLock, localPlanet, time, playerPosition); if (!flag) { return (false, item); } _actualWorkNodes[workStepIndex][nodeIndex] = null; if (Interlocked.Increment(ref _completedWorkIndex[workStepIndex]) != _actualWorkNodes[workStepIndex].Length) { return (false, true); } int num = Interlocked.Increment(ref _workStepIndex); _workNodeBarriers[workStepIndex].Set(); return (_actualWorkNodes.Length == num, true); } public IEnumerable GetAllWorkChunks() { return _preservedWorkNodes.SelectMany((IWorkNode[] x) => x.Where((IWorkNode y) => !(y is NoWorkNode)).SelectMany((IWorkNode y) => y.GetAllWorkChunks())); } public void Reset() { for (int i = 0; i < _preservedWorkNodes.Length; i++) { Array.Copy(_preservedWorkNodes[i], _actualWorkNodes[i], _preservedWorkNodes[i].Length); _workNodeBarriers[i].Reset(); for (int j = 0; j < _preservedWorkNodes[i].Length; j++) { _preservedWorkNodes[i][j].Reset(); } } Array.Clear(_scheduledWorkIndex, 0, _scheduledWorkIndex.Length); Array.Clear(_completedWorkIndex, 0, _scheduledWorkIndex.Length); _workStepIndex = 0; } public int GetWorkChunkCount() { return _preservedWorkNodes.Sum((IWorkNode[] x) => x.Sum((IWorkNode y) => y.GetWorkChunkCount())); } public void DeepDispose() { Dispose(); for (int i = 0; i < _preservedWorkNodes.Length; i++) { for (int j = 0; j < _preservedWorkNodes[i].Length; j++) { _preservedWorkNodes[i][j].DeepDispose(); } } } public void Dispose() { for (int i = 0; i < _workNodeBarriers.Length; i++) { _workNodeBarriers[i].Dispose(); } } } internal static class ThreadLocalData { public static ThreadLocal ThreadIndex { get; } = new ThreadLocal(); } internal static class WeaverThreadHelper { public static int GetParallelism() { return Math.Max(1, GameMain.logic.threadController.wantedThreadCount); } } internal sealed class WeaverThread : IDisposable { private readonly WorkStealingMultiThreadedFactorySimulation _workStealingMultiThreadedFactorySimulation; private readonly ManualResetEvent _doWork; private readonly ManualResetEvent _workerDone; private readonly Thread _thread; private WorkExecutor? _workExecutor; private WorkTaskType _workTaskType; private bool _isWorking = true; [MemberNotNullWhen(true, "_workExecutor")] public bool IsInitialized { [MemberNotNullWhen(true, "_workExecutor")] get { return _workExecutor != null; } } public static WeaverThread CreateThread(WorkStealingMultiThreadedFactorySimulation workStealingMultiThreadedFactorySimulation) { Thread thread = new Thread(delegate(object obj) { try { ((WeaverThread)obj).DoWork(); } catch (Exception ex) { WeaverFixes.Logger.LogError((object)ex.Message); WeaverFixes.Logger.LogError((object)ex.StackTrace); } }); WeaverThread weaverThread = new WeaverThread(workStealingMultiThreadedFactorySimulation, thread); thread.Start(weaverThread); return weaverThread; } private WeaverThread(WorkStealingMultiThreadedFactorySimulation workStealingMultiThreadedFactorySimulation, Thread thread) { _workStealingMultiThreadedFactorySimulation = workStealingMultiThreadedFactorySimulation; _doWork = new ManualResetEvent(initialState: false); _workerDone = new ManualResetEvent(initialState: false); _thread = thread; } public void StartWork(WorkTaskType workTaskType) { _workTaskType = workTaskType; _doWork.Set(); } public void WaitForCompletion() { _workerDone.WaitOne(); _workerDone.Reset(); } public void DoWork() { //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) try { while (_isWorking) { _doWork.WaitOne(); _doWork.Reset(); if (_isWorking) { if (!IsInitialized) { throw new InvalidOperationException("Weaver thread was not initialized with work."); } ThreadLocalData.ThreadIndex.Value = _workExecutor.WorkerIndex; switch (_workTaskType) { case WorkTaskType.FactorySimulation: _workExecutor.ExecuteFactorySimulation(_workStealingMultiThreadedFactorySimulation._localPlanet, _workStealingMultiThreadedFactorySimulation._time, _workStealingMultiThreadedFactorySimulation._playerPosition); break; case WorkTaskType.DefenseSystemTurret: _workExecutor.ExecuteDefenseSystemTurret(_workStealingMultiThreadedFactorySimulation._localPlanet, _workStealingMultiThreadedFactorySimulation._time, _workStealingMultiThreadedFactorySimulation._playerPosition); break; case WorkTaskType.DysonSphereAttach: _workExecutor.ExecuteDysonSphereAttachUpdate(_workStealingMultiThreadedFactorySimulation._localPlanet, _workStealingMultiThreadedFactorySimulation._time, _workStealingMultiThreadedFactorySimulation._playerPosition); break; default: throw new InvalidOperationException($"Unknown work type: {_workTaskType}"); } _workerDone.Set(); continue; } break; } } catch (Exception ex) { WeaverFixes.Logger.LogError((object)ex.Message); WeaverFixes.Logger.LogError((object)ex.StackTrace); _workerDone.Set(); } } public void SetWorkExecutor(WorkExecutor workExecutor) { _workExecutor = workExecutor; } public void ClearWorkExecutor() { _workExecutor = null; } public void Dispose() { _isWorking = false; _doWork.Set(); _thread.Join(); _doWork.Dispose(); _workerDone.Dispose(); } } internal enum WorkTaskType { FactorySimulation, DefenseSystemTurret, DysonSphereAttach } internal sealed class WorkStealingMultiThreadedFactorySimulation : IDisposable { private readonly HighStopwatch _stopWatch = new HighStopwatch(); private readonly object _singleThreadedCodeLock = new object(); private readonly StarClusterResearchManager _starClusterResearchManager; private readonly DysonSphereManager _dysonSphereManager; private readonly UniverseStaticDataBuilder _universeStaticDataBuilder; private StarClusterWorkManager? _starClusterWorkManager; private WeaverThread[]? _threads; public PlanetData? _localPlanet; public long _time; public Vector3 _playerPosition; public WorkStealingMultiThreadedFactorySimulation(StarClusterResearchManager starClusterResearchManager, DysonSphereManager dysonSphereManager, UniverseStaticDataBuilder universeStaticDataBuilder) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown _starClusterResearchManager = starClusterResearchManager; _dysonSphereManager = dysonSphereManager; _universeStaticDataBuilder = universeStaticDataBuilder; } public void Simulate(GameLogic gameLogic, PlanetFactory?[] planetsToUpdate) { //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) try { int parallelism = WeaverThreadHelper.GetParallelism(); if (_starClusterWorkManager == null) { _starClusterWorkManager = new StarClusterWorkManager(); } if (_threads == null || _threads.Length != parallelism) { ThreadLocalData.ThreadIndex.Value = -1; if (_threads == null) { _threads = new WeaverThread[parallelism]; } else if (_threads.Length < parallelism) { Array.Resize(ref _threads, parallelism); } for (int i = 0; i < _threads.Length; i++) { new WorkExecutor(_starClusterWorkManager, i, _singleThreadedCodeLock); if (_threads[i] == null) { _threads[i] = WeaverThread.CreateThread(this); } } } for (int j = 0; j < _threads.Length; j++) { if (!_threads[j].IsInitialized) { WorkExecutor workExecutor = new WorkExecutor(_starClusterWorkManager, j, _singleThreadedCodeLock); _threads[j].SetWorkExecutor(workExecutor); } } DeepProfiler.BeginSample((DPEntry)82, -1, -1L); _starClusterWorkManager.UpdateListOfPlanets(gameLogic, GameMain.data.factories, GameMain.data.dysonSpheres, parallelism); _starClusterWorkManager.Reset(); DeepProfiler.EndSample((DPEntry)82, -1); _stopWatch.Begin(); _localPlanet = GameMain.localPlanet; _time = GameMain.gameTick; _playerPosition = GameMain.mainPlayer.position; _universeStaticDataBuilder.UpdateStaticDataIfRequired(); ExecutePreFactorySingleThreadedSteps(gameLogic, planetsToUpdate, _localPlanet, _time, parallelism); ExecuteParallel(parallelism, WorkTaskType.FactorySimulation); _starClusterResearchManager.UIThreadUnlockResearchedTechnologies(GameMain.history); _dysonSphereManager.UIThreadCreateDysonSpheres(); ExecutePostFactorySingleThreadedSteps(gameLogic, planetsToUpdate, _time, parallelism); _ = _stopWatch.duration; } catch (Exception ex) { WeaverFixes.Logger.LogError((object)ex.Message); WeaverFixes.Logger.LogError((object)ex.StackTrace); } } private void ExecuteParallel(int targetThreadCount, WorkTaskType workTaskType) { for (int i = 0; i < targetThreadCount; i++) { _threads[i].StartWork(workTaskType); } for (int j = 0; j < targetThreadCount; j++) { _threads[j].WaitForCompletion(); } } public void Clear() { _starClusterWorkManager?.Dispose(); _starClusterWorkManager = null; if (_threads != null) { for (int i = 0; i < _threads.Length; i++) { _threads[i]?.ClearWorkExecutor(); } } } public void Dispose() { Clear(); if (_threads != null) { for (int i = 0; i < _threads.Length; i++) { _threads[i]?.Dispose(); } } } public void PrintWorkStatistics() { if (_starClusterWorkManager == null) { _starClusterWorkManager = new StarClusterWorkManager(); } _starClusterWorkManager.UpdateListOfPlanets(GameMain.logic, GameMain.data.factories, GameMain.data.dysonSpheres, WeaverThreadHelper.GetParallelism()); StarClusterWorkStatistics starClusterStatistics = _starClusterWorkManager.GetStarClusterStatistics(); WeaverFixes.Logger.LogInfo((object)$"Planet Count: {starClusterStatistics.PlanetWorkStatistics.Length:N0}"); WeaverFixes.Logger.LogInfo((object)$"Total work steps: {starClusterStatistics.PlanetWorkStatistics.Sum((PlanetWorkStatistics x) => x.WorkStepsCount):N0}"); WeaverFixes.Logger.LogInfo((object)$"Total work chunks: {starClusterStatistics.PlanetWorkStatistics.Sum((PlanetWorkStatistics x) => x.TotalWorkChunkCount):N0}"); WeaverFixes.Logger.LogInfo((object)"All planets:"); PlanetWorkStatistics[] planetWorkStatistics = starClusterStatistics.PlanetWorkStatistics; foreach (PlanetWorkStatistics planetWorkStatistics2 in planetWorkStatistics) { WeaverFixes.Logger.LogInfo((object)$"\t{planetWorkStatistics2}"); } WeaverFixes.Logger.LogInfo((object)""); WeaverFixes.Logger.LogInfo((object)"Work chunk types:"); foreach (var (arg, num) in from x in _starClusterWorkManager.GetAllWorkChunks() group x by x.GetType().Name into x select (x.Key, x.Count())) { WeaverFixes.Logger.LogInfo((object)$"\t{arg}: {num:10,10}"); } } private static void ExecutePreFactorySingleThreadedSteps(GameLogic gameLogic, PlanetFactory?[] planetsToUpdate, PlanetData localPlanet, long time, int targetThreadCount) { gameLogic.UniverseGameTick(); gameLogic.GalaxyGameTick(); gameLogic.PropertySystemGameTick(); gameLogic.StatisticsPrepare(); gameLogic.SpaceSectorPrepare(); gameLogic.LocalFactoryPrepare(); gameLogic.DigitalSystemPrepare(); gameLogic.LocalPlanetPhysics(); gameLogic.SpaceSectorPhysics(); gameLogic.PlayerGameTick(); gameLogic.GalacticTransportGameTick(); gameLogic.GalacticDigitalGameTick(); gameLogic.OnFactoryBeginProfiler(); gameLogic.OnFactoryFrameBegin(); gameLogic.FactoryBeforeGameTick(); if (gameLogic.isCombatMode) { DeepProfiler.BeginSample((DPEntry)64, -1, 99L); PlanetFactory localLoadedPlanetFactory = gameLogic.data.localLoadedPlanetFactory; if (localLoadedPlanetFactory != null) { localLoadedPlanetFactory.LocalizeEnemies(); } DeepProfiler.EndSample((DPEntry)64, -1); } if (gameLogic.isCombatMode) { DeepProfiler.BeginSample((DPEntry)64, -1, -1L); PlanetFactory localLoadedPlanetFactory2 = gameLogic.data.localLoadedPlanetFactory; if (localLoadedPlanetFactory2 != null) { localLoadedPlanetFactory2.LocalizeEnemies(); } DeepProfiler.EndSample((DPEntry)64, -1); } if (localPlanet != null) { DeepProfiler.BeginSample((DPEntry)34, -1, -1L); PlanetFactory factory = localPlanet.factory; factory.constructionSystem.GameTick(time, true, false); factory.constructionSystem.ExcuteDeferredTargetChange(); DeepProfiler.EndSample((DPEntry)34, -1); } } private void ExecutePostFactorySingleThreadedSteps(GameLogic gameLogic, PlanetFactory?[] planetsToUpdate, long time, int targetThreadCount) { gameLogic.EnemyGroundGameTick(); gameLogic.FactoryRuinGameTick(); gameLogic.OnFactoryFrameEnd(); gameLogic.CombatGroundSystemGameTick(); gameLogic.DefenseGroundSystemGameTick(); ExecuteParallel(targetThreadCount, WorkTaskType.DefenseSystemTurret); gameLogic.OnFactoryEndProfiler(); gameLogic.TrashSystemGameTick(); gameLogic.DysonSphereGameTick(); ExecuteParallel(targetThreadCount, WorkTaskType.DysonSphereAttach); DysonSphere[] dysonSpheres = gameLogic.data.dysonSpheres; if (dysonSpheres != null) { for (int i = 0; i < dysonSpheres.Length; i++) { DysonSwarm val = dysonSpheres[i]?.swarm; if (val != null) { DeepProfiler.BeginSample((DPEntry)54, -1, (long)val.starData.id); val.GameTick(time); DeepProfiler.EndSample(-1, -2L); } } } gameLogic.DysonSwarmGameTickPost(); gameLogic.SpaceSectorGameTick(); gameLogic.OnFactoryBeginProfiler(); gameLogic.EnemyGroundSystemPostGameTick(); gameLogic.CombatGroundSystemPostGameTick(); gameLogic.DefenseGroundSystemPostGameTick(); gameLogic.OnFactoryEndProfiler(); gameLogic.SpaceSectorPostGameTick(); gameLogic.LocalPlanetAudio(); gameLogic.SpaceSectorAudio(); gameLogic.SpaceSectorAudioPost(); DeepProfiler.BeginSample((DPEntry)75, -1, -1L); if (!DSPGame.IsMenuDemo) { GameMain.data.statistics.GameTickStats(time); } DeepProfiler.EndSample((DPEntry)75, -1); gameLogic.WarningSystemGameTick(); gameLogic.StatisticsPostGameTick(); gameLogic.ScenarioGameTick(); gameLogic.CollectPreferences(); } } internal enum WorkType { BeforePower, Power, Construction, CheckBefore, Miner, Fractionator, Ejector, Silo, Assembler, LabProduce, LabResearchMode, LabOutput2NextData, TransportData, InputFromBelt, InserterData, Storage, CargoPathsData, Splitter, CargoTrafficMisc, OutputToBelt, SandboxMode, PresentCargoPathsData, Digital } } namespace Weaver.Optimizations.WorkDistributors.WorkChunks { internal sealed class PostSubFactoryStep : IWorkChunk { private readonly OptimizedTerrestrialPlanet _optimizedPlanet; public PostSubFactoryStep(OptimizedTerrestrialPlanet optimizedPlanet) { _optimizedPlanet = optimizedPlanet; } public void Execute(int workerIndex, object singleThreadedCodeLock, PlanetData localPlanet, long time, Vector3 playerPosition) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) _optimizedPlanet.TransportGameTick(workerIndex, time, playerPosition); _optimizedPlanet.DigitalSystemStep(workerIndex); _optimizedPlanet.AggregateSubFactoryDataStep(workerIndex, time); } } internal sealed class DefenseSystemTurret : IWorkChunk { private readonly PlanetFactory _planet; private readonly int _workIndex; private readonly int _maxWorkCount; public DefenseSystemTurret(PlanetFactory planet, int workIndex, int maxWorkCount) { _planet = planet; _workIndex = workIndex; _maxWorkCount = maxWorkCount; } public void Execute(int workerIndex, object singleThreadedCodeLock, PlanetData localPlanet, long time, Vector3 playerPosition) { DeepProfiler.BeginSample((DPEntry)43, workerIndex, -1L); GameTickTurret(time); DeepProfiler.EndSample((DPEntry)43, workerIndex); } private void GameTickTurret(long time) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Invalid comparison between Unknown and I4 //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Expected I4, but got Unknown //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Invalid comparison between Unknown and I4 //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_0297: Invalid comparison between Unknown and I4 //IL_0547: Unknown result type (might be due to invalid IL or missing references) //IL_054d: Invalid comparison between Unknown and I4 GameLogic logic = GameMain.logic; CombatUpgradeData val = default(CombatUpgradeData); logic.history.GetCombatUpgradeData(ref val); SkillSystem skillSystem = logic.sector.skillSystem; EnemyData[] enemyPool = logic.sector.enemyPool; DefenseSystem defenseSystem = _planet.defenseSystem; int[] consumeRegister = logic.statistics.production.factoryStatPool[_planet.index].consumeRegister; TurretComponent[] buffer = defenseSystem.turrets.buffer; PowerSystem powerSystem = _planet.powerSystem; float[] networkServes = powerSystem.networkServes; PowerConsumerComponent[] consumerPool = powerSystem.consumerPool; EntityData[] entityPool = _planet.entityPool; AnimData[] entityAnimPool = _planet.entityAnimPool; SignData[] entitySignPool = _planet.entitySignPool; int num = 10000; (int startIndex, int workLength) workChunkIndices = UnOptimizedPlanetWorkChunk.GetWorkChunkIndices(defenseSystem.turrets.cursor, _maxWorkCount, _workIndex); int item = workChunkIndices.startIndex; int item2 = workChunkIndices.workLength; for (int i = Math.Max(1, item); i < item + item2; i++) { ref TurretComponent reference = ref buffer[i]; if (reference.id != i) { continue; } float num2 = networkServes[consumerPool[reference.pcId].networkId]; PrefabDesc val2 = PlanetFactory.PrefabDescByModelIndex[entityPool[reference.entityId].modelIndex]; ((TurretComponent)(ref reference)).InternalUpdate(time, num2, _planet, skillSystem, val2, true); ((TurretComponent)(ref reference)).Aim(_planet, enemyPool, val2, num2); ((TurretComponent)(ref reference)).Shoot(_planet, enemyPool, val2, consumeRegister, num2, time, ref val); if (reference.supernovaTick < 0) { int num3 = -reference.supernovaTick; if (num3 < num) { num = num3; } } if (reference.isLockingTarget) { ETurretType type = reference.type; switch (type - 1) { case 0: Interlocked.Increment(ref defenseSystem.engagingGaussCount); break; case 1: Interlocked.Increment(ref defenseSystem.engagingLaserCount); break; case 2: Interlocked.Increment(ref defenseSystem.engagingCannonCount); break; case 3: Interlocked.Increment(ref defenseSystem.engagingPlasmaCount); break; case 4: Interlocked.Increment(ref defenseSystem.engagingMissileCount); break; case 5: Interlocked.Increment(ref defenseSystem.engagingLocalPlasmaCount); break; } } ? val3 = reference.vsCaps & reference.vsSettings; if ((val3 & 0xF0) > 0) { defenseSystem.turretEnableDefenseSpace = true; if (((TurretComponent)(ref reference)).DeterminActiveEnemyUnits(true, time)) { ((TurretComponent)(ref reference)).ActiveEnemyUnits_Space(_planet, val2); } } if ((val3 & 0xF) > 0 && ((TurretComponent)(ref reference)).DeterminActiveEnemyUnits(false, time)) { ((TurretComponent)(ref reference)).ActiveEnemyUnits_Ground(_planet, val2); } int entityId = reference.entityId; if ((int)reference.type == 7) { entityAnimPool[entityId].state = 1u; if (((TurretComponent)(ref reference)).CalculateAnimState(num2) > 1) { float anim_working_length = val2.anim_working_length; entityAnimPool[entityId].working_length = anim_working_length; if (entityAnimPool[entityId].time < anim_working_length) { entityAnimPool[entityId].time += logic.deltaTime; } if (entityAnimPool[entityId].time > anim_working_length) { entityAnimPool[entityId].time = anim_working_length - 0.01f; } } else { float anim_working_length2 = val2.anim_working_length; entityAnimPool[entityId].working_length = anim_working_length2; if (entityAnimPool[entityId].time > 0f) { entityAnimPool[entityId].time -= logic.deltaTime; } if (entityAnimPool[entityId].time < 0f) { entityAnimPool[entityId].time = 0f; } } entityAnimPool[entityId].power = num2; } else { bool num4 = ((TurretComponent)(ref reference)).isWorking && num2 >= 0.1f; float num5 = (float)(entityAnimPool[entityId].state / 100000) / 100f; int num6 = (int)((num5 - (float)(int)num5) * 100f + 0.5f); if (num4) { num6++; if (num6 > 40) { num6 = 40; } } else { num6--; if (num6 < 0) { num6 = 0; } } uint num7 = ((TurretComponent)(ref reference)).CalculateAnimState(num2); entityAnimPool[entityId].prepare_length = reference.localDir.x; entityAnimPool[entityId].working_length = reference.localDir.y; entityAnimPool[entityId].power = reference.localDir.z; entityAnimPool[entityId].state = (uint)((int)num7 + (((TurretComponent)(ref reference)).supernovaBursting ? ((int)(10 + (uint)(((TurretComponent)(ref reference)).supernova_strength * 10f + 0.5f) * 100)) : (((TurretComponent)(ref reference)).supernovaCharging ? (-reference.supernovaTick * 100) : 0)) + num6 * 100000 + reference.muzzleIndex * 10000000); entityAnimPool[entityId].time = ((val2.turretMuzzleCount == 1) ? ((1f - (float)reference.roundFire / (float)val2.turretRoundInterval) * 10f) : ((1f - (float)reference.muzzleFire / (float)val2.turretMuzzleInterval) * 10f)); } if ((entitySignPool[entityId].signType == 0 || entitySignPool[entityId].signType > 3) && (int)reference.type != 2) { entitySignPool[entityId].signType = ((reference.bulletCount <= 0 && reference.itemCount <= 0) ? 14u : 0u); } } defenseSystem.engagingTurretTotalCount = defenseSystem.engagingGaussCount + defenseSystem.engagingLaserCount + defenseSystem.engagingCannonCount + defenseSystem.engagingPlasmaCount + defenseSystem.engagingMissileCount + defenseSystem.engagingLocalPlasmaCount; lock (defenseSystem.incoming_supernova_time_lock) { if (num < defenseSystem.incomingSupernovaTime) { defenseSystem.incomingSupernovaTime = num; } } } } internal sealed class DysonSphereAttach : IWorkChunk { private readonly DysonSphere _dysonSphere; private readonly int _workIndex; private readonly int _maxWorkCount; public DysonSphereAttach(DysonSphere dysonSphere, int workIndex, int maxWorkCount) { _dysonSphere = dysonSphere; _workIndex = workIndex; _maxWorkCount = maxWorkCount; } public void Execute(int workerIndex, object singleThreadedCodeLock, PlanetData localPlanet, long time, Vector3 playerPosition) { DysonSwarm swarm = _dysonSphere.swarm; if (swarm != null && swarm.bulletCursor > 0) { DeepProfiler.BeginSample((DPEntry)54, workerIndex, -1L); ParallelDysonSwarmGameTick(); DeepProfiler.EndSample((DPEntry)54, workerIndex); } if (_dysonSphere.rocketCursor > 0) { DeepProfiler.BeginSample((DPEntry)57, workerIndex, -1L); ParallelDysonRocketGameTick(time); DeepProfiler.EndSample((DPEntry)57, workerIndex); } } private void ParallelDysonSwarmGameTick() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected I4, but got Unknown //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_0284: Expected I4, but got Unknown //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Unknown result type (might be due to invalid IL or missing references) //IL_02a3: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02ad: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: Unknown result type (might be due to invalid IL or missing references) //IL_02c2: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Unknown result type (might be due to invalid IL or missing references) //IL_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_02ed: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Unknown result type (might be due to invalid IL or missing references) //IL_0313: Unknown result type (might be due to invalid IL or missing references) //IL_0318: Unknown result type (might be due to invalid IL or missing references) //IL_031d: Unknown result type (might be due to invalid IL or missing references) //IL_0328: Unknown result type (might be due to invalid IL or missing references) //IL_032f: Unknown result type (might be due to invalid IL or missing references) //IL_0334: Unknown result type (might be due to invalid IL or missing references) //IL_0342: Unknown result type (might be due to invalid IL or missing references) //IL_0347: Unknown result type (might be due to invalid IL or missing references) //IL_034c: Unknown result type (might be due to invalid IL or missing references) //IL_0355: Unknown result type (might be due to invalid IL or missing references) //IL_035c: Unknown result type (might be due to invalid IL or missing references) //IL_0361: Unknown result type (might be due to invalid IL or missing references) //IL_036f: Unknown result type (might be due to invalid IL or missing references) //IL_0374: Unknown result type (might be due to invalid IL or missing references) //IL_0379: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0195: 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_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) GameData data = GameMain.data; VectorLF3 relativePos = data.relativePos; Quaternion relativeRot = data.relativeRot; DysonSwarm val = null; if (data.dysonSpheres != null) { StarData val2 = null; ERenderPlace renderPlace = DysonSphere.renderPlace; switch ((int)renderPlace) { case 0: val2 = data.localStar; break; case 1: val2 = UIRoot.instance.uiGame.starmap.viewStarSystem; break; case 2: val2 = UIRoot.instance.uiGame.dysonEditor.selection.viewStar; break; } if (val2 != null) { val = data.dysonSpheres[val2.index]?.swarm; } } DysonSwarm swarm = _dysonSphere.swarm; SailBullet[] bulletPool = swarm.bulletPool; int orbitCursor = swarm.orbitCursor; SailOrbit[] orbits = swarm.orbits; StarData starData = swarm.starData; ref int randSeed = ref swarm.randSeed; (int startIndex, int workLength) workChunkIndices = UnOptimizedPlanetWorkChunk.GetWorkChunkIndices(swarm.bulletCursor, _maxWorkCount, _workIndex); int item = workChunkIndices.startIndex; int item2 = workChunkIndices.workLength; for (int i = Math.Max(1, item); i < item + item2; i++) { ref SailBullet reference = ref bulletPool[i]; if (reference.id != i) { continue; } reference.t += 1f / 60f; if (reference.t >= reference.maxt) { if (reference.state > 0) { if (reference.state < orbitCursor && orbits[reference.state].id == reference.state) { DysonSail val3 = default(DysonSail); VectorLF3 val4 = reference.uEnd - starData.uPosition; val3.px = (float)val4.x; val3.py = (float)val4.y; val3.pz = (float)val4.z; val4 = VectorLF3.op_Implicit(reference.uEndVel); val4 += SphericNormalThreadSafe(ref randSeed, 0.5); val3.vx = (float)val4.x; val3.vy = (float)val4.y; val3.vz = (float)val4.z; val3.gs = 1f; swarm.AddSolarSailList(ref val3, reference.state); } } else if (reference.t > reference.maxt + 0.7f) { swarm.RemoveBullet(i); } reference.state = 0; } if (val == swarm) { ERenderPlace renderPlace = DysonSphere.renderPlace; switch ((int)renderPlace) { case 0: reference.rBegin = VectorLF3.op_Implicit(Maths.QInvRotateLF(relativeRot, reference.uBegin - relativePos)); reference.rEnd = VectorLF3.op_Implicit(Maths.QInvRotateLF(relativeRot, reference.uEnd - relativePos)); break; case 1: reference.rBegin = VectorLF3.op_Implicit((reference.uBegin - UIStarmap.viewTargetStatic) * 0.00025); reference.rEnd = VectorLF3.op_Implicit((reference.uEnd - UIStarmap.viewTargetStatic) * 0.00025); break; case 2: reference.rBegin = VectorLF3.op_Implicit((reference.uBegin - starData.uPosition) * 0.00025); reference.rEnd = VectorLF3.op_Implicit((reference.uEnd - starData.uPosition) * 0.00025); break; default: Assert.CannotBeReached(); break; } } } } private void ParallelDysonRocketGameTick(long time) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_06e9: Unknown result type (might be due to invalid IL or missing references) //IL_06ed: Unknown result type (might be due to invalid IL or missing references) //IL_06f2: Unknown result type (might be due to invalid IL or missing references) //IL_06f7: Unknown result type (might be due to invalid IL or missing references) //IL_06f9: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_0786: Unknown result type (might be due to invalid IL or missing references) //IL_078d: Unknown result type (might be due to invalid IL or missing references) //IL_0792: Unknown result type (might be due to invalid IL or missing references) //IL_079c: Unknown result type (might be due to invalid IL or missing references) //IL_07a1: Unknown result type (might be due to invalid IL or missing references) //IL_07aa: Unknown result type (might be due to invalid IL or missing references) //IL_07b8: Unknown result type (might be due to invalid IL or missing references) //IL_07c2: Unknown result type (might be due to invalid IL or missing references) //IL_07c7: Unknown result type (might be due to invalid IL or missing references) //IL_0897: Unknown result type (might be due to invalid IL or missing references) //IL_089c: Unknown result type (might be due to invalid IL or missing references) //IL_089e: Unknown result type (might be due to invalid IL or missing references) //IL_08a5: Unknown result type (might be due to invalid IL or missing references) //IL_08aa: Unknown result type (might be due to invalid IL or missing references) //IL_08ed: Unknown result type (might be due to invalid IL or missing references) //IL_08f2: Unknown result type (might be due to invalid IL or missing references) //IL_08f9: Unknown result type (might be due to invalid IL or missing references) //IL_08fe: Unknown result type (might be due to invalid IL or missing references) //IL_0a66: Unknown result type (might be due to invalid IL or missing references) //IL_0a6d: Unknown result type (might be due to invalid IL or missing references) //IL_0a72: Unknown result type (might be due to invalid IL or missing references) //IL_0a7d: Unknown result type (might be due to invalid IL or missing references) //IL_0a82: Unknown result type (might be due to invalid IL or missing references) //IL_0a87: Unknown result type (might be due to invalid IL or missing references) //IL_0a8c: Unknown result type (might be due to invalid IL or missing references) //IL_0a8e: Unknown result type (might be due to invalid IL or missing references) //IL_0a93: Unknown result type (might be due to invalid IL or missing references) //IL_0935: Unknown result type (might be due to invalid IL or missing references) //IL_093a: Unknown result type (might be due to invalid IL or missing references) //IL_093c: Unknown result type (might be due to invalid IL or missing references) //IL_0941: Unknown result type (might be due to invalid IL or missing references) //IL_0943: Unknown result type (might be due to invalid IL or missing references) //IL_0922: Unknown result type (might be due to invalid IL or missing references) //IL_0911: Unknown result type (might be due to invalid IL or missing references) //IL_0916: Unknown result type (might be due to invalid IL or missing references) //IL_091b: Unknown result type (might be due to invalid IL or missing references) //IL_0427: Unknown result type (might be due to invalid IL or missing references) //IL_042c: Unknown result type (might be due to invalid IL or missing references) //IL_0aaa: Unknown result type (might be due to invalid IL or missing references) //IL_0ab1: Unknown result type (might be due to invalid IL or missing references) //IL_0ab6: Unknown result type (might be due to invalid IL or missing references) //IL_0abb: Unknown result type (might be due to invalid IL or missing references) //IL_0abd: Unknown result type (might be due to invalid IL or missing references) //IL_0924: Unknown result type (might be due to invalid IL or missing references) //IL_0ae0: Unknown result type (might be due to invalid IL or missing references) //IL_0ae7: Unknown result type (might be due to invalid IL or missing references) //IL_0aee: Unknown result type (might be due to invalid IL or missing references) //IL_0af3: Unknown result type (might be due to invalid IL or missing references) //IL_0b03: Unknown result type (might be due to invalid IL or missing references) //IL_0b08: Unknown result type (might be due to invalid IL or missing references) //IL_0b0d: Unknown result type (might be due to invalid IL or missing references) //IL_0b12: Unknown result type (might be due to invalid IL or missing references) //IL_0b1b: Unknown result type (might be due to invalid IL or missing references) //IL_0b22: Unknown result type (might be due to invalid IL or missing references) //IL_0b27: Unknown result type (might be due to invalid IL or missing references) //IL_0b2c: Unknown result type (might be due to invalid IL or missing references) //IL_0b31: Unknown result type (might be due to invalid IL or missing references) //IL_0477: Unknown result type (might be due to invalid IL or missing references) //IL_047e: Unknown result type (might be due to invalid IL or missing references) //IL_0483: Unknown result type (might be due to invalid IL or missing references) //IL_048a: Unknown result type (might be due to invalid IL or missing references) //IL_048f: Unknown result type (might be due to invalid IL or missing references) //IL_049d: Unknown result type (might be due to invalid IL or missing references) //IL_04a2: Unknown result type (might be due to invalid IL or missing references) //IL_04a7: Unknown result type (might be due to invalid IL or missing references) //IL_09c4: Unknown result type (might be due to invalid IL or missing references) //IL_09c9: Unknown result type (might be due to invalid IL or missing references) //IL_09cb: Unknown result type (might be due to invalid IL or missing references) //IL_09d0: Unknown result type (might be due to invalid IL or missing references) //IL_09d2: Unknown result type (might be due to invalid IL or missing references) //IL_0a15: Unknown result type (might be due to invalid IL or missing references) //IL_0a1a: Unknown result type (might be due to invalid IL or missing references) //IL_0a21: Unknown result type (might be due to invalid IL or missing references) //IL_0a26: Unknown result type (might be due to invalid IL or missing references) //IL_0a4a: Unknown result type (might be due to invalid IL or missing references) //IL_0a39: Unknown result type (might be due to invalid IL or missing references) //IL_0a3e: Unknown result type (might be due to invalid IL or missing references) //IL_0a43: Unknown result type (might be due to invalid IL or missing references) //IL_032c: Unknown result type (might be due to invalid IL or missing references) //IL_033a: Unknown result type (might be due to invalid IL or missing references) //IL_033f: Unknown result type (might be due to invalid IL or missing references) //IL_0344: Unknown result type (might be due to invalid IL or missing references) //IL_0346: Unknown result type (might be due to invalid IL or missing references) //IL_034d: Unknown result type (might be due to invalid IL or missing references) //IL_0355: Unknown result type (might be due to invalid IL or missing references) //IL_035c: Unknown result type (might be due to invalid IL or missing references) //IL_0365: Unknown result type (might be due to invalid IL or missing references) //IL_036c: Unknown result type (might be due to invalid IL or missing references) //IL_038d: Unknown result type (might be due to invalid IL or missing references) //IL_03a2: Unknown result type (might be due to invalid IL or missing references) //IL_03b8: Unknown result type (might be due to invalid IL or missing references) //IL_063c: Unknown result type (might be due to invalid IL or missing references) //IL_0643: Unknown result type (might be due to invalid IL or missing references) //IL_0648: Unknown result type (might be due to invalid IL or missing references) //IL_064a: Unknown result type (might be due to invalid IL or missing references) //IL_064f: Unknown result type (might be due to invalid IL or missing references) //IL_0656: Unknown result type (might be due to invalid IL or missing references) //IL_065b: Unknown result type (might be due to invalid IL or missing references) //IL_065f: Unknown result type (might be due to invalid IL or missing references) //IL_0664: Unknown result type (might be due to invalid IL or missing references) //IL_0a4c: Unknown result type (might be due to invalid IL or missing references) //IL_06ae: Unknown result type (might be due to invalid IL or missing references) //IL_06b3: Unknown result type (might be due to invalid IL or missing references) //IL_06b8: Unknown result type (might be due to invalid IL or missing references) //IL_0690: Unknown result type (might be due to invalid IL or missing references) //IL_0697: Unknown result type (might be due to invalid IL or missing references) //IL_069c: Unknown result type (might be due to invalid IL or missing references) //IL_06a3: Unknown result type (might be due to invalid IL or missing references) //IL_06a8: Unknown result type (might be due to invalid IL or missing references) //IL_06be: Unknown result type (might be due to invalid IL or missing references) //IL_06c3: Unknown result type (might be due to invalid IL or missing references) //IL_06ca: Unknown result type (might be due to invalid IL or missing references) //IL_06cf: Unknown result type (might be due to invalid IL or missing references) //IL_05b5: Unknown result type (might be due to invalid IL or missing references) //IL_05bc: Unknown result type (might be due to invalid IL or missing references) //IL_05ca: Unknown result type (might be due to invalid IL or missing references) //IL_05cf: Unknown result type (might be due to invalid IL or missing references) GameLogic logic = GameMain.logic; DysonSphere dysonSphere = _dysonSphere; DysonRocket[] rocketPool = dysonSphere.rocketPool; DysonSphereLayer[] layersIdBased = dysonSphere.layersIdBased; StarData starData = dysonSphere.starData; AstroData[] astrosData = starData.galaxy.astrosData; float num = 7.5f; float num2 = Mathf.Max(1f, (float)Math.Pow((double)dysonSphere.defOrbitRadius / 40000.0 * 4.0, 0.4)); float num3 = 18f * num2; float num4 = 2800f * num2; VectorLF3 uPosition = starData.uPosition; (int startIndex, int workLength) workChunkIndices = UnOptimizedPlanetWorkChunk.GetWorkChunkIndices(dysonSphere.rocketCursor, _maxWorkCount, _workIndex); int item = workChunkIndices.startIndex; int item2 = workChunkIndices.workLength; VectorLF3 val2 = default(VectorLF3); VectorLF3 val8 = default(VectorLF3); VectorLF3 val9 = default(VectorLF3); VectorLF3 val10 = default(VectorLF3); Quaternion val12 = default(Quaternion); Quaternion val13 = default(Quaternion); VectorLF3 val14 = default(VectorLF3); Quaternion val16 = default(Quaternion); Quaternion val17 = default(Quaternion); for (int i = Math.Max(1, item); i < item + item2; i++) { ref DysonRocket reference = ref rocketPool[i]; if (reference.id != i) { continue; } if (reference.node == null) { dysonSphere.RemoveDysonRocket(i); continue; } bool flag = false; DysonSphereLayer val = layersIdBased[reference.node.layerId]; ref AstroData reference2 = ref astrosData[reference.planetId]; VectorLF3 vectorLF = reference.uPos - reference2.uPos; double num5 = VectorLength(vectorLF) - (double)reference2.uRadius; if (reference.t <= 0f) { if (num5 < 200.0) { float num6 = (float)num5 / 200f; if (num6 < 0f) { num6 = 0f; } float num7 = num6 * num6 * 600f + 15f; reference.uSpeed = reference.uSpeed * 0.9f + num7 * 0.1f; reference.t = (num6 - 1f) * 1.2f; if (reference.t < -1f) { reference.t = -1f; } } else { val.NodeEnterUPos(reference.node, ref val2); VectorLF3 vectorLF2 = val2 - reference.uPos; double num8 = VectorLength(vectorLF2); if (num8 < 50.0) { reference.t = 0.0001f; } else { reference.t = 0f; } double num9 = num8 / ((double)reference.uSpeed + 0.1) * 0.382; double num10 = num8 / (double)num4; float num11 = (float)((double)reference.uSpeed * num9) + 150f; if (num11 > num4) { num11 = num4; } if (reference.uSpeed < num11 - num) { reference.uSpeed += num; } else if (reference.uSpeed > num11 + num3) { reference.uSpeed -= num3; } else { reference.uSpeed = num11; } int num12 = -1; double num13 = 0.0; double num14 = 1E+40; int num15 = reference.planetId / 100 * 100; for (int j = num15; j < num15 + 10; j++) { float uRadius = astrosData[j].uRadius; if (!(uRadius < 1f) && j != reference.planetId) { float num16 = ((j == num15) ? (val.orbitRadius + 8000f) : (uRadius + 6500f)); VectorLF3 val3 = reference.uPos - astrosData[j].uPos; double num17 = val3.x * val3.x + val3.y * val3.y + val3.z * val3.z; double num18 = 0.0 - ((double)reference.uVel.x * val3.x + (double)reference.uVel.y * val3.y + (double)reference.uVel.z * val3.z); if ((num18 > 0.0 || num17 < (double)(uRadius * uRadius * 7f)) && num17 < num14 && num17 < (double)(num16 * num16)) { num13 = ((num18 < 0.0) ? 0.0 : num18); num12 = j; num14 = num17; } } } VectorLF3 val4 = VectorLF3.zero; float num19 = 0f; if (num12 > 0) { float num20 = astrosData[num12].uRadius; bool flag2 = num12 % 100 == 0; if (flag2) { num20 = val.orbitRadius - 400f; } double num21 = 1.25; VectorLF3 val5 = reference.uPos + VectorLF3.op_Implicit(reference.uVel) * num13 - astrosData[num12].uPos; double num22 = ((VectorLF3)(ref val5)).magnitude / (double)num20; if (num22 < num21) { double num23 = Math.Sqrt(num14) - (double)num20 * 0.82; if (num23 < 1.0) { num23 = 1.0; } double num24 = (num22 - 1.0) / (num21 - 1.0); if (num24 < 0.0) { num24 = 0.0; } num24 = 1.0 - num24 * num24; double num25 = (double)(reference.uSpeed - 6f) / num23 * 2.5 - 0.01; if (num25 > 1.5) { num25 = 1.5; } else if (num25 < 0.0) { num25 = 0.0; } num25 = num25 * num25 * num24; num19 = (float)(flag2 ? 0.0 : (num25 * 0.5)); val4 = ((VectorLF3)(ref val5)).normalized * num25 * 2.0; } } int num26 = ((num12 > 0 || num5 < 2000.0 || num8 < 2000.0) ? 1 : 6); if (num26 == 1 || (time + i) % num26 == 0L) { float num27 = 1f / (float)num10 - 0.05f; num27 += num19; float num28 = Mathf.Lerp(0.005f, 0.08f, num27) * (float)num26; Vector3 val6 = Vector3.Slerp(reference.uVel, VectorLF3.op_Implicit(((VectorLF3)(ref vectorLF2)).normalized + val4), num28); reference.uVel = ((Vector3)(ref val6)).normalized; Quaternion val7; if (num8 < 350.0) { float num29 = ((float)num8 - 50f) / 300f; val7 = Quaternion.Slerp(val.NodeURot(reference.node), Quaternion.LookRotation(reference.uVel), num29); } else { val7 = Quaternion.LookRotation(reference.uVel); } reference.uRot = Quaternion.Slerp(reference.uRot, val7, 0.2f); } } } else { val.NodeSlotUPos(reference.node, ref val8); VectorLF3 vectorLF3 = val8 - reference.uPos; double num30 = VectorLength(vectorLF3); if (num30 < 2.0) { flag = true; } float num31 = (float)(num30 * 0.75 + 15.0); if (num31 > num4) { num31 = num4; } if (reference.uSpeed < num31 - num) { reference.uSpeed += num; } else if (reference.uSpeed > num31 + num3) { reference.uSpeed -= num3; } else { reference.uSpeed = num31; } if ((time + i) % 2 == 0L) { reference.uVel = Vector3.Slerp(reference.uVel, VectorLF3.op_Implicit(((VectorLF3)(ref vectorLF3)).normalized), 0.15f); reference.uRot = Quaternion.Slerp(reference.uRot, val.NodeURot(reference.node), 0.2f); } reference.t = (350f - (float)num30) / 330f; if (reference.t > 1f) { reference.t = 1f; } else if (reference.t < 0.0001f) { reference.t = 0.0001f; } } ((VectorLF3)(ref val9))..ctor(0f, 0f, 0f); bool flag3 = false; double num32 = 2f - (float)num5 / 200f; if (num32 > 1.0) { num32 = 1.0; } else if (num32 < 0.0) { num32 = 0.0; } if (num32 > 0.0) { Maths.QInvRotateLF_refout(ref reference2.uRot, ref vectorLF, ref val10); VectorLF3 val11 = Maths.QRotateLF(reference2.uRotNext, val10) + reference2.uPosNext; Maths.QInvMultiply_ref(ref reference2.uRot, ref reference.uRot, ref val12); Maths.QMultiply_ref(ref reference2.uRotNext, ref val12, ref val13); num32 = (3.0 - num32 - num32) * num32 * num32; val9 = (val11 - reference.uPos) * num32; reference.uRot = ((num32 == 1.0) ? val13 : Quaternion.Slerp(reference.uRot, val13, (float)num32)); flag3 = true; } if (!flag3) { VectorLF3 vectorLF4 = reference.uPos - uPosition; double num33 = Math.Abs(VectorLength(vectorLF4) - (double)val.orbitRadius); double num34 = 1.5 - (double)((float)num33 / 1800f); if (num34 > 1.0) { num34 = 1.0; } else if (num34 < 0.0) { num34 = 0.0; } if (num34 > 0.0) { Maths.QInvRotateLF_refout(ref val.currentRotation, ref vectorLF4, ref val14); VectorLF3 val15 = Maths.QRotateLF(val.nextRotation, val14) + uPosition; Maths.QInvMultiply_ref(ref val.currentRotation, ref reference.uRot, ref val16); Maths.QMultiply_ref(ref val.nextRotation, ref val16, ref val17); num34 = (3.0 - num34 - num34) * num34 * num34; val9 = (val15 - reference.uPos) * num34; reference.uRot = ((num34 == 1.0) ? val17 : Quaternion.Slerp(reference.uRot, val17, (float)num34)); } } double num35 = (double)reference.uSpeed * logic.deltaTime_lf; reference.uPos = reference.uPos + VectorLF3.op_Implicit(reference.uVel) * new VectorLF3(num35, num35, num35) + val9; if (num5 < 250.0) { vectorLF = reference2.uPos - reference.uPos; num5 = VectorLength(vectorLF) - (double)reference2.uRadius; if (num5 < 180.0) { reference.uPos = reference2.uPos + Maths.QRotateLF(reference2.uRot, VectorLF3.op_Implicit(reference.launch) * ((double)reference2.uRadius + num5)); reference.uRot = reference2.uRot * Quaternion.LookRotation(reference.launch); } } if (flag) { dysonSphere.ConstructSp(reference.node); dysonSphere.RemoveDysonRocket(i); } } } private static double VectorLength(VectorLF3 vectorLF) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) return Math.Sqrt(vectorLF.x * vectorLF.x + vectorLF.y * vectorLF.y + vectorLF.z * vectorLF.z); } private static VectorLF3 SphericNormalThreadSafe(ref int seed, double scale) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) int num = Interlocked.Increment(ref seed); if (num == 65535) { Interlocked.Exchange(ref seed, 0); } num &= 0xFFFF; return new VectorLF3(RandomTable.sphericNormal[num].x * scale, RandomTable.sphericNormal[num].y * scale, RandomTable.sphericNormal[num].z * scale); } } internal sealed class DysonSpherePowerRequest : IWorkChunk { private readonly OptimizedTerrestrialPlanet _optimizedPlanet; public DysonSpherePowerRequest(OptimizedTerrestrialPlanet optimizedPlanet) { _optimizedPlanet = optimizedPlanet; } public void Execute(int workerIndex, object singleThreadedCodeLock, PlanetData localPlanet, long time, Vector3 playerPosition) { _optimizedPlanet.RequestDysonSpherePower(workerIndex); } } internal sealed class EnemyGroundCombatWorkChunk : IWorkChunk { private readonly PlanetFactory _planet; private readonly int _workIndex; private readonly int _maxWorkCount; public EnemyGroundCombatWorkChunk(PlanetFactory planet, int workIndex, int maxWorkCount) { _planet = planet; _workIndex = workIndex; _maxWorkCount = maxWorkCount; } public void Execute(int workerIndex, object singleThreadedCodeLock, PlanetData localPlanet, long time, Vector3 playerPosition) { EnemyDFGroundSystem enemySystem = _planet.enemySystem; DeepProfiler.BeginSample((DPEntry)64, workerIndex, -1L); if (enemySystem.turrets.count > 0) { DeepProfiler.BeginSample((DPEntry)66, workerIndex, -1L); EnemyGroundTurretGameTick(workerIndex, time); DeepProfiler.EndSample((DPEntry)66, workerIndex); } if (enemySystem.units.count > 0) { DeepProfiler.BeginSample((DPEntry)67, workerIndex, -1L); EnemyGroundUnitGameTick(workerIndex, time); DeepProfiler.EndSample((DPEntry)67, workerIndex); } DeepProfiler.EndSample((DPEntry)64, workerIndex); } public static int GetParallelCount(PlanetFactory planet, int maxParallelism) { EnemyDFGroundSystem enemySystem = planet.enemySystem; if (enemySystem.turrets.count == 0 && enemySystem.units.count == 0) { return 0; } return Math.Min((Math.Max(enemySystem.turrets.cursor - 1, enemySystem.units.cursor - 1) + 99) / 100, maxParallelism); } private void EnemyGroundTurretGameTick(int workerIndex, long time) { //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_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Expected I4, but got Unknown //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Expected I4, but got Unknown //IL_0288: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Invalid comparison between Unknown and I4 EAggressiveLevel aggressiveLevel = GameMain.logic.aggressiveLevel; EnemyData[] enemyPool = _planet.enemyPool; AnimData[] enemyAnimPool = _planet.enemyAnimPool; bool isLocalLoaded = _planet.enemySystem.isLocalLoaded; ObjectPool bases = _planet.enemySystem.bases; DataPool builders = _planet.enemySystem.builders; DataPool turrets = _planet.enemySystem.turrets; (int startIndex, int workLength) workChunkIndices = UnOptimizedPlanetWorkChunk.GetWorkChunkIndices(turrets.cursor, _maxWorkCount, _workIndex); int item = workChunkIndices.startIndex; int item2 = workChunkIndices.workLength; for (int i = Math.Max(1, item); i < item + item2; i++) { ref DFGTurretComponent reference = ref turrets.buffer[i]; if (reference.id != i) { continue; } int enemyId = reference.enemyId; ref EnemyData reference2 = ref enemyPool[enemyId]; PrefabDesc val = SpaceSector.PrefabDescByModelIndex[reference2.modelIndex]; ((DFGTurretComponent)(ref reference)).InternalUpdate(val); EDFTurretState state = reference.state; switch ((int)state) { case 0: ((DFGTurretComponent)(ref reference)).NoneState(); break; case 1: if (((DFGTurretComponent)(ref reference)).DetermineSearchTarget(time)) { ((DFGTurretComponent)(ref reference)).SearchTarget(_planet, bases.buffer[reference.baseId], aggressiveLevel, workerIndex); } break; case 2: if (reference.target.id == 0) { reference.state = (EDFTurretState)1; } ((DFGTurretComponent)(ref reference)).Aim(_planet, bases.buffer[reference.baseId], builders.buffer, aggressiveLevel, workerIndex); break; } if (isLocalLoaded && builders.buffer[reference.builderId].state > 0) { enemyAnimPool[enemyId].prepare_length = reference.localDir.x; enemyAnimPool[enemyId].working_length = reference.localDir.y; enemyAnimPool[enemyId].power = reference.localDir.z; enemyAnimPool[enemyId].state = (uint)(int)reference.state; int dfTurretAttackInterval = val.dfTurretAttackInterval; float num = (float)(-reference.fire) / (float)dfTurretAttackInterval; if (num < -1f) { num = -1f; } float num2 = 2f; if (reference.heat < 0) { num2 = (float)reference.heat / 3600f + 1f; num2 = ((num2 > 1f) ? 1f : ((num2 < 0f) ? 0f : num2)); } else if (reference.heat > 0) { num2 = 0f; } float num3 = 0f; if ((int)reference.state == 2 && num >= 0f) { float x = reference.localDir.x; float y = reference.localDir.y; float z = reference.localDir.z; float num4 = Mathf.Sqrt(x * x + y * y + z * z); num3 = (reference.sensorRange - num4) / (reference.sensorRange - reference.attackRange); num3 = ((num3 < 0f) ? 0f : ((num3 >= 1f) ? 1f : num3)); } if (num >= 0f) { num += ((!(num2 < 2f)) ? num3 : ((num2 > num3) ? num3 : num2)); } enemyAnimPool[enemyId].time = num + 10f; } } } private void EnemyGroundUnitGameTick(int workerIndex, long time) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Invalid comparison between Unknown and I4 //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Invalid comparison between Unknown and I4 //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Invalid comparison between Unknown and I4 //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Invalid comparison between Unknown and I4 //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Invalid comparison between Unknown and I4 //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Invalid comparison between Unknown and I4 //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: 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_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Invalid comparison between Unknown and I4 //IL_030d: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_0314: Unknown result type (might be due to invalid IL or missing references) //IL_0343: Expected I4, but got Unknown //IL_042c: Unknown result type (might be due to invalid IL or missing references) //IL_0432: Invalid comparison between Unknown and I4 //IL_03a0: Unknown result type (might be due to invalid IL or missing references) //IL_03a6: Invalid comparison between Unknown and I4 //IL_05a0: Unknown result type (might be due to invalid IL or missing references) //IL_05a6: Invalid comparison between Unknown and I4 //IL_044a: Unknown result type (might be due to invalid IL or missing references) //IL_045e: Unknown result type (might be due to invalid IL or missing references) //IL_0474: Unknown result type (might be due to invalid IL or missing references) //IL_04d3: Unknown result type (might be due to invalid IL or missing references) //IL_04d8: Unknown result type (might be due to invalid IL or missing references) //IL_04dd: Unknown result type (might be due to invalid IL or missing references) //IL_053f: Unknown result type (might be due to invalid IL or missing references) //IL_0546: Invalid comparison between Unknown and I4 //IL_0524: Unknown result type (might be due to invalid IL or missing references) //IL_0529: Unknown result type (might be due to invalid IL or missing references) //IL_052e: Unknown result type (might be due to invalid IL or missing references) //IL_0581: Unknown result type (might be due to invalid IL or missing references) //IL_0586: Unknown result type (might be due to invalid IL or missing references) //IL_058b: Unknown result type (might be due to invalid IL or missing references) GameLogic logic = GameMain.logic; SkillSystem skillSystem = logic.sector.skillSystem; EAggressiveLevel aggressiveLevel = logic.aggressiveLevel; float num = 0.75f; int num2 = 5; int maxHatredGroundTmp = skillSystem.maxHatredGroundTmp; int maxHatredGroundBaseTmp = skillSystem.maxHatredGroundBaseTmp; if ((int)aggressiveLevel <= 15) { if ((int)aggressiveLevel != 0) { if ((int)aggressiveLevel == 10 || (int)aggressiveLevel == 15) { num = 0.6f; num2 = 6; } } else { num = 0f; num2 = 0; } } else if ((int)aggressiveLevel != 20) { if ((int)aggressiveLevel != 30) { if ((int)aggressiveLevel == 40) { num = 0.93f; num2 = 1; } } else { num = 0.86f; num2 = 3; } } else { num = 0.75f; num2 = 5; } VectorLF3 playerSkillTargetU = skillSystem.playerSkillTargetU; int num3 = (int)(time % 60); DataPool units = _planet.enemySystem.units; ObjectPool bases = _planet.enemySystem.bases; EnemyData[] enemyPool = _planet.enemyPool; bool flag = _planet.enemySystem.isLocalLoaded; ObjectRenderer[] array = (flag ? _planet.planet.factoryModel.gpuiManager.objectRenderers : null); VectorLF3 val = Maths.QInvRotateLF(_planet.planet.runtimeRotation, playerSkillTargetU - _planet.planet.uPosition); if (array == null) { flag = false; } else { _planet.planet.factoryModel.enemyUnitsDirty = true; } int num4 = (int)((_planet.planet.seed + time) % 151200); float realRadius = _planet.planet.realRadius; (int startIndex, int workLength) workChunkIndices = UnOptimizedPlanetWorkChunk.GetWorkChunkIndices(units.cursor, _maxWorkCount, _workIndex); int item = workChunkIndices.startIndex; int item2 = workChunkIndices.workLength; for (int i = Math.Max(1, item); i < item + item2; i++) { ref EnemyUnitComponent reference = ref units.buffer[i]; if (reference.id != i) { continue; } ref EnemyData reference2 = ref enemyPool[reference.enemyId]; DFGBaseComponent val2 = bases[(int)reference2.owner]; if (val2 != null) { Interlocked.Increment(ref val2.currentActivatedUnitCount); } PrefabDesc val3 = SpaceSector.PrefabDescByModelIndex[reference2.modelIndex]; if (i % 60 == num3) { ((SimpleLock)(ref reference.hatredLock)).Enter(); ((HatredList)(ref reference.hatred)).Fade(num, num2); ((SimpleLock)(ref reference.hatredLock)).Exit(); ((EnemyUnitComponent)(ref reference)).SensorLogic_Ground(ref reference2, _planet, maxHatredGroundTmp, aggressiveLevel, workerIndex); reference2.hashAddress = _planet.hashSystemDynamic.UpdateObjectHashAddress(reference2.hashAddress, reference2.id, VectorLF3.op_Implicit(reference2.pos), (EObjectType)4); if ((int)aggressiveLevel > 0 && ((EnemyData)(ref reference2)).willBroadcast) { ((EnemyData)(ref reference2)).willBroadcast = false; if (reference.hatred.max.value > 80 && reference.hatred.max.target > 0) { ((EnemyUnitComponent)(ref reference)).BroadcastHatred(_planet, units.buffer, ref reference2, true, maxHatredGroundTmp, maxHatredGroundBaseTmp, workerIndex); } } } int num5 = (int)((1f - reference.disturbValue) * 11f + 0.5f); if (time * 7 % 11 < num5) { ((EnemyUnitComponent)(ref reference)).UpdateFireCondition(val3); } EEnemyBehavior behavior = reference.behavior; switch ((int)behavior) { case 0: ((EnemyUnitComponent)(ref reference)).RunBehavior_None(ref reference2); break; case 1: ((EnemyUnitComponent)(ref reference)).RunBehavior_Initial(ref reference2); break; case 2: ((EnemyUnitComponent)(ref reference)).ReclaimThreatCarry(_planet.enemySystem); ((EnemyUnitComponent)(ref reference)).RunBehavior_KeepForm(num4, enemyPool, bases.buffer, realRadius, ref reference2); if (reference2.combatStatId == 0 && reference.stateTick == 0 && (int)reference.behavior == 2) { _planet.enemySystem.DeactivateUnitDeferred(i); } break; case 3: ((EnemyUnitComponent)(ref reference)).RunBehavior_SeekForm_Ground(num4, enemyPool, bases.buffer, realRadius, ref reference2); break; case 4: ((EnemyUnitComponent)(ref reference)).RunBehavior_SeekTarget_Ground(_planet, ref reference2); break; case 7: ((EnemyUnitComponent)(ref reference)).RunBehavior_Defense_Ground(num4, skillSystem, enemyPool, bases.buffer, realRadius, ref reference2); break; case 9: ((EnemyUnitComponent)(ref reference)).RunBehavior_Engage_Ground(_planet, ref reference2); break; } if (i % 60 == num3) { ((EnemyUnitComponent)(ref reference)).UndergroundRescue(_planet.planet, ref reference2); } if ((int)reference.behavior >= 4) { if (val2 != null) { double num6 = reference2.pos.x - val.x; double num7 = reference2.pos.y - val.y; double num8 = reference2.pos.z - val.z; double num9 = num6 * num6 + num7 * num7 + num8 * num8; ((SimpleLock)(ref val2.incomingUnitStatLock)).Enter(); val2.currentIncomingAttackingUnitCount++; if (num9 < val2.currentClosetIncomingAttackingUnitDist2 || val2.currentClosetIncomingAttackingUnitDist2 == 0.0) { val2.currentClosetIncomingAttackingUnitDist2 = num9; val2.currentIncomingAttackingUnitPos = VectorLF3.op_Implicit(reference2.pos); } if (((EnemyData)(ref reference2)).isAssaultingUnit) { val2.currentIncomingAssaultingUnitCount++; if (num9 < val2.currentClosetIncomingAssaultingUnitDist2 || val2.currentClosetIncomingAssaultingUnitDist2 == 0.0) { val2.currentClosetIncomingAssaultingUnitDist2 = num9; val2.currentIncomingAssaultingUnitPos = VectorLF3.op_Implicit(reference2.pos); } } if ((int)((HatredTarget)(ref reference.hatred.max)).targetType == 15) { val2.currentIncomingAttackingPlayerUnitCount++; if (num9 < val2.currentClosetIncomingAttackingPlayerUnitDist2 || val2.currentClosetIncomingAttackingPlayerUnitDist2 == 0.0) { val2.currentClosetIncomingAttackingPlayerUnitDist2 = num9; val2.currentIncomingAttackingPlayerUnitPos = VectorLF3.op_Implicit(reference2.pos); } } ((SimpleLock)(ref val2.incomingUnitStatLock)).Exit(); } } else if ((int)reference.behavior <= 2 && val2 != null) { Interlocked.Increment(ref val2.currentReadyUnitCount); if (reference2.protoId == 8128) { Interlocked.Increment(ref val2.currentReadyRaiderCount); } else if (reference2.protoId == 8129) { Interlocked.Increment(ref val2.currentReadyRangerCount); } } float num10 = 1.25f - reference.disturbValue; if (num10 < 0.1f) { num10 = 0.1f; } reference.disturbValue -= num10 / 120f; if (reference.disturbValue < 0f) { reference.disturbValue = 0f; } if (flag) { ObjectRenderer obj = array[reference2.modelIndex]; DynamicRenderer val4 = (DynamicRenderer)(object)((obj is DynamicRenderer) ? obj : null); if (val4 != null) { ref GPUOBJECT reference3 = ref ((ObjectRenderer)val4).instPool[reference2.modelId]; reference3.posx = (float)reference2.pos.x; reference3.posy = (float)reference2.pos.y; reference3.posz = (float)reference2.pos.z; reference3.rotx = reference2.rot.x; reference3.roty = reference2.rot.y; reference3.rotz = reference2.rot.z; reference3.rotw = reference2.rot.w; ref Vector4 reference4 = ref val4.extraPool[reference2.modelId]; reference4.x = reference.anim; reference4.y = reference.disturbValue; reference4.z = reference.steering; reference4.w = reference.speed; } } } } } internal sealed class EntirePlanet : IWorkChunk { private readonly PlanetWidePower _planetWidePower; private readonly SubFactoryGameTick _subFactory; private readonly PostSubFactoryStep _postSubFactoryStep; public EntirePlanet(OptimizedTerrestrialPlanet optimizedPlanet, OptimizedSubFactory subFactory, SubFactoryPowerConsumption subFactoryPowerConsumption) { _planetWidePower = new PlanetWidePower(optimizedPlanet); _subFactory = new SubFactoryGameTick(subFactory, subFactoryPowerConsumption); _postSubFactoryStep = new PostSubFactoryStep(optimizedPlanet); } public void Execute(int workerIndex, object singleThreadedCodeLock, PlanetData localPlanet, long time, Vector3 playerPosition) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) _planetWidePower.Execute(workerIndex, singleThreadedCodeLock, localPlanet, time, playerPosition); _subFactory.Execute(workerIndex, singleThreadedCodeLock, localPlanet, time, playerPosition); _postSubFactoryStep.Execute(workerIndex, singleThreadedCodeLock, localPlanet, time, playerPosition); } } internal interface IWorkChunk { void Execute(int workerIndex, object singleThreadedCodeLock, PlanetData localPlanet, long time, Vector3 playerPosition); } internal sealed class PlanetWideDigitalSystem : IWorkChunk { private readonly OptimizedTerrestrialPlanet _optimizedPlanet; public PlanetWideDigitalSystem(OptimizedTerrestrialPlanet optimizedPlanet) { _optimizedPlanet = optimizedPlanet; } public void Execute(int workerIndex, object singleThreadedCodeLock, PlanetData localPlanet, long time, Vector3 playerPosition) { _optimizedPlanet.DigitalSystemStep(workerIndex); } } internal sealed class PlanetWidePower : IWorkChunk { private readonly OptimizedTerrestrialPlanet _optimizedPlanet; public PlanetWidePower(OptimizedTerrestrialPlanet optimizedPlanet) { _optimizedPlanet = optimizedPlanet; } public void Execute(int workerIndex, object singleThreadedCodeLock, PlanetData localPlanet, long time, Vector3 playerPosition) { DeepProfiler.BeginSample((DPEntry)15, workerIndex, -1L); _optimizedPlanet.BeforePowerStep(time); DeepProfiler.EndSample((DPEntry)15, workerIndex); DeepProfiler.BeginSample((DPEntry)12, workerIndex, -1L); _optimizedPlanet.PowerStep(time, workerIndex); DeepProfiler.EndSample((DPEntry)12, workerIndex); } } internal sealed class PlanetWideTransport : IWorkChunk { private readonly IOptimizedPlanet _optimizedPlanet; public PlanetWideTransport(IOptimizedPlanet optimizedPlanet) { _optimizedPlanet = optimizedPlanet; } public void Execute(int workerIndex, object singleThreadedCodeLock, PlanetData localPlanet, long time, Vector3 playerPosition) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) _optimizedPlanet.TransportGameTick(workerIndex, time, playerPosition); } } internal sealed class PrePlanetFactorySteps : IWorkChunk { private readonly GameLogic _gameLogic; private readonly PlanetFactory _planet; public PrePlanetFactorySteps(GameLogic gameLogic, PlanetFactory planet) { _gameLogic = gameLogic; _planet = planet; } public void Execute(int workerIndex, object singleThreadedCodeLock, PlanetData localPlanet, long time, Vector3 playerPosition) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) if (time > 0 && _gameLogic.isCombatMode) { DeepProfiler.BeginSample((DPEntry)64, workerIndex, -1L); DeepProfiler.BeginSample((DPEntry)65, workerIndex, -1L); _planet.enemySystem.GameTickLogic_Prepare(); _planet.enemySystem.GameTickLogic_Base(_gameLogic.aggressiveLevel); DeepProfiler.EndSample((DPEntry)65, workerIndex); DeepProfiler.EndSample((DPEntry)64, workerIndex); } if (_planet.constructionSystem != null && _planet.planet != localPlanet) { DeepProfiler.BeginSample((DPEntry)34, workerIndex, -1L); bool flag = _planet == localPlanet?.factory; _planet.constructionSystem.GameTick(time, flag, false); _planet.constructionSystem.ExcuteDeferredTargetChange(); DeepProfiler.EndSample((DPEntry)34, workerIndex); } } } internal sealed class SolarSystemDysonSphereWorkChunk : IWorkChunk { private readonly DysonSphere _dysonSphere; public SolarSystemDysonSphereWorkChunk(DysonSphere dysonSphere) { _dysonSphere = dysonSphere; } public void Execute(int workerIndex, object singleThreadedCodeLock, PlanetData localPlanet, long time, Vector3 playerPosition) { DeepProfiler.BeginSample((DPEntry)53, workerIndex, -1L); _dysonSphere.BeforeGameTick(time); DeepProfiler.EndSample((DPEntry)53, workerIndex); } } internal sealed class SubFactoryGameTick : IWorkChunk { private readonly OptimizedSubFactory _subFactory; private readonly SubFactoryPowerConsumption _subFactoryPowerConsumption; public SubFactoryGameTick(OptimizedSubFactory subFactory, SubFactoryPowerConsumption subFactoryPowerConsumption) { _subFactory = subFactory; _subFactoryPowerConsumption = subFactoryPowerConsumption; } public void Execute(int workerIndex, object singleThreadedCodeLock, PlanetData localPlanet, long time, Vector3 playerPosition) { _subFactory.GameTick(workerIndex, time, _subFactoryPowerConsumption); } } internal struct UnOptimizedWorkChunkCounts : IEquatable { private readonly PlanetFactory _planet; private int _beforePowerWorkWorkChunkCount; private int _powerNetworkWorkChunkCount; private int _minerWorkChunkCount; private int _assemblerWorkChunkCount; private int _fractionatorWorkChunkCount; private int _ejectorWorkChunkCount; private int _siloWorkChunkCount; private int _producingLabWorkChunkCount; private int _researchingLabWorkChunkCount; private int _labWorkChunkCount; private int _transportEntitiesWorkChunkCount; private int _stationWorkChunkCount; private int _inserterWorkWorkChunkCount; private int _storageAndTankWorkChunkCount; private int _cargoPathsWorkWorkChunkCount; private int _splitterWorkChunkCount; private int _cargoTrafficMiscWorkChunkCount; private int _sandboxModeWorkWorkChunkCount; private int _cargoPathPresentWorkChunkCount; private int _markerWorkChunkCount; public UnOptimizedWorkChunkCounts(PlanetFactory planet) { _beforePowerWorkWorkChunkCount = 0; _powerNetworkWorkChunkCount = 0; _minerWorkChunkCount = 0; _assemblerWorkChunkCount = 0; _fractionatorWorkChunkCount = 0; _ejectorWorkChunkCount = 0; _siloWorkChunkCount = 0; _producingLabWorkChunkCount = 0; _researchingLabWorkChunkCount = 0; _labWorkChunkCount = 0; _transportEntitiesWorkChunkCount = 0; _stationWorkChunkCount = 0; _inserterWorkWorkChunkCount = 0; _storageAndTankWorkChunkCount = 0; _cargoPathsWorkWorkChunkCount = 0; _splitterWorkChunkCount = 0; _cargoTrafficMiscWorkChunkCount = 0; _sandboxModeWorkWorkChunkCount = 0; _cargoPathPresentWorkChunkCount = 0; _markerWorkChunkCount = 0; _planet = planet; } public static UnOptimizedWorkChunkCounts ComputeWorkChunkCounts(PlanetFactory planet, int maxParallelism) { UnOptimizedWorkChunkCounts result = new UnOptimizedWorkChunkCounts(planet); int num = planet.factorySystem.minerCursor - 1; int num2 = planet.factorySystem.assemblerCursor - 1; int num3 = planet.factorySystem.fractionatorCursor - 1; int num4 = planet.factorySystem.ejectorCursor - 1; int num5 = planet.factorySystem.siloCursor - 1; int num6 = planet.cargoTraffic.monitorCursor - 1; int num7 = planet.cargoTraffic.spraycoaterCursor - 1; int num8 = planet.cargoTraffic.pilerCursor - 1; int num9 = planet.cargoTraffic.splitterCursor - 1; int componentCount = planet.cargoTraffic.pathCursor - 1; int num10 = planet.transport.stationCursor - 1; int num11 = planet.transport.dispenserCursor - 1; int componentCount2 = num10 + num11; int num12 = planet.defenseSystem.turrets.cursor - 1; int num13 = planet.defenseSystem.fieldGenerators.cursor - 1; int num14 = planet.defenseSystem.battleBases.cursor - 1; int num15 = planet.digitalSystem.markers.cursor - 1; int componentCount3 = planet.factorySystem.inserterCursor - 1; int componentCount4 = planet.factorySystem.labCursor - 1; int componentCount5 = planet.factorySystem.labCursor - 1; int componentCount6 = planet.factorySystem.labCursor - 1; int num16 = planet.factoryStorage.storageCursor - 1; int num17 = planet.factoryStorage.tankCursor - 1; int num18 = planet.powerSystem.netCursor - 1; int num19 = num + num2 + num3 + num4 + num5 + num6 + num7 + num8 + num10 + num11 + num12 + num13 + num14 + num15; result._beforePowerWorkWorkChunkCount = (num19 + 499) / 500; result._beforePowerWorkWorkChunkCount = Math.Min(result._beforePowerWorkWorkChunkCount, maxParallelism); result._powerNetworkWorkChunkCount = ((num18 > 0) ? 1 : 0); result._minerWorkChunkCount = GetComponentWorkChunkCount(maxParallelism, 500, num); result._assemblerWorkChunkCount = GetComponentWorkChunkCount(maxParallelism, 500, num2); result._fractionatorWorkChunkCount = GetComponentWorkChunkCount(maxParallelism, 500, num3); result._ejectorWorkChunkCount = GetComponentWorkChunkCount(maxParallelism, 500, num4); result._siloWorkChunkCount = GetComponentWorkChunkCount(maxParallelism, 500, num5); result._producingLabWorkChunkCount = GetComponentWorkChunkCount(maxParallelism, 500, componentCount4); result._researchingLabWorkChunkCount = GetComponentWorkChunkCount(1, 500, componentCount5); result._labWorkChunkCount = GetComponentWorkChunkCount(1, 500, componentCount6); result._transportEntitiesWorkChunkCount = GetComponentWorkChunkCount(1, 500, componentCount2); result._stationWorkChunkCount = ((num10 > 0) ? 1 : 0); result._inserterWorkWorkChunkCount = GetComponentWorkChunkCount(maxParallelism, 2000, componentCount3); result._storageAndTankWorkChunkCount = ((num16 + num17 > 0) ? 1 : 0); result._cargoPathsWorkWorkChunkCount = GetComponentWorkChunkCount(maxParallelism, 500, componentCount); result._splitterWorkChunkCount = ((num9 > 0) ? 1 : 0); result._cargoTrafficMiscWorkChunkCount = GetComponentWorkChunkCount(maxParallelism, 500, Math.Max(Math.Max(num6, num7), num8)); result._sandboxModeWorkWorkChunkCount = (GameMain.sandboxToolsEnabled ? GetComponentWorkChunkCount(maxParallelism, 500, componentCount2) : 0); result._cargoPathPresentWorkChunkCount = GetComponentWorkChunkCount(maxParallelism, 100, componentCount); result._markerWorkChunkCount = GetComponentWorkChunkCount(1, 500, num15); return result; } public readonly IWorkNode CreateWorkNode() { List list = new List(); if (_beforePowerWorkWorkChunkCount > 0) { IWorkNode[] item = UnOptimizedPlanetWorkChunk.CreateDuplicateChunksInWorkLeafs(_planet, WorkType.BeforePower, _beforePowerWorkWorkChunkCount); list.Add(item); } if (_powerNetworkWorkChunkCount > 0) { IWorkNode[] item = UnOptimizedPlanetWorkChunk.CreateDuplicateChunksInWorkLeafs(_planet, WorkType.Power, _powerNetworkWorkChunkCount); list.Add(item); } List list2 = new List(); list2.AddRange(UnOptimizedPlanetWorkChunk.CreateDuplicateChunksInWorkLeafs(_planet, WorkType.Miner, _minerWorkChunkCount)); list2.AddRange(UnOptimizedPlanetWorkChunk.CreateDuplicateChunksInWorkLeafs(_planet, WorkType.Assembler, _assemblerWorkChunkCount)); list2.AddRange(UnOptimizedPlanetWorkChunk.CreateDuplicateChunksInWorkLeafs(_planet, WorkType.Fractionator, _fractionatorWorkChunkCount)); list2.AddRange(UnOptimizedPlanetWorkChunk.CreateDuplicateChunksInWorkLeafs(_planet, WorkType.Ejector, _ejectorWorkChunkCount)); list2.AddRange(UnOptimizedPlanetWorkChunk.CreateDuplicateChunksInWorkLeafs(_planet, WorkType.Silo, _siloWorkChunkCount)); list2.AddRange(UnOptimizedPlanetWorkChunk.CreateDuplicateChunksInWorkLeafs(_planet, WorkType.LabProduce, _producingLabWorkChunkCount)); list2.AddRange(UnOptimizedPlanetWorkChunk.CreateDuplicateChunksInWorkLeafs(_planet, WorkType.LabResearchMode, _researchingLabWorkChunkCount)); if (list2.Count > 0) { IWorkNode[] item = list2.ToArray(); list.Add(item); } list2.Clear(); list2.AddRange(UnOptimizedPlanetWorkChunk.CreateDuplicateChunksInWorkLeafs(_planet, WorkType.LabOutput2NextData, _labWorkChunkCount)); list2.AddRange(UnOptimizedPlanetWorkChunk.CreateDuplicateChunksInWorkLeafs(_planet, WorkType.TransportData, _transportEntitiesWorkChunkCount)); if (list2.Count > 0) { IWorkNode[] item = list2.ToArray(); list.Add(item); } if (_stationWorkChunkCount > 0) { IWorkNode[] item = UnOptimizedPlanetWorkChunk.CreateDuplicateChunksInWorkLeafs(_planet, WorkType.InputFromBelt, _stationWorkChunkCount); list.Add(item); } if (_inserterWorkWorkChunkCount > 0) { IWorkNode[] item = UnOptimizedPlanetWorkChunk.CreateDuplicateChunksInWorkLeafs(_planet, WorkType.InserterData, _inserterWorkWorkChunkCount); list.Add(item); } if (_storageAndTankWorkChunkCount > 0) { IWorkNode[] item = UnOptimizedPlanetWorkChunk.CreateDuplicateChunksInWorkLeafs(_planet, WorkType.Storage, _storageAndTankWorkChunkCount); list.Add(item); } if (_cargoPathsWorkWorkChunkCount > 0) { IWorkNode[] item = UnOptimizedPlanetWorkChunk.CreateDuplicateChunksInWorkLeafs(_planet, WorkType.CargoPathsData, _cargoPathsWorkWorkChunkCount); list.Add(item); } if (_splitterWorkChunkCount > 0) { IWorkNode[] item = UnOptimizedPlanetWorkChunk.CreateDuplicateChunksInWorkLeafs(_planet, WorkType.Splitter, _splitterWorkChunkCount); list.Add(item); } if (_cargoTrafficMiscWorkChunkCount > 0) { IWorkNode[] item = UnOptimizedPlanetWorkChunk.CreateDuplicateChunksInWorkLeafs(_planet, WorkType.CargoTrafficMisc, _cargoTrafficMiscWorkChunkCount); list.Add(item); } if (_stationWorkChunkCount > 0) { IWorkNode[] item = UnOptimizedPlanetWorkChunk.CreateDuplicateChunksInWorkLeafs(_planet, WorkType.OutputToBelt, _stationWorkChunkCount); list.Add(item); } if (_sandboxModeWorkWorkChunkCount > 0) { IWorkNode[] item = UnOptimizedPlanetWorkChunk.CreateDuplicateChunksInWorkLeafs(_planet, WorkType.SandboxMode, _sandboxModeWorkWorkChunkCount); list.Add(item); } list2.Clear(); list2.AddRange(UnOptimizedPlanetWorkChunk.CreateDuplicateChunksInWorkLeafs(_planet, WorkType.PresentCargoPathsData, _cargoPathPresentWorkChunkCount)); list2.AddRange(UnOptimizedPlanetWorkChunk.CreateDuplicateChunksInWorkLeafs(_planet, WorkType.Digital, _markerWorkChunkCount)); if (list2.Count > 0) { IWorkNode[] item = list2.ToArray(); list.Add(item); } if (list.Count == 0) { return new NoWorkNode(); } return new WorkNode(list.ToArray()); } public readonly bool Equals(UnOptimizedWorkChunkCounts other) { if (_beforePowerWorkWorkChunkCount == other._beforePowerWorkWorkChunkCount && _powerNetworkWorkChunkCount == other._powerNetworkWorkChunkCount && _minerWorkChunkCount == other._minerWorkChunkCount && _assemblerWorkChunkCount == other._assemblerWorkChunkCount && _fractionatorWorkChunkCount == other._fractionatorWorkChunkCount && _ejectorWorkChunkCount == other._ejectorWorkChunkCount && _siloWorkChunkCount == other._siloWorkChunkCount && _producingLabWorkChunkCount == other._producingLabWorkChunkCount && _researchingLabWorkChunkCount == other._researchingLabWorkChunkCount && _labWorkChunkCount == other._labWorkChunkCount && _transportEntitiesWorkChunkCount == other._transportEntitiesWorkChunkCount && _stationWorkChunkCount == other._stationWorkChunkCount && _inserterWorkWorkChunkCount == other._inserterWorkWorkChunkCount && _storageAndTankWorkChunkCount == other._storageAndTankWorkChunkCount && _cargoPathsWorkWorkChunkCount == other._cargoPathsWorkWorkChunkCount && _splitterWorkChunkCount == other._splitterWorkChunkCount && _cargoTrafficMiscWorkChunkCount == other._cargoTrafficMiscWorkChunkCount && _sandboxModeWorkWorkChunkCount == other._sandboxModeWorkWorkChunkCount && _cargoPathPresentWorkChunkCount == other._cargoPathPresentWorkChunkCount) { return _markerWorkChunkCount == other._markerWorkChunkCount; } return false; } public override readonly bool Equals(object other) { if (other is UnOptimizedWorkChunkCounts other2) { return Equals(other2); } return false; } public override readonly int GetHashCode() { HashCode hashCode = default(HashCode); hashCode.Add(_beforePowerWorkWorkChunkCount); hashCode.Add(_powerNetworkWorkChunkCount); hashCode.Add(_minerWorkChunkCount); hashCode.Add(_assemblerWorkChunkCount); hashCode.Add(_fractionatorWorkChunkCount); hashCode.Add(_ejectorWorkChunkCount); hashCode.Add(_siloWorkChunkCount); hashCode.Add(_producingLabWorkChunkCount); hashCode.Add(_researchingLabWorkChunkCount); hashCode.Add(_labWorkChunkCount); hashCode.Add(_transportEntitiesWorkChunkCount); hashCode.Add(_stationWorkChunkCount); hashCode.Add(_inserterWorkWorkChunkCount); hashCode.Add(_storageAndTankWorkChunkCount); hashCode.Add(_cargoPathsWorkWorkChunkCount); hashCode.Add(_splitterWorkChunkCount); hashCode.Add(_cargoTrafficMiscWorkChunkCount); hashCode.Add(_sandboxModeWorkWorkChunkCount); hashCode.Add(_cargoPathPresentWorkChunkCount); hashCode.Add(_markerWorkChunkCount); return hashCode.ToHashCode(); } public static int GetComponentWorkChunkCount(int maxParallelism, int minimumWorkPerCore, int componentCount) { return Math.Min((componentCount + (minimumWorkPerCore - 1)) / minimumWorkPerCore, maxParallelism); } } internal sealed class UnOptimizedPlanetWorkChunk : IWorkChunk { private readonly PlanetFactory _planet; private readonly WorkType _workType; private readonly int _workIndex; private readonly int _maxWorkCount; private UnOptimizedPlanetWorkChunk(PlanetFactory planet, WorkType workType, int workIndex, int maxWorkCount) { _planet = planet; _workType = workType; _workIndex = workIndex; _maxWorkCount = maxWorkCount; } public static SingleWorkLeaf[] CreateDuplicateChunksInWorkLeafs(PlanetFactory planet, WorkType workType, int count) { if (count == 0) { return Array.Empty(); } SingleWorkLeaf[] array = new SingleWorkLeaf[count]; for (int i = 0; i < array.Length; i++) { array[i] = new SingleWorkLeaf(new UnOptimizedPlanetWorkChunk(planet, workType, i, count)); } return array; } public void Execute(int workerIndex, object singleThreadedCodeLock, PlanetData localPlanet, long time, Vector3 playerPosition) { //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) bool flag = localPlanet == _planet.planet; if (_workType == WorkType.BeforePower) { DeepProfiler.BeginSample((DPEntry)12, workerIndex, -1L); DeepProfiler.BeginSample((DPEntry)15, workerIndex, -1L); DefenseSystem defenseSystem = _planet.defenseSystem; if (defenseSystem != null) { defenseSystem.ParallelGameTickBeforePower(time, _maxWorkCount, _workIndex, 2); } DigitalSystem digitalSystem = _planet.digitalSystem; if (digitalSystem != null) { digitalSystem.ParallelGameTickBeforePower(time, _maxWorkCount, _workIndex, 2); } DeepProfiler.EndSample((DPEntry)15, workerIndex); DeepProfiler.EndSample((DPEntry)12, workerIndex); return; } if (_workType == WorkType.Power && _planet.powerSystem != null) { DeepProfiler.BeginSample((DPEntry)12, workerIndex, -1L); _planet.powerSystem.multithreadPlayerPos = playerPosition; _planet.powerSystem.GameTick(time, flag, true, workerIndex); DeepProfiler.EndSample((DPEntry)12, workerIndex); return; } if (_workType == WorkType.Construction && _planet.constructionSystem != null) { throw new InvalidOperationException("The work type Construction is not thread safe."); } if (_workType == WorkType.CheckBefore && _planet.factorySystem != null) { throw new InvalidOperationException("The work type CheckBefore is not thread safe."); } if (_workType == WorkType.Miner) { if (_planet.factorySystem == null) { throw new InvalidOperationException($"Attempted to execute {WorkType.Miner} work on a null planet."); } ParallelMinerGameTick(workerIndex, time, flag); } else if (_workType == WorkType.Fractionator) { if (_planet.factorySystem == null) { throw new InvalidOperationException($"Attempted to execute {WorkType.Fractionator} work on a null planet."); } ParallelFractionatorGameTick(workerIndex, time, flag); } else if (_workType == WorkType.Ejector) { if (_planet.factorySystem == null) { throw new InvalidOperationException($"Attempted to execute {WorkType.Ejector} work on a null planet."); } ParallelEjectorGameTick(workerIndex, time, flag); } else if (_workType == WorkType.Silo) { if (_planet.factorySystem == null) { throw new InvalidOperationException($"Attempted to execute {WorkType.Silo} work on a null planet."); } ParallelSiloGameTick(workerIndex, time, flag); } else if (_workType == WorkType.Assembler) { if (_planet.factorySystem == null) { throw new InvalidOperationException($"Attempted to execute {WorkType.Assembler} work on a null planet."); } ParallelAssemblerGameTick(workerIndex, time, flag); } else if (_workType == WorkType.LabProduce) { if (_planet.factorySystem == null) { throw new InvalidOperationException($"Attempted to execute {WorkType.LabProduce} work on a null planet."); } ParallelLabProduceGameTick(workerIndex, time, flag); } else if (_workType == WorkType.LabResearchMode) { DeepProfiler.BeginMajorSample((DPEntry)24, workerIndex, -1L); OptimizedStarCluster.ThreadSafeGameTickLabResearchMode(_planet, time, flag); DeepProfiler.EndMajorSample((DPEntry)24, workerIndex); } else if (_workType == WorkType.LabOutput2NextData) { if (_planet.factorySystem == null) { throw new InvalidOperationException($"Attempted to execute {WorkType.LabOutput2NextData} work on a null planet."); } DeepProfiler.BeginSample((DPEntry)24, workerIndex, -1L); _planet.factorySystem.GameTickLabOutputToNext(time, flag); DeepProfiler.EndSample((DPEntry)24, workerIndex); } else if (_workType == WorkType.TransportData && _planet.transport != null) { DeepProfiler.BeginSample((DPEntry)36, workerIndex, 99L); _planet.transport.GameTick(time, flag, false, -1); DeepProfiler.EndSample((DPEntry)36, workerIndex); } else if (_workType == WorkType.InputFromBelt && _planet.transport != null) { DeepProfiler.BeginSample((DPEntry)37, workerIndex, -1L); _planet.transport.GameTick_InputFromBelt(time); DeepProfiler.EndSample((DPEntry)37, workerIndex); } else if (_workType == WorkType.InserterData) { if (_planet.factorySystem == null) { throw new InvalidOperationException($"Attempted to execute {WorkType.InserterData} work on a null planet."); } ParallelInserterGameTick(workerIndex, time, flag); } else if (_workType == WorkType.Storage && _planet.factoryStorage != null) { DeepProfiler.BeginSample((DPEntry)26, workerIndex, -1L); _planet.factoryStorage.GameTickStorage(time, flag); DeepProfiler.EndSample((DPEntry)26, workerIndex); DeepProfiler.BeginSample((DPEntry)27, workerIndex, -1L); _planet.factoryStorage.GameTickTank(); DeepProfiler.EndSample((DPEntry)27, workerIndex); } else if (_workType == WorkType.CargoPathsData) { ParallelCargoPathsGameTick(workerIndex); } else if (_workType == WorkType.Splitter && _planet.cargoTraffic != null) { DeepProfiler.BeginSample((DPEntry)29, workerIndex, -1L); _planet.cargoTraffic.SplitterGameTick(time); DeepProfiler.EndSample((DPEntry)29, workerIndex); } else if (_workType == WorkType.CargoTrafficMisc && _planet.cargoTraffic != null) { ParallelCargoTrafficMiscGameTick(workerIndex); } else if (_workType == WorkType.OutputToBelt && _planet.transport != null) { DeepProfiler.BeginSample((DPEntry)37, workerIndex, -1L); int stationPilerLevel = GameMain.history.stationPilerLevel; _planet.transport.GameTick_OutputToBelt(stationPilerLevel, time); DeepProfiler.EndSample((DPEntry)37, workerIndex); } else if (_workType == WorkType.SandboxMode && _planet.transport != null) { DeepProfiler.BeginSample((DPEntry)37, workerIndex, -1L); lock (singleThreadedCodeLock) { _planet.transport.GameTick_SandboxMode(workerIndex); } DeepProfiler.EndSample((DPEntry)37, workerIndex); } else if (_workType == WorkType.PresentCargoPathsData && _planet.cargoTraffic != null && flag) { ParallelPresentCargoPathsGameTick(workerIndex); } else if (_workType == WorkType.Digital && _planet.digitalSystem != null) { DeepProfiler.BeginSample((DPEntry)39, workerIndex, -1L); _planet.digitalSystem.GameTick(flag); DeepProfiler.EndSample((DPEntry)39, workerIndex); } } private void ParallelMinerGameTick(int workerIndex, long time, bool isActive) { //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Invalid comparison between Unknown and I4 //IL_0283: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Expected I4, but got Unknown //IL_0367: Unknown result type (might be due to invalid IL or missing references) //IL_036d: Invalid comparison between Unknown and I4 DeepProfiler.BeginSample((DPEntry)19, workerIndex, -1L); GameHistoryData history = GameMain.history; int[] productRegister = GameMain.statistics.production.factoryStatPool[_planet.index].productRegister; PowerSystem powerSystem = _planet.powerSystem; float[] networkServes = powerSystem.networkServes; EntityData[] entityPool = _planet.entityPool; VeinData[] veinPool = _planet.veinPool; AnimData[] entityAnimPool = _planet.entityAnimPool; SignData[] entitySignPool = _planet.entitySignPool; PowerConsumerComponent[] consumerPool = powerSystem.consumerPool; StationComponent[] stationPool = _planet.transport.stationPool; MinerComponent[] minerPool = _planet.factorySystem.minerPool; float num = 1f / 60f; float num2; float num3 = (num2 = _planet.gameData.gameDesc.resourceMultiplier); if (num2 < 5f / 12f) { num2 = 5f / 12f; } float num4 = history.miningCostRate; float miningSpeedScale = history.miningSpeedScale; float num5 = history.miningCostRate * 0.40111667f / num2; if (num3 > 99.5f) { num4 = 0f; num5 = 0f; } bool flag = isActive && num4 > 0f; int num6 = MinerComponent.InsufficientWarningThresAmount(num3, num4); (int startIndex, int workLength) workChunkIndices = GetWorkChunkIndices(_planet.factorySystem.minerCursor, _maxWorkCount, _workIndex); int item = workChunkIndices.startIndex; int item2 = workChunkIndices.workLength; for (int i = Math.Max(1, item); i < item + item2; i++) { if (minerPool[i].id != i) { continue; } int entityId = minerPool[i].entityId; int stationId = entityPool[entityId].stationId; float num7 = networkServes[consumerPool[minerPool[i].pcId].networkId]; uint num8 = ((MinerComponent)(ref minerPool[i])).InternalUpdate(_planet, veinPool, num7, ((int)minerPool[i].type == 3) ? num5 : num4, miningSpeedScale, productRegister); int num9 = (int)Mathf.Floor(entityAnimPool[entityId].time / 10f); entityAnimPool[entityId].time = entityAnimPool[entityId].time % 10f; ((AnimData)(ref entityAnimPool[entityId])).Step(num8, num * num7); entityAnimPool[entityId].power = num7; if (stationId > 0) { if (minerPool[i].veinCount > 0) { EVeinType veinTypeByItemId = LDB.veins.GetVeinTypeByItemId(veinPool[minerPool[i].veins[0]].productId); ref uint state = ref entityAnimPool[entityId].state; state = (uint)(int)(state + veinTypeByItemId * 100); } entityAnimPool[entityId].power += 10f; entityAnimPool[entityId].power += minerPool[i].speed; if (num8 == 1) { num9 = 3000; } else { num9 -= (int)(num * 1000f); if (num9 < 0) { num9 = 0; } } entityAnimPool[entityId].time += num9 * 10; } if (entitySignPool[entityId].signType == 0 || entitySignPool[entityId].signType > 3) { entitySignPool[entityId].signType = ((minerPool[i].minimumVeinAmount < num6) ? 7u : 0u); } if (flag && (int)minerPool[i].type == 2) { if ((long)i % 30L == time % 30) { ((MinerComponent)(ref minerPool[i])).GetTotalVeinAmount(veinPool); } entitySignPool[entityId].count0 = minerPool[i].totalVeinAmount; } else { entitySignPool[entityId].count0 = 0f; } if (stationId > 0) { StationStore[] storage = stationPool[stationId].storage; int num10 = storage[0].count; if (storage[0].localOrder < -4000) { num10 += storage[0].localOrder + 4000; } int max = storage[0].max; max = ((max < 3000) ? 3000 : max); float num11 = (float)num10 / (float)max; num11 = ((num11 > 1f) ? 1f : num11); float num12 = -2.45f * num11 + 2.47f; num12 = ((num12 > 1f) ? 1f : num12); minerPool[i].speedDamper = num12; } else { float num13 = (float)minerPool[i].productCount / 50f; num13 = ((num13 > 1f) ? 1f : num13); float num14 = -2.45f * num13 + 2.47f; num14 = ((num14 > 1f) ? 1f : num14); minerPool[i].speedDamper = num14; } ((MinerComponent)(ref minerPool[i])).SetPCState(consumerPool); } DeepProfiler.EndSample((DPEntry)19, workerIndex); } private void ParallelFractionatorGameTick(int workerIndex, long time, bool isActive) { DeepProfiler.BeginSample((DPEntry)20, workerIndex, -1L); AnimData[] entityAnimPool = _planet.entityAnimPool; SignData[] entitySignPool = _planet.entitySignPool; FractionatorComponent[] fractionatorPool = _planet.factorySystem.fractionatorPool; PowerConsumerComponent[] consumerPool = _planet.powerSystem.consumerPool; float[] networkServes = _planet.powerSystem.networkServes; FactoryProductionStat obj = _planet.gameData.statistics.production.factoryStatPool[_planet.index]; int[] productRegister = obj.productRegister; int[] consumeRegister = obj.consumeRegister; (int startIndex, int workLength) workChunkIndices = GetWorkChunkIndices(_planet.factorySystem.fractionatorCursor, _maxWorkCount, _workIndex); int item = workChunkIndices.startIndex; int item2 = workChunkIndices.workLength; for (int i = Math.Max(1, item); i < item + item2; i++) { ref FractionatorComponent reference = ref fractionatorPool[i]; if (reference.id == i) { int entityId = reference.entityId; float num = networkServes[consumerPool[reference.pcId].networkId]; uint state = ((FractionatorComponent)(ref reference)).InternalUpdate(_planet, num, entitySignPool, productRegister, consumeRegister); if (isActive) { entityAnimPool[entityId].time = Mathf.Sqrt((float)reference.fluidInputCount * 0.025f); entityAnimPool[entityId].state = state; entityAnimPool[entityId].power = num; } ((FractionatorComponent)(ref reference)).SetPCState(consumerPool); } } DeepProfiler.EndSample((DPEntry)20, workerIndex); } private void ParallelEjectorGameTick(int workerIndex, long time, bool isActive) { DeepProfiler.BeginSample((DPEntry)22, workerIndex, -1L); AnimData[] entityAnimPool = _planet.entityAnimPool; SignData[] entitySignPool = _planet.entitySignPool; int[][] entityNeeds = _planet.entityNeeds; EjectorComponent[] ejectorPool = _planet.factorySystem.ejectorPool; PowerConsumerComponent[] consumerPool = _planet.powerSystem.consumerPool; float[] networkServes = _planet.powerSystem.networkServes; int[] consumeRegister = _planet.gameData.statistics.production.factoryStatPool[_planet.index].consumeRegister; AstroData[] array = null; lock (ejectorPool) { if (_planet.factorySystem.ejectorCount > 0) { array = _planet.planet.galaxy.astrosData; } } DysonSwarm val = null; if (_planet.dysonSphere != null) { val = _planet.dysonSphere.swarm; } (int startIndex, int workLength) workChunkIndices = GetWorkChunkIndices(_planet.factorySystem.ejectorCursor, _maxWorkCount, _workIndex); int item = workChunkIndices.startIndex; int item2 = workChunkIndices.workLength; for (int i = Math.Max(1, item); i < item + item2; i++) { ref EjectorComponent reference = ref ejectorPool[i]; if (reference.id != i) { continue; } int entityId = reference.entityId; float num = networkServes[consumerPool[reference.pcId].networkId]; uint state = ((EjectorComponent)(ref reference)).InternalUpdate(num, time, val, array, entityAnimPool, consumeRegister); entityNeeds[entityId] = reference.needs; if (isActive) { entityAnimPool[entityId].state = state; if (entitySignPool[entityId].signType == 0 || entitySignPool[entityId].signType > 3) { entitySignPool[entityId].signType = ((reference.orbitId <= 0 && !reference.autoOrbit) ? 5u : 0u); } } ((EjectorComponent)(ref reference)).SetPCState(consumerPool); } DeepProfiler.EndSample((DPEntry)22, workerIndex); } private void ParallelSiloGameTick(int workerIndex, long time, bool isActive) { DeepProfiler.BeginSample((DPEntry)23, workerIndex, -1L); AnimData[] entityAnimPool = _planet.entityAnimPool; SignData[] entitySignPool = _planet.entitySignPool; int[][] entityNeeds = _planet.entityNeeds; SiloComponent[] siloPool = _planet.factorySystem.siloPool; PowerConsumerComponent[] consumerPool = _planet.powerSystem.consumerPool; float[] networkServes = _planet.powerSystem.networkServes; int[] consumeRegister = _planet.gameData.statistics.production.factoryStatPool[_planet.index].consumeRegister; DysonSphere dysonSphere = _planet.dysonSphere; bool flag = dysonSphere != null && dysonSphere.autoNodeCount > 0; (int startIndex, int workLength) workChunkIndices = GetWorkChunkIndices(_planet.factorySystem.siloCursor, _maxWorkCount, _workIndex); int item = workChunkIndices.startIndex; int item2 = workChunkIndices.workLength; for (int i = Math.Max(1, item); i < item + item2; i++) { ref SiloComponent reference = ref siloPool[i]; if (reference.id != i) { continue; } int entityId = reference.entityId; float num = networkServes[consumerPool[reference.pcId].networkId]; uint state = ((SiloComponent)(ref reference)).InternalUpdate(num, dysonSphere, entityAnimPool, consumeRegister); entityNeeds[entityId] = reference.needs; if (isActive) { entityAnimPool[entityId].state = state; if (entitySignPool[entityId].signType == 0 || entitySignPool[entityId].signType > 3) { entitySignPool[entityId].signType = ((!flag) ? 9u : 0u); } } ((SiloComponent)(ref reference)).SetPCState(consumerPool); } DeepProfiler.EndSample((DPEntry)23, workerIndex); } private void ParallelAssemblerGameTick(int workerIndex, long time, bool isActive) { //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Invalid comparison between Unknown and I4 DeepProfiler.BeginSample((DPEntry)20, workerIndex, -1L); GameLogic logic = GameMain.logic; bool flag = isActive || (time + _planet.index) % 15 == 0; AnimData[] entityAnimPool = _planet.entityAnimPool; SignData[] entitySignPool = _planet.entitySignPool; int[][] entityNeeds = _planet.entityNeeds; AssemblerComponent[] assemblerPool = _planet.factorySystem.assemblerPool; PowerConsumerComponent[] consumerPool = _planet.powerSystem.consumerPool; float[] networkServes = _planet.powerSystem.networkServes; FactoryProductionStat obj = _planet.gameData.statistics.production.factoryStatPool[_planet.index]; int[] productRegister = obj.productRegister; int[] consumeRegister = obj.consumeRegister; (int startIndex, int workLength) workChunkIndices = GetWorkChunkIndices(_planet.factorySystem.assemblerCursor, _maxWorkCount, _workIndex); int item = workChunkIndices.startIndex; int item2 = workChunkIndices.workLength; for (int i = Math.Max(1, item); i < item + item2; i++) { ref AssemblerComponent reference = ref assemblerPool[i]; if (reference.id != i) { continue; } int entityId = reference.entityId; if (flag) { uint num = 0u; float num2 = networkServes[consumerPool[reference.pcId].networkId]; if (reference.recipeId != 0) { ((AssemblerComponent)(ref reference)).UpdateNeeds(); num = ((AssemblerComponent)(ref reference)).InternalUpdate(num2, productRegister, consumeRegister); } if ((int)reference.recipeType == 2) { entityAnimPool[entityId].working_length = 2f; ((AnimData)(ref entityAnimPool[entityId])).Step(num, logic.deltaTime * num2); entityAnimPool[entityId].power = num2; entityAnimPool[entityId].working_length = reference.recipeId; } else { ((AnimData)(ref entityAnimPool[entityId])).Step(num, logic.deltaTime * num2); entityAnimPool[entityId].power = num2; } entityNeeds[entityId] = reference.needs; if (entitySignPool[entityId].signType == 0 || entitySignPool[entityId].signType > 3) { entitySignPool[entityId].signType = ((reference.recipeId == 0) ? 4u : ((num == 0) ? 6u : 0u)); } } else { float num3 = networkServes[consumerPool[reference.pcId].networkId]; if (reference.recipeId != 0) { ((AssemblerComponent)(ref reference)).UpdateNeeds(); ((AssemblerComponent)(ref reference)).InternalUpdate(num3, productRegister, consumeRegister); } entityNeeds[entityId] = reference.needs; } ((AssemblerComponent)(ref reference)).SetPCState(consumerPool); } DeepProfiler.EndSample((DPEntry)20, workerIndex); } private void ParallelLabProduceGameTick(int workerIndex, long time, bool isActive) { DeepProfiler.BeginSample((DPEntry)24, workerIndex, -1L); GameLogic logic = GameMain.logic; bool flag = isActive || (time + _planet.index) % 15 == 0; AnimData[] entityAnimPool = _planet.entityAnimPool; SignData[] entitySignPool = _planet.entitySignPool; int[][] entityNeeds = _planet.entityNeeds; LabComponent[] labPool = _planet.factorySystem.labPool; PowerConsumerComponent[] consumerPool = _planet.powerSystem.consumerPool; float[] networkServes = _planet.powerSystem.networkServes; FactoryProductionStat obj = _planet.gameData.statistics.production.factoryStatPool[_planet.index]; int[] productRegister = obj.productRegister; int[] consumeRegister = obj.consumeRegister; (int startIndex, int workLength) workChunkIndices = GetWorkChunkIndices(_planet.factorySystem.labCursor, _maxWorkCount, _workIndex); int item = workChunkIndices.startIndex; int item2 = workChunkIndices.workLength; for (int i = Math.Max(1, item); i < item + item2; i++) { ref LabComponent reference = ref labPool[i]; if (reference.id != i || reference.researchMode) { continue; } int entityId = reference.entityId; float num = networkServes[consumerPool[reference.pcId].networkId]; if (reference.recipeId > 0) { ((LabComponent)(ref reference)).UpdateNeedsAssemble(); uint num2 = ((LabComponent)(ref reference)).InternalUpdateAssemble(num, productRegister, consumeRegister); if (isActive) { entityAnimPool[entityId].working_length = LabComponent.matrixShaderStates[num2]; entityAnimPool[entityId].prepare_length = 0f; entityAnimPool[entityId].power = num; ((AnimData)(ref entityAnimPool[entityId])).Step01(num2, logic.deltaTime); if (flag && (entitySignPool[entityId].signType == 0 || entitySignPool[entityId].signType > 3)) { entitySignPool[entityId].signType = (reference.researchMode ? ((num2 == 0) ? 6u : 0u) : ((reference.recipeId == 0) ? 4u : ((num2 == 0) ? 6u : 0u))); } } } entityNeeds[entityId] = reference.needs; } DeepProfiler.EndSample((DPEntry)24, workerIndex); } private void ParallelInserterGameTick(int workerIndex, long time, bool isActive) { InserterComponent[] inserterPool = _planet.factorySystem.inserterPool; PowerSystem powerSystem = _planet.powerSystem; float[] networkServes = powerSystem.networkServes; CargoTraffic cargoTraffic = _planet.cargoTraffic; AnimData[] entityAnimPool = _planet.entityAnimPool; int[][] entityNeeds = _planet.entityNeeds; PowerConsumerComponent[] consumerPool = powerSystem.consumerPool; EntityData[] entityPool = _planet.entityPool; BeltComponent[] beltPool = _planet.cargoTraffic.beltPool; bool flag = time % 60 == 0; var (num, num2) = GetWorkChunkIndices(_planet.factorySystem.inserterCursor, _maxWorkCount, _workIndex); if (num2 == 0) { return; } DeepProfiler.BeginSample((DPEntry)25, workerIndex, -1L); for (int i = Math.Max(1, num); i < num + num2; i++) { ref InserterComponent reference = ref inserterPool[i]; if (reference.id == i) { float num3 = networkServes[consumerPool[reference.pcId].networkId]; if (flag) { ((InserterComponent)(ref reference)).InternalOffsetCorrection(entityPool, cargoTraffic, beltPool); } if (reference.bidirectional) { ((InserterComponent)(ref reference)).InternalUpdate_Bidirectional(_planet, entityNeeds, entityAnimPool, num3, isActive); } else if (isActive) { ((InserterComponent)(ref reference)).InternalUpdate(_planet, entityNeeds, entityAnimPool, num3); } else { ((InserterComponent)(ref reference)).InternalUpdateNoAnim(_planet, entityNeeds, num3); } ((InserterComponent)(ref reference)).SetPCState(consumerPool); } } DeepProfiler.EndSample((DPEntry)25, workerIndex); } private void ParallelCargoPathsGameTick(int workerIndex) { CargoPath[] pathPool = _planet.cargoTraffic.pathPool; var (num, num2) = GetWorkChunkIndices(_planet.cargoTraffic.pathCursor, _maxWorkCount, _workIndex); if (num2 == 0) { return; } DeepProfiler.BeginSample((DPEntry)28, workerIndex, -1L); for (int i = Math.Max(1, num); i < num + num2; i++) { CargoPath val = pathPool[i]; if (val != null && val.id == i) { val.Update(); } } DeepProfiler.EndSample((DPEntry)28, workerIndex); } private void ParallelCargoTrafficMiscGameTick(int workerIndex) { AnimData[] entityAnimPool = _planet.entityAnimPool; DigitalSystem digitalSystem = _planet.digitalSystem; EntityData[] entityPool = _planet.entityPool; PowerConsumerComponent[] consumerPool = _planet.powerSystem.consumerPool; CargoTraffic cargoTraffic = _planet.cargoTraffic; bool sandboxToolsEnabled = GameMain.sandboxToolsEnabled; if (cargoTraffic.monitorCursor > 0) { DeepProfiler.BeginSample((DPEntry)30, workerIndex, -1L); (int startIndex, int workLength) workChunkIndices = GetWorkChunkIndices(cargoTraffic.monitorCursor, _maxWorkCount, _workIndex); int item = workChunkIndices.startIndex; int item2 = workChunkIndices.workLength; MonitorComponent[] monitorPool = cargoTraffic.monitorPool; for (int i = Math.Max(1, item); i < item + item2; i++) { ref MonitorComponent reference = ref monitorPool[i]; if (reference.id == i) { ((MonitorComponent)(ref reference)).InternalUpdate(cargoTraffic, sandboxToolsEnabled, entityPool, digitalSystem, entityAnimPool); ((MonitorComponent)(ref reference)).SetPCState(consumerPool); } } DeepProfiler.EndSample((DPEntry)30, workerIndex); } if (cargoTraffic.spraycoaterCursor > 0) { int[] consumeRegister = GameMain.statistics.production.factoryStatPool[_planet.index].consumeRegister; DeepProfiler.BeginSample((DPEntry)31, workerIndex, -1L); (int startIndex, int workLength) workChunkIndices2 = GetWorkChunkIndices(cargoTraffic.spraycoaterCursor, _maxWorkCount, _workIndex); int item3 = workChunkIndices2.startIndex; int item4 = workChunkIndices2.workLength; SpraycoaterComponent[] spraycoaterPool = cargoTraffic.spraycoaterPool; for (int j = Math.Max(1, item3); j < item3 + item4; j++) { ref SpraycoaterComponent reference2 = ref spraycoaterPool[j]; if (reference2.id == j) { ((SpraycoaterComponent)(ref reference2)).InternalUpdate(cargoTraffic, entityAnimPool, consumeRegister); ((SpraycoaterComponent)(ref reference2)).SetPCState(consumerPool); } } DeepProfiler.EndSample((DPEntry)31, workerIndex); } if (cargoTraffic.pilerCursor <= 0) { return; } DeepProfiler.BeginSample((DPEntry)32, workerIndex, -1L); (int startIndex, int workLength) workChunkIndices3 = GetWorkChunkIndices(cargoTraffic.pilerCursor, _maxWorkCount, _workIndex); int item5 = workChunkIndices3.startIndex; int item6 = workChunkIndices3.workLength; PilerComponent[] pilerPool = cargoTraffic.pilerPool; for (int k = Math.Max(1, item5); k < item5 + item6; k++) { if (pilerPool[k].id == k) { ((PilerComponent)(ref pilerPool[k])).InternalUpdate(cargoTraffic, entityAnimPool); ((PilerComponent)(ref pilerPool[k])).SetPCState(consumerPool); } } DeepProfiler.EndSample((DPEntry)32, workerIndex); } private void ParallelPresentCargoPathsGameTick(int workerIndex) { CargoPath[] pathPool = _planet.cargoTraffic.pathPool; var (num, num2) = GetWorkChunkIndices(_planet.cargoTraffic.pathCursor, _maxWorkCount, _workIndex); if (num2 == 0) { return; } DeepProfiler.BeginSample((DPEntry)33, workerIndex, -1L); for (int i = Math.Max(1, num); i < num + num2; i++) { CargoPath val = pathPool[i]; if (val != null && val.id == i) { val.PresentCargos(); } } DeepProfiler.EndSample((DPEntry)33, workerIndex); } internal static (int startIndex, int workLength) GetWorkChunkIndices(int totalLength, int maxWorkCount, int workIndex) { int num = (totalLength + maxWorkCount - 1) / maxWorkCount; int num2 = num * workIndex; int num3 = Math.Min(num, totalLength - num2); if (num3 <= 0) { return (0, 0); } return (num2, num3); } } } namespace Weaver.Optimizations.Turrets { [StructLayout(LayoutKind.Sequential, Pack = 1)] internal readonly struct OptimizedTurret { private readonly OptimizedIndexedCargoPath targetBelt; private readonly int targetBeltOffset; public readonly int turretIndex; public OptimizedTurret(OptimizedIndexedCargoPath targetBelt, int targetBeltOffset, int turretIndex) { this.targetBelt = targetBelt; this.targetBeltOffset = targetBeltOffset; this.turretIndex = turretIndex; } public static bool NeedToCheckBelt(ref TurretComponent turret) { if (turret.targetBeltId == 0 || turret.itemCount >= 5) { return false; } return true; } public void BeltUpdate(ref TurretComponent turret, Dictionary beltLocks) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) if (!targetBelt.HasBelt || turret.itemCount >= 5) { return; } lock (beltLocks[targetBelt.BeltIndex]) { OptimizedCargo cargo2; if (turret.itemId == 0) { if (targetBelt.Belt.TryPickItem(targetBeltOffset - 2, 5, 0, ItemProto.turretNeeds[turret.ammoType], out var cargo)) { ((TurretComponent)(ref turret)).SetNewItem((int)cargo.Item, (short)cargo.Stack, (short)cargo.Inc); } } else if (targetBelt.Belt.TryPickItem(targetBeltOffset - 2, 5, turret.itemId, out cargo2)) { ref short itemCount = ref turret.itemCount; itemCount += cargo2.Stack; ref short itemInc = ref turret.itemInc; itemInc += cargo2.Inc; } } } } internal sealed class TurretExecutor { private readonly OptimizedTurret[] _optimizedTurrets; private readonly Dictionary _turretIdToOptimizedTurretIndex; private readonly Dictionary _beltLocks; public TurretExecutor(OptimizedTurret[] optimizedTurrets, Dictionary turretIdToOptimizedTurretIndex, Dictionary beltLocks) { _optimizedTurrets = optimizedTurrets; _turretIdToOptimizedTurretIndex = turretIdToOptimizedTurretIndex; _beltLocks = beltLocks; } public void TurretBeltUpdate(ref TurretComponent turret) { int num = _turretIdToOptimizedTurretIndex[turret.id]; _optimizedTurrets[num].BeltUpdate(ref turret, _beltLocks); } } internal sealed class TurretExecutorBuilder { private readonly List _optimizedTurrets = new List(); private readonly Dictionary _turretIdToOptimizedTurretIndex = new Dictionary(); private readonly Dictionary _beltLocks = new Dictionary(); public void Initialize(PlanetFactory planet, Graph subFactoryGraph, PlanetWideProductionRegisterBuilder planetWideProductionRegisterBuilder, BeltExecutor beltExecutor) { //IL_0116: Unknown result type (might be due to invalid IL or missing references) foreach (int item in from x in subFactoryGraph.GetAllNodes() where x.EntityTypeIndex.EntityType == EntityType.Turret select x.EntityTypeIndex.Index into x orderby x select x) { ref TurretComponent reference = ref planet.defenseSystem.turrets.buffer[item]; if (reference.id != item) { continue; } OptimizedIndexedCargoPath targetBelt = OptimizedIndexedCargoPath.NoBelt; int targetBeltOffset = 0; if (beltExecutor.TryGetOptimizedCargoPathIndex(planet, reference.targetBeltId, out var beltIndex)) { targetBeltOffset = ((BeltComponent)(ref planet.cargoTraffic.beltPool[reference.targetBeltId])).pivotOnPath; targetBelt = new OptimizedIndexedCargoPath(beltExecutor.OptimizedCargoPaths, beltIndex); if (!_beltLocks.ContainsKey(beltIndex)) { _beltLocks.Add(beltIndex, new object()); } } int[] array = ItemProto.turretNeeds[reference.ammoType]; for (int i = 0; i < array.Length; i++) { planetWideProductionRegisterBuilder.AdditionalConsumeItemsIdToWatch(array[i]); } _turretIdToOptimizedTurretIndex.Add(reference.id, _optimizedTurrets.Count); _optimizedTurrets.Add(new OptimizedTurret(targetBelt, targetBeltOffset, item)); } } public TurretExecutor Build() { return new TurretExecutor(_optimizedTurrets.ToArray(), _turretIdToOptimizedTurretIndex, _beltLocks); } } } namespace Weaver.Optimizations.Tanks { [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct OptimizedTank { public const int NO_TANK = -1; private int id; private readonly BeltIndex belt0Index; private readonly BeltIndex belt1Index; private readonly BeltIndex belt2Index; private readonly BeltIndex belt3Index; private readonly bool isOutput0; private readonly bool isOutput1; private readonly bool isOutput2; private readonly bool isOutput3; private readonly int fluidCapacity; private readonly bool outputSwitch; private readonly bool inputSwitch; private readonly bool isBottom; private readonly int lastTankIndex; private readonly int nextTankIndex; private int fluidInc; public int fluidCount; public int fluidId; public OptimizedTank([In][RequiresLocation] ref TankComponent tank, int tankIndex, BeltIndex belt0Index, BeltIndex belt1Index, BeltIndex belt2Index, BeltIndex belt3Index) { id = tankIndex; lastTankIndex = int.MaxValue; nextTankIndex = int.MaxValue; this.belt0Index = belt0Index; this.belt1Index = belt1Index; this.belt2Index = belt2Index; this.belt3Index = belt3Index; isOutput0 = tank.isOutput0; isOutput1 = tank.isOutput1; isOutput2 = tank.isOutput2; isOutput3 = tank.isOutput3; fluidCapacity = tank.fluidCapacity; outputSwitch = tank.outputSwitch; inputSwitch = tank.inputSwitch; isBottom = tank.isBottom; fluidCount = tank.fluidCount; fluidInc = tank.fluidInc; fluidId = tank.fluidId; } public OptimizedTank(int? lastTankIndex, int? nextTankIndex, OptimizedTank tank) { id = tank.id; this.lastTankIndex = lastTankIndex.GetValueOrDefault(-1); this.nextTankIndex = nextTankIndex.GetValueOrDefault(-1); belt0Index = tank.belt0Index; belt1Index = tank.belt1Index; belt2Index = tank.belt2Index; belt3Index = tank.belt3Index; isOutput0 = tank.isOutput0; isOutput1 = tank.isOutput1; isOutput2 = tank.isOutput2; isOutput3 = tank.isOutput3; fluidCapacity = tank.fluidCapacity; outputSwitch = tank.outputSwitch; inputSwitch = tank.inputSwitch; isBottom = tank.isBottom; fluidCount = tank.fluidCount; fluidInc = tank.fluidInc; fluidId = tank.fluidId; } public void TickOutput(TankExecutor tankExecutor) { if (lastTankIndex == -1 || !outputSwitch) { return; } OptimizedTank optimizedTank = tankExecutor._optimizedTanks[lastTankIndex]; if (!optimizedTank.inputSwitch || (optimizedTank.fluidId > 0 && optimizedTank.fluidId != fluidId)) { return; } if (optimizedTank.fluidCount <= optimizedTank.fluidCapacity - 2) { if (fluidCount >= 2) { if (optimizedTank.fluidId == 0) { tankExecutor._optimizedTanks[lastTankIndex].fluidId = fluidId; } int n = fluidCount; int m = fluidInc; int num = 2; int num2 = split_inc(ref n, ref m, num); fluidCount -= num; fluidInc -= num2; tankExecutor._optimizedTanks[lastTankIndex].fluidCount += num; tankExecutor._optimizedTanks[lastTankIndex].fluidInc += num2; } else if (fluidCount > 0 && fluidCount < 2) { if (optimizedTank.fluidId == 0) { tankExecutor._optimizedTanks[lastTankIndex].fluidId = fluidId; } int num3 = fluidCount; int num4 = fluidInc; fluidCount = 0; fluidInc = 0; if (fluidId != 0) { fluidId = 0; } tankExecutor._optimizedTanks[lastTankIndex].fluidCount += num3; tankExecutor._optimizedTanks[lastTankIndex].fluidInc += num4; } } else { if (optimizedTank.fluidCount >= optimizedTank.fluidCapacity || optimizedTank.fluidCount <= optimizedTank.fluidCapacity - 2) { return; } int num5 = optimizedTank.fluidCapacity - optimizedTank.fluidCount; if (fluidCount >= num5) { if (optimizedTank.fluidId == 0) { tankExecutor._optimizedTanks[lastTankIndex].fluidId = fluidId; } int n2 = fluidCount; int m2 = fluidInc; int num6 = num5; int num7 = split_inc(ref n2, ref m2, num6); fluidCount -= num6; fluidInc -= num7; tankExecutor._optimizedTanks[lastTankIndex].fluidCount += num6; tankExecutor._optimizedTanks[lastTankIndex].fluidInc += num7; } else if (fluidCount > 0 && fluidCount < num5) { if (optimizedTank.fluidId == 0) { tankExecutor._optimizedTanks[lastTankIndex].fluidId = fluidId; } int num8 = fluidCount; int num9 = fluidInc; fluidCount = 0; fluidInc = 0; if (fluidId != 0) { fluidId = 0; } tankExecutor._optimizedTanks[lastTankIndex].fluidCount += num8; tankExecutor._optimizedTanks[lastTankIndex].fluidInc += num9; } } } public void GameTick(TankExecutor tankExecutor, OptimizedCargoPath[] optimizedCargoPaths) { if (fluidInc < 0) { fluidInc = 0; } if (isBottom) { byte stack = 0; byte inc = 0; UpdateTankBelt(belt0Index, isOutput0, tankExecutor, ref stack, ref inc, optimizedCargoPaths); UpdateTankBelt(belt1Index, isOutput1, tankExecutor, ref stack, ref inc, optimizedCargoPaths); UpdateTankBelt(belt2Index, isOutput2, tankExecutor, ref stack, ref inc, optimizedCargoPaths); UpdateTankBelt(belt3Index, isOutput3, tankExecutor, ref stack, ref inc, optimizedCargoPaths); } } public readonly void Save(ref TankComponent tank) { tank.fluidCount = fluidCount; tank.fluidInc = fluidInc; tank.fluidId = fluidId; } private void UpdateTankBelt(BeltIndex beltIndex, bool isOutput, TankExecutor tankExecutor, ref byte stack, ref byte inc, OptimizedCargoPath[] optimizedCargoPaths) { if (!beltIndex.HasValue) { return; } ref OptimizedCargoPath belt = ref beltIndex.GetBelt(optimizedCargoPaths); if (isOutput && outputSwitch) { if (fluidId > 0 && fluidCount > 0) { int num = ((fluidInc != 0) ? (fluidInc / fluidCount) : 0); if (belt.TryInsertItemAtHeadAndFillBlank(fluidId, 1, (byte)num)) { fluidCount--; fluidInc -= num; } } } else { if (isOutput || !inputSwitch) { return; } if (fluidId > 0 && fluidCount < fluidCapacity) { OptimizedCargo cargo; bool num2 = CargoPathMethods.TryPickItemAtRear(ref belt, fluidId, null, out cargo); stack = cargo.Stack; inc = cargo.Inc; if (num2) { fluidCount += stack; fluidInc += inc; } } if (fluidId == 0) { OptimizedCargo cargo2; bool num3 = CargoPathMethods.TryPickItemAtRear(ref belt, 0, ItemProto.fluids, out cargo2); stack = cargo2.Stack; inc = cargo2.Inc; if (num3) { fluidId = cargo2.Item; fluidCount += stack; fluidInc += inc; } } if (fluidCount < fluidCapacity) { return; } belt.TryGetCargoIdAtRear(out var cargo3); if (cargo3.Item != fluidId || nextTankIndex <= -1) { return; } OptimizedTank optimizedTank = tankExecutor._optimizedTanks[nextTankIndex]; OptimizedTank optimizedTank2 = optimizedTank; while (optimizedTank.fluidCount >= optimizedTank.fluidCapacity) { OptimizedTank optimizedTank3 = tankExecutor._optimizedTanks[optimizedTank2.lastTankIndex]; if (optimizedTank.fluidId != optimizedTank3.fluidId) { optimizedTank2 = optimizedTank3; break; } if (optimizedTank.inputSwitch) { if (optimizedTank.nextTankIndex > -1) { optimizedTank = tankExecutor._optimizedTanks[optimizedTank.nextTankIndex]; optimizedTank2 = optimizedTank; continue; } optimizedTank2.id = id; break; } optimizedTank2 = tankExecutor._optimizedTanks[optimizedTank2.lastTankIndex]; break; } OptimizedTank optimizedTank4 = tankExecutor._optimizedTanks[optimizedTank2.lastTankIndex]; if (!optimizedTank2.inputSwitch || (optimizedTank2.fluidId != optimizedTank4.fluidId && optimizedTank2.fluidId != 0)) { optimizedTank2 = optimizedTank4; } bool flag = true; if (optimizedTank2.id == id || optimizedTank2.fluidCount >= optimizedTank2.fluidCapacity || !optimizedTank4.outputSwitch) { flag = false; } if (!flag) { return; } OptimizedCargo cargo4; bool num4 = CargoPathMethods.TryPickItemAtRear(ref belt, fluidId, null, out cargo4); stack = cargo4.Stack; inc = cargo4.Inc; if (num4) { if (tankExecutor._optimizedTanks[optimizedTank2.id].fluidCount == 0) { tankExecutor._optimizedTanks[optimizedTank2.id].fluidId = fluidId; } tankExecutor._optimizedTanks[optimizedTank2.id].fluidCount += stack; tankExecutor._optimizedTanks[optimizedTank2.id].fluidInc += inc; } } } private static int split_inc(ref int n, ref int m, int p) { if (n == 0) { return 0; } int num = m / n; int num2 = m - num * n; n -= p; num2 -= n; num = ((num2 > 0) ? (num * p + num2) : (num * p)); m -= num; return num; } } internal sealed class TankExecutor { public OptimizedTank[] _optimizedTanks; private Dictionary _tankIdToOptimizedTankIndex; public int Count => _optimizedTanks.Length; public void GameTick(OptimizedCargoPath[] optimizedCargoPaths) { OptimizedTank[] optimizedTanks = _optimizedTanks; for (int i = 0; i < optimizedTanks.Length; i++) { ref OptimizedTank reference = ref optimizedTanks[i]; reference.GameTick(this, optimizedCargoPaths); reference.TickOutput(this); if (reference.fluidCount == 0) { reference.fluidId = 0; } } } public void Save(PlanetFactory planet) { TankComponent[] tankPool = planet.factoryStorage.tankPool; OptimizedTank[] optimizedTanks = _optimizedTanks; for (int i = 1; i < planet.factoryStorage.tankCursor; i++) { if (_tankIdToOptimizedTankIndex.TryGetValue(i, out var value)) { optimizedTanks[value].Save(ref tankPool[i]); } } } public void Initialize(PlanetFactory planet, Graph subFactoryGraph, BeltExecutor beltExecutor) { List list = new List(); Dictionary dictionary = new Dictionary(); int[] array = (from x in subFactoryGraph.GetAllNodes() where x.EntityTypeIndex.EntityType == EntityType.Tank select x.EntityTypeIndex.Index into x orderby x select x).ToArray(); foreach (int num in array) { ref TankComponent reference = ref planet.factoryStorage.tankPool[num]; if (reference.id == num) { beltExecutor.TryGetOptimizedCargoPathIndex(planet, reference.belt0, out var beltIndex); beltExecutor.TryGetOptimizedCargoPathIndex(planet, reference.belt1, out var beltIndex2); beltExecutor.TryGetOptimizedCargoPathIndex(planet, reference.belt2, out var beltIndex3); beltExecutor.TryGetOptimizedCargoPathIndex(planet, reference.belt3, out var beltIndex4); int count = list.Count; dictionary.Add(reference.id, count); list.Add(new OptimizedTank(ref reference, count, beltIndex, beltIndex2, beltIndex3, beltIndex4)); } } foreach (int num2 in array) { ref TankComponent reference2 = ref planet.factoryStorage.tankPool[num2]; if (reference2.id == num2) { int? nextTankIndex = null; if (reference2.nextTankId > 0) { nextTankIndex = dictionary[reference2.nextTankId]; } int? lastTankIndex = null; if (reference2.lastTankId > 0) { lastTankIndex = dictionary[reference2.lastTankId]; } list[dictionary[reference2.id]] = new OptimizedTank(lastTankIndex, nextTankIndex, list[dictionary[reference2.id]]); } } _optimizedTanks = list.ToArray(); _tankIdToOptimizedTankIndex = dictionary; } } } namespace Weaver.Optimizations.Storages { internal sealed class OptimizedStorage { public static bool TakeTailItems(StorageComponent storageComponent, ref int itemId, ref int count, ComponentNeeds componentNeeds, short[] needsPatterns, int needsSize, out int inc, bool useBan = false) { inc = 0; if (count == 0) { itemId = 0; count = 0; return false; } bool result = false; int num = count; count = 0; for (int num2 = (useBan ? (storageComponent.size - storageComponent.bans - 1) : (storageComponent.size - 1)); num2 >= 0; num2--) { if (storageComponent.grids[num2].itemId != 0 && storageComponent.grids[num2].count != 0 && (itemId == 0 || storageComponent.grids[num2].itemId == itemId)) { result = true; if (IsInNeed(storageComponent.grids[num2].itemId, componentNeeds, needsPatterns, needsSize)) { itemId = storageComponent.grids[num2].itemId; if (storageComponent.grids[num2].count > num) { inc += storageComponent.split_inc(ref storageComponent.grids[num2].count, ref storageComponent.grids[num2].inc, num); count += num; break; } inc += storageComponent.grids[num2].inc; count += storageComponent.grids[num2].count; num -= storageComponent.grids[num2].count; storageComponent.grids[num2].itemId = storageComponent.grids[num2].filter; storageComponent.grids[num2].count = 0; storageComponent.grids[num2].inc = 0; if (storageComponent.grids[num2].filter == 0) { storageComponent.grids[num2].stackSize = 0; } } } } if (count == 0) { itemId = 0; count = 0; } else { storageComponent.lastFullItem = -1; storageComponent.NotifyStorageChange(); } return result; } public static bool TakeTailFuel(StorageComponent storageComponent, ref int itemId, ref int count, OptimizedItemId[]? fuelMask, out int inc, bool useBan = false) { inc = 0; if (count == 0) { itemId = 0; count = 0; return false; } bool result = false; int num = count; count = 0; for (int num2 = (useBan ? (storageComponent.size - storageComponent.bans - 1) : (storageComponent.size - 1)); num2 >= 0; num2--) { if (storageComponent.grids[num2].itemId != 0 && storageComponent.grids[num2].count != 0 && (itemId == 0 || storageComponent.grids[num2].itemId == itemId)) { result = true; for (int i = 0; i < fuelMask.Length; i++) { if (fuelMask[i].ItemIndex == storageComponent.grids[num2].itemId) { itemId = storageComponent.grids[num2].itemId; if (storageComponent.grids[num2].count > num) { inc += storageComponent.split_inc(ref storageComponent.grids[num2].count, ref storageComponent.grids[num2].inc, num); count += num; num = 0; break; } inc += storageComponent.grids[num2].inc; count += storageComponent.grids[num2].count; num -= storageComponent.grids[num2].count; storageComponent.grids[num2].itemId = storageComponent.grids[num2].filter; storageComponent.grids[num2].count = 0; storageComponent.grids[num2].inc = 0; if (storageComponent.grids[num2].filter == 0) { storageComponent.grids[num2].stackSize = 0; } } } } } if (count == 0) { itemId = 0; count = 0; } else { storageComponent.lastFullItem = -1; storageComponent.NotifyStorageChange(); } return result; } private static bool IsInNeed(int productItemIndex, ComponentNeeds componentNeeds, short[] needsPatterns, int needsSize) { for (int i = 0; i < needsSize; i++) { if (componentNeeds.GetNeeds(i) && needsPatterns[componentNeeds.PatternIndex + i] == productItemIndex) { return true; } } return false; } } } namespace Weaver.Optimizations.Statistics { public class CustomChartsPatches { [HarmonyPrefix] [HarmonyPatch(typeof(CustomCharts), "GameTick")] private static bool GameTick_Parallelize(CustomCharts __instance) { new ParallelOptions().MaxDegreeOfParallelism = WeaverThreadHelper.GetParallelism(); 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; } } internal static class KillStatisticsPatches { private static bool?[]? _isStarUpdated; private static List[]? _starsStatistics; private static bool?[]? _isPlanetUpdated; private static List[]? _planetsStatistics; internal static void Clear() { _isStarUpdated = null; _starsStatistics = null; _isPlanetUpdated = null; _planetsStatistics = null; } [HarmonyPrefix] [HarmonyPatch(typeof(KillStatistics), "PrepareTick")] private static bool PrepareTick_Parallelize(KillStatistics __instance) { if (_isStarUpdated == null || __instance.starKillStatPool.Length != _isStarUpdated.Length) { _isStarUpdated = new bool?[__instance.starKillStatPool.Length]; _starsStatistics = new List[__instance.starKillStatPool.Length]; GetKillStatsForWholeStartCluster(__instance.starKillStatPool, _starsStatistics); } if (_isPlanetUpdated == null || __instance.factoryKillStatPool.Length != _isPlanetUpdated.Length) { _isPlanetUpdated = new bool?[__instance.factoryKillStatPool.Length]; _planetsStatistics = new List[__instance.factoryKillStatPool.Length]; GetKillStatsForWholeStartCluster(__instance.factoryKillStatPool, _planetsStatistics); } return false; } private static void GetKillStatsForWholeStartCluster(AstroKillStat?[] astroStatistics, List[] clusterStatistics) { for (int i = 0; i < astroStatistics.Length; i++) { List list = (clusterStatistics[i] = new List()); AstroKillStat val = astroStatistics[i]; if (val == null) { continue; } for (int j = 0; j <= ModelProto.maxModelIndex; j++) { if (val.killStatPool[j] != null) { list.Add(val.killStatPool[j]); } } } } [HarmonyPrefix] [HarmonyPatch(typeof(KillStatistics), "RegisterStarKillStat")] private static void RegisterStarKillStat(int starId) { if (_isStarUpdated != null && !_isStarUpdated[starId].GetValueOrDefault()) { _isStarUpdated[starId] = true; } } [HarmonyPrefix] [HarmonyPatch(typeof(KillStatistics), "RegisterFactoryKillStat")] private static void RegisterFactoryKillStat(int factoryIndex) { if (_isPlanetUpdated != null && !_isPlanetUpdated[factoryIndex].GetValueOrDefault()) { _isPlanetUpdated[factoryIndex] = true; } } [HarmonyPrefix] [HarmonyPatch(typeof(KillStatistics), "GameTick")] private static bool GameTick_Parallelize(KillStatistics __instance, long time) { KillStatistics __instance2 = __instance; bool?[] isStarUpdated = _isStarUpdated; if (isStarUpdated == null) { throw new InvalidOperationException("isStarUpdated was null"); } List[] starsStatistics = _starsStatistics; if (starsStatistics == null) { throw new InvalidOperationException("starsStatistics was null"); } bool?[] isPlanetUpdated = _isPlanetUpdated; if (isPlanetUpdated == null) { throw new InvalidOperationException("isPlanetUpdated was null"); } List[] planetsStatistics = _planetsStatistics; if (planetsStatistics == null) { throw new InvalidOperationException("planetsStatistics was null"); } ParallelOptions parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = WeaverThreadHelper.GetParallelism() }; Parallel.For(0, __instance2.starKillStatPool.Length + __instance2.factoryKillStatPool.Length, parallelOptions, delegate(int i) { if (i < __instance2.starKillStatPool.Length) { KillStatGameTick(__instance2.starKillStatPool, isStarUpdated, starsStatistics, i, time); } else { KillStatGameTick(__instance2.factoryKillStatPool, isPlanetUpdated, planetsStatistics, i - __instance2.starKillStatPool.Length, time); } }); AstroKillStat mechaKillStat = __instance2.mechaKillStat; if (mechaKillStat != null) { mechaKillStat.GameTick(time); } return false; } private static void KillStatGameTick(AstroKillStat[] astroStatistics, bool?[] isStatisticsUpdated, List[] statistics, int statisticsIndex, long time) { if (isStatisticsUpdated[statisticsIndex].GetValueOrDefault() || !isStatisticsUpdated[statisticsIndex].HasValue) { GameTick(astroStatistics[statisticsIndex], statistics[statisticsIndex], time); isStatisticsUpdated[statisticsIndex] = false; } else { OptimizeGameTick(astroStatistics[statisticsIndex], statistics[statisticsIndex], time); } } private static void GameTick(AstroKillStat? astroKillStat, List killStats, long time) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown if (astroKillStat == null) { return; } if (time % 1 == 0L) { int num = 0; int num2 = 6; int[] killRegister = astroKillStat.killRegister; for (int i = 0; i <= ModelProto.maxModelIndex; i++) { int num3 = killRegister[i]; killRegister[i] = 0; if (astroKillStat.killStatPool[i] == null) { if (num3 == 0) { continue; } astroKillStat.killStatPool[i] = new KillStat(); astroKillStat.killStatPool[i].Init(i); killStats.Add(astroKillStat.killStatPool[i]); } KillStat obj = astroKillStat.killStatPool[i]; int[] count = obj.count; int[] cursor = obj.cursor; int[] total = obj.total; int num4 = cursor[num]; int num5 = num3 - count[num4]; count[num4] = num3; total[num] += num5; total[num2] += num3; cursor[num]++; if (cursor[num] >= 600) { cursor[num] -= 600; } } } if (time % 6 == 0L) { int num6 = 1; astroKillStat.ComputeTheMiddleLevel(num6); } if (time % 60 == 0L) { int num7 = 2; astroKillStat.ComputeTheMiddleLevel(num7); } if (time % 360 == 0L) { int num8 = 3; astroKillStat.ComputeTheMiddleLevel(num8); } if (time % 3600 == 0L) { int num9 = 4; astroKillStat.ComputeTheMiddleLevel(num9); } if (time % 36000 == 0L) { int num10 = 5; astroKillStat.ComputeTheMiddleLevel(num10); } } private static void OptimizeGameTick(AstroKillStat? astroKillStat, List killStats, long time) { if (astroKillStat == null) { return; } if (time % 1 == 0L) { int num = 0; int num2 = 6; for (int i = 0; i < killStats.Count; i++) { int num3 = 0; KillStat obj = killStats[i]; int[] count = obj.count; int[] cursor = obj.cursor; int[] total = obj.total; int num4 = cursor[num]; int num5 = num3 - count[num4]; count[num4] = num3; total[num] += num5; total[num2] += num3; cursor[num]++; if (cursor[num] >= 600) { cursor[num] -= 600; } } } if (time % 6 == 0L) { int num6 = 1; astroKillStat.ComputeTheMiddleLevel(num6); } if (time % 60 == 0L) { int num7 = 2; astroKillStat.ComputeTheMiddleLevel(num7); } if (time % 360 == 0L) { int num8 = 3; astroKillStat.ComputeTheMiddleLevel(num8); } if (time % 3600 == 0L) { int num9 = 4; astroKillStat.ComputeTheMiddleLevel(num9); } if (time % 36000 == 0L) { int num10 = 5; astroKillStat.ComputeTheMiddleLevel(num10); } } } internal readonly struct OptimizedItemId : IEquatable, IMemorySize { public readonly short ItemIndex; public readonly short OptimizedItemIndex; public OptimizedItemId(int itemIndex, int optimizedItemIndex) { if (itemIndex > 32767 || itemIndex < -32768) { throw new InvalidOperationException("Assumption that itemIndex first in a short is not correct."); } if (optimizedItemIndex > 32767 || optimizedItemIndex < -32768) { throw new InvalidOperationException("Assumption that optimizedItemIndex first in a short is not correct."); } ItemIndex = (short)itemIndex; OptimizedItemIndex = (short)optimizedItemIndex; } public int GetSize() { return Marshal.SizeOf(); } public bool Equals(OptimizedItemId other) { if (ItemIndex == other.ItemIndex) { return OptimizedItemIndex == other.OptimizedItemIndex; } return false; } public override bool Equals(object obj) { if (obj is OptimizedItemId other) { return Equals(other); } return false; } public override int GetHashCode() { return HashCode.Combine(ItemIndex, OptimizedItemIndex); } } internal sealed class OptimizedPlanetWideProductionStatistics { private readonly ReadonlyArray _productIndexes; private readonly ReadonlyArray _consumeIndexes; private readonly ReadonlyArray _additionalProductsToWatch; private readonly ReadonlyArray _additionalConsumesToWatch; private readonly OptimizedProductionStatistics[] _optimizedProductionStatistics = Array.Empty(); private readonly FactoryProductionStat _factoryProductionStat; private readonly int[] _sumProductRegister; private readonly int[] _sumConsumeRegister; public OptimizedPlanetWideProductionStatistics(ReadonlyArray productIndexes, ReadonlyArray consumeIndexes, ReadonlyArray additionalProductsToWatch, ReadonlyArray additionalConsumesToWatch, OptimizedProductionStatistics[] optimizedProductionStatistics, FactoryProductionStat factoryProductionStat) { _productIndexes = productIndexes; _consumeIndexes = consumeIndexes; _additionalProductsToWatch = additionalProductsToWatch; _additionalConsumesToWatch = additionalConsumesToWatch; _optimizedProductionStatistics = optimizedProductionStatistics; _factoryProductionStat = factoryProductionStat; _sumProductRegister = new int[productIndexes.Length]; _sumConsumeRegister = new int[consumeIndexes.Length]; } public void UpdateStatistics(long time, int[] gameProductRegister, int[] gameConsumeRegister) { int[] sumProductRegister = _sumProductRegister; int[] sumConsumeRegister = _sumConsumeRegister; OptimizedProductionStatistics[] optimizedProductionStatistics = _optimizedProductionStatistics; for (int i = 0; i < optimizedProductionStatistics.Length; i++) { optimizedProductionStatistics[i].AddToPlanetWideProductionStatistics(sumProductRegister, sumConsumeRegister); } AddItemsToWatch(gameProductRegister, sumProductRegister, _additionalProductsToWatch); AddItemsToWatch(gameConsumeRegister, sumConsumeRegister, _additionalConsumesToWatch); GameTick(time); Array.Clear(sumProductRegister, 0, sumProductRegister.Length); Array.Clear(sumConsumeRegister, 0, sumConsumeRegister.Length); for (int j = 0; j < optimizedProductionStatistics.Length; j++) { optimizedProductionStatistics[j].Clear(); } } private void GameTick(long time) { FactoryProductionStat factoryProductionStat = _factoryProductionStat; if (time % 1 == 0L) { int num = 0; int num2 = 6; int num3 = 6 + num; int num4 = 7 + num; int num5 = 13; int num6 = 4200; ReadonlyArray productIndexes = _productIndexes; int[] sumProductRegister = _sumProductRegister; for (int i = 0; i < productIndexes.Length; i++) { OptimizedItemId optimizedItemId = productIndexes[i]; int itemIndex = optimizedItemId.ItemIndex; int num7 = sumProductRegister[optimizedItemId.OptimizedItemIndex]; int num8 = factoryProductionStat.productIndices[itemIndex]; if (num8 <= 0) { if (num7 <= 0) { continue; } int productCursor = factoryProductionStat.productCursor; factoryProductionStat.CreateProductStat(itemIndex); factoryProductionStat.productIndices[itemIndex] = productCursor; num8 = productCursor; } ProductStat obj = factoryProductionStat.productPool[num8]; int[] count = obj.count; int[] cursor = obj.cursor; long[] total = obj.total; int num9 = cursor[num]; int num10 = num7 - count[num9]; count[num9] = num7; total[num] += num10; total[num2] += num7; cursor[num]++; if (cursor[num] >= 600) { cursor[num] -= 600; } } ReadonlyArray consumeIndexes = _consumeIndexes; int[] sumConsumeRegister = _sumConsumeRegister; for (int j = 0; j < consumeIndexes.Length; j++) { OptimizedItemId optimizedItemId2 = consumeIndexes[j]; int itemIndex2 = optimizedItemId2.ItemIndex; int num11 = sumConsumeRegister[optimizedItemId2.OptimizedItemIndex]; int num12 = factoryProductionStat.productIndices[itemIndex2]; if (num12 <= 0) { if (num11 <= 0) { continue; } int productCursor2 = factoryProductionStat.productCursor; factoryProductionStat.CreateProductStat(itemIndex2); factoryProductionStat.productIndices[itemIndex2] = productCursor2; num12 = productCursor2; } ProductStat obj2 = factoryProductionStat.productPool[num12]; int[] count2 = obj2.count; int[] cursor2 = obj2.cursor; long[] total2 = obj2.total; int num13 = cursor2[num3]; int num14 = num11 - count2[num13]; count2[num13] = num11; total2[num4] += num14; total2[num5] += num11; cursor2[num3]++; if (cursor2[num3] >= num6) { cursor2[num3] -= 600; } } for (int k = 0; k < factoryProductionStat.powerPool.Length; k++) { PowerStat obj3 = factoryProductionStat.powerPool[k]; long[] energy = obj3.energy; long[] total3 = obj3.total; int[] cursor3 = obj3.cursor; long num15 = 0L; switch (k) { case 0: num15 = factoryProductionStat.powerGenRegister; break; case 1: num15 = factoryProductionStat.powerConRegister; break; case 2: num15 = factoryProductionStat.powerChaRegister; break; case 3: num15 = factoryProductionStat.powerDisRegister; break; case 4: num15 = factoryProductionStat.hashRegister; break; } int num16 = cursor3[num]; long num17 = num15 - energy[num16]; energy[num16] = num15; total3[num] += num17; total3[num2] += num15; cursor3[num]++; if (cursor3[num] >= 600) { cursor3[num] -= 600; } } } if (time % 6 == 0L) { int num18 = 1; factoryProductionStat.ComputeTheMiddleLevel(num18); } if (time % 60 == 0L) { int num19 = 2; factoryProductionStat.ComputeTheMiddleLevel(num19); } if (time % 360 == 0L) { int num20 = 3; factoryProductionStat.ComputeTheMiddleLevel(num20); } if (time % 3600 == 0L) { int num21 = 4; factoryProductionStat.ComputeTheMiddleLevel(num21); } if (time % 36000 == 0L) { int num22 = 5; factoryProductionStat.ComputeTheMiddleLevel(num22); } } public static void AddItemsToWatch(int[] gameRegister, int[] optimizedRegister, ReadonlyArray additionalItemsToWatch) { for (int i = 0; i < additionalItemsToWatch.Length; i++) { ItemIdWithOptimizedRegisterIndex itemIdWithOptimizedRegisterIndex = additionalItemsToWatch[i]; optimizedRegister[itemIdWithOptimizedRegisterIndex.OptimizedRegisterIndex] += gameRegister[itemIdWithOptimizedRegisterIndex.ItemIndex]; gameRegister[itemIdWithOptimizedRegisterIndex.ItemIndex] = 0; } } } internal readonly struct OptimizedProductionStatistics { private readonly ReadonlyArray _planetWideOptimizedProductIndex; private readonly ReadonlyArray _planetWideOptimizedConsumeIndex; public readonly int[] ProductRegister; public readonly int[] ConsumeRegister; public OptimizedProductionStatistics(ReadonlyArray planetWideOptimizedProductIndex, ReadonlyArray planetWideOptimizedConsumeIndex) { _planetWideOptimizedProductIndex = planetWideOptimizedProductIndex; _planetWideOptimizedConsumeIndex = planetWideOptimizedConsumeIndex; ProductRegister = new int[planetWideOptimizedProductIndex.Length]; ConsumeRegister = new int[planetWideOptimizedConsumeIndex.Length]; } public void AddToPlanetWideProductionStatistics(int[] sumProductRegister, int[] sumConsumeRegister) { ReadonlyArray planetWideOptimizedProductIndex = _planetWideOptimizedProductIndex; int[] productRegister = ProductRegister; for (int i = 0; i < planetWideOptimizedProductIndex.Length; i++) { sumProductRegister[planetWideOptimizedProductIndex[i]] += productRegister[i]; } ReadonlyArray planetWideOptimizedConsumeIndex = _planetWideOptimizedConsumeIndex; int[] consumeRegister = ConsumeRegister; for (int j = 0; j < planetWideOptimizedConsumeIndex.Length; j++) { sumConsumeRegister[planetWideOptimizedConsumeIndex[j]] += consumeRegister[j]; } } public void Clear() { Array.Clear(ProductRegister, 0, ProductRegister.Length); Array.Clear(ConsumeRegister, 0, ConsumeRegister.Length); } } internal sealed class PlanetWideProductionRegisterBuilder { private readonly PlanetFactory _planet; private readonly Dictionary _productIndexToOptimizedProductIndex = new Dictionary(); private readonly Dictionary _consumeIndexToOptimizedConsumeIndex = new Dictionary(); private readonly Dictionary _productIndexToItemIdWithOptimizedRegisterIndex = new Dictionary(); private readonly Dictionary _consumeIndexToItemIdWithOptimizedRegisterIndex = new Dictionary(); private readonly List _optimizedProductionStatistics = new List(); public PlanetWideProductionRegisterBuilder(PlanetFactory planet) { _planet = planet; } public SubFactoryProductionRegisterBuilder GetSubFactoryBuilder() { return new SubFactoryProductionRegisterBuilder(this); } public int AddProduct(int productIndex) { if (!_productIndexToOptimizedProductIndex.TryGetValue(productIndex, out var value)) { value = _productIndexToOptimizedProductIndex.Count; _productIndexToOptimizedProductIndex.Add(productIndex, value); } return value; } public int AddConsume(int consumeIndex) { if (!_consumeIndexToOptimizedConsumeIndex.TryGetValue(consumeIndex, out var value)) { value = _consumeIndexToOptimizedConsumeIndex.Count; _consumeIndexToOptimizedConsumeIndex.Add(consumeIndex, value); } return value; } public void AddOptimizedProductionStatistics([In][RequiresLocation] ref OptimizedProductionStatistics optimizedProductionStatistics) { _optimizedProductionStatistics.Add(optimizedProductionStatistics); } public void AdditionalProductItemsIdToWatch(int itemId) { if (!_productIndexToItemIdWithOptimizedRegisterIndex.TryGetValue(itemId, out var _)) { int optimizedRegisterIndex = AddProduct(itemId); _productIndexToItemIdWithOptimizedRegisterIndex.Add(itemId, new ItemIdWithOptimizedRegisterIndex(itemId, optimizedRegisterIndex)); } } public void AdditionalConsumeItemsIdToWatch(int itemId) { if (!_consumeIndexToItemIdWithOptimizedRegisterIndex.TryGetValue(itemId, out var _)) { int optimizedRegisterIndex = AddConsume(itemId); _consumeIndexToItemIdWithOptimizedRegisterIndex.Add(itemId, new ItemIdWithOptimizedRegisterIndex(itemId, optimizedRegisterIndex)); } } public OptimizedPlanetWideProductionStatistics Build(UniverseStaticDataBuilder universeStaticDataBuilder) { if (CanPickupItemsFromEnemy(_planet)) { int[] enemyDropRangeTable = ItemProto.enemyDropRangeTable; for (int i = 0; i < enemyDropRangeTable.Length; i++) { AdditionalProductItemsIdToWatch(enemyDropRangeTable[i]); } } if (HasStationConsumingWarpers(_planet)) { AdditionalConsumeItemsIdToWatch(1210); } OptimizedItemId[] toDeduplicate = (from x in _productIndexToOptimizedProductIndex select new OptimizedItemId(x.Key, x.Value) into x orderby x.ItemIndex select x).ToArray(); OptimizedItemId[] toDeduplicate2 = (from x in _consumeIndexToOptimizedConsumeIndex select new OptimizedItemId(x.Key, x.Value) into x orderby x.ItemIndex select x).ToArray(); ItemIdWithOptimizedRegisterIndex[] toDeduplicate3 = _productIndexToItemIdWithOptimizedRegisterIndex.Values.OrderBy((ItemIdWithOptimizedRegisterIndex x) => x.ItemIndex).ToArray(); ItemIdWithOptimizedRegisterIndex[] toDeduplicate4 = _consumeIndexToItemIdWithOptimizedRegisterIndex.Values.OrderBy((ItemIdWithOptimizedRegisterIndex x) => x.ItemIndex).ToArray(); return new OptimizedPlanetWideProductionStatistics(universeStaticDataBuilder.DeduplicateArray(toDeduplicate), universeStaticDataBuilder.DeduplicateArray(toDeduplicate2), universeStaticDataBuilder.DeduplicateArray(toDeduplicate3), universeStaticDataBuilder.DeduplicateArray(toDeduplicate4), _optimizedProductionStatistics.ToArray(), GameMain.statistics.production.factoryStatPool[_planet.index]); } private static bool CanPickupItemsFromEnemy(PlanetFactory planet) { if (planet.defenseSystem.battleBases.count == 0) { return false; } bool flag = false; for (int i = 1; i < planet.defenseSystem.battleBases.cursor; i++) { ref BattleBaseComponent reference = ref planet.defenseSystem.battleBases.buffer[i]; if (reference != null && reference.id == i && reference.autoPickEnabled) { flag = true; } } if (!flag) { return false; } return true; } private static bool HasStationConsumingWarpers(PlanetFactory planet) { for (int i = 1; i < planet.transport.stationCursor; i++) { StationComponent val = planet.transport.stationPool[i]; if (val != null && val.id == i) { return true; } } return false; } } internal readonly struct ItemIdWithOptimizedRegisterIndex : IEquatable, IMemorySize { public readonly short ItemIndex; public readonly short OptimizedRegisterIndex; public ItemIdWithOptimizedRegisterIndex(int itemIndex, int optimizedRegisterIndex) { if (itemIndex > 32767 || itemIndex < -32768) { throw new InvalidOperationException("Assumption that itemIndex first in a short is not correct."); } if (optimizedRegisterIndex > 32767 || optimizedRegisterIndex < -32768) { throw new InvalidOperationException("Assumption that optimizedRegisterIndex first in a short is not correct."); } ItemIndex = (short)itemIndex; OptimizedRegisterIndex = (short)optimizedRegisterIndex; } public int GetSize() { return Marshal.SizeOf(); } public bool Equals(ItemIdWithOptimizedRegisterIndex other) { if (ItemIndex == other.ItemIndex) { return OptimizedRegisterIndex == other.OptimizedRegisterIndex; } return false; } public override bool Equals(object obj) { if (obj is ItemIdWithOptimizedRegisterIndex other) { return Equals(other); } return false; } public override int GetHashCode() { return HashCode.Combine(ItemIndex, OptimizedRegisterIndex); } } internal sealed class SubFactoryProductionRegisterBuilder { private record struct OptimizedIndexes(int SubFactoryOptimizedIndex, int PlanetWideOptimizedIndex); private readonly PlanetWideProductionRegisterBuilder _planetWideProductionRegisterBuilder; private readonly Dictionary _productIndexToOptimizedProductIndexes = new Dictionary(); private readonly Dictionary _consumeIndexToOptimizedConsumeIndexes = new Dictionary(); public SubFactoryProductionRegisterBuilder(PlanetWideProductionRegisterBuilder planetWideProductionRegisterBuilder) { _planetWideProductionRegisterBuilder = planetWideProductionRegisterBuilder; } public OptimizedItemId AddProduct(int productIndex) { int planetWideOptimizedIndex = _planetWideProductionRegisterBuilder.AddProduct(productIndex); if (!_productIndexToOptimizedProductIndexes.TryGetValue(productIndex, out var value)) { value = new OptimizedIndexes(_productIndexToOptimizedProductIndexes.Count, planetWideOptimizedIndex); _productIndexToOptimizedProductIndexes.Add(productIndex, value); } return new OptimizedItemId(productIndex, value.SubFactoryOptimizedIndex); } public OptimizedItemId[] AddProduct(int[] productIndexes) { OptimizedItemId[] array = new OptimizedItemId[productIndexes.Length]; for (int i = 0; i < productIndexes.Length; i++) { array[i] = AddProduct(productIndexes[i]); } return array; } public OptimizedItemId AddConsume(int consumeIndex) { int planetWideOptimizedIndex = _planetWideProductionRegisterBuilder.AddConsume(consumeIndex); if (!_consumeIndexToOptimizedConsumeIndexes.TryGetValue(consumeIndex, out var value)) { value = new OptimizedIndexes(_consumeIndexToOptimizedConsumeIndexes.Count, planetWideOptimizedIndex); _consumeIndexToOptimizedConsumeIndexes.Add(consumeIndex, value); } return new OptimizedItemId(consumeIndex, value.SubFactoryOptimizedIndex); } public OptimizedItemId[] AddConsume(int[] consumeIndexes) { OptimizedItemId[] array = new OptimizedItemId[consumeIndexes.Length]; for (int i = 0; i < consumeIndexes.Length; i++) { array[i] = AddConsume(consumeIndexes[i]); } return array; } public OptimizedProductionStatistics Build(UniverseStaticDataBuilder universeStaticDataBuilder) { ReadonlyArray planetWideOptimizedProductIndex = universeStaticDataBuilder.DeduplicateArrayUnmanaged((from x in _productIndexToOptimizedProductIndexes orderby x.Value.SubFactoryOptimizedIndex select x.Value.PlanetWideOptimizedIndex).ToArray()); ReadonlyArray planetWideOptimizedConsumeIndex = universeStaticDataBuilder.DeduplicateArrayUnmanaged((from x in _consumeIndexToOptimizedConsumeIndexes orderby x.Value.SubFactoryOptimizedIndex select x.Value.PlanetWideOptimizedIndex).ToArray()); OptimizedProductionStatistics optimizedProductionStatistics = new OptimizedProductionStatistics(planetWideOptimizedProductIndex, planetWideOptimizedConsumeIndex); _planetWideProductionRegisterBuilder.AddOptimizedProductionStatistics(ref optimizedProductionStatistics); return optimizedProductionStatistics; } } public sealed class TrafficStatisticsPatches { private static bool?[]? _isStarUpdated; private static List[]? _starsStatistics; private static bool?[]? _isPlanetUpdated; private static List[]? _planetsStatistics; internal static void Clear() { _isStarUpdated = null; _starsStatistics = null; _isPlanetUpdated = null; _planetsStatistics = null; } [HarmonyPrefix] [HarmonyPatch(typeof(TrafficStatistics), "PrepareTick")] public static void PrepareTick(TrafficStatistics __instance) { if (_isStarUpdated == null || __instance.starTrafficPool.Length != _isStarUpdated.Length) { _isStarUpdated = new bool?[__instance.starTrafficPool.Length]; _starsStatistics = new List[__instance.starTrafficPool.Length]; GetTrafficStatsForWholeStartCluster(__instance.starTrafficPool, _starsStatistics); } if (_isPlanetUpdated == null || __instance.factoryTrafficPool.Length != _isPlanetUpdated.Length) { _isPlanetUpdated = new bool?[__instance.factoryTrafficPool.Length]; _planetsStatistics = new List[__instance.factoryTrafficPool.Length]; GetTrafficStatsForWholeStartCluster(__instance.factoryTrafficPool, _planetsStatistics); } } private static void GetTrafficStatsForWholeStartCluster(AstroTrafficStat?[] astroStatistics, List[] clusterStatistics) { for (int i = 0; i < astroStatistics.Length; i++) { List list = (clusterStatistics[i] = new List()); AstroTrafficStat val = astroStatistics[i]; if (val == null) { continue; } for (int j = 0; j < val.trafficPool.Length; j++) { if (val.trafficPool[j] != null) { list.Add(val.trafficPool[j]); } } } } [HarmonyPrefix] [HarmonyPatch(typeof(TrafficStatistics), "RegisterStarInputStat")] private static void RegisterStarInputStat(int starId, int itemId, int count) { StarTrafficStatisticsUpdated(starId, itemId, count); } [HarmonyPrefix] [HarmonyPatch(typeof(TrafficStatistics), "RegisterStarOutputStat")] private static void RegisterStarOutputStat(int starId, int itemId, int count) { StarTrafficStatisticsUpdated(starId, itemId, count); } [HarmonyPrefix] [HarmonyPatch(typeof(TrafficStatistics), "RegisterStarInternalStat")] private static void RegisterStarInternalStat(int starId, int itemId, int count) { StarTrafficStatisticsUpdated(starId, itemId, count); } private static void StarTrafficStatisticsUpdated(int starId, int itemId, int count) { if (starId > 0 && itemId > 0 && count > 0 && _isStarUpdated != null && !_isStarUpdated[starId].GetValueOrDefault()) { _isStarUpdated[starId] = true; } } [HarmonyPrefix] [HarmonyPatch(typeof(TrafficStatistics), "RegisterPlanetInputStat")] private static void RegisterPlanetInputStat(int planetId, int itemId, int count) { PlanetTrafficStatisticsUpdated(planetId, itemId, count); } [HarmonyPrefix] [HarmonyPatch(typeof(TrafficStatistics), "RegisterPlanetOutputStat")] private static void RegisterPlanetOutputStat(int planetId, int itemId, int count) { PlanetTrafficStatisticsUpdated(planetId, itemId, count); } [HarmonyPrefix] [HarmonyPatch(typeof(TrafficStatistics), "RegisterPlanetInternalStat")] private static void RegisterPlanetInternalStat(int planetId, int itemId, int count) { PlanetTrafficStatisticsUpdated(planetId, itemId, count); } private static void PlanetTrafficStatisticsUpdated(int planetId, int itemId, int count) { if (planetId <= 0 || itemId <= 0 || count <= 0 || _isPlanetUpdated == null) { return; } PlanetFactory val = GameMain.data.galaxy.PlanetById(planetId)?.factory; if (val != null) { int index = val.index; if (!_isPlanetUpdated[index].GetValueOrDefault()) { _isPlanetUpdated[index] = true; } } } [HarmonyPrefix] [HarmonyPatch(typeof(TrafficStatistics), "GameTick")] private static bool GameTick_Parallelize(TrafficStatistics __instance, long time) { TrafficStatistics __instance2 = __instance; if (!IsTimeToUpdateStatistics(time)) { return false; } bool?[] isStarUpdated = _isStarUpdated; if (isStarUpdated == null) { throw new InvalidOperationException("isStarUpdated was null"); } List[] starsStatistics = _starsStatistics; if (starsStatistics == null) { throw new InvalidOperationException("starsStatistics was null"); } bool?[] isPlanetUpdated = _isPlanetUpdated; if (isPlanetUpdated == null) { throw new InvalidOperationException("isPlanetUpdated was null"); } List[] planetsStatistics = _planetsStatistics; if (planetsStatistics == null) { throw new InvalidOperationException("planetsStatistics was null"); } ParallelOptions parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = WeaverThreadHelper.GetParallelism() }; Parallel.For(0, __instance2.starTrafficPool.Length + __instance2.factoryTrafficPool.Length, parallelOptions, delegate(int i) { if (i < __instance2.starTrafficPool.Length) { TrafficStatGameTick(__instance2, __instance2.starTrafficPool, isStarUpdated, starsStatistics, i, time); } else { TrafficStatGameTick(__instance2, __instance2.factoryTrafficPool, isPlanetUpdated, planetsStatistics, i - __instance2.starTrafficPool.Length, time); } }); return false; } private static bool IsTimeToUpdateStatistics(long time) { if (time % 10 == 0L) { return true; } if (time % 60 == 6) { return true; } if (time % 600 == 60) { return true; } if (time % 3600 == 360) { return true; } if (time % 36000 == 3600) { return true; } if (time % 360000 == 36000) { return true; } return false; } private static void TrafficStatGameTick(TrafficStatistics trafficStatistics, AstroTrafficStat[] astroStatistics, bool?[] isStatisticsUpdated, List[] statistics, int statisticsIndex, long time) { AstroTrafficStat val = astroStatistics[statisticsIndex]; if (val == null) { return; } if (isStatisticsUpdated[statisticsIndex].GetValueOrDefault() || !isStatisticsUpdated[statisticsIndex].HasValue) { GameTick(val, statistics[statisticsIndex], time); isStatisticsUpdated[statisticsIndex] = false; } else { OptimizeGameTick(val, statistics[statisticsIndex], time); } if (!val.itemChanged) { return; } try { trafficStatistics.RaiseActionEvent("onItemChange"); } catch (Exception ex) { WeaverFixes.Logger.LogError((object)ex); } } private static void GameTick(AstroTrafficStat astroTrafficStat, List trafficStats, long time) { if (time % 10 == 0L) { int num = 0; int num2 = 6; int num3 = 6 + num; int num4 = 7 + num; int num5 = 13; int num6 = 420; int num7 = 12 + num; int num8 = 14 + num; int num9 = 20; int num10 = 780; int[] itemIds = ItemProto.itemIds; int num11 = itemIds.Length; int[] inputRegister = astroTrafficStat.inputRegister; int[] outputRegister = astroTrafficStat.outputRegister; int[] internalRegister = astroTrafficStat.internalRegister; for (int i = 0; i < num11; i++) { int num12 = itemIds[i]; int num13 = num12; int num14 = inputRegister[num12]; int num15 = outputRegister[num12]; int num16 = internalRegister[num12]; inputRegister[num12] = 0; outputRegister[num12] = 0; internalRegister[num12] = 0; int num17 = astroTrafficStat.itemIndices[num13]; if (num17 <= 0) { if (num14 <= 0 && num15 <= 0 && num16 <= 0) { continue; } int trafficCursor = astroTrafficStat.trafficCursor; astroTrafficStat.CreateTrafficStat(num13); astroTrafficStat.itemIndices[num13] = trafficCursor; num17 = trafficCursor; trafficStats.Add(astroTrafficStat.trafficPool[num17]); } TrafficStat obj = astroTrafficStat.trafficPool[num17]; int[] count = obj.count; int[] cursor = obj.cursor; long[] total = obj.total; int num18 = cursor[num]; int num19 = num14 - count[num18]; count[num18] = num14; total[num] += num19; total[num2] += num14; cursor[num]++; if (cursor[num] >= 60) { cursor[num] -= 60; } int num20 = cursor[num3]; int num21 = num15 - count[num20]; count[num20] = num15; total[num4] += num21; total[num5] += num15; cursor[num3]++; if (cursor[num3] >= num6) { cursor[num3] -= 60; } int num22 = cursor[num7]; int num23 = num16 - count[num22]; count[num22] = num16; total[num8] += num23; total[num9] += num16; cursor[num7]++; if (cursor[num7] >= num10) { cursor[num7] -= 60; } } } if (time % 60 == 6) { int num24 = 1; astroTrafficStat.ComputeTheMiddleLevel(num24); } if (time % 600 == 60) { int num25 = 2; astroTrafficStat.ComputeTheMiddleLevel(num25); } if (time % 3600 == 360) { int num26 = 3; astroTrafficStat.ComputeTheMiddleLevel(num26); } if (time % 36000 == 3600) { int num27 = 4; astroTrafficStat.ComputeTheMiddleLevel(num27); } if (time % 360000 == 36000) { int num28 = 5; astroTrafficStat.ComputeTheMiddleLevel(num28); } } private static void OptimizeGameTick(AstroTrafficStat astroTrafficStat, List trafficStats, long time) { if (time % 10 == 0L) { int num = 0; int num2 = 6; int num3 = 6 + num; int num4 = 7 + num; int num5 = 13; int num6 = 420; int num7 = 12 + num; int num8 = 14 + num; int num9 = 20; int num10 = 780; for (int i = 0; i < trafficStats.Count; i++) { int num11 = 0; int num12 = 0; int num13 = 0; TrafficStat obj = trafficStats[i]; int[] count = obj.count; int[] cursor = obj.cursor; long[] total = obj.total; int num14 = cursor[num]; int num15 = num11 - count[num14]; count[num14] = num11; total[num] += num15; total[num2] += num11; cursor[num]++; if (cursor[num] >= 60) { cursor[num] -= 60; } int num16 = cursor[num3]; int num17 = num12 - count[num16]; count[num16] = num12; total[num4] += num17; total[num5] += num12; cursor[num3]++; if (cursor[num3] >= num6) { cursor[num3] -= 60; } int num18 = cursor[num7]; int num19 = num13 - count[num18]; count[num18] = num13; total[num8] += num19; total[num9] += num13; cursor[num7]++; if (cursor[num7] >= num10) { cursor[num7] -= 60; } } } if (time % 60 == 6) { int num20 = 1; astroTrafficStat.ComputeTheMiddleLevel(num20); } if (time % 600 == 60) { int num21 = 2; astroTrafficStat.ComputeTheMiddleLevel(num21); } if (time % 3600 == 360) { int num22 = 3; astroTrafficStat.ComputeTheMiddleLevel(num22); } if (time % 36000 == 3600) { int num23 = 4; astroTrafficStat.ComputeTheMiddleLevel(num23); } if (time % 360000 == 36000) { int num24 = 5; astroTrafficStat.ComputeTheMiddleLevel(num24); } } } } namespace Weaver.Optimizations.Stations { internal sealed class GasPlanetWideStationExecutor { private OptimizedStation[] _optimizedStations; public int Count => _optimizedStations.Length; public void StationGameTick(PlanetFactory planet, long time, ref MiningFlags miningFlags) { //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Invalid comparison between Unknown and I4 int num = (int)(time % 60); if (num < 0) { num += 60; } PlanetTransport transport = planet.transport; GameHistoryData history = GameMain.history; FactoryProductionStat val = GameMain.statistics.production.factoryStatPool[transport.factory.index]; int[] productRegister = val.productRegister; int[] consumeRegister = val.consumeRegister; float logisticShipSailSpeedModified = history.logisticShipSailSpeedModified; float num2 = (history.logisticShipWarpDrive ? history.logisticShipWarpSpeedModified : logisticShipSailSpeedModified); int logisticShipCarries = history.logisticShipCarries; StationComponent[] stationPool = transport.gameData.galacticTransport.stationPool; AstroData[] astrosData = transport.gameData.galaxy.astrosData; VectorLF3 relativePos = transport.gameData.relativePos; Quaternion relativeRot = transport.gameData.relativeRot; double num3 = history.miningSpeedScale; double collectorsWorkCost = transport.collectorsWorkCost; double gasTotalHeat = transport.planet.gasTotalHeat; float collectSpeedRate = ((gasTotalHeat - collectorsWorkCost <= 0.0) ? 1f : ((float)((num3 * gasTotalHeat - collectorsWorkCost) / (gasTotalHeat - collectorsWorkCost)))); bool flag = (int)UIGame.viewMode == 4; OptimizedStation[] optimizedStations = _optimizedStations; GameTick_SandboxMode(); long num4 = 0L; for (int i = 0; i < optimizedStations.Length; i++) { OptimizedStation optimizedStation = optimizedStations[i]; optimizedStation.UpdateCollection(collectSpeedRate, productRegister, ref miningFlags); num4 += transport.collectorWorkEnergyPerTick; optimizedStation.stationComponent.InternalTickRemote(transport.factory, num, logisticShipSailSpeedModified, num2, logisticShipCarries, stationPool, astrosData, ref relativePos, ref relativeRot, flag, consumeRegister); } for (int j = 0; j < optimizedStations.Length; j++) { optimizedStations[j].stationComponent.UpdateNeeds(); } lock (val) { val.energyConsumption += num4; } } public void Initialize(PlanetFactory planet) { List list = new List(); for (int i = 1; i < planet.transport.stationCursor; i++) { StationComponent val = planet.transport.stationPool[i]; if (val != null && val.id == i) { list.Add(new OptimizedStation(val, Array.Empty(), null)); planet.entityNeeds[val.entityId] = val.needs; } } _optimizedStations = list.ToArray(); } private void GameTick_SandboxMode() { if (GameMain.sandboxToolsEnabled) { OptimizedStation[] optimizedStations = _optimizedStations; for (int i = 0; i < optimizedStations.Length; i++) { optimizedStations[i].stationComponent.UpdateKeepMode(); } } } } internal readonly struct OptimizedStation { public readonly StationComponent stationComponent; private readonly BeltIndex[]? _beltIndexes; private readonly int? _optimizedMinerIndex; public OptimizedStation(StationComponent stationComponent, BeltIndex[]? beltIndexes, int? optimizedMinerIndex) { this.stationComponent = stationComponent; _beltIndexes = beltIndexes; _optimizedMinerIndex = optimizedMinerIndex; } public void UpdateOutputSlots(int maxPilerCount, OptimizedCargoPath[] optimizedCargoPaths) { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Invalid comparison between Unknown and I4 //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Invalid comparison between Unknown and I4 //IL_02d6: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Invalid comparison between Unknown and I4 //IL_03bd: Unknown result type (might be due to invalid IL or missing references) //IL_03c3: Invalid comparison between Unknown and I4 BeltIndex[] beltIndexes = _beltIndexes; if (beltIndexes == null) { return; } lock (stationComponent.storage) { int num = ((stationComponent.pilerCount == 0) ? maxPilerCount : stationComponent.pilerCount); int num2 = stationComponent.slots.Length; int num3 = stationComponent.storage.Length; int num4 = -1; if (!stationComponent.isVeinCollector) { for (int i = 0; i < num2; i++) { BeltIndex beltIndex = beltIndexes[i]; if (!beltIndex.HasValue) { continue; } ref OptimizedCargoPath belt = ref beltIndex.GetBelt(optimizedCargoPaths); ref SlotData reference = ref stationComponent.slots[i]; if ((int)reference.dir == 1) { if (reference.counter > 0) { reference.counter--; } else { if (belt.buffer[9] != 0) { continue; } int num5 = reference.storageIdx - 1; int num6 = 0; if (num5 < 0) { continue; } if (num5 < num3) { num6 = stationComponent.storage[num5].itemId; if (num6 > 0 && stationComponent.storage[num5].count > 0) { int num7 = ((stationComponent.storage[num5].count < num) ? stationComponent.storage[num5].count : num); int n = stationComponent.storage[num5].count; int m = stationComponent.storage[num5].inc; int num8 = split_inc(ref n, ref m, num7); if (belt.TryInsertItemAtHeadAndFillBlank(num6, (byte)num7, (byte)num8)) { stationComponent.storage[num5].count = n; stationComponent.storage[num5].inc = m; reference.counter = 1; } } } else { num6 = 1210; if (stationComponent.warperCount > 0 && belt.TryInsertItemAtHeadAndFillBlank(num6, 1, 0)) { StationComponent obj = stationComponent; obj.warperCount--; reference.counter = 1; } } } } else if ((int)reference.dir != 2) { beltIndexes[i] = BeltIndex.NoBelt; reference.beltId = 0; reference.counter = 0; } } return; } for (int j = 0; j < num; j++) { for (int k = 0; k < num2; k++) { int num9 = (stationComponent.outSlotOffset + k) % num2; BeltIndex beltIndex2 = beltIndexes[num9]; if (!beltIndex2.HasValue) { continue; } ref OptimizedCargoPath belt2 = ref beltIndex2.GetBelt(optimizedCargoPaths); ref SlotData reference2 = ref stationComponent.slots[num9]; if ((int)reference2.dir == 1) { int num10 = 0; int num11 = 0; if (num10 < 0 || num10 >= num3) { continue; } num11 = stationComponent.storage[num10].itemId; if (num11 > 0 && stationComponent.storage[num10].count > 0) { int num12 = stationComponent.storage[num10].inc / stationComponent.storage[num10].count; if (belt2.TryUpdateItemAtHeadAndFillBlank(num11, num, 1, (byte)num12)) { stationComponent.storage[num10].count--; stationComponent.storage[num10].inc -= num12; num4 = (num9 + 1) % num2; } } } else if ((int)reference2.dir != 2) { beltIndexes[num9] = BeltIndex.NoBelt; reference2.beltId = 0; reference2.counter = 0; } } } if (num4 >= 0) { stationComponent.outSlotOffset = num4; } } } public void UpdateInputSlots(OptimizedCargoPath[] optimizedCargoPaths) { //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Invalid comparison between Unknown and I4 //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Invalid comparison between Unknown and I4 BeltIndex[] beltIndexes = _beltIndexes; if (beltIndexes == null) { return; } lock (stationComponent.storage) { int num = stationComponent.slots.Length; _ = stationComponent.storage.Length; int num2 = stationComponent.needs[0] + stationComponent.needs[1] + stationComponent.needs[2] + stationComponent.needs[3] + stationComponent.needs[4] + stationComponent.needs[5]; for (int i = 0; i < num; i++) { BeltIndex beltIndex = beltIndexes[i]; if (!beltIndex.HasValue) { continue; } ref OptimizedCargoPath belt = ref beltIndex.GetBelt(optimizedCargoPaths); ref SlotData reference = ref stationComponent.slots[i]; if ((int)reference.dir == 2) { if (reference.counter > 0) { reference.counter--; } else if (num2 != 0) { int needIdx = -1; OptimizedCargo optimizedCargo = belt.TryPickItemAtRear(stationComponent.needs, out needIdx); if (needIdx >= 0) { InputItem(optimizedCargo, needIdx); reference.storageIdx = needIdx + 1; reference.counter = 1; } } } else if ((int)reference.dir != 1) { beltIndexes[i] = BeltIndex.NoBelt; reference.beltId = 0; reference.counter = 0; } } } } public void UpdateCollection(float collectSpeedRate, int[] productRegister, ref MiningFlags miningFlags) { //IL_0103: Unknown result type (might be due to invalid IL or missing references) if (stationComponent.collectionPerTick == null) { return; } for (int i = 0; i < stationComponent.collectionIds.Length; i++) { lock (stationComponent.storage) { if (stationComponent.storage[i].count < stationComponent.storage[i].max) { stationComponent.currentCollections[i] += stationComponent.collectionPerTick[i] * collectSpeedRate; int num = (int)stationComponent.currentCollections[i]; if (num != 0) { stationComponent.storage[i].count += num; productRegister[stationComponent.storage[i].itemId] += num; stationComponent.currentCollections[i] -= num; miningFlags.AddMiningFlagUnsafe(LDB.veins.GetVeinTypeByItemId(stationComponent.storage[i].itemId)); } } } } } public void UpdateVeinCollection(OptimizedVeinMiner[] stationMiners, ref MiningFlags miningFlags) { //IL_01dd: Unknown result type (might be due to invalid IL or missing references) lock (stationComponent.storage) { if (((StationStore)(ref stationComponent.storage[0])).localSupplyCount >= stationComponent.storage[0].max) { return; } if (!_optimizedMinerIndex.HasValue) { throw new InvalidOperationException("OptimizedStation attempted to update its miner counterpart but _optimizedMinerIndex was null."); } ref OptimizedVeinMiner reference = ref stationMiners[_optimizedMinerIndex.Value]; if (reference.productId.ItemIndex == 0 || reference.productId.ItemIndex != stationComponent.collectionIds[0] || reference.ProductCount <= 0) { return; } int productCount = reference.ProductCount; int num = stationComponent.storage[0].count; int max = stationComponent.storage[0].max; if (stationComponent.storage[0].localOrder < -max / 2) { num = ((stationComponent.storage[0].localOrder >= -max / 2 - max) ? (num + stationComponent.storage[0].localOrder + max / 2) : (num - stationComponent.storage[0].max)); } int num2 = stationComponent.storage[0].max - num; num2 = ((num2 > productCount) ? productCount : num2); if (num2 != 0) { stationComponent.storage[0].count += num2; reference.ProductCount -= num2; if (reference.ProductCount == 0) { reference.productId = default(OptimizedItemId); } miningFlags.AddMiningFlagUnsafe(LDB.veins.GetVeinTypeByItemId(stationComponent.storage[0].itemId)); } } } private static int split_inc(ref int n, ref int m, int p) { if (n == 0) { return 0; } int num = m / n; int num2 = m - num * n; n -= p; num2 -= n; num = ((num2 > 0) ? (num * p + num2) : (num * p)); m -= num; return num; } private void InputItem(OptimizedCargo optimizedCargo, int needIdx) { if (optimizedCargo.Item <= 0) { return; } lock (stationComponent.storage) { if (needIdx < stationComponent.storage.Length && stationComponent.storage[needIdx].itemId == optimizedCargo.Item) { stationComponent.storage[needIdx].count += optimizedCargo.Stack; stationComponent.storage[needIdx].inc += optimizedCargo.Inc; } else if (optimizedCargo.Item == 1210) { StationComponent obj = stationComponent; obj.warperCount += optimizedCargo.Stack; } } } } internal sealed class StationExecutor { private OptimizedStation[] _optimizedStations; private ReadonlyArray _networkIds; public int Count => _optimizedStations.Length; public void InputFromBelt(OptimizedCargoPath[] optimizedCargoPaths) { OptimizedStation[] optimizedStations = _optimizedStations; for (int i = 0; i < optimizedStations.Length; i++) { optimizedStations[i].UpdateInputSlots(optimizedCargoPaths); } } public void StationGameTick(PlanetFactory planet, long time, VeinMinerExecutor stationVeinMinerExecutor, ref MiningFlags miningFlags) { //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Invalid comparison between Unknown and I4 int num = (int)(time % 1163962800); if (num < 0) { num += 1163962800; } int num2 = (int)(time % 60); if (num2 < 0) { num2 += 60; } PlanetTransport transport = planet.transport; GameHistoryData history = GameMain.history; int[] consumeRegister = GameMain.statistics.production.factoryStatPool[transport.factory.index].consumeRegister; float[] networkServes = transport.powerSystem.networkServes; PowerConsumerComponent[] consumerPool = transport.powerSystem.consumerPool; float logisticDroneSpeedModified = history.logisticDroneSpeedModified; int logisticDroneCarries = history.logisticDroneCarries; float logisticShipSailSpeedModified = history.logisticShipSailSpeedModified; float num3 = (history.logisticShipWarpDrive ? history.logisticShipWarpSpeedModified : logisticShipSailSpeedModified); int logisticShipCarries = history.logisticShipCarries; StationComponent[] stationPool = transport.gameData.galacticTransport.stationPool; AstroData[] astrosData = transport.gameData.galaxy.astrosData; VectorLF3 relativePos = transport.gameData.relativePos; Quaternion relativeRot = transport.gameData.relativeRot; bool flag = (int)UIGame.viewMode == 4; OptimizedVeinMiner[] optimizedMiners = stationVeinMinerExecutor._optimizedMiners; OptimizedStation[] optimizedStations = _optimizedStations; ReadonlyArray networkIds = _networkIds; GameTick_SandboxMode(); for (int i = 0; i < optimizedStations.Length; i++) { OptimizedStation optimizedStation = optimizedStations[i]; float num4 = networkServes[networkIds[i]]; optimizedStation.stationComponent.InternalTickLocal(transport.factory, num, num4, logisticDroneSpeedModified, logisticDroneCarries, transport.stationPool); if (optimizedStation.stationComponent.isVeinCollector) { optimizedStation.UpdateVeinCollection(optimizedMiners, ref miningFlags); } if (optimizedStation.stationComponent.isStellar) { optimizedStation.stationComponent.InternalTickRemote(transport.factory, num2, logisticShipSailSpeedModified, num3, logisticShipCarries, stationPool, astrosData, ref relativePos, ref relativeRot, flag, consumeRegister); } if (!optimizedStation.stationComponent.isCollector && !optimizedStation.stationComponent.isVeinCollector) { optimizedStation.stationComponent.SetPCState(consumerPool); } } for (int j = 0; j < optimizedStations.Length; j++) { optimizedStations[j].stationComponent.UpdateNeeds(); } } public void OutputToBelt(OptimizedCargoPath[] optimizedCargoPaths) { OptimizedStation[] optimizedStations = _optimizedStations; int stationPilerLevel = GameMain.history.stationPilerLevel; for (int i = 0; i < optimizedStations.Length; i++) { optimizedStations[i].UpdateOutputSlots(stationPilerLevel, optimizedCargoPaths); } } public void Initialize(PlanetFactory planet, Graph subFactoryGraph, BeltExecutor beltExecutor, VeinMinerExecutor stationVeinMinerExecutor, UniverseStaticDataBuilder universeStaticDataBuilder) { List list = new List(); List list2 = new List(); foreach (int item in from x in subFactoryGraph.GetAllNodes() where x.EntityTypeIndex.EntityType == EntityType.Station select x.EntityTypeIndex.Index into x orderby x select x) { StationComponent val = planet.transport.stationPool[item]; if (val.id != item) { continue; } BeltIndex[] array = null; for (int i = 0; i < val.slots.Length; i++) { if (beltExecutor.TryGetOptimizedCargoPathIndex(planet, val.slots[i].beltId, out var beltIndex)) { if (array == null) { array = new BeltIndex[val.slots.Length]; array.Fill(BeltIndex.NoBelt); } array[i] = beltIndex; } } int? optimizedMinerIndex = null; if (val.isVeinCollector) { optimizedMinerIndex = stationVeinMinerExecutor.GetOptimizedMinerIndexFromMinerId(val.minerId); } int networkId = planet.powerSystem.consumerPool[val.pcId].networkId; list.Add(new OptimizedStation(val, array, optimizedMinerIndex)); list2.Add(ConverterUtilities.ThrowIfNotWithinPositiveShortRange(networkId, "networkIndex")); planet.entityNeeds[val.entityId] = val.needs; } _optimizedStations = list.ToArray(); _networkIds = universeStaticDataBuilder.DeduplicateArrayUnmanaged(list2); } private void GameTick_SandboxMode() { if (GameMain.sandboxToolsEnabled) { OptimizedStation[] optimizedStations = _optimizedStations; for (int i = 0; i < optimizedStations.Length; i++) { optimizedStations[i].stationComponent.UpdateKeepMode(); } } } } } namespace Weaver.Optimizations.StaticData { internal sealed class ComparableArrayDeduplicator : IComparableArrayDeduplicator where T : IEquatable { private readonly HashSet> _arrays = new HashSet>(new CompareArrayCollections()); public int TotalBytes { get; private set; } public int BytesDeduplicated { get; private set; } public ReadonlyArray Deduplicate(IList toDeduplicate, int itemSize) { int num = itemSize * toDeduplicate.Count; TotalBytes += num; if (_arrays.TryGetValue(toDeduplicate, out IList actualValue)) { BytesDeduplicated += num; return new ReadonlyArray((T[])actualValue); } T[] array = ((!(toDeduplicate is List list)) ? ((T[])toDeduplicate) : list.ToArray()); _arrays.Add(array); return new ReadonlyArray(array); } public void Clear() { _arrays.Clear(); TotalBytes = 0; BytesDeduplicated = 0; } } internal sealed class CompareArrayCollections : IEqualityComparer> where T : IEquatable { public bool Equals(IList x, IList y) { if (x.Count != y.Count) { return false; } for (int i = 0; i < x.Count; i++) { if (!x[i].Equals(y[i])) { return false; } } return true; } public int GetHashCode(IList value) { HashCode hashCode = default(HashCode); hashCode.Add(value.Count); for (int i = 0; i < value.Count; i++) { hashCode.Add(value[i]); } return hashCode.ToHashCode(); } } internal sealed class DataDeduplicator where T : struct, IEquatable, IMemorySize { private readonly Dictionary _uniqueValueToIndex; private readonly List _uniqueValues; private bool _dataUpdated; public int TotalBytes { get; private set; } public int BytesDeduplicated { get; private set; } public DataDeduplicator() { _uniqueValueToIndex = new Dictionary(); _uniqueValues = new List(); _dataUpdated = true; } public int GetDeduplicatedValueIndex([In][RequiresLocation] ref T potentiallyDuplicatedValue) { T val = potentiallyDuplicatedValue; int size = val.GetSize(); TotalBytes += size; if (!_uniqueValueToIndex.TryGetValue(potentiallyDuplicatedValue, out var value)) { _dataUpdated = true; value = _uniqueValues.Count; _uniqueValues.Add(potentiallyDuplicatedValue); _uniqueValueToIndex.Add(potentiallyDuplicatedValue, value); } else { BytesDeduplicated += size; } return value; } public bool TryGetUpdatedData([NotNullWhen(true)] out ReadonlyArray? updatedData) { if (!_dataUpdated) { updatedData = null; return false; } _dataUpdated = false; updatedData = new ReadonlyArray(_uniqueValues.ToArray()); return true; } public void Clear() { _uniqueValueToIndex.Clear(); _uniqueValues.Clear(); _dataUpdated = true; TotalBytes = 0; BytesDeduplicated = 0; } } internal interface IComparableArrayDeduplicator { int TotalBytes { get; } int BytesDeduplicated { get; } void Clear(); } internal interface IMemorySize { int GetSize(); } internal readonly struct ReadonlyArray where T : IEquatable { private readonly T[] _array; public int Length => _array.Length; public ref readonly T this[int index] => ref _array[index]; public ReadonlyArray(T[] array) { _array = array; } public bool SequenceEqual(ReadonlyArray other) { if (Length != other.Length) { return false; } for (int i = 0; i < Length; i++) { ref T reference = ref _array[i]; T val = default(T); if (val == null) { val = reference; reference = ref val; } if (!reference.Equals(other._array[i])) { return false; } } return true; } } internal sealed class UniverseInserterStaticDataBuilder where TInserterGrade : struct, IInserterGrade, IMemorySize { private readonly DataDeduplicator _inserterGrades = new DataDeduplicator(); public int TotalBytes => _inserterGrades.TotalBytes; public int BytesDeduplicated => _inserterGrades.BytesDeduplicated; public int AddInserterGrade([In][RequiresLocation] ref TInserterGrade inserterGrade) { return _inserterGrades.GetDeduplicatedValueIndex(ref inserterGrade); } public bool TryGetUpdatedData([NotNullWhen(true)] out ReadonlyArray? updatedData) { return _inserterGrades.TryGetUpdatedData(out updatedData); } public void Clear() { _inserterGrades.Clear(); } } internal sealed class UniverseStaticData { public ReadonlyArray AssemblerRecipes { get; private set; } = new ReadonlyArray(Array.Empty()); public ReadonlyArray FractionatorConfigurations { get; private set; } = new ReadonlyArray(Array.Empty()); public ReadonlyArray ProducingLabRecipes { get; private set; } = new ReadonlyArray(Array.Empty()); public ReadonlyArray PowerConsumerTypes { get; private set; } = new ReadonlyArray(Array.Empty()); public ReadonlyArray BiInserterGrades { get; private set; } = new ReadonlyArray(Array.Empty()); public ReadonlyArray InserterGrades { get; private set; } = new ReadonlyArray(Array.Empty()); public void UpdateAssemblerRecipes(ReadonlyArray assemblerRecipes) { AssemblerRecipes = assemblerRecipes; } public void UpdateFractionatorConfigurations(ReadonlyArray fractionatorConfigurations) { FractionatorConfigurations = fractionatorConfigurations; } public void UpdateProducingLabRecipes(ReadonlyArray producingLabRecipes) { ProducingLabRecipes = producingLabRecipes; } public void UpdatePowerConsumerTypes(ReadonlyArray powerConsumerTypes) { PowerConsumerTypes = powerConsumerTypes; } public void UpdateBiInserterGrades(ReadonlyArray biInserterGrades) { BiInserterGrades = biInserterGrades; } public void UpdateInserterGrades(ReadonlyArray inserterGrades) { InserterGrades = inserterGrades; } } internal sealed class UniverseStaticDataBuilder { private static bool _printStatistics; private readonly DataDeduplicator _assemblerRecipes = new DataDeduplicator(); private readonly DataDeduplicator _fractionatorConfigurations = new DataDeduplicator(); private readonly DataDeduplicator _producingLabRecipes = new DataDeduplicator(); private readonly DataDeduplicator _powerConsumerTypes = new DataDeduplicator(); private readonly Dictionary _typeToComparableArrayDeduplicator = new Dictionary(); public UniverseInserterStaticDataBuilder BiInserterGrades { get; } = new UniverseInserterStaticDataBuilder(); public UniverseInserterStaticDataBuilder InserterGrades { get; } = new UniverseInserterStaticDataBuilder(); public UniverseStaticData UniverseStaticData { get; } = new UniverseStaticData(); public static void EnableStatistics() { _printStatistics = true; } public int AddAssemblerRecipe([In][RequiresLocation] ref AssemblerRecipe assemblerRecipe) { return _assemblerRecipes.GetDeduplicatedValueIndex(ref assemblerRecipe); } public int AddFractionatorConfiguration([In][RequiresLocation] ref FractionatorConfiguration fractionatorConfiguration) { return _fractionatorConfigurations.GetDeduplicatedValueIndex(ref fractionatorConfiguration); } public int AddProducingLabRecipe([In][RequiresLocation] ref ProducingLabRecipe producingLabRecipe) { return _producingLabRecipes.GetDeduplicatedValueIndex(ref producingLabRecipe); } public int AddPowerConsumerType([In][RequiresLocation] ref PowerConsumerType powerConsumerType) { return _powerConsumerTypes.GetDeduplicatedValueIndex(ref powerConsumerType); } public ReadonlyArray DeduplicateArrayUnmanaged(IList toDeduplicate) where T : unmanaged, IEquatable { return DeduplicateArray(toDeduplicate, Marshal.SizeOf()); } public ReadonlyArray DeduplicateArray(IList toDeduplicate) where T : IEquatable, IMemorySize { if (toDeduplicate.Count == 0) { return new ReadonlyArray(Array.Empty()); } return DeduplicateArray(toDeduplicate, toDeduplicate[0].GetSize()); } public void UpdateStaticDataIfRequired() { bool flag = false; if (_assemblerRecipes.TryGetUpdatedData(out var updatedData)) { UniverseStaticData.UpdateAssemblerRecipes(updatedData.Value); flag = true; } if (_fractionatorConfigurations.TryGetUpdatedData(out var updatedData2)) { UniverseStaticData.UpdateFractionatorConfigurations(updatedData2.Value); flag = true; } if (_producingLabRecipes.TryGetUpdatedData(out var updatedData3)) { UniverseStaticData.UpdateProducingLabRecipes(updatedData3.Value); flag = true; } if (_powerConsumerTypes.TryGetUpdatedData(out var updatedData4)) { UniverseStaticData.UpdatePowerConsumerTypes(updatedData4.Value); flag = true; } if (BiInserterGrades.TryGetUpdatedData(out var updatedData5)) { UniverseStaticData.UpdateBiInserterGrades(updatedData5.Value); flag = true; } if (InserterGrades.TryGetUpdatedData(out var updatedData6)) { UniverseStaticData.UpdateInserterGrades(updatedData6.Value); flag = true; } if (flag && _printStatistics) { PrintStaticDataStatistics(); } } public void Clear() { _assemblerRecipes.Clear(); _fractionatorConfigurations.Clear(); _producingLabRecipes.Clear(); BiInserterGrades.Clear(); InserterGrades.Clear(); foreach (IComparableArrayDeduplicator value in _typeToComparableArrayDeduplicator.Values) { value.Clear(); } UpdateStaticDataIfRequired(); } private ReadonlyArray DeduplicateArray(IList toDeduplicate, int itemSize) where T : IEquatable { if (!_typeToComparableArrayDeduplicator.TryGetValue(typeof(T), out IComparableArrayDeduplicator value)) { value = new ComparableArrayDeduplicator(); _typeToComparableArrayDeduplicator.Add(typeof(T), value); } return ((ComparableArrayDeduplicator)value).Deduplicate(toDeduplicate, itemSize); } private void PrintStaticDataStatistics() { int num = 0; num += _assemblerRecipes.TotalBytes; num += _fractionatorConfigurations.TotalBytes; num += _producingLabRecipes.TotalBytes; num += _powerConsumerTypes.TotalBytes; num += BiInserterGrades.TotalBytes; num += InserterGrades.TotalBytes; int num2 = 0; num2 += _assemblerRecipes.BytesDeduplicated; num2 += _fractionatorConfigurations.BytesDeduplicated; num2 += _producingLabRecipes.BytesDeduplicated; num2 += _powerConsumerTypes.BytesDeduplicated; num2 += BiInserterGrades.BytesDeduplicated; num2 += InserterGrades.BytesDeduplicated; foreach (IComparableArrayDeduplicator value in _typeToComparableArrayDeduplicator.Values) { num += value.TotalBytes; num2 += value.BytesDeduplicated; } WeaverFixes.Logger.LogMessage((object)"Static data statistics:"); WeaverFixes.Logger.LogMessage((object)$"\tTotal: {num,12:N0} bytes"); WeaverFixes.Logger.LogMessage((object)$"\tDeduplicated: {num2,12:N0} bytes"); } } } namespace Weaver.Optimizations.Spraycoaters { [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct OptimizedSpraycoater { public readonly int incommingBeltSegIndexPlusSegPivotOffset; public readonly BeltIndex incommingBeltIndex; public readonly BeltIndex outgoingBeltIndex; public readonly int outgoingBeltSegIndexPlusSegPivotOffset; public readonly int outgoingBeltSpeed; public readonly int incCapacity; public readonly PowerNetwork? powerNetwork; public OptimizedItemId incItemId; public int incAbility; public int incSprayTimes; public int incCount; public int extraIncCount; public bool incUsed; public OptimizedSpraycoater(int incommingBeltSegIndexPlusSegPivotOffset, BeltIndex incommingBeltIndex, BeltIndex outgoingBeltIndex, int outgoingBeltSegIndexPlusSegPivotOffset, int outgoingBeltSpeed, PowerNetwork? powerNetwork, OptimizedItemId incItemId, [In][RequiresLocation] ref SpraycoaterComponent spraycoater) { this.incommingBeltSegIndexPlusSegPivotOffset = incommingBeltSegIndexPlusSegPivotOffset; this.incommingBeltIndex = incommingBeltIndex; this.outgoingBeltIndex = outgoingBeltIndex; this.outgoingBeltSegIndexPlusSegPivotOffset = outgoingBeltSegIndexPlusSegPivotOffset; this.outgoingBeltSpeed = outgoingBeltSpeed; this.powerNetwork = powerNetwork; this.incItemId = incItemId; incCapacity = spraycoater.incCapacity; incAbility = spraycoater.incAbility; incSprayTimes = spraycoater.incSprayTimes; incCount = spraycoater.incCount; extraIncCount = spraycoater.extraIncCount; incUsed = spraycoater.incUsed; } public void InternalUpdate(OptimizedItemId[] incItemIds, int[] consumeRegister, ref bool isSpraycoatingItem, ref int sprayTime, OptimizedCargoPath[] optimizedCargoPaths) { int offset; if (incommingBeltIndex.HasValue && incCount + extraIncCount < incCapacity) { ref OptimizedCargoPath belt = ref incommingBeltIndex.GetBelt(optimizedCargoPaths); if (belt.GetCargoAtIndex(incommingBeltSegIndexPlusSegPivotOffset, out var cargo, out var _, out offset)) { if (cargo.Item != incItemId.ItemIndex && incCount == 0 && incCount == 0) { incItemId = default(OptimizedItemId); incAbility = 0; } if (incItemId.ItemIndex == 0 && cargo.Item != 0) { for (int i = 0; i < incItemIds.Length; i++) { if (cargo.Item == incItemIds[i].ItemIndex) { ItemProto val = ((ProtoSet)(object)LDB.items).Select((int)incItemIds[i].ItemIndex); incItemId = incItemIds[i]; incAbility = val.Ability; incSprayTimes = val.HpMax; break; } } } if (incItemId.ItemIndex != 0 && incItemId.ItemIndex == cargo.Item && belt.TryPickItem(incommingBeltSegIndexPlusSegPivotOffset - 2, 5, incItemId.ItemIndex, out var cargo2)) { int num = cargo2.Inc; int stack = cargo2.Stack; for (int j = 0; j < stack; j++) { int num2 = stack - j; int num3 = (int)((float)num / (float)num2 + 0.5f); num3 = ((num3 > 10) ? 10 : num3); incCount += incSprayTimes; extraIncCount += (int)((double)incSprayTimes * ((double)Cargo.incTable[num3] * 0.001) + 0.1); if (!incUsed) { incUsed = extraIncCount > 0; } num -= num3; } } } } float num4 = ((powerNetwork != null) ? ((float)powerNetwork.consumerRatio) : 0f); bool flag = num4 > 0.1f; if (!outgoingBeltIndex.HasValue) { return; } if (sprayTime < 10000) { sprayTime += (flag ? (outgoingBeltSpeed * (int)(1000f * num4)) : 0); } else { isSpraycoatingItem = false; } ref OptimizedCargoPath belt2 = ref outgoingBeltIndex.GetBelt(optimizedCargoPaths); if (!flag || !belt2.GetCargoAtIndex(outgoingBeltSegIndexPlusSegPivotOffset, out var cargo3, out var cargoBufferIndex2, out offset) || sprayTime < 10000) { return; } int num5 = ((cargo3.Stack > incCount + extraIncCount) ? (incCount + extraIncCount) : cargo3.Stack); if (num5 * incAbility > cargo3.Inc) { sprayTime -= 10000; cargo3.Inc = (byte)(num5 * incAbility); belt2.SetCargoInBuffer(cargoBufferIndex2, cargo3); extraIncCount -= num5; if (extraIncCount < 0) { int num6 = incCount; incCount += extraIncCount; extraIncCount = 0; consumeRegister[incItemId.OptimizedItemIndex] += num6 / incSprayTimes - incCount / incSprayTimes; if (incCount <= 0) { incItemId = default(OptimizedItemId); incAbility = 0; } } } isSpraycoatingItem = true; } public readonly void Save(ref SpraycoaterComponent spraycoater, bool isSpraycoatingItem, int sprayTime) { spraycoater.incItemId = incItemId.ItemIndex; spraycoater.incAbility = incAbility; spraycoater.incSprayTimes = incSprayTimes; spraycoater.incCount = incCount; spraycoater.extraIncCount = extraIncCount; spraycoater.incUsed = incUsed; spraycoater.cargoBeltItemId = (isSpraycoatingItem ? 1 : 0); spraycoater.sprayTime = sprayTime; } } internal sealed class SpraycoaterExecutor { private ReadonlyArray _spraycoaterNetworkIds; private OptimizedSpraycoater[] _optimizedSpraycoaters; private bool[] _isSpraycoatingItems; private int[] _sprayTimes; private OptimizedItemId[] _incItemIds; public Dictionary _spraycoaterIdToOptimizedSpraycoaterIndex; private PrototypePowerConsumptionExecutor _prototypePowerConsumptionExecutor; public int Count => _optimizedSpraycoaters.Length; public void GameTick(ReadonlyArray spraycoaterPowerConsumerTypeIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption, int[] consumeRegister, OptimizedCargoPath[] optimizedCargoPaths) { OptimizedSpraycoater[] optimizedSpraycoaters = _optimizedSpraycoaters; bool[] isSpraycoatingItems = _isSpraycoatingItems; int[] sprayTimes = _sprayTimes; OptimizedItemId[] incItemIds = _incItemIds; ReadonlyArray spraycoaterNetworkIds = _spraycoaterNetworkIds; for (int i = 0; i < optimizedSpraycoaters.Length; i++) { _ = isSpraycoatingItems[i]; _ = sprayTimes[i]; optimizedSpraycoaters[i].InternalUpdate(incItemIds, consumeRegister, ref isSpraycoatingItems[i], ref sprayTimes[i], optimizedCargoPaths); short networkIndex = spraycoaterNetworkIds[i]; UpdatePower(spraycoaterPowerConsumerTypeIndexes, powerConsumerTypes, thisSubFactoryNetworkPowerConsumption, i, networkIndex, isSpraycoatingItems[i], sprayTimes[i]); } } public void UpdatePower(ReadonlyArray spraycoaterPowerConsumerTypeIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption) { ReadonlyArray spraycoaterNetworkIds = _spraycoaterNetworkIds; bool[] isSpraycoatingItems = _isSpraycoatingItems; int[] sprayTimes = _sprayTimes; for (int i = 0; i < spraycoaterNetworkIds.Length; i++) { short networkIndex = spraycoaterNetworkIds[i]; UpdatePower(spraycoaterPowerConsumerTypeIndexes, powerConsumerTypes, thisSubFactoryNetworkPowerConsumption, i, networkIndex, isSpraycoatingItems[i], sprayTimes[i]); } } private static void UpdatePower(ReadonlyArray spraycoaterPowerConsumerTypeIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption, int spraycoaterIndex, short networkIndex, bool isSpraycoatingItem, int sprayTime) { int index = spraycoaterPowerConsumerTypeIndexes[spraycoaterIndex]; PowerConsumerType powerConsumerType = powerConsumerTypes[index]; thisSubFactoryNetworkPowerConsumption[networkIndex] += GetPowerConsumption(powerConsumerType, isSpraycoatingItem, sprayTime); } public PrototypePowerConsumptions UpdatePowerConsumptionPerPrototype(ReadonlyArray spraycoaterPowerConsumerTypeIndexes, ReadonlyArray powerConsumerTypes) { PrototypePowerConsumptionExecutor prototypePowerConsumptionExecutor = _prototypePowerConsumptionExecutor; prototypePowerConsumptionExecutor.Clear(); bool[] isSpraycoatingItems = _isSpraycoatingItems; int[] sprayTimes = _sprayTimes; ReadonlyArray prototypeIdIndexes = prototypePowerConsumptionExecutor.PrototypeIdIndexes; long[] prototypeIdPowerConsumption = prototypePowerConsumptionExecutor.PrototypeIdPowerConsumption; for (int i = 0; i < isSpraycoatingItems.Length; i++) { bool isSpraycoatingItem = isSpraycoatingItems[i]; int sprayTime = sprayTimes[i]; UpdatePowerConsumptionPerPrototype(spraycoaterPowerConsumerTypeIndexes, powerConsumerTypes, prototypeIdIndexes, prototypeIdPowerConsumption, i, isSpraycoatingItem, sprayTime); } return prototypePowerConsumptionExecutor.GetPowerConsumption(); } private static void UpdatePowerConsumptionPerPrototype(ReadonlyArray spraycoaterPowerConsumerTypeIndexes, ReadonlyArray powerConsumerTypes, ReadonlyArray prototypeIdIndexes, long[] prototypeIdPowerConsumption, int spraycoaterIndex, bool isSpraycoatingItem, int sprayTime) { int index = spraycoaterPowerConsumerTypeIndexes[spraycoaterIndex]; PowerConsumerType powerConsumerType = powerConsumerTypes[index]; prototypeIdPowerConsumption[prototypeIdIndexes[spraycoaterIndex]] += GetPowerConsumption(powerConsumerType, isSpraycoatingItem, sprayTime); } public void Save(PlanetFactory planet) { SpraycoaterComponent[] spraycoaterPool = planet.cargoTraffic.spraycoaterPool; OptimizedSpraycoater[] optimizedSpraycoaters = _optimizedSpraycoaters; bool[] isSpraycoatingItems = _isSpraycoatingItems; int[] sprayTimes = _sprayTimes; for (int i = 1; i < planet.cargoTraffic.spraycoaterCursor; i++) { if (_spraycoaterIdToOptimizedSpraycoaterIndex.TryGetValue(i, out var value)) { optimizedSpraycoaters[value].Save(ref spraycoaterPool[i], isSpraycoatingItems[value], sprayTimes[value]); } } } public void Initialize(PlanetFactory planet, Graph subFactoryGraph, SubFactoryPowerSystemBuilder subFactoryPowerSystemBuilder, SubFactoryProductionRegisterBuilder subFactoryProductionRegisterBuilder, BeltExecutor beltExecutor, UniverseStaticDataBuilder universeStaticDataBuilder) { //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0131: 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_017f: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_019a: 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 list = new List(); List list2 = new List(); List list3 = new List(); List list4 = new List(); Dictionary dictionary = new Dictionary(); PrototypePowerConsumptionBuilder prototypePowerConsumptionBuilder = new PrototypePowerConsumptionBuilder(); int[] array = null; foreach (int item in from x in subFactoryGraph.GetAllNodes() where x.EntityTypeIndex.EntityType == EntityType.SprayCoater select x.EntityTypeIndex.Index into x orderby x select x) { ref SpraycoaterComponent reference = ref planet.cargoTraffic.spraycoaterPool[item]; if (reference.id == item && (reference.incBeltId != 0 || reference.cargoBeltId != 0)) { BeltComponent? val = null; int incommingBeltSegIndexPlusSegPivotOffset = 0; if (beltExecutor.TryGetOptimizedCargoPathIndex(planet, reference.incBeltId, out var beltIndex)) { val = planet.cargoTraffic.beltPool[reference.incBeltId]; incommingBeltSegIndexPlusSegPivotOffset = val.Value.segIndex + val.Value.segPivotOffset; } BeltComponent? val2 = null; int outgoingBeltSegIndexPlusSegPivotOffset = 0; int outgoingBeltSpeed = 0; if (beltExecutor.TryGetOptimizedCargoPathIndex(planet, reference.cargoBeltId, out var beltIndex2)) { val2 = planet.cargoTraffic.beltPool[reference.cargoBeltId]; outgoingBeltSegIndexPlusSegPivotOffset = val2.Value.segIndex + val2.Value.segPivotOffset; outgoingBeltSpeed = val2.Value.speed; } OptimizedItemId incItemId = default(OptimizedItemId); if (reference.incItemId != 0) { incItemId = subFactoryProductionRegisterBuilder.AddConsume(reference.incItemId); } int[] incItemId2 = ((ProtoSet)(object)LDB.models).Select((int)planet.cargoTraffic.factory.entityPool[reference.entityId].modelIndex).prefabDesc.incItemId; if (array != null && !array.SequenceEqual(incItemId2)) { throw new InvalidOperationException("Assumption that incItemIds is the same for all spray coaters is not correct."); } array = incItemId2; _ = reference; int networkId = planet.powerSystem.consumerPool[reference.pcId].networkId; PowerNetwork powerNetwork = ((networkId != 0) ? planet.powerSystem.netPool[networkId] : null); subFactoryPowerSystemBuilder.AddSpraycoater(ref reference, networkId); dictionary.Add(item, list2.Count); list.Add(ConverterUtilities.ThrowIfNotWithinPositiveShortRange(networkId, "networkId")); list2.Add(new OptimizedSpraycoater(incommingBeltSegIndexPlusSegPivotOffset, beltIndex, beltIndex2, outgoingBeltSegIndexPlusSegPivotOffset, outgoingBeltSpeed, powerNetwork, incItemId, ref reference)); list3.Add(reference.cargoBeltItemId != 0); list4.Add(reference.sprayTime); prototypePowerConsumptionBuilder.AddPowerConsumer(ref planet.entityPool[reference.entityId]); } } if (array == null) { array = Array.Empty(); } _incItemIds = subFactoryProductionRegisterBuilder.AddConsume(array); _spraycoaterNetworkIds = universeStaticDataBuilder.DeduplicateArrayUnmanaged(list); _optimizedSpraycoaters = list2.ToArray(); _isSpraycoatingItems = list3.ToArray(); _sprayTimes = list4.ToArray(); _spraycoaterIdToOptimizedSpraycoaterIndex = dictionary; _prototypePowerConsumptionExecutor = prototypePowerConsumptionBuilder.Build(universeStaticDataBuilder); } private static long GetPowerConsumption(PowerConsumerType powerConsumerType, bool isSprayCoatingItem, int sprayTime) { return powerConsumerType.GetRequiredEnergy(sprayTime < 10000 && isSprayCoatingItem); } } } namespace Weaver.Optimizations.Splitters { [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct OptimizedSplitter { private readonly BeltIndex beltA; private readonly BeltIndex beltB; private readonly BeltIndex beltC; private readonly BeltIndex beltD; private readonly int topId; private bool inPriority; private bool outPriority; private byte prioritySlotPresets; private int outFilter; private int outFilterPreset; private BeltIndex input0Index; private BeltIndex input1Index; private BeltIndex input2Index; private BeltIndex input3Index; private BeltIndex output0Index; private BeltIndex output1Index; private BeltIndex output2Index; private BeltIndex output3Index; public OptimizedSplitter([In][RequiresLocation] ref SplitterComponent splitter, BeltIndex beltA, BeltIndex beltB, BeltIndex beltC, BeltIndex beltD, BeltIndex input0Index, BeltIndex input1Index, BeltIndex input2Index, BeltIndex input3Index, BeltIndex output0Index, BeltIndex output1Index, BeltIndex output2Index, BeltIndex output3Index) { this.beltA = beltA; this.beltB = beltB; this.beltC = beltC; this.beltD = beltD; topId = splitter.topId; inPriority = splitter.inPriority; outPriority = splitter.outPriority; prioritySlotPresets = splitter.prioritySlotPresets; outFilter = splitter.outFilter; outFilterPreset = splitter.outFilterPreset; this.input0Index = input0Index; this.input1Index = input1Index; this.input2Index = input2Index; this.input3Index = input3Index; this.output0Index = output0Index; this.output1Index = output1Index; this.output2Index = output2Index; this.output3Index = output3Index; } public void UpdateSplitter(OptimizedSubFactory subFactory, OptimizedCargoPath[] optimizedCargoPaths) { CheckPriorityPreset(); if (topId == 0) { if (!input0Index.HasValue || !output0Index.HasValue) { return; } } else if (!input0Index.HasValue && !output0Index.HasValue) { return; } BeltIndex beltIndex = BeltIndex.NoBelt; BeltIndex beltIndex2 = BeltIndex.NoBelt; BeltIndex beltIndex3 = BeltIndex.NoBelt; BeltIndex noBelt = BeltIndex.NoBelt; OptimizedCargo cargo = default(OptimizedCargo); OptimizedCargo optimizedCargo = default(OptimizedCargo); OptimizedCargo optimizedCargo2 = default(OptimizedCargo); OptimizedCargo optimizedCargo3 = default(OptimizedCargo); int index = -1; int num = -1; int num2 = -1; int num3 = -1; BeltIndex noBelt2 = BeltIndex.NoBelt; if (input0Index.HasValue) { if (input0Index.GetBelt(optimizedCargoPaths).TryGetCargoIdAtRear(out var cargo2)) { cargo = cargo2; beltIndex = input0Index; index = 0; } if (input1Index.HasValue) { if (input1Index.GetBelt(optimizedCargoPaths).TryGetCargoIdAtRear(out cargo2)) { if (!beltIndex.HasValue) { cargo = cargo2; beltIndex = input1Index; index = 1; } else { optimizedCargo = cargo2; beltIndex2 = input1Index; num = 1; } } if (input2Index.HasValue) { if (input2Index.GetBelt(optimizedCargoPaths).TryGetCargoIdAtRear(out cargo2)) { if (!beltIndex.HasValue) { cargo = cargo2; beltIndex = input2Index; index = 2; } else if (!beltIndex2.HasValue) { optimizedCargo = cargo2; beltIndex2 = input2Index; num = 2; } else { optimizedCargo2 = cargo2; beltIndex3 = input2Index; num2 = 2; } } if (input3Index.HasValue && input3Index.GetBelt(optimizedCargoPaths).TryGetCargoIdAtRear(out cargo2)) { if (!beltIndex.HasValue) { cargo = cargo2; beltIndex = input3Index; index = 3; } else if (!beltIndex2.HasValue) { optimizedCargo = cargo2; beltIndex2 = input3Index; num = 3; } else if (!beltIndex3.HasValue) { optimizedCargo2 = cargo2; beltIndex3 = input3Index; num2 = 3; } else { optimizedCargo3 = cargo2; noBelt = input3Index; num3 = 3; } } } } } int index2; while (beltIndex.HasValue) { bool flag = true; if (outFilter != 0) { flag = cargo.Item == outFilter; } noBelt2 = BeltIndex.NoBelt; index2 = 0; int num4 = -1; if (!flag && outFilter != 0) { goto IL_0279; } if (output0Index.HasValue) { ref OptimizedCargoPath belt = ref output0Index.GetBelt(optimizedCargoPaths); num4 = belt.TestBlankAtHead(); if (belt.pathLength <= 10 || num4 < 0) { goto IL_0279; } noBelt2 = output0Index; index2 = 0; } goto IL_033d; IL_0279: if ((!flag || outFilter == 0) && output1Index.HasValue) { ref OptimizedCargoPath belt2 = ref output1Index.GetBelt(optimizedCargoPaths); num4 = belt2.TestBlankAtHead(); if (belt2.pathLength > 10 && num4 >= 0) { noBelt2 = output1Index; index2 = 1; } else if (output2Index.HasValue) { ref OptimizedCargoPath belt3 = ref output2Index.GetBelt(optimizedCargoPaths); num4 = belt3.TestBlankAtHead(); if (belt3.pathLength > 10 && num4 >= 0) { noBelt2 = output2Index; index2 = 2; } else if (output3Index.HasValue) { ref OptimizedCargoPath belt4 = ref output3Index.GetBelt(optimizedCargoPaths); num4 = belt4.TestBlankAtHead(); if (belt4.pathLength > 10 && num4 >= 0) { noBelt2 = output3Index; index2 = 3; } } } } goto IL_033d; IL_033d: if (noBelt2.HasValue) { ref OptimizedCargoPath belt5 = ref beltIndex.GetBelt(optimizedCargoPaths); ref OptimizedCargoPath belt6 = ref noBelt2.GetBelt(optimizedCargoPaths); belt5.TryPickCargoAtEnd(out var cargo3); Assert.True(cargo3.Item >= 0); belt6.InsertCargoAtHeadDirect(cargo3, num4); InputAlternate(index); OutputAlternate(index2); } else if (topId != 0 && (flag || outFilter == 0) && subFactory.InsertCargoIntoStorage(topId, cargo)) { beltIndex.GetBelt(optimizedCargoPaths).TryPickCargoAtEnd(out var cargo4); Assert.True(cargo4.Item >= 0); InputAlternate(index); } beltIndex = beltIndex2; cargo = optimizedCargo; index = num; beltIndex2 = beltIndex3; optimizedCargo = optimizedCargo2; num = num2; beltIndex3 = noBelt; optimizedCargo2 = optimizedCargo3; num2 = num3; noBelt = BeltIndex.NoBelt; optimizedCargo3 = default(OptimizedCargo); num3 = -1; } if (topId == 0) { return; } if (outFilter == 0) { int num5 = 4; while (num5-- > 0) { noBelt2 = BeltIndex.NoBelt; index2 = 0; int num6 = -1; if (output0Index.HasValue) { ref OptimizedCargoPath belt7 = ref output0Index.GetBelt(optimizedCargoPaths); num6 = belt7.TestBlankAtHead(); if (belt7.pathLength > 10 && num6 >= 0) { noBelt2 = output0Index; index2 = 0; } else if (output1Index.HasValue) { ref OptimizedCargoPath belt8 = ref output1Index.GetBelt(optimizedCargoPaths); num6 = belt8.TestBlankAtHead(); if (belt8.pathLength > 10 && num6 >= 0) { noBelt2 = output1Index; index2 = 1; } else if (output2Index.HasValue) { ref OptimizedCargoPath belt9 = ref output2Index.GetBelt(optimizedCargoPaths); num6 = belt9.TestBlankAtHead(); if (belt9.pathLength > 10 && num6 >= 0) { noBelt2 = output2Index; index2 = 2; } else if (output3Index.HasValue) { ref OptimizedCargoPath belt10 = ref output3Index.GetBelt(optimizedCargoPaths); num6 = belt10.TestBlankAtHead(); if (belt10.pathLength > 10 && num6 >= 0) { noBelt2 = output3Index; index2 = 3; } } } } } if (noBelt2.HasValue) { int filter = ((index2 == 0) ? outFilter : (-outFilter)); int inc; int num7 = subFactory.PickFromStorageFiltered(topId, ref filter, 1, out inc); if (filter > 0 && num7 > 0) { OptimizedCargo optimizedCargo4 = new OptimizedCargo((short)filter, (byte)num7, (byte)inc); noBelt2.GetBelt(optimizedCargoPaths).InsertCargoAtHeadDirect(optimizedCargo4, num6); OutputAlternate(index2); continue; } break; } break; } return; } noBelt2 = BeltIndex.NoBelt; index2 = 0; int num8 = -1; if (output0Index.HasValue) { ref OptimizedCargoPath belt11 = ref output0Index.GetBelt(optimizedCargoPaths); num8 = belt11.TestBlankAtHead(); if (belt11.pathLength > 10 && num8 >= 0) { noBelt2 = output0Index; index2 = 0; } } if (noBelt2.HasValue) { int filter2 = outFilter; int inc2; int num9 = subFactory.PickFromStorageFiltered(topId, ref filter2, 1, out inc2); if (filter2 > 0 && num9 > 0) { OptimizedCargo optimizedCargo5 = new OptimizedCargo((short)filter2, (byte)num9, (byte)inc2); noBelt2.GetBelt(optimizedCargoPaths).InsertCargoAtHeadDirect(optimizedCargo5, num8); OutputAlternate(index2); } } int num10 = 3; while (num10-- > 0) { noBelt2 = BeltIndex.NoBelt; index2 = 0; int num11 = -1; if (output1Index.HasValue) { ref OptimizedCargoPath belt12 = ref output1Index.GetBelt(optimizedCargoPaths); num11 = belt12.TestBlankAtHead(); if (belt12.pathLength > 10 && num11 >= 0) { noBelt2 = output1Index; index2 = 1; } else if (output2Index.HasValue) { ref OptimizedCargoPath belt13 = ref output2Index.GetBelt(optimizedCargoPaths); num11 = belt13.TestBlankAtHead(); if (belt13.pathLength > 10 && num11 >= 0) { noBelt2 = output2Index; index2 = 2; } else if (output3Index.HasValue) { ref OptimizedCargoPath belt14 = ref output3Index.GetBelt(optimizedCargoPaths); num11 = belt14.TestBlankAtHead(); if (belt14.pathLength > 10 && num11 >= 0) { noBelt2 = output3Index; index2 = 3; } } } } if (noBelt2.HasValue) { int filter3 = -outFilter; int inc3; int num12 = subFactory.PickFromStorageFiltered(topId, ref filter3, 1, out inc3); if (filter3 > 0 && num12 > 0) { OptimizedCargo optimizedCargo6 = new OptimizedCargo((short)filter3, (byte)num12, (byte)inc3); noBelt2.GetBelt(optimizedCargoPaths).InsertCargoAtHeadDirect(optimizedCargo6, num11); OutputAlternate(index2); continue; } break; } break; } } private void CheckPriorityPreset() { if (prioritySlotPresets > 0) { if ((prioritySlotPresets & 1) == 1) { SetPriority(0, isPriority: true, outFilterPreset); } if ((prioritySlotPresets & 2) == 2) { SetPriority(1, isPriority: true, outFilterPreset); } if ((prioritySlotPresets & 4) == 4) { SetPriority(2, isPriority: true, outFilterPreset); } if ((prioritySlotPresets & 8) == 8) { SetPriority(3, isPriority: true, outFilterPreset); } } else { outFilterPreset = 0; } } private void SetPriority(int slot, bool isPriority, int filter) { BeltIndex noBelt = BeltIndex.NoBelt; switch (slot) { case 0: noBelt = beltA; break; case 1: noBelt = beltB; break; case 2: noBelt = beltC; break; case 3: noBelt = beltD; break; } if (!noBelt.HasValue) { if (isPriority) { prioritySlotPresets |= (byte)(1 << slot); outFilterPreset = filter; } else { prioritySlotPresets &= (byte)(~(1 << slot)); } return; } prioritySlotPresets &= (byte)(~(1 << slot)); if (prioritySlotPresets == 0) { outFilterPreset = 0; } if (isPriority) { if (input0Index == noBelt) { inPriority = true; } else if (input1Index == noBelt) { inPriority = true; BeltIndex beltIndex = input0Index; input0Index = input1Index; input1Index = beltIndex; } else if (input2Index == noBelt) { inPriority = true; BeltIndex beltIndex2 = input0Index; input0Index = input2Index; input2Index = beltIndex2; } else if (input3Index == noBelt) { inPriority = true; BeltIndex beltIndex3 = input0Index; input0Index = input3Index; input3Index = beltIndex3; } else if (output0Index == noBelt) { outPriority = true; outFilter = filter; outFilterPreset = 0; } else if (output1Index == noBelt) { outPriority = true; BeltIndex beltIndex4 = output0Index; output0Index = output1Index; output1Index = beltIndex4; outFilter = filter; outFilterPreset = 0; } else if (output2Index == noBelt) { outPriority = true; BeltIndex beltIndex5 = output0Index; output0Index = output2Index; output2Index = beltIndex5; outFilter = filter; outFilterPreset = 0; } else if (output3Index == noBelt) { outPriority = true; BeltIndex beltIndex6 = output0Index; output0Index = output3Index; output3Index = beltIndex6; outFilter = filter; outFilterPreset = 0; } InputReorder(); OutputReorder(); } else if (input0Index == noBelt) { inPriority = false; } else if (output0Index == noBelt) { outPriority = false; outFilter = 0; outFilterPreset = 0; } } private void InputAlternate(int index) { switch (index) { case 0: { if (inPriority) { return; } BeltIndex beltIndex3 = input0Index; input0Index = input1Index; input1Index = input2Index; input2Index = input3Index; input3Index = beltIndex3; break; } case 1: { BeltIndex beltIndex2 = input1Index; input1Index = input2Index; input2Index = input3Index; input3Index = beltIndex2; break; } case 2: { BeltIndex beltIndex = input2Index; input2Index = input3Index; input3Index = beltIndex; break; } } InputReorder(); } private void InputReorder() { if (!input0Index.HasValue) { if (!input1Index.HasValue) { if (input2Index.HasValue) { input0Index = input2Index; input1Index = input3Index; input2Index = BeltIndex.NoBelt; input3Index = BeltIndex.NoBelt; } else if (input3Index.HasValue) { input0Index = input3Index; input1Index = BeltIndex.NoBelt; input2Index = BeltIndex.NoBelt; input3Index = BeltIndex.NoBelt; } return; } input0Index = input1Index; input1Index = input2Index; input2Index = input3Index; input3Index = BeltIndex.NoBelt; } if (!input1Index.HasValue) { if (input2Index.HasValue) { input1Index = input2Index; input2Index = input3Index; input3Index = BeltIndex.NoBelt; } else if (input3Index.HasValue) { input1Index = input3Index; input2Index = BeltIndex.NoBelt; input3Index = BeltIndex.NoBelt; } } else if (!input2Index.HasValue) { input2Index = input3Index; input3Index = BeltIndex.NoBelt; } } private void OutputAlternate(int index) { switch (index) { case 0: { if (outPriority) { return; } BeltIndex beltIndex3 = output0Index; output0Index = output1Index; output1Index = output2Index; output2Index = output3Index; output3Index = beltIndex3; break; } case 1: { BeltIndex beltIndex2 = output1Index; output1Index = output2Index; output2Index = output3Index; output3Index = beltIndex2; break; } case 2: { BeltIndex beltIndex = output2Index; output2Index = output3Index; output3Index = beltIndex; break; } } OutputReorder(); } private void OutputReorder() { if (!output0Index.HasValue) { if (!output1Index.HasValue) { if (output2Index.HasValue) { output0Index = output2Index; output1Index = output3Index; output2Index = BeltIndex.NoBelt; output3Index = BeltIndex.NoBelt; } else if (output3Index.HasValue) { output0Index = output3Index; output1Index = BeltIndex.NoBelt; output2Index = BeltIndex.NoBelt; output3Index = BeltIndex.NoBelt; } return; } output0Index = output1Index; output1Index = output2Index; output2Index = output3Index; output3Index = BeltIndex.NoBelt; } if (!output1Index.HasValue) { if (output2Index.HasValue) { output1Index = output2Index; output2Index = output3Index; output3Index = BeltIndex.NoBelt; } else if (output3Index.HasValue) { output1Index = output3Index; output2Index = BeltIndex.NoBelt; output3Index = BeltIndex.NoBelt; } } else if (!output2Index.HasValue) { output2Index = output3Index; output3Index = BeltIndex.NoBelt; } } } internal sealed class SplitterExecutor { private OptimizedSplitter[] _optimizedSplitters; public int Count => _optimizedSplitters.Length; public void GameTick(OptimizedSubFactory subFactory, OptimizedCargoPath[] optimizedCargoPaths) { OptimizedSplitter[] optimizedSplitters = _optimizedSplitters; for (int i = 0; i < optimizedSplitters.Length; i++) { optimizedSplitters[i].UpdateSplitter(subFactory, optimizedCargoPaths); } } public void Initialize(PlanetFactory planet, Graph subFactoryGraph, BeltExecutor beltExecutor) { List list = new List(); foreach (int item in from x in subFactoryGraph.GetAllNodes() where x.EntityTypeIndex.EntityType == EntityType.Splitter select x.EntityTypeIndex.Index into x orderby x select x) { ref SplitterComponent reference = ref planet.cargoTraffic.splitterPool[item]; if (reference.id == item) { beltExecutor.TryGetOptimizedCargoPathIndex(planet, reference.beltA, out var beltIndex); beltExecutor.TryGetOptimizedCargoPathIndex(planet, reference.beltB, out var beltIndex2); beltExecutor.TryGetOptimizedCargoPathIndex(planet, reference.beltC, out var beltIndex3); beltExecutor.TryGetOptimizedCargoPathIndex(planet, reference.beltD, out var beltIndex4); beltExecutor.TryGetOptimizedCargoPathIndex(planet, reference.input0, out var beltIndex5); beltExecutor.TryGetOptimizedCargoPathIndex(planet, reference.input1, out var beltIndex6); beltExecutor.TryGetOptimizedCargoPathIndex(planet, reference.input2, out var beltIndex7); beltExecutor.TryGetOptimizedCargoPathIndex(planet, reference.input3, out var beltIndex8); beltExecutor.TryGetOptimizedCargoPathIndex(planet, reference.output0, out var beltIndex9); beltExecutor.TryGetOptimizedCargoPathIndex(planet, reference.output1, out var beltIndex10); beltExecutor.TryGetOptimizedCargoPathIndex(planet, reference.output2, out var beltIndex11); beltExecutor.TryGetOptimizedCargoPathIndex(planet, reference.output3, out var beltIndex12); list.Add(new OptimizedSplitter(ref reference, beltIndex, beltIndex2, beltIndex3, beltIndex4, beltIndex5, beltIndex6, beltIndex7, beltIndex8, beltIndex9, beltIndex10, beltIndex11, beltIndex12)); } } _optimizedSplitters = list.ToArray(); } } } namespace Weaver.Optimizations.Silos { internal sealed class SiloExecutor { public ReadonlyArray _siloIndexes; private ReadonlyArray _optimizedBulletItemId; private ReadonlyArray _siloNetworkIds; private Dictionary _siloIdToOptimizedSiloIndex; private PrototypePowerConsumptionExecutor _prototypePowerConsumptionExecutor; public const int SoleSiloNeedsIndex = 0; public int Count => _siloIndexes.Length; public int GetOptimizedSiloIndex(int siloId) { return _siloIdToOptimizedSiloIndex[siloId]; } public void GameTick(PlanetFactory planet, ReadonlyArray siloPowerConsumerTypeIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption, int[] consumeRegister, SubFactoryNeeds subFactoryNeeds) { float[] networkServes = planet.powerSystem.networkServes; ReadonlyArray siloIndexes = _siloIndexes; ReadonlyArray siloNetworkIds = _siloNetworkIds; SiloComponent[] siloPool = planet.factorySystem.siloPool; ReadonlyArray optimizedBulletItemId = _optimizedBulletItemId; GroupNeeds groupNeeds = subFactoryNeeds.GetGroupNeeds(EntityType.Silo); ComponentNeeds[] componentsNeeds = subFactoryNeeds.ComponentsNeeds; DysonSphere dysonSphere = planet.factorySystem.factory.dysonSphere; for (int i = 0; i < siloIndexes.Length; i++) { int num = siloIndexes[i]; short optimizedBulletId = optimizedBulletItemId[i]; int objectNeedsIndex = groupNeeds.GetObjectNeedsIndex(i); short num2 = siloNetworkIds[i]; float power = networkServes[num2]; ref SiloComponent silo = ref siloPool[num]; InternalUpdate(ref silo, power, dysonSphere, optimizedBulletId, consumeRegister, componentsNeeds, objectNeedsIndex); UpdatePower(siloPowerConsumerTypeIndexes, powerConsumerTypes, thisSubFactoryNetworkPowerConsumption, i, num2, ref silo); } } public void UpdatePower(PlanetFactory planet, ReadonlyArray siloPowerConsumerTypeIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption) { ReadonlyArray siloIndexes = _siloIndexes; ReadonlyArray siloNetworkIds = _siloNetworkIds; SiloComponent[] siloPool = planet.factorySystem.siloPool; for (int i = 0; i < siloIndexes.Length; i++) { int num = siloIndexes[i]; short networkIndex = siloNetworkIds[i]; UpdatePower(siloPowerConsumerTypeIndexes, powerConsumerTypes, thisSubFactoryNetworkPowerConsumption, i, networkIndex, ref siloPool[num]); } } private static void UpdatePower(ReadonlyArray siloPowerConsumerTypeIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption, int siloIndexIndex, short networkIndex, [In][RequiresLocation] ref SiloComponent silo) { int index = siloPowerConsumerTypeIndexes[siloIndexIndex]; PowerConsumerType powerConsumerType = powerConsumerTypes[index]; thisSubFactoryNetworkPowerConsumption[networkIndex] += GetPowerConsumption(powerConsumerType, ref silo); } public PrototypePowerConsumptions UpdatePowerConsumptionPerPrototype(PlanetFactory planet, ReadonlyArray siloPowerConsumerTypeIndexes, ReadonlyArray powerConsumerTypes) { PrototypePowerConsumptionExecutor prototypePowerConsumptionExecutor = _prototypePowerConsumptionExecutor; prototypePowerConsumptionExecutor.Clear(); ReadonlyArray siloIndexes = _siloIndexes; SiloComponent[] siloPool = planet.factorySystem.siloPool; ReadonlyArray prototypeIdIndexes = prototypePowerConsumptionExecutor.PrototypeIdIndexes; long[] prototypeIdPowerConsumption = prototypePowerConsumptionExecutor.PrototypeIdPowerConsumption; for (int i = 0; i < siloIndexes.Length; i++) { int num = siloIndexes[i]; UpdatePowerConsumptionPerPrototype(siloPowerConsumerTypeIndexes, powerConsumerTypes, prototypeIdIndexes, prototypeIdPowerConsumption, i, ref siloPool[num]); } return prototypePowerConsumptionExecutor.GetPowerConsumption(); } private static void UpdatePowerConsumptionPerPrototype(ReadonlyArray siloPowerConsumerTypeIndexes, ReadonlyArray powerConsumerTypes, ReadonlyArray prototypeIdIndexes, long[] prototypeIdPowerConsumption, int siloIndexIndex, [In][RequiresLocation] ref SiloComponent silo) { int index = siloPowerConsumerTypeIndexes[siloIndexIndex]; PowerConsumerType powerConsumerType = powerConsumerTypes[index]; prototypeIdPowerConsumption[prototypeIdIndexes[siloIndexIndex]] += GetPowerConsumption(powerConsumerType, ref silo); } public void Save(PlanetFactory planet, SubFactoryNeeds subFactoryNeeds) { ReadonlyArray siloIndexes = _siloIndexes; SiloComponent[] siloPool = planet.factorySystem.siloPool; GroupNeeds groupNeeds = subFactoryNeeds.GetGroupNeeds(EntityType.Silo); ComponentNeeds[] componentsNeeds = subFactoryNeeds.ComponentsNeeds; short[] needsPatterns = subFactoryNeeds.NeedsPatterns; for (int i = 0; i < siloIndexes.Length; i++) { int num = siloIndexes[i]; int objectNeedsIndex = groupNeeds.GetObjectNeedsIndex(i); ComponentNeeds componentNeeds = componentsNeeds[objectNeedsIndex]; ref SiloComponent reference = ref siloPool[num]; for (int j = 0; j < groupNeeds.GroupNeedsSize; j++) { GroupNeeds.SetNeedsIfInRange(reference.needs, componentNeeds, needsPatterns, j); } } } public void Initialize(PlanetFactory planet, Graph subFactoryGraph, SubFactoryPowerSystemBuilder subFactoryPowerSystemBuilder, SubFactoryProductionRegisterBuilder subFactoryProductionRegisterBuilder, SubFactoryNeedsBuilder subFactoryNeedsBuilder, UniverseStaticDataBuilder universeStaticDataBuilder) { _siloIndexes = universeStaticDataBuilder.DeduplicateArrayUnmanaged((from x in subFactoryGraph.GetAllNodes() where x.EntityTypeIndex.EntityType == EntityType.Silo select x.EntityTypeIndex.Index into x orderby x select x).ToArray()); short[] array = new short[_siloIndexes.Length]; short[] array2 = new short[_siloIndexes.Length]; Dictionary dictionary = new Dictionary(); PrototypePowerConsumptionBuilder prototypePowerConsumptionBuilder = new PrototypePowerConsumptionBuilder(); GroupNeedsBuilder groupNeedsBuilder = subFactoryNeedsBuilder.CreateGroupNeedsBuilder(EntityType.Silo); for (int i = 0; i < _siloIndexes.Length; i++) { int num = _siloIndexes[i]; ref SiloComponent reference = ref planet.factorySystem.siloPool[num]; array[i] = subFactoryProductionRegisterBuilder.AddConsume(reference.bulletId).OptimizedItemIndex; int networkId = planet.powerSystem.consumerPool[reference.pcId].networkId; array2[i] = ConverterUtilities.ThrowIfNotWithinPositiveShortRange(networkId, "networkIndex"); dictionary.Add(num, i); ref int[] needs = ref reference.needs; if (needs == null) { needs = new int[6]; } planet.entityNeeds[reference.entityId] = reference.needs; groupNeedsBuilder.AddNeeds(reference.needs, new int[1] { reference.bulletId }); subFactoryPowerSystemBuilder.AddSilo(ref reference, networkId); prototypePowerConsumptionBuilder.AddPowerConsumer(ref planet.entityPool[reference.entityId]); } _optimizedBulletItemId = universeStaticDataBuilder.DeduplicateArrayUnmanaged(array); _siloNetworkIds = universeStaticDataBuilder.DeduplicateArrayUnmanaged(array2); _siloIdToOptimizedSiloIndex = dictionary; _prototypePowerConsumptionExecutor = prototypePowerConsumptionBuilder.Build(universeStaticDataBuilder); groupNeedsBuilder.Complete(); } private static long GetPowerConsumption(PowerConsumerType powerConsumerType, [In][RequiresLocation] ref SiloComponent silo) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) bool working = silo.direction != 0; int[] powerTable = Cargo.powerTable; SiloComponent val = silo; return powerConsumerType.GetRequiredEnergy(working, 1000 + powerTable[((SiloComponent)(ref val)).incLevel]); } private static uint InternalUpdate(ref SiloComponent silo, float power, DysonSphere sphere, short optimizedBulletId, int[] consumeRegister, ComponentNeeds[] componentsNeeds, int needsOffset) { //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_0228: 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_0239: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_024d: 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_0257: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_02a2: Unknown result type (might be due to invalid IL or missing references) //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: Unknown result type (might be due to invalid IL or missing references) componentsNeeds[needsOffset].Needs = ((silo.bulletCount < 20) ? ((byte)1) : ((byte)0)); if (silo.fired && silo.direction != -1) { silo.fired = false; } float num = (float)Cargo.accTableMilli[((SiloComponent)(ref silo)).incLevel]; int num2 = (int)(power * 10000f * (1f + num) + 0.1f); if (silo.boost) { num2 *= 10; } lock (sphere.dysonSphere_mx) { silo.hasNode = sphere.GetAutoNodeCount() > 0; if (!silo.hasNode) { silo.autoIndex = 0; if (silo.direction == 1) { silo.time = (int)((long)silo.time * (long)silo.coldSpend / silo.chargeSpend); silo.direction = -1; } if (silo.direction == -1) { silo.time -= num2; if (silo.time <= 0) { silo.time = 0; silo.direction = 0; } } if (power >= 0.1f) { return 1u; } return 0u; } if (power < 0.1f) { if (silo.direction == 1) { silo.time = (int)((long)silo.time * (long)silo.coldSpend / silo.chargeSpend); silo.direction = -1; } return 0u; } bool flag; int result = ((flag = silo.bulletCount > 0) ? 3 : 2); if (silo.direction == 1) { if (!flag) { silo.time = (int)((long)silo.time * (long)silo.coldSpend / silo.chargeSpend); silo.direction = -1; } } else if (silo.direction == 0 && flag) { silo.direction = 1; } if (silo.direction == 1) { silo.time += num2; if (silo.time >= silo.chargeSpend) { AstroData[] astrosData = sphere.starData.galaxy.astrosData; silo.fired = true; DysonNode autoDysonNode = sphere.GetAutoDysonNode(silo.autoIndex + silo.id); DysonRocket val = default(DysonRocket); val.planetId = silo.planetId; val.uPos = astrosData[silo.planetId].uPos + Maths.QRotateLF(astrosData[silo.planetId].uRot, VectorLF3.op_Implicit(silo.localPos + ((Vector3)(ref silo.localPos)).normalized * 6.1f)); val.uRot = astrosData[silo.planetId].uRot * silo.localRot * Quaternion.Euler(-90f, 0f, 0f); val.uVel = val.uRot * Vector3.forward; val.uSpeed = 0f; val.launch = ((Vector3)(ref silo.localPos)).normalized; sphere.AddDysonRocket(val, autoDysonNode); silo.autoIndex++; int num3 = silo.bulletInc / silo.bulletCount; if (!silo.incUsed) { silo.incUsed = num3 > 0; } silo.bulletInc -= num3; silo.bulletCount--; if (silo.bulletCount == 0) { silo.bulletInc = 0; } consumeRegister[optimizedBulletId]++; silo.time = silo.coldSpend; silo.direction = -1; sphere.gameData.spaceSector.AddHivePlanetHatred(sphere.starData.index, silo.planetId, 1); } } else if (silo.direction == -1) { silo.time -= num2; if (silo.time <= 0) { silo.time = 0; silo.direction = (flag ? 1 : 0); } } else { silo.time = 0; } return (uint)result; } } } } namespace Weaver.Optimizations.PowerSystems { internal record struct GeneratorID(int SubId, int PrototypeId); internal record struct GeneratorIDWithGenerators(GeneratorID GeneratorID, T[] OptimizedFuelGenerators); internal sealed class OptimizedPowerNetwork { private readonly PowerNetwork _powerNetwork; private readonly int _networkIndex; private readonly ReadonlyArray _networkNonOptimizedPowerConsumerIndexes; private readonly WindGeneratorExecutor _windExecutor; private readonly SolarGeneratorExecutor _solarExecutor; private readonly GammaPowerGeneratorExecutor _gammaPowerGeneratorExecutor; private readonly GeothermalGeneratorExecutor _geothermalGeneratorExecutor; private readonly FuelGeneratorExecutor _fuelGeneratorExecutor; private readonly PowerExchangerExecutor _powerExchangerExecutor; private readonly long _totalPowerNodeEnergyConsumption; public OptimizedPowerNetwork(PowerNetwork powerNetwork, int networkIndex, ReadonlyArray networkNonOptimizedPowerConsumerIndexes, WindGeneratorExecutor windExecutor, SolarGeneratorExecutor solarGeneratorExecutor, GammaPowerGeneratorExecutor gammaPowerGeneratorExecutor, GeothermalGeneratorExecutor geothermalGeneratorExecutor, FuelGeneratorExecutor fuelGeneratorExecutor, PowerExchangerExecutor powerExchangerExecutor, long totalPowerNodeEnergyConsumption) { _powerNetwork = powerNetwork; _networkIndex = networkIndex; _networkNonOptimizedPowerConsumerIndexes = networkNonOptimizedPowerConsumerIndexes; _windExecutor = windExecutor; _solarExecutor = solarGeneratorExecutor; _gammaPowerGeneratorExecutor = gammaPowerGeneratorExecutor; _geothermalGeneratorExecutor = geothermalGeneratorExecutor; _fuelGeneratorExecutor = fuelGeneratorExecutor; _powerExchangerExecutor = powerExchangerExecutor; _totalPowerNodeEnergyConsumption = totalPowerNodeEnergyConsumption; } public (long, bool) RequestDysonSpherePower(PowerSystem powerSystem, float eta, float increase, Vector3 normalized) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) return _gammaPowerGeneratorExecutor.EnergyCap_Gamma_Req(eta, increase, normalized); } public void GameTick(PlanetFactory planet, long time, int[] productRegister, int[] consumeRegister, ref long num, ref long num2, ref long num3, ref long num4, ref long num5, ref long num7, float windStrength, float luminosity, Vector3 normalized, bool flag2, Dictionary.ValueCollection subFactoryToPowerConsumption, int workerIndex) { //IL_0180: Unknown result type (might be due to invalid IL or missing references) PowerSystem powerSystem = planet.powerSystem; PowerNetwork powerNetwork = _powerNetwork; ReadonlyArray networkNonOptimizedPowerConsumerIndexes = _networkNonOptimizedPowerConsumerIndexes; long num8 = 0L; if (networkNonOptimizedPowerConsumerIndexes.Length > 0) { DeepProfiler.BeginSample((DPEntry)15, workerIndex, -1L); for (int i = 0; i < networkNonOptimizedPowerConsumerIndexes.Length; i++) { long requiredEnergy = powerSystem.consumerPool[networkNonOptimizedPowerConsumerIndexes[i]].requiredEnergy; num8 += requiredEnergy; num2 += requiredEnergy; } DeepProfiler.EndSample((DPEntry)15, workerIndex); } num8 += _totalPowerNodeEnergyConsumption; num2 += _totalPowerNodeEnergyConsumption; foreach (SubFactoryPowerConsumption item3 in subFactoryToPowerConsumption) { num8 += item3.NetworksPowerConsumption[_networkIndex]; num2 += item3.NetworksPowerConsumption[_networkIndex]; } long num9 = 0L; long num10 = 0L; (long inputEnergySum, long outputEnergySum) tuple = _powerExchangerExecutor.InputOutputUpdate(powerSystem.currentGeneratorCapacities, workerIndex); long item = tuple.inputEnergySum; long item2 = tuple.outputEnergySum; long num11 = item; long num12 = item2; long num13 = item2; if (_windExecutor.GeneratorCount + _solarExecutor.GeneratorCount + _gammaPowerGeneratorExecutor.GeneratorCount + _geothermalGeneratorExecutor.GeneratorCount + _fuelGeneratorExecutor.GeneratorCount > 0) { DeepProfiler.BeginSample((DPEntry)13, workerIndex, -1L); long num14 = _windExecutor.EnergyCap(windStrength, powerSystem.currentGeneratorCapacities); num13 += num14; long num15 = _solarExecutor.EnergyCap(luminosity, normalized, flag2, powerSystem.currentGeneratorCapacities); num13 += num15; long num16 = _gammaPowerGeneratorExecutor.EnergyCap(planet, powerSystem.currentGeneratorCapacities); num13 += num16; long num17 = _geothermalGeneratorExecutor.EnergyCap(powerSystem.currentGeneratorCapacities); num13 += num17; long num18 = _fuelGeneratorExecutor.EnergyCap(powerSystem.currentGeneratorCapacities); num13 += num18; DeepProfiler.EndSample((DPEntry)13, workerIndex); } num += num13 - num12; long num19 = num13 - num8; long num20 = 0L; if (num19 > 0 && powerNetwork.exportDemandRatio > 0.0) { if (powerNetwork.exportDemandRatio > 1.0) { powerNetwork.exportDemandRatio = 1.0; } num20 = (long)((double)num19 * powerNetwork.exportDemandRatio + 0.5); num19 -= num20; num8 += num20; } powerNetwork.exportDemandRatio = 0.0; num7 += num20; powerNetwork.energyStored = 0L; List accumulators = powerNetwork.accumulators; int count = accumulators.Count; long num21 = 0L; long num22 = 0L; if (count > 0) { DeepProfiler.BeginSample((DPEntry)18, workerIndex, (long)count); if (num19 >= 0) { for (int j = 0; j < count; j++) { int num23 = accumulators[j]; powerSystem.accPool[num23].curPower = 0L; long num24 = ((PowerAccumulatorComponent)(ref powerSystem.accPool[num23])).InputCap(); if (num24 > 0) { num24 = ((num24 < num19) ? num24 : num19); powerSystem.accPool[num23].curEnergy += num24; powerSystem.accPool[num23].curPower = num24; num19 -= num24; num21 += num24; num4 += num24; } powerNetwork.energyStored += powerSystem.accPool[num23].curEnergy; } } else { long num25 = -num19; for (int k = 0; k < count; k++) { int num26 = accumulators[k]; powerSystem.accPool[num26].curPower = 0L; long num27 = ((PowerAccumulatorComponent)(ref powerSystem.accPool[num26])).OutputCap(); if (num27 > 0) { num27 = ((num27 < num25) ? num27 : num25); powerSystem.accPool[num26].curEnergy -= num27; powerSystem.accPool[num26].curPower = -num27; num25 -= num27; num22 += num27; num3 += num27; } powerNetwork.energyStored += powerSystem.accPool[num26].curEnergy; } } DeepProfiler.EndSample((DPEntry)18, workerIndex); } double num28 = ((num19 < num11) ? ((double)num19 / (double)num11) : 1.0); _powerExchangerExecutor.UpdateInput(productRegister, consumeRegister, num28, ref num19, ref num9, ref num4, workerIndex); long num29 = ((num13 < num8 + num9) ? (num13 + num21 + num9) : (num8 + num21 + num9)); double num30 = ((num29 < num12) ? ((double)num29 / (double)num12) : 1.0); _powerExchangerExecutor.UpdateOutput(productRegister, consumeRegister, num30, ref num29, ref num10, ref num3, workerIndex); powerNetwork.energyCapacity = num13 - num12; powerNetwork.energyRequired = num8 - num20; powerNetwork.energyExport = num20; powerNetwork.energyServed = ((num13 + num22 < num8) ? (num13 + num22) : num8); powerNetwork.energyAccumulated = num21 - num22; powerNetwork.energyExchanged = num9 - num10; powerNetwork.energyExchangedInputTotal = num9; powerNetwork.energyExchangedOutputTotal = num10; if (num20 > 0) { PlanetATField planetATField = powerSystem.factory.planetATField; planetATField.energy += num20; planetATField.atFieldRechargeCurrent = num20 * 60; } num13 += num22; num8 += num21; num5 += ((num13 >= num8) ? (num2 + num20) : num13); long num31 = ((num10 - num8 > 0) ? (num10 - num8) : 0); double num32 = ((num13 >= num8) ? 1.0 : ((double)num13 / (double)num8)); num8 += num9 - num31; num13 -= num10; double num33 = ((num13 > num8) ? ((double)num8 / (double)num13) : 1.0); powerNetwork.consumerRatio = num32; powerNetwork.generaterRatio = num33; powerNetwork.energyDischarge = num22 + num10; powerNetwork.energyCharge = num21 + num9; float num34 = ((num13 > 0 || powerNetwork.energyStored > 0 || num10 > 0) ? ((float)num32) : 0f); float num35 = ((num13 > 0 || powerNetwork.energyStored > 0 || num10 > 0) ? ((float)num33) : 0f); powerSystem.networkServes[_networkIndex] = num34; powerSystem.networkGenerates[_networkIndex] = num35; if (_gammaPowerGeneratorExecutor.GeneratorCount + _geothermalGeneratorExecutor.GeneratorCount + _fuelGeneratorExecutor.GeneratorCount > 0) { DeepProfiler.BeginSample((DPEntry)13, workerIndex, -1L); _gammaPowerGeneratorExecutor.GameTick(time, productRegister, consumeRegister); _geothermalGeneratorExecutor.GameTick(); _fuelGeneratorExecutor.GameTick(ref num29, num33, consumeRegister); DeepProfiler.EndSample((DPEntry)13, workerIndex); } } public void RefreshPowerGenerationCapacites(ProductionStatistics statistics, PlanetFactory planet) { int[] powerGenId2Index = ItemProto.powerGenId2Index; if (_windExecutor.IsUsed) { int num = powerGenId2Index[_windExecutor.PrototypeId.Value]; statistics.genCapacities[num] += _windExecutor.TotalCapacityCurrentTick; statistics.genCount[num] += _windExecutor.GeneratorCount; statistics.totalGenCapacity += _windExecutor.TotalCapacityCurrentTick; } if (_solarExecutor.IsUsed) { int num2 = powerGenId2Index[_solarExecutor.PrototypeId.Value]; statistics.genCapacities[num2] += _solarExecutor.TotalCapacityCurrentTick; statistics.genCount[num2] += _solarExecutor.GeneratorCount; statistics.totalGenCapacity += _solarExecutor.TotalCapacityCurrentTick; } if (_gammaPowerGeneratorExecutor.IsUsed) { int num3 = powerGenId2Index[_gammaPowerGeneratorExecutor.PrototypeId.Value]; statistics.genCapacities[num3] += _gammaPowerGeneratorExecutor.TotalCapacityCurrentTick; statistics.genCount[num3] += _gammaPowerGeneratorExecutor.GeneratorCount; statistics.totalGenCapacity += _gammaPowerGeneratorExecutor.TotalCapacityCurrentTick; } if (_geothermalGeneratorExecutor.IsUsed) { int num4 = powerGenId2Index[_geothermalGeneratorExecutor.PrototypeId.Value]; statistics.genCapacities[num4] += _geothermalGeneratorExecutor.TotalCapacityCurrentTick; statistics.genCount[num4] += _geothermalGeneratorExecutor.GeneratorCount; statistics.totalGenCapacity += _geothermalGeneratorExecutor.TotalCapacityCurrentTick; } GeneratorIDWithGenerators[] generators = _fuelGeneratorExecutor.Generators; long[] totalGeneratorCapacitiesCurrentTick = _fuelGeneratorExecutor.TotalGeneratorCapacitiesCurrentTick; for (int i = 0; i < generators.Length; i++) { GeneratorIDWithGenerators generatorIDWithGenerators = generators[i]; int num5 = powerGenId2Index[generatorIDWithGenerators.GeneratorID.PrototypeId]; statistics.genCount[num5] += generatorIDWithGenerators.OptimizedFuelGenerators.Length; long num6 = totalGeneratorCapacitiesCurrentTick[i]; statistics.genCapacities[num5] += num6; statistics.totalGenCapacity += num6; } if (_powerExchangerExecutor.IsUsed) { int num7 = powerGenId2Index[_powerExchangerExecutor.PrototypeId.Value]; statistics.genCapacities[num7] += _powerExchangerExecutor.TotalGenerationCapacityCurrentTick; statistics.genCount[num7] += _powerExchangerExecutor.GeneratorCount; statistics.totalGenCapacity += _powerExchangerExecutor.TotalGenerationCapacityCurrentTick; } } public void RefreshPowerConsumptionDemands(ProductionStatistics statistics, PlanetFactory planet) { EntityData[] entityPool = planet.entityPool; PowerSystem powerSystem = planet.powerSystem; int[] powerConId2Index = ItemProto.powerConId2Index; PowerConsumerComponent[] consumerPool = powerSystem.consumerPool; ReadonlyArray networkNonOptimizedPowerConsumerIndexes = _networkNonOptimizedPowerConsumerIndexes; for (int i = 0; i < networkNonOptimizedPowerConsumerIndexes.Length; i++) { int num = networkNonOptimizedPowerConsumerIndexes[i]; int num2 = powerConId2Index[entityPool[consumerPool[num].entityId].protoId]; statistics.conDemands[num2] += consumerPool[num].requiredEnergy; statistics.conCount[num2]++; statistics.totalConDemand += consumerPool[num].requiredEnergy; } if (_powerExchangerExecutor.IsUsed) { int num3 = powerConId2Index[_powerExchangerExecutor.PrototypeId.Value]; statistics.conDemands[num3] += _powerExchangerExecutor.TotalConsumptionCapacityCurrentTick; statistics.conCount[num3] += _powerExchangerExecutor.GeneratorCount; statistics.totalConDemand += _powerExchangerExecutor.TotalConsumptionCapacityCurrentTick; } } public void Save(PlanetFactory planet) { _windExecutor.Save(planet); _solarExecutor.Save(planet); _gammaPowerGeneratorExecutor.Save(planet); _geothermalGeneratorExecutor.Save(planet); _fuelGeneratorExecutor.Save(planet); _powerExchangerExecutor.Save(planet); } } internal sealed class OptimizedPowerSystem { private readonly OptimizedPowerNetwork[] _optimizedPowerNetworks; public readonly Dictionary _subFactoryToPowerConsumption; private readonly OptimizedProductionStatistics _optimizedProductionStatistics; private readonly UniverseStaticData _universeStaticData; public OptimizedPowerSystem(OptimizedPowerNetwork[] optimizedPowerNetworks, Dictionary subFactoryToPowerConsumption, OptimizedProductionStatistics optimizedProductionStatistics, UniverseStaticData universeStaticData) { _optimizedPowerNetworks = optimizedPowerNetworks; _subFactoryToPowerConsumption = subFactoryToPowerConsumption; _optimizedProductionStatistics = optimizedProductionStatistics; _universeStaticData = universeStaticData; } public SubFactoryPowerConsumption GetSubFactoryPowerConsumption(OptimizedSubFactory subFactory) { return _subFactoryToPowerConsumption[subFactory]; } public void RequestDysonSpherePower(PlanetFactory planet, int workerIndex) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) OptimizedPowerNetwork[] optimizedPowerNetworks = _optimizedPowerNetworks; if (optimizedPowerNetworks.Length != 0) { DeepProfiler.BeginSample((DPEntry)14, workerIndex, -1L); DysonSphere dysonSphere = planet.dysonSphere; float eta = 1f - GameMain.history.solarEnergyLossRate; float increase = ((dysonSphere != null) ? ((float)((double)dysonSphere.grossRadius / ((double)planet.planet.sunDistance * 40000.0))) : 0f); Vector3 normalized = ((Vector3)(ref planet.planet.runtimeLocalSunDirection)).normalized; long num = 0L; for (int i = 0; i < optimizedPowerNetworks.Length; i++) { long item = optimizedPowerNetworks[i].RequestDysonSpherePower(planet.powerSystem, eta, increase, normalized).Item1; num += item; } if (dysonSphere != null) { Interlocked.Add(ref dysonSphere.energyReqCurrentTick, num); } DeepProfiler.EndSample((DPEntry)14, workerIndex); } } public void BeforePower(PlanetFactory planet, OptimizedSubFactory subFactory) { if (!subFactory.HasCalculatedPowerConsumption) { SubFactoryPowerConsumption subFactoryPowerConsumption = _subFactoryToPowerConsumption[subFactory]; long[] networksPowerConsumption = subFactoryPowerConsumption.NetworksPowerConsumption; Array.Clear(networksPowerConsumption, 0, networksPowerConsumption.Length); ReadonlyArray powerConsumerTypes = _universeStaticData.PowerConsumerTypes; FactorySystemBeforePower(planet, subFactory, subFactoryPowerConsumption, networksPowerConsumption, powerConsumerTypes); CargoTrafficBeforePower(subFactory, subFactoryPowerConsumption, networksPowerConsumption, powerConsumerTypes); } } public void GameTick(PlanetFactory planet, long time, int workerIndex) { //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Invalid comparison between Unknown and I4 //IL_01ca: Unknown result type (might be due to invalid IL or missing references) foreach (OptimizedSubFactory key in _subFactoryToPowerConsumption.Keys) { BeforePower(planet, key); } PowerSystem powerSystem = planet.powerSystem; FactoryProductionStat val = GameMain.statistics.production.factoryStatPool[planet.index]; int[] productRegister = _optimizedProductionStatistics.ProductRegister; int[] consumeRegister = _optimizedProductionStatistics.ConsumeRegister; long num = 0L; long num2 = 0L; long num3 = 0L; long num4 = 0L; long num5 = 0L; long num6 = 0L; PlanetData planet2 = powerSystem.factory.planet; float windStrength = planet2.windStrength; float luminosity = planet2.luminosity; Vector3 normalized = ((Vector3)(ref planet2.runtimeLocalSunDirection)).normalized; if (powerSystem.networkServes == null || powerSystem.networkServes.Length != powerSystem.netPool.Length) { powerSystem.networkServes = new float[powerSystem.netPool.Length]; } if (powerSystem.networkGenerates == null || powerSystem.networkGenerates.Length != powerSystem.netPool.Length) { powerSystem.networkGenerates = new float[powerSystem.netPool.Length]; } Array.Clear(powerSystem.currentGeneratorCapacities, 0, powerSystem.currentGeneratorCapacities.Length); int num7 = (int)((float)Math.Min(Math.Abs(powerSystem.factory.planet.rotationPeriod), Math.Abs(powerSystem.factory.planet.orbitalPeriod)) * 60f / 2160f); if (num7 < 1) { num7 = 1; } else if (num7 > 60) { num7 = 60; } if ((int)powerSystem.factory.planet.singularity == 1) { num7 = 60; } bool flag = time % num7 == 0L || GameMain.onceGameTick <= 2; OptimizedPowerNetwork[] optimizedPowerNetworks = _optimizedPowerNetworks; for (int i = 0; i < optimizedPowerNetworks.Length; i++) { optimizedPowerNetworks[i].GameTick(planet, time, productRegister, consumeRegister, ref num, ref num2, ref num3, ref num4, ref num5, ref num6, windStrength, luminosity, normalized, flag, _subFactoryToPowerConsumption.Values, workerIndex); } lock (val) { val.powerGenRegister = num; val.powerConRegister = num2; val.powerDisRegister = num3; val.powerChaRegister = num4; val.energyConsumption += num5; val.powerExpRegister = num6; } } public void RefreshPowerGenerationCapacites(ProductionStatistics statistics, PlanetFactory planet) { OptimizedPowerNetwork[] optimizedPowerNetworks = _optimizedPowerNetworks; for (int i = 0; i < optimizedPowerNetworks.Length; i++) { optimizedPowerNetworks[i].RefreshPowerGenerationCapacites(statistics, planet); } EntityData[] entityPool = planet.entityPool; PowerSystem powerSystem = planet.powerSystem; int[] powerGenId2Index = ItemProto.powerGenId2Index; PowerAccumulatorComponent[] accPool = powerSystem.accPool; int accCursor = powerSystem.accCursor; for (int j = 1; j < accCursor; j++) { if (accPool[j].id == j && accPool[j].curPower < 0) { int num = powerGenId2Index[entityPool[accPool[j].entityId].protoId]; statistics.genCapacities[num] += -accPool[j].curPower; statistics.genCount[num]++; statistics.totalGenCapacity += -accPool[j].curPower; } } } public void RefreshPowerConsumptionDemands(ProductionStatistics statistics, PlanetFactory planet) { OptimizedPowerNetwork[] optimizedPowerNetworks = _optimizedPowerNetworks; for (int i = 0; i < optimizedPowerNetworks.Length; i++) { optimizedPowerNetworks[i].RefreshPowerConsumptionDemands(statistics, planet); } EntityData[] entityPool = planet.entityPool; PowerSystem powerSystem = planet.powerSystem; int[] powerConId2Index = ItemProto.powerConId2Index; PowerNodeComponent[] nodePool = powerSystem.nodePool; int nodeCursor = powerSystem.nodeCursor; for (int j = 1; j < nodeCursor; j++) { if (nodePool[j].id == j) { int num = powerConId2Index[entityPool[nodePool[j].entityId].protoId]; statistics.conDemands[num] += nodePool[j].requiredEnergy; statistics.conCount[num]++; statistics.totalConDemand += nodePool[j].requiredEnergy; } } PowerAccumulatorComponent[] accPool = powerSystem.accPool; int accCursor = powerSystem.accCursor; for (int k = 1; k < accCursor; k++) { if (accPool[k].id == k && accPool[k].curPower > 0) { int num2 = powerConId2Index[entityPool[accPool[k].entityId].protoId]; statistics.conDemands[num2] += accPool[k].curPower; statistics.conCount[num2]++; statistics.totalConDemand += accPool[k].curPower; } } } public void Save(PlanetFactory planet) { OptimizedPowerNetwork[] optimizedPowerNetworks = _optimizedPowerNetworks; for (int i = 0; i < optimizedPowerNetworks.Length; i++) { optimizedPowerNetworks[i].Save(planet); } } private static void FactorySystemBeforePower(PlanetFactory planet, OptimizedSubFactory subFactory, SubFactoryPowerConsumption subFactoryPowerConsumption, long[] networksPowerConsumption, ReadonlyArray powerConsumerTypes) { subFactory._beltVeinMinerExecutor.UpdatePower(subFactoryPowerConsumption.BeltVeinMinerPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption); subFactory._stationVeinMinerExecutor.UpdatePower(subFactoryPowerConsumption.StationVeinMinerPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption); subFactory._oilMinerExecutor.UpdatePower(subFactoryPowerConsumption.OilMinerPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption); subFactory._waterMinerExecutor.UpdatePower(subFactoryPowerConsumption.WaterMinerPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption); subFactory._assemblerExecutor.UpdatePower(subFactoryPowerConsumption.AssemblerPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption); subFactory._fractionatorExecutor.UpdatePower(subFactoryPowerConsumption.FractionatorPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption); subFactory._ejectorExecutor.UpdatePower(planet, subFactoryPowerConsumption.EjectorPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption); subFactory._siloExecutor.UpdatePower(planet, subFactoryPowerConsumption.SiloPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption); subFactory._producingLabExecutor.UpdatePower(subFactoryPowerConsumption.ProducingLabPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption); subFactory._researchingLabExecutor.UpdatePower(subFactoryPowerConsumption.ResearchingLabPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption); subFactory._optimizedBiInserterExecutor.UpdatePower(subFactoryPowerConsumption.InserterBiPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption); subFactory._optimizedInserterExecutor.UpdatePower(subFactoryPowerConsumption.InserterPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption); } private static void CargoTrafficBeforePower(OptimizedSubFactory subFactory, SubFactoryPowerConsumption subFactoryPowerConsumption, long[] networksPowerConsumption, ReadonlyArray powerConsumerTypes) { subFactory._monitorExecutor.UpdatePower(subFactoryPowerConsumption.MonitorPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption); subFactory._spraycoaterExecutor.UpdatePower(subFactoryPowerConsumption.SpraycoaterPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption); subFactory._pilerExecutor.UpdatePower(subFactoryPowerConsumption.PilerPowerConsumerTypeIndexes, powerConsumerTypes, networksPowerConsumption); } } internal sealed class SubFactoryPowerSystemBuilder { private readonly PlanetFactory _planet; private readonly OptimizedPowerSystemBuilder _optimizedPowerSystemBuilder; private readonly List _assemblerPowerConsumerTypeIndexes = new List(); private readonly List _inserterBiPowerConsumerTypeIndexes = new List(); private readonly List _inserterPowerConsumerTypeIndexes = new List(); private readonly List _producingLabPowerConsumerTypeIndexes = new List(); private readonly List _researchingLabPowerConsumerTypeIndexes = new List(); private readonly List _spraycoaterPowerConsumerTypeIndexes = new List(); private readonly List _fractionatorPowerConsumerTypeIndexes = new List(); private readonly List _ejectorPowerConsumerTypeIndexes = new List(); private readonly List _siloPowerConsumerTypeIndexes = new List(); private readonly List _pilerPowerConsumerTypeIndexes = new List(); private readonly List _monitorPowerConsumerTypeIndexes = new List(); private readonly List _waterMinerPowerConsumerTypeIndexes = new List(); private readonly List _oilMinerPowerConsumerTypeIndexes = new List(); private readonly List _beltVeinMinerPowerConsumerTypeIndexes = new List(); private readonly List _stationVeinMinerPowerConsumerTypeIndexes = new List(); private readonly long[] _networksPowerConsumptions; private readonly Dictionary _fuelGeneratorIdToOptimizedFueldGeneratorLocation; public OptimizedFuelGenerator[][] FuelGeneratorSegments { get; } public SubFactoryPowerSystemBuilder(PlanetFactory planet, OptimizedPowerSystemBuilder optimizedPowerSystemBuilder, long[] networksPowerConsumptions, Dictionary fuelGeneratorIdToOptimizedFueldGeneratorLocation, OptimizedFuelGenerator[][] fuelGeneratorSegments) { _planet = planet; _optimizedPowerSystemBuilder = optimizedPowerSystemBuilder; _networksPowerConsumptions = networksPowerConsumptions; _fuelGeneratorIdToOptimizedFueldGeneratorLocation = fuelGeneratorIdToOptimizedFueldGeneratorLocation; FuelGeneratorSegments = fuelGeneratorSegments; } public void AddAssembler([In][RequiresLocation] ref AssemblerComponent assembler, int networkIndex) { AddEntity(_assemblerPowerConsumerTypeIndexes, assembler.pcId, networkIndex); } public OptimizedPowerSystemInserterBuilder CreateBiInserterBuilder() { return new OptimizedPowerSystemInserterBuilder(this, _inserterBiPowerConsumerTypeIndexes, _fuelGeneratorIdToOptimizedFueldGeneratorLocation); } public OptimizedPowerSystemInserterBuilder CreateInserterBuilder() { return new OptimizedPowerSystemInserterBuilder(this, _inserterPowerConsumerTypeIndexes, _fuelGeneratorIdToOptimizedFueldGeneratorLocation); } public void AddProducingLab([In][RequiresLocation] ref LabComponent lab, int networkIndex) { AddEntity(_producingLabPowerConsumerTypeIndexes, lab.pcId, networkIndex); } public void AddResearchingLab([In][RequiresLocation] ref LabComponent lab, int networkIndex) { AddEntity(_researchingLabPowerConsumerTypeIndexes, lab.pcId, networkIndex); } public void AddSpraycoater([In][RequiresLocation] ref SpraycoaterComponent spraycoater, int networkIndex) { AddEntity(_spraycoaterPowerConsumerTypeIndexes, spraycoater.pcId, networkIndex); } public void AddFractionator([In][RequiresLocation] ref FractionatorComponent fractionator, int networkIndex) { AddEntity(_fractionatorPowerConsumerTypeIndexes, fractionator.pcId, networkIndex); } public void AddEjector([In][RequiresLocation] ref EjectorComponent ejector, int networkIndex) { AddEntity(_ejectorPowerConsumerTypeIndexes, ejector.pcId, networkIndex); } public void AddSilo([In][RequiresLocation] ref SiloComponent silo, int networkIndex) { AddEntity(_siloPowerConsumerTypeIndexes, silo.pcId, networkIndex); } public void AddPiler([In][RequiresLocation] ref PilerComponent piler, int networkIndex) { AddEntity(_pilerPowerConsumerTypeIndexes, piler.pcId, networkIndex); } public void AddMonitor([In][RequiresLocation] ref MonitorComponent monitor, int networkIndex) { AddEntity(_monitorPowerConsumerTypeIndexes, monitor.pcId, networkIndex); } public void AddWaterMiner([In][RequiresLocation] ref MinerComponent miner, int networkIndex) { AddEntity(_waterMinerPowerConsumerTypeIndexes, miner.pcId, networkIndex); } public void AddOilMiner([In][RequiresLocation] ref MinerComponent miner, int networkIndex) { AddEntity(_oilMinerPowerConsumerTypeIndexes, miner.pcId, networkIndex); } public OptimizedPowerSystemVeinMinerBuilder CreateBeltVeinMinerBuilder() { return new OptimizedPowerSystemVeinMinerBuilder(_planet.powerSystem, this, _beltVeinMinerPowerConsumerTypeIndexes); } public OptimizedPowerSystemVeinMinerBuilder CreateStationVeinMinerBuilder() { return new OptimizedPowerSystemVeinMinerBuilder(_planet.powerSystem, this, _stationVeinMinerPowerConsumerTypeIndexes); } public void AddEntity(List powerConsumerTypeIndexes, int powerConsumerIndex, int networkIndex) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) PowerConsumerComponent val = _planet.powerSystem.consumerPool[powerConsumerIndex]; PowerConsumerType powerConsumerType = new PowerConsumerType(val.workEnergyPerTick, val.idleEnergyPerTick); powerConsumerTypeIndexes.Add(_optimizedPowerSystemBuilder.GetOrAddPowerConsumerType(powerConsumerType)); _optimizedPowerSystemBuilder.AddPowerConsumerIndexToNetwork(powerConsumerIndex, networkIndex); } public SubFactoryPowerConsumption Build(UniverseStaticDataBuilder universeStaticDataBuilder) { return new SubFactoryPowerConsumption(universeStaticDataBuilder.DeduplicateArrayUnmanaged(_assemblerPowerConsumerTypeIndexes), universeStaticDataBuilder.DeduplicateArrayUnmanaged(_inserterBiPowerConsumerTypeIndexes), universeStaticDataBuilder.DeduplicateArrayUnmanaged(_inserterPowerConsumerTypeIndexes), universeStaticDataBuilder.DeduplicateArrayUnmanaged(_producingLabPowerConsumerTypeIndexes), universeStaticDataBuilder.DeduplicateArrayUnmanaged(_researchingLabPowerConsumerTypeIndexes), universeStaticDataBuilder.DeduplicateArrayUnmanaged(_spraycoaterPowerConsumerTypeIndexes), universeStaticDataBuilder.DeduplicateArrayUnmanaged(_fractionatorPowerConsumerTypeIndexes), universeStaticDataBuilder.DeduplicateArrayUnmanaged(_ejectorPowerConsumerTypeIndexes), universeStaticDataBuilder.DeduplicateArrayUnmanaged(_siloPowerConsumerTypeIndexes), universeStaticDataBuilder.DeduplicateArrayUnmanaged(_pilerPowerConsumerTypeIndexes), universeStaticDataBuilder.DeduplicateArrayUnmanaged(_monitorPowerConsumerTypeIndexes), universeStaticDataBuilder.DeduplicateArrayUnmanaged(_waterMinerPowerConsumerTypeIndexes), universeStaticDataBuilder.DeduplicateArrayUnmanaged(_oilMinerPowerConsumerTypeIndexes), universeStaticDataBuilder.DeduplicateArrayUnmanaged(_beltVeinMinerPowerConsumerTypeIndexes), universeStaticDataBuilder.DeduplicateArrayUnmanaged(_stationVeinMinerPowerConsumerTypeIndexes), _networksPowerConsumptions); } } internal sealed class OptimizedPowerSystemBuilder { private readonly PlanetFactory _planet; private readonly SubFactoryProductionRegisterBuilder _subProductionRegisterBuilder; private readonly Dictionary> _networkIndexToOptimizedConsumerIndexes = new Dictionary>(); private readonly Dictionary _subFactoryToPowerSystemBuilder = new Dictionary(); private readonly Dictionary _networkIndexToFueldGeneratorExecutor; private readonly Dictionary _fuelGeneratorIdToOptimizedFueldGeneratorLocation; private readonly OptimizedFuelGenerator[][] _fuelGeneratorSegments; private readonly UniverseStaticDataBuilder _universeStaticDataBuilder; private OptimizedPowerSystemBuilder(PlanetFactory planet, SubFactoryProductionRegisterBuilder subProductionRegisterBuilder, Dictionary networkIndexToFueldGeneratorExecutor, Dictionary fuelGeneratorIdToOptimizedFueldGeneratorLocation, OptimizedFuelGenerator[][] fuelGeneratorSegments, UniverseStaticDataBuilder universeStaticDataBuilder) { _planet = planet; _subProductionRegisterBuilder = subProductionRegisterBuilder; _networkIndexToFueldGeneratorExecutor = networkIndexToFueldGeneratorExecutor; _fuelGeneratorIdToOptimizedFueldGeneratorLocation = fuelGeneratorIdToOptimizedFueldGeneratorLocation; _fuelGeneratorSegments = fuelGeneratorSegments; _universeStaticDataBuilder = universeStaticDataBuilder; } public static OptimizedPowerSystemBuilder Create(PlanetFactory planet, SubFactoryProductionRegisterBuilder subProductionRegisterBuilder, UniverseStaticDataBuilder universeStaticDataBuilder, out OptimizedItemId[]?[]? fuelNeeds) { Dictionary dictionary = new Dictionary(); Dictionary dictionary2 = new Dictionary(); List list = new List(); fuelNeeds = null; for (int i = 1; i < planet.powerSystem.netCursor; i++) { PowerNetwork val = planet.powerSystem.netPool[i]; if (val == null || val.id != i) { continue; } FuelGeneratorExecutor fuelGeneratorExecutor = new FuelGeneratorExecutor(); fuelGeneratorExecutor.Initialize(planet, i, subProductionRegisterBuilder, ref fuelNeeds); dictionary.Add(i, fuelGeneratorExecutor); foreach (KeyValuePair item in fuelGeneratorExecutor.FuelGeneratorIdToOptimizedFuelGeneratorLocation) { dictionary2.Add(item.Key, new OptimizedFuelGeneratorLocation(list.Count + item.Value.SegmentIndex, item.Value.Index)); } list.AddRange(fuelGeneratorExecutor.GeneratorSegments); } return new OptimizedPowerSystemBuilder(planet, subProductionRegisterBuilder, dictionary, dictionary2, list.ToArray(), universeStaticDataBuilder); } public SubFactoryPowerSystemBuilder AddSubFactory(OptimizedSubFactory subFactory) { SubFactoryPowerSystemBuilder subFactoryPowerSystemBuilder = new SubFactoryPowerSystemBuilder(_planet, this, new long[_planet.powerSystem.netCursor], _fuelGeneratorIdToOptimizedFueldGeneratorLocation, _fuelGeneratorSegments); _subFactoryToPowerSystemBuilder.Add(subFactory, subFactoryPowerSystemBuilder); return subFactoryPowerSystemBuilder; } public short GetOrAddPowerConsumerType(PowerConsumerType powerConsumerType) { int num = _universeStaticDataBuilder.AddPowerConsumerType(ref powerConsumerType); if (num > 32767) { throw new InvalidOperationException($"Assumption that there will exist a max of {short.MaxValue} different PowerConsumerTypes was incorrect."); } return (short)num; } public void AddPowerConsumerIndexToNetwork(int powerConsumerIndex, int networkIndex) { if (!_networkIndexToOptimizedConsumerIndexes.TryGetValue(networkIndex, out HashSet value)) { value = new HashSet(); _networkIndexToOptimizedConsumerIndexes.Add(networkIndex, value); } value.Add(powerConsumerIndex); } public OptimizedPowerSystem Build(PlanetWideBeltExecutor planetWideBeltExecutor) { int[][] array = new int[_planet.powerSystem.netCursor][]; for (int i = 0; i < array.Length; i++) { if (!_networkIndexToOptimizedConsumerIndexes.TryGetValue(i, out HashSet value)) { array[i] = _planet.powerSystem.netPool[i].consumers.ToArray(); } else { array[i] = _planet.powerSystem.netPool[i].consumers.Except(value).ToArray(); } } OptimizedPowerNetwork[] optimizedPowerNetworks = GetOptimizedPowerNetworks(_planet, planetWideBeltExecutor, _networkIndexToOptimizedConsumerIndexes); Dictionary subFactoryToPowerConsumption = _subFactoryToPowerSystemBuilder.ToDictionary, OptimizedSubFactory, SubFactoryPowerConsumption>((KeyValuePair x) => x.Key, (KeyValuePair x) => x.Value.Build(_universeStaticDataBuilder)); return new OptimizedPowerSystem(optimizedPowerNetworks, subFactoryToPowerConsumption, _subProductionRegisterBuilder.Build(_universeStaticDataBuilder), _universeStaticDataBuilder.UniverseStaticData); } private OptimizedPowerNetwork[] GetOptimizedPowerNetworks(PlanetFactory planet, PlanetWideBeltExecutor planetWideBeltExecutor, Dictionary> networkIndexToOptimizedConsumerIndexes) { List list = new List(); for (int i = 1; i < planet.powerSystem.netCursor; i++) { PowerNetwork val = planet.powerSystem.netPool[i]; if (val != null && val.id == i) { HashSet value; ReadonlyArray networkNonOptimizedPowerConsumerIndexes = ((!networkIndexToOptimizedConsumerIndexes.TryGetValue(i, out value)) ? _universeStaticDataBuilder.DeduplicateArrayUnmanaged(planet.powerSystem.netPool[i].consumers) : _universeStaticDataBuilder.DeduplicateArrayUnmanaged((from x in planet.powerSystem.netPool[i].consumers.Except(value) orderby x select x).ToArray())); WindGeneratorExecutor windGeneratorExecutor = new WindGeneratorExecutor(); windGeneratorExecutor.Initialize(planet, i); SolarGeneratorExecutor solarGeneratorExecutor = new SolarGeneratorExecutor(); solarGeneratorExecutor.Initialize(planet, i); GammaPowerGeneratorExecutor gammaPowerGeneratorExecutor = new GammaPowerGeneratorExecutor(); gammaPowerGeneratorExecutor.Initialize(planet, i, _subProductionRegisterBuilder, planetWideBeltExecutor); GeothermalGeneratorExecutor geothermalGeneratorExecutor = new GeothermalGeneratorExecutor(); geothermalGeneratorExecutor.Initialize(planet, i); FuelGeneratorExecutor fuelGeneratorExecutor = _networkIndexToFueldGeneratorExecutor[i]; PowerExchangerExecutor powerExchangerExecutor = new PowerExchangerExecutor(); powerExchangerExecutor.Initialize(planet, i, _subProductionRegisterBuilder, planetWideBeltExecutor); long totalPowerNodeEnergyConsumption = GetTotalPowerNodeEnergyConsumption(planet, val); list.Add(new OptimizedPowerNetwork(val, i, networkNonOptimizedPowerConsumerIndexes, windGeneratorExecutor, solarGeneratorExecutor, gammaPowerGeneratorExecutor, geothermalGeneratorExecutor, fuelGeneratorExecutor, powerExchangerExecutor, totalPowerNodeEnergyConsumption)); } } return list.ToArray(); } private static long GetTotalPowerNodeEnergyConsumption(PlanetFactory planet, PowerNetwork powerNetwork) { long num = 0L; foreach (Node node in powerNetwork.nodes) { int id = node.id; if (planet.powerSystem.nodePool[id].id == id && planet.powerSystem.nodePool[id].isCharger) { planet.powerSystem.nodePool[id].requiredEnergy = planet.powerSystem.nodePool[id].idleEnergyPerTick; num += planet.powerSystem.nodePool[id].requiredEnergy; } } return num; } } internal sealed class OptimizedPowerSystemInserterBuilder { private readonly SubFactoryPowerSystemBuilder _subFactoryPowerSystemBuilder; private readonly List _inserterPowerConsumerTypeIndexes; private readonly Dictionary _fuelGeneratorIdToOptimizedLocation; public OptimizedPowerSystemInserterBuilder(SubFactoryPowerSystemBuilder subFactoryPowerSystemBuilder, List inserterPowerConsumerTypeIndexes, Dictionary fuelGeneratorIdToOptimizedLocation) { _subFactoryPowerSystemBuilder = subFactoryPowerSystemBuilder; _inserterPowerConsumerTypeIndexes = inserterPowerConsumerTypeIndexes; _fuelGeneratorIdToOptimizedLocation = fuelGeneratorIdToOptimizedLocation; } public void AddInserter([In][RequiresLocation] ref InserterComponent inserter, int networkIndex) { _subFactoryPowerSystemBuilder.AddEntity(_inserterPowerConsumerTypeIndexes, inserter.pcId, networkIndex); } public OptimizedFuelGeneratorLocation GetOptimizedFuelGeneratorLocation(int fuelGeneratorId) { return _fuelGeneratorIdToOptimizedLocation[fuelGeneratorId]; } } internal sealed class OptimizedPowerSystemVeinMinerBuilder { private readonly SubFactoryPowerSystemBuilder _subFactoryPowerSystemBuilder; private readonly List _veinMinerPowerConsumerTypeIndexes; public OptimizedPowerSystemVeinMinerBuilder(PowerSystem powerSystem, SubFactoryPowerSystemBuilder subFactoryPowerSystemBuilder, List veinMinerPowerConsumerTypeIndexes) { _subFactoryPowerSystemBuilder = subFactoryPowerSystemBuilder; _veinMinerPowerConsumerTypeIndexes = veinMinerPowerConsumerTypeIndexes; } public void AddMiner([In][RequiresLocation] ref MinerComponent miner, int networkIndex) { _subFactoryPowerSystemBuilder.AddEntity(_veinMinerPowerConsumerTypeIndexes, miner.pcId, networkIndex); } } internal readonly struct PowerConsumerType : IEquatable, IMemorySize { public readonly long WorkEnergyPerTick; public readonly long IdleEnergyPerTick; public PowerConsumerType(long workEnergyPerTick, long idleEnergyPerTick) { WorkEnergyPerTick = workEnergyPerTick; IdleEnergyPerTick = idleEnergyPerTick; } public long GetRequiredEnergy(bool working, int permillage) { if (!working) { return IdleEnergyPerTick; } return WorkEnergyPerTick * permillage / 1000; } public long GetRequiredEnergy(bool working) { if (!working) { return IdleEnergyPerTick; } return WorkEnergyPerTick; } public long GetRequiredEnergy(double ratio) { return (long)((double)WorkEnergyPerTick * ratio + (double)IdleEnergyPerTick * (1.0 - ratio)); } public int GetSize() { return Marshal.SizeOf(); } public bool Equals(PowerConsumerType other) { if (WorkEnergyPerTick == other.WorkEnergyPerTick) { return IdleEnergyPerTick == other.IdleEnergyPerTick; } return false; } public override bool Equals(object obj) { if (obj is PowerConsumerType other) { return Equals(other); } return false; } public override int GetHashCode() { return HashCode.Combine(WorkEnergyPerTick, IdleEnergyPerTick); } } internal sealed class PowerExchangerExecutor { private OptimizedPowerExchanger[] _optimizedPowerExchangers; private Dictionary _powerExchangerIdToOptimizedIndex; private int _subId; [MemberNotNullWhen(true, "PrototypeId")] public bool IsUsed { [MemberNotNullWhen(true, "PrototypeId")] get { return _optimizedPowerExchangers.Length != 0; } } public int GeneratorCount { get; private set; } public int ConsumerCount { get; private set; } public int? PrototypeId { get; private set; } public long TotalGenerationCapacityCurrentTick { get; private set; } public long TotalConsumptionCapacityCurrentTick { get; private set; } public (long inputEnergySum, long outputEnergySum) InputOutputUpdate(long[] currentGeneratorCapacities, int workerIndex) { if (_optimizedPowerExchangers.Length == 0) { return (0L, 0L); } DeepProfiler.BeginSample((DPEntry)17, workerIndex, (long)_optimizedPowerExchangers.Length); long num = 0L; long num2 = 0L; OptimizedPowerExchanger[] optimizedPowerExchangers = _optimizedPowerExchangers; for (int i = 0; i < optimizedPowerExchangers.Length; i++) { ref OptimizedPowerExchanger reference = ref optimizedPowerExchangers[i]; reference.StateUpdate(); reference.BeltUpdate(); bool flag = reference.state >= 1f; bool flag2 = reference.state <= -1f; if (!flag && !flag2) { reference.capsCurrentTick = 0L; reference.currEnergyPerTick = 0L; } if (flag2) { num2 += reference.OutputCaps(); } else if (flag) { num += reference.InputCaps(); } } currentGeneratorCapacities[_subId] += num2; DeepProfiler.EndSample((DPEntry)17, workerIndex); return (num, num2); } public void UpdateInput(int[] productRegister, int[] consumeRegister, double num40, ref long num32, ref long num23, ref long num4, int workerIndex) { ConsumerCount = 0; long num41 = 0L; OptimizedPowerExchanger[] optimizedPowerExchangers = _optimizedPowerExchangers; if (optimizedPowerExchangers.Length != 0) { DeepProfiler.BeginSample((DPEntry)17, workerIndex, (long)optimizedPowerExchangers.Length); for (int i = 0; i < optimizedPowerExchangers.Length; i++) { ref OptimizedPowerExchanger reference = ref optimizedPowerExchangers[i]; if (reference.state >= 1f && num40 >= 0.0) { long num42 = (long)(num40 * (double)reference.capsCurrentTick + 0.99999); long remaining = ((num32 < num42) ? num32 : num42); num41 += reference.InputUpdate(remaining, productRegister, consumeRegister); ConsumerCount++; } else { reference.currEnergyPerTick = 0L; } } DeepProfiler.EndSample((DPEntry)17, workerIndex); num32 -= num41; num23 += num41; num4 += num41; } TotalConsumptionCapacityCurrentTick = num41; } public void UpdateOutput(int[] productRegister, int[] consumeRegister, double num45, ref long num44, ref long num24, ref long num3, int workerIndex) { GeneratorCount = 0; long num46 = 0L; OptimizedPowerExchanger[] optimizedPowerExchangers = _optimizedPowerExchangers; if (optimizedPowerExchangers.Length != 0) { DeepProfiler.BeginSample((DPEntry)17, workerIndex, (long)optimizedPowerExchangers.Length); for (int i = 0; i < optimizedPowerExchangers.Length; i++) { ref OptimizedPowerExchanger reference = ref optimizedPowerExchangers[i]; if (reference.state <= -1f) { long num47 = (long)(num45 * (double)reference.capsCurrentTick + 0.99999); long energyPay = ((num44 < num47) ? num44 : num47); num46 += reference.OutputUpdate(energyPay, productRegister, consumeRegister); GeneratorCount++; } } DeepProfiler.EndSample((DPEntry)17, workerIndex); num24 += num46; num3 += num46; num44 -= num46; } TotalGenerationCapacityCurrentTick = num46; } public void Save(PlanetFactory planet) { PowerExchangerComponent[] excPool = planet.powerSystem.excPool; OptimizedPowerExchanger[] optimizedPowerExchangers = _optimizedPowerExchangers; for (int i = 1; i < planet.powerSystem.excCursor; i++) { if (_powerExchangerIdToOptimizedIndex.TryGetValue(i, out var value)) { optimizedPowerExchangers[value].Save(ref excPool[i]); } } } public void Initialize(PlanetFactory planet, int networkId, SubFactoryProductionRegisterBuilder subProductionRegisterBuilder, PlanetWideBeltExecutor beltExecutor) { List list = new List(); Dictionary dictionary = new Dictionary(); int? num = null; int? num2 = null; for (int i = 1; i < planet.powerSystem.excCursor; i++) { ref PowerExchangerComponent reference = ref planet.powerSystem.excPool[i]; if (reference.id == i && reference.networkId == networkId) { if (num.HasValue && num != reference.subId) { throw new InvalidOperationException("Assumption that subId is the same for all power exchangers is incorrect."); } num = reference.subId; int protoId = planet.entityPool[reference.entityId].protoId; if (num2.HasValue && num2 != protoId) { throw new InvalidOperationException("Assumption that protoId is the same for all power exchanger machines is incorrect."); } num2 = protoId; OptimizedIndexedCargoPath belt = OptimizedIndexedCargoPath.NoBelt; OptimizedIndexedCargoPath belt2 = OptimizedIndexedCargoPath.NoBelt; OptimizedIndexedCargoPath belt3 = OptimizedIndexedCargoPath.NoBelt; OptimizedIndexedCargoPath belt4 = OptimizedIndexedCargoPath.NoBelt; OptimizedItemId emptyId = default(OptimizedItemId); OptimizedItemId fullId = default(OptimizedItemId); if (reference.targetState == 1f) { emptyId = subProductionRegisterBuilder.AddConsume(reference.emptyId); fullId = subProductionRegisterBuilder.AddProduct(reference.fullId); } else if (reference.targetState == -1f) { emptyId = subProductionRegisterBuilder.AddProduct(reference.emptyId); fullId = subProductionRegisterBuilder.AddConsume(reference.fullId); } if (reference.belt0 > 0) { belt = beltExecutor.GetOptimizedCargoPath(planet.cargoTraffic.pathPool[planet.cargoTraffic.beltPool[reference.belt0].segPathId]); } if (reference.belt1 > 0) { belt2 = beltExecutor.GetOptimizedCargoPath(planet.cargoTraffic.pathPool[planet.cargoTraffic.beltPool[reference.belt1].segPathId]); } if (reference.belt2 > 0) { belt3 = beltExecutor.GetOptimizedCargoPath(planet.cargoTraffic.pathPool[planet.cargoTraffic.beltPool[reference.belt2].segPathId]); } if (reference.belt3 > 0) { belt4 = beltExecutor.GetOptimizedCargoPath(planet.cargoTraffic.pathPool[planet.cargoTraffic.beltPool[reference.belt3].segPathId]); } dictionary.Add(reference.id, list.Count); list.Add(new OptimizedPowerExchanger(emptyId, fullId, belt, belt2, belt3, belt4, ref reference)); } } _optimizedPowerExchangers = list.ToArray(); _powerExchangerIdToOptimizedIndex = dictionary; _subId = num.GetValueOrDefault(-1); PrototypeId = num2; } } internal sealed class PrototypePowerConsumptionBuilder { private readonly Dictionary _prototypeIdToIndex = new Dictionary(); private readonly List _prototypeIds = new List(); private readonly List _prototypeCounts = new List(); private readonly List _prototypeIdIndexes = new List(); public void AddPowerConsumer([In][RequiresLocation] ref EntityData entity) { int protoId = entity.protoId; if (!_prototypeIdToIndex.TryGetValue(protoId, out var value)) { value = _prototypeIds.Count; _prototypeIds.Add(protoId); _prototypeIdToIndex.Add(protoId, value); _prototypeCounts.Add(0); } _prototypeIdIndexes.Add(value); _prototypeCounts[value]++; } public PrototypePowerConsumptionExecutor Build(UniverseStaticDataBuilder universeStaticDataBuilder) { return new PrototypePowerConsumptionExecutor(universeStaticDataBuilder.DeduplicateArrayUnmanaged(_prototypeIds), universeStaticDataBuilder.DeduplicateArrayUnmanaged(_prototypeCounts), universeStaticDataBuilder.DeduplicateArrayUnmanaged(_prototypeIdIndexes), new long[_prototypeIds.Count]); } public PrototypePowerConsumptionExecutor Build(UniverseStaticDataBuilder universeStaticDataBuilder, int[] reorder) { return new PrototypePowerConsumptionExecutor(universeStaticDataBuilder.DeduplicateArrayUnmanaged(_prototypeIds), universeStaticDataBuilder.DeduplicateArrayUnmanaged(_prototypeCounts), universeStaticDataBuilder.DeduplicateArrayUnmanaged(reorder.Select((int x) => _prototypeIdIndexes[x]).ToArray()), new long[_prototypeIds.Count]); } } internal readonly struct PrototypePowerConsumptionExecutor { private readonly ReadonlyArray _prototypeIds; private readonly ReadonlyArray _prototypeIdCounts; public readonly ReadonlyArray PrototypeIdIndexes; public readonly long[] PrototypeIdPowerConsumption; public PrototypePowerConsumptionExecutor(ReadonlyArray prototypeIds, ReadonlyArray prototypeIdCounts, ReadonlyArray prototypeIdIndexes, long[] prototypeIdPowerConsumption) { _prototypeIds = prototypeIds; _prototypeIdCounts = prototypeIdCounts; PrototypeIdIndexes = prototypeIdIndexes; PrototypeIdPowerConsumption = prototypeIdPowerConsumption; } public PrototypePowerConsumptions GetPowerConsumption() { return new PrototypePowerConsumptions(_prototypeIds, _prototypeIdCounts, PrototypeIdPowerConsumption); } public void Clear() { Array.Clear(PrototypeIdPowerConsumption, 0, PrototypeIdPowerConsumption.Length); } } internal record struct PrototypePowerConsumptions(ReadonlyArray PrototypeIds, ReadonlyArray PrototypeIdCounts, long[] PrototypeIdPowerConsumption); internal sealed class SubFactoryPowerConsumption { public ReadonlyArray AssemblerPowerConsumerTypeIndexes { get; } public ReadonlyArray InserterBiPowerConsumerTypeIndexes { get; } public ReadonlyArray InserterPowerConsumerTypeIndexes { get; } public ReadonlyArray ProducingLabPowerConsumerTypeIndexes { get; } public ReadonlyArray ResearchingLabPowerConsumerTypeIndexes { get; } public ReadonlyArray SpraycoaterPowerConsumerTypeIndexes { get; } public ReadonlyArray FractionatorPowerConsumerTypeIndexes { get; } public ReadonlyArray EjectorPowerConsumerTypeIndexes { get; } public ReadonlyArray SiloPowerConsumerTypeIndexes { get; } public ReadonlyArray PilerPowerConsumerTypeIndexes { get; } public ReadonlyArray MonitorPowerConsumerTypeIndexes { get; } public ReadonlyArray WaterMinerPowerConsumerTypeIndexes { get; } public ReadonlyArray OilMinerPowerConsumerTypeIndexes { get; } public ReadonlyArray BeltVeinMinerPowerConsumerTypeIndexes { get; } public ReadonlyArray StationVeinMinerPowerConsumerTypeIndexes { get; } public long[] NetworksPowerConsumption { get; } public SubFactoryPowerConsumption(ReadonlyArray assemblerPowerConsumerTypeIndexes, ReadonlyArray inserterBiPowerConsumerTypeIndexes, ReadonlyArray inserterPowerConsumerTypeIndexes, ReadonlyArray producingLabPowerConsumerTypeIndexes, ReadonlyArray researchingLabPowerConsumerTypeIndexes, ReadonlyArray spraycoaterPowerConsumerTypeIndexes, ReadonlyArray fractionatorPowerConsumerTypeIndexes, ReadonlyArray ejectorPowerConsumerTypeIndexes, ReadonlyArray siloPowerConsumerTypeIndexes, ReadonlyArray pilerPowerConsumerTypeIndexes, ReadonlyArray monitorPowerConsumerTypeIndexes, ReadonlyArray waterMinerPowerConsumerTypeIndexes, ReadonlyArray oilMinerPowerConsumerTypeIndexes, ReadonlyArray beltVeinMinerPowerConsumerTypeIndexes, ReadonlyArray stationVeinMinerPowerConsumerTypeIndexes, long[] networksPowerConsumption) { AssemblerPowerConsumerTypeIndexes = assemblerPowerConsumerTypeIndexes; InserterBiPowerConsumerTypeIndexes = inserterBiPowerConsumerTypeIndexes; InserterPowerConsumerTypeIndexes = inserterPowerConsumerTypeIndexes; ProducingLabPowerConsumerTypeIndexes = producingLabPowerConsumerTypeIndexes; ResearchingLabPowerConsumerTypeIndexes = researchingLabPowerConsumerTypeIndexes; SpraycoaterPowerConsumerTypeIndexes = spraycoaterPowerConsumerTypeIndexes; FractionatorPowerConsumerTypeIndexes = fractionatorPowerConsumerTypeIndexes; EjectorPowerConsumerTypeIndexes = ejectorPowerConsumerTypeIndexes; SiloPowerConsumerTypeIndexes = siloPowerConsumerTypeIndexes; PilerPowerConsumerTypeIndexes = pilerPowerConsumerTypeIndexes; MonitorPowerConsumerTypeIndexes = monitorPowerConsumerTypeIndexes; WaterMinerPowerConsumerTypeIndexes = waterMinerPowerConsumerTypeIndexes; OilMinerPowerConsumerTypeIndexes = oilMinerPowerConsumerTypeIndexes; BeltVeinMinerPowerConsumerTypeIndexes = beltVeinMinerPowerConsumerTypeIndexes; StationVeinMinerPowerConsumerTypeIndexes = stationVeinMinerPowerConsumerTypeIndexes; NetworksPowerConsumption = networksPowerConsumption; } } } namespace Weaver.Optimizations.PowerSystems.Generators { internal sealed class FuelGeneratorExecutor { private record struct GeneratorIdIndexWithOptimizedGeneratorIndex(int GeneratorIDIndex, int OptimizedGeneratorIndex); private GeneratorIDWithGenerators[] _generatorIDWithOptimizedFuelGenerators; private Dictionary _fuelIdToOptimizedIndex; private long[] _totalGeneratorCapacitiesCurrentTick; private Dictionary _fuelGeneratorIdToOptimizedFuelGeneratorLocation; public GeneratorIDWithGenerators[] Generators => _generatorIDWithOptimizedFuelGenerators; public long[] TotalGeneratorCapacitiesCurrentTick => _totalGeneratorCapacitiesCurrentTick; public Dictionary FuelGeneratorIdToOptimizedFuelGeneratorLocation => _fuelGeneratorIdToOptimizedFuelGeneratorLocation; public IEnumerable GeneratorSegments => _generatorIDWithOptimizedFuelGenerators.Select((GeneratorIDWithGenerators x) => x.OptimizedFuelGenerators); public int GeneratorCount => _generatorIDWithOptimizedFuelGenerators.Sum((GeneratorIDWithGenerators x) => x.OptimizedFuelGenerators.Length); public long EnergyCap(long[] currentGeneratorCapacities) { if (_generatorIDWithOptimizedFuelGenerators.Length == 0) { return 0L; } long num = 0L; long[] totalGeneratorCapacitiesCurrentTick = _totalGeneratorCapacitiesCurrentTick; GeneratorIDWithGenerators[] generatorIDWithOptimizedFuelGenerators = _generatorIDWithOptimizedFuelGenerators; for (int i = 0; i < generatorIDWithOptimizedFuelGenerators.Length; i++) { GeneratorIDWithGenerators generatorIDWithGenerators = generatorIDWithOptimizedFuelGenerators[i]; OptimizedFuelGenerator[] optimizedFuelGenerators = generatorIDWithGenerators.OptimizedFuelGenerators; long num2 = 0L; for (int j = 0; j < optimizedFuelGenerators.Length; j++) { num2 += optimizedFuelGenerators[j].EnergyCap_Fuel(); } currentGeneratorCapacities[generatorIDWithGenerators.GeneratorID.SubId] += num2; totalGeneratorCapacitiesCurrentTick[i] = num2; num += num2; } return num; } public void GameTick(ref long num44, double num51, int[] consumeRegister) { GeneratorIDWithGenerators[] generatorIDWithOptimizedFuelGenerators = _generatorIDWithOptimizedFuelGenerators; for (int i = 0; i < generatorIDWithOptimizedFuelGenerators.Length; i++) { OptimizedFuelGenerator[] optimizedFuelGenerators = generatorIDWithOptimizedFuelGenerators[i].OptimizedFuelGenerators; for (int j = 0; j < optimizedFuelGenerators.Length; j++) { optimizedFuelGenerators[j].GeneratePower(ref num44, num51, consumeRegister); } } } public void Save(PlanetFactory planet) { PowerGeneratorComponent[] genPool = planet.powerSystem.genPool; GeneratorIDWithGenerators[] generatorIDWithOptimizedFuelGenerators = _generatorIDWithOptimizedFuelGenerators; for (int i = 1; i < planet.powerSystem.genCursor; i++) { if (_fuelIdToOptimizedIndex.TryGetValue(i, out var value)) { generatorIDWithOptimizedFuelGenerators[value.GeneratorIDIndex].OptimizedFuelGenerators[value.OptimizedGeneratorIndex].Save(ref genPool[i]); } } } public void Initialize(PlanetFactory planet, int networkId, SubFactoryProductionRegisterBuilder subProductionRegisterBuilder, ref OptimizedItemId[]?[]? fuelNeeds) { Dictionary> dictionary = new Dictionary>(); Dictionary dictionary2 = new Dictionary(); Dictionary dictionary3 = new Dictionary(); if (fuelNeeds == null) { fuelNeeds = new OptimizedItemId[ItemProto.fuelNeeds.Length][]; } for (int i = 1; i < planet.powerSystem.genCursor; i++) { ref PowerGeneratorComponent reference = ref planet.powerSystem.genPool[i]; if (reference.id == i && reference.networkId == networkId && !reference.wind && !reference.photovoltaic && !reference.gamma && !reference.geothermal) { if (fuelNeeds[reference.fuelMask] == null && ItemProto.fuelNeeds[reference.fuelMask] != null) { fuelNeeds[reference.fuelMask] = subProductionRegisterBuilder.AddConsume(ItemProto.fuelNeeds[reference.fuelMask]); } OptimizedItemId fuelId = default(OptimizedItemId); if (reference.fuelId != 0) { fuelId = subProductionRegisterBuilder.AddConsume(reference.fuelId); } int subId = reference.subId; int protoId = planet.entityPool[reference.entityId].protoId; GeneratorID key = new GeneratorID(subId, protoId); if (!dictionary.TryGetValue(key, out var value)) { value = new List(); dictionary.Add(key, value); dictionary3.Add(key, dictionary3.Count); } dictionary2.Add(reference.id, new GeneratorIdIndexWithOptimizedGeneratorIndex(dictionary3[key], value.Count)); value.Add(new OptimizedFuelGenerator(fuelId, ref reference)); } } _generatorIDWithOptimizedFuelGenerators = dictionary.Select((KeyValuePair> x) => new GeneratorIDWithGenerators(x.Key, x.Value.ToArray())).ToArray(); _fuelIdToOptimizedIndex = dictionary2; _totalGeneratorCapacitiesCurrentTick = new long[_generatorIDWithOptimizedFuelGenerators.Length]; Dictionary dictionary4 = new Dictionary(); for (int j = 0; j < _generatorIDWithOptimizedFuelGenerators.Length; j++) { GeneratorIDWithGenerators generatorIDWithGenerators = _generatorIDWithOptimizedFuelGenerators[j]; for (int k = 0; k < generatorIDWithGenerators.OptimizedFuelGenerators.Length; k++) { dictionary4.Add(generatorIDWithGenerators.OptimizedFuelGenerators[k].id, new OptimizedFuelGeneratorLocation(j, k)); } } _fuelGeneratorIdToOptimizedFuelGeneratorLocation = dictionary4; } } internal sealed class GammaPowerGeneratorExecutor { private OptimizedGammaPowerGenerator[] _optimizedGammaPowerGenerators; private Dictionary _gammaIdToOptimizedIndex; private int _subId; private int _gammaMachinesGeneratingEnergyCount; [MemberNotNullWhen(true, "PrototypeId")] public bool IsUsed { [MemberNotNullWhen(true, "PrototypeId")] get { return GeneratorCount > 0; } } public int GeneratorCount => _gammaMachinesGeneratingEnergyCount; public int? PrototypeId { get; private set; } public long TotalCapacityCurrentTick { get; private set; } public Dictionary.KeyCollection OptimizedPowerGeneratorIds => _gammaIdToOptimizedIndex.Keys; public (long, bool) EnergyCap_Gamma_Req(float eta, float increase, Vector3 normalized) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) long num = 0L; OptimizedGammaPowerGenerator[] optimizedGammaPowerGenerators = _optimizedGammaPowerGenerators; for (int i = 0; i < optimizedGammaPowerGenerators.Length; i++) { num += optimizedGammaPowerGenerators[i].EnergyCap_Gamma_Req(normalized, increase, eta); } return (num, optimizedGammaPowerGenerators.Length != 0); } public long EnergyCap(PlanetFactory planet, long[] currentGeneratorCapacities) { if (_optimizedGammaPowerGenerators.Length == 0) { return 0L; } DysonSphere dysonSphere = planet.dysonSphere; float response = ((dysonSphere != null) ? dysonSphere.energyRespCoef : 0f); long num = 0L; OptimizedGammaPowerGenerator[] optimizedGammaPowerGenerators = _optimizedGammaPowerGenerators; for (int i = 0; i < optimizedGammaPowerGenerators.Length; i++) { num += optimizedGammaPowerGenerators[i].EnergyCap_Gamma(response); } currentGeneratorCapacities[_subId] += num; TotalCapacityCurrentTick = num; return num; } public void GameTick(long time, int[] productRegister, int[] consumeRegister) { bool useIonLayer = GameMain.history.useIonLayer; bool useCata = time % 10 == 0; int num = (int)(time % 90); OptimizedGammaPowerGenerator[] optimizedGammaPowerGenerators = _optimizedGammaPowerGenerators; for (int i = 0; i < optimizedGammaPowerGenerators.Length; i++) { bool keyFrame = (i + num) % 90 == 0; optimizedGammaPowerGenerators[i].GameTick_Gamma(useIonLayer, useCata, keyFrame, productRegister, consumeRegister); } } public void Save(PlanetFactory planet) { PowerGeneratorComponent[] genPool = planet.powerSystem.genPool; OptimizedGammaPowerGenerator[] optimizedGammaPowerGenerators = _optimizedGammaPowerGenerators; for (int i = 1; i < planet.powerSystem.genCursor; i++) { if (_gammaIdToOptimizedIndex.TryGetValue(i, out var value)) { optimizedGammaPowerGenerators[value].Save(ref genPool[i]); } } } public void Initialize(PlanetFactory planet, int networkId, SubFactoryProductionRegisterBuilder subProductionRegisterBuilder, PlanetWideBeltExecutor beltExecutor) { List list = new List(); Dictionary dictionary = new Dictionary(); int? num = null; int? num2 = null; int num3 = 0; int num5 = default(int); bool slot0IsOutput = default(bool); int num6 = default(int); bool slot1IsOutput = default(bool); int num7 = default(int); for (int i = 1; i < planet.powerSystem.genCursor; i++) { ref PowerGeneratorComponent reference = ref planet.powerSystem.genPool[i]; if (reference.id != i || reference.networkId != networkId || !reference.gamma) { continue; } if (num.HasValue) { int? num4 = num; num5 = reference.subId; if (num4 != num5) { throw new InvalidOperationException("Assumption that subId is the same for all gamma machines is incorrect."); } } num = reference.subId; int protoId = planet.entityPool[reference.entityId].protoId; if (num2.HasValue) { int? num4 = num2; num5 = protoId; if (num4 != num5) { throw new InvalidOperationException("Assumption that protoId is the same for all gamma machines is incorrect."); } } num2 = protoId; planet.ReadObjectConn(reference.entityId, 0, ref slot0IsOutput, ref num6, ref num5); OptimizedIndexedCargoPath slot0Belt = OptimizedIndexedCargoPath.NoBelt; int slot0BeltOffset = 0; if (num6 > 0 && planet.entityPool[num6].beltId > 0) { int beltId = planet.entityPool[num6].beltId; slot0BeltOffset = ((BeltComponent)(ref planet.cargoTraffic.beltPool[beltId])).pivotOnPath; CargoPath cargoPath = planet.cargoTraffic.pathPool[planet.cargoTraffic.beltPool[beltId].segPathId]; slot0Belt = beltExecutor.GetOptimizedCargoPath(cargoPath); } planet.ReadObjectConn(reference.entityId, 1, ref slot1IsOutput, ref num7, ref num5); OptimizedIndexedCargoPath slot1Belt = OptimizedIndexedCargoPath.NoBelt; int slot1BeltOffset = 0; if (num7 > 0 && planet.entityPool[num7].beltId > 0) { int beltId2 = planet.entityPool[num7].beltId; slot1BeltOffset = ((BeltComponent)(ref planet.cargoTraffic.beltPool[beltId2])).pivotOnPath; CargoPath cargoPath2 = planet.cargoTraffic.pathPool[planet.cargoTraffic.beltPool[beltId2].segPathId]; slot1Belt = beltExecutor.GetOptimizedCargoPath(cargoPath2); } OptimizedItemId catalystId = default(OptimizedItemId); if (reference.catalystId != 0) { catalystId = subProductionRegisterBuilder.AddConsume(reference.catalystId); } OptimizedItemId productId = default(OptimizedItemId); if (reference.productId != 0) { productId = subProductionRegisterBuilder.AddProduct(reference.productId); } dictionary.Add(reference.id, list.Count); list.Add(new OptimizedGammaPowerGenerator(slot0Belt, slot0BeltOffset, slot0IsOutput, slot1Belt, slot1BeltOffset, slot1IsOutput, catalystId, productId, ref reference)); if (reference.productId <= 0) { num3++; } } _optimizedGammaPowerGenerators = list.ToArray(); _gammaIdToOptimizedIndex = dictionary; _subId = num.GetValueOrDefault(-1); PrototypeId = num2; _gammaMachinesGeneratingEnergyCount = num3; } } internal sealed class GeothermalGeneratorExecutor { private OptimizedGeothermalGenerator[] _optimizedGeothermalGenerators; private Dictionary _geothermalIdToOptimizedIndex; private int _subId; [MemberNotNullWhen(true, "PrototypeId")] public bool IsUsed { [MemberNotNullWhen(true, "PrototypeId")] get { return GeneratorCount > 0; } } public int GeneratorCount => _optimizedGeothermalGenerators.Length; public int? PrototypeId { get; private set; } public long TotalCapacityCurrentTick { get; private set; } public Dictionary.KeyCollection OptimizedPowerGeneratorIds => _geothermalIdToOptimizedIndex.Keys; public long EnergyCap(long[] currentGeneratorCapacities) { if (_optimizedGeothermalGenerators.Length == 0) { return 0L; } long num = 0L; OptimizedGeothermalGenerator[] optimizedGeothermalGenerators = _optimizedGeothermalGenerators; for (int i = 0; i < optimizedGeothermalGenerators.Length; i++) { num += optimizedGeothermalGenerators[i].EnergyCap_GTH(); } currentGeneratorCapacities[_subId] += num; TotalCapacityCurrentTick = num; return num; } public void GameTick() { OptimizedGeothermalGenerator[] optimizedGeothermalGenerators = _optimizedGeothermalGenerators; for (int i = 0; i < optimizedGeothermalGenerators.Length; i++) { optimizedGeothermalGenerators[i].GeneratePower(); } } public void Save(PlanetFactory planet) { PowerGeneratorComponent[] genPool = planet.powerSystem.genPool; OptimizedGeothermalGenerator[] optimizedGeothermalGenerators = _optimizedGeothermalGenerators; for (int i = 1; i < planet.powerSystem.genCursor; i++) { if (_geothermalIdToOptimizedIndex.TryGetValue(i, out var value)) { optimizedGeothermalGenerators[value].Save(ref genPool[i]); } } } public void Initialize(PlanetFactory planet, int networkId) { List list = new List(); Dictionary dictionary = new Dictionary(); int? num = null; int? num2 = null; for (int i = 1; i < planet.powerSystem.genCursor; i++) { ref PowerGeneratorComponent reference = ref planet.powerSystem.genPool[i]; if (reference.id == i && reference.networkId == networkId && reference.geothermal) { if (num.HasValue && num != reference.subId) { throw new InvalidOperationException("Assumption that subId is the same for all geothermal machines is incorrect."); } num = reference.subId; int protoId = planet.entityPool[reference.entityId].protoId; if (num2.HasValue && num2 != protoId) { throw new InvalidOperationException("Assumption that protoId is the same for all geothermal machines is incorrect."); } num2 = protoId; dictionary.Add(reference.id, list.Count); list.Add(new OptimizedGeothermalGenerator(ref reference)); } } _optimizedGeothermalGenerators = list.ToArray(); _geothermalIdToOptimizedIndex = dictionary; _subId = num.GetValueOrDefault(-1); PrototypeId = num2; } } [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct OptimizedFuelGenerator { public int id; private readonly long genEnergyPerTick; private readonly long useFuelPerTick; public readonly short fuelMask; private readonly bool boost; private long fuelEnergy; private short curFuelId; public OptimizedItemId fuelId; public short fuelCount; public short fuelInc; private bool productive; private bool incUsed; private byte fuelIncLevel; private long fuelHeat; private float currentStrength; private long capacityCurrentTick; public OptimizedFuelGenerator(OptimizedItemId fuelId, [In][RequiresLocation] ref PowerGeneratorComponent powerGenerator) { id = powerGenerator.id; genEnergyPerTick = powerGenerator.genEnergyPerTick; useFuelPerTick = powerGenerator.useFuelPerTick; fuelMask = powerGenerator.fuelMask; boost = powerGenerator.boost; fuelEnergy = powerGenerator.fuelEnergy; curFuelId = powerGenerator.curFuelId; this.fuelId = fuelId; fuelCount = powerGenerator.fuelCount; fuelInc = powerGenerator.fuelInc; productive = powerGenerator.productive; incUsed = powerGenerator.incUsed; fuelIncLevel = powerGenerator.fuelIncLevel; fuelHeat = powerGenerator.fuelHeat; currentStrength = powerGenerator.currentStrength; capacityCurrentTick = powerGenerator.capacityCurrentTick; } public long EnergyCap_Fuel() { long num = ((fuelCount > 0 || fuelEnergy >= useFuelPerTick) ? genEnergyPerTick : (fuelEnergy * genEnergyPerTick / useFuelPerTick)); capacityCurrentTick = (productive ? ((long)((double)num * (1.0 + Cargo.incTableMilli[fuelIncLevel]) + 0.1)) : ((long)((double)num * (1.0 + Cargo.accTableMilli[fuelIncLevel]) + 0.1))); if (fuelMask == 4) { if (boost) { capacityCurrentTick *= 100L; } if (curFuelId == 1804) { capacityCurrentTick *= 2L; } } return capacityCurrentTick; } public void GeneratePower(ref long num44, double num51, int[] consumeRegister) { currentStrength = ((num44 > 0 && capacityCurrentTick > 0) ? 1 : 0); if (num44 > 0) { long num52 = (long)(num51 * (double)capacityCurrentTick + 0.99999); long num53 = ((num44 < num52) ? num44 : num52); if (num53 > 0) { num44 -= num53; GenEnergyByFuel(num53, consumeRegister); } } } public void GenEnergyByFuel(long energy, int[] consumeRegister) { long num = (productive ? (energy * useFuelPerTick * 40 / (genEnergyPerTick * Cargo.incFastDivisionNumerator[fuelIncLevel])) : (energy * useFuelPerTick / genEnergyPerTick)); num = ((energy > 0 && num == 0L) ? 1 : num); if (fuelEnergy >= num) { fuelEnergy -= num; return; } curFuelId = 0; if (fuelCount > 0) { int num2 = fuelInc / fuelCount; num2 = ((num2 > 0) ? ((num2 > 10) ? 10 : num2) : 0); fuelInc -= (short)num2; productive = ((ProtoSet)(object)LDB.items).Select((int)fuelId.ItemIndex).Productive; if (productive) { fuelIncLevel = (byte)num2; num = energy * useFuelPerTick * 40 / (genEnergyPerTick * Cargo.incFastDivisionNumerator[fuelIncLevel]); } else { fuelIncLevel = (byte)num2; num = energy * useFuelPerTick / genEnergyPerTick; } if (!incUsed) { incUsed = fuelIncLevel > 0; } long num3 = num - fuelEnergy; fuelEnergy = fuelHeat - num3; curFuelId = fuelId.ItemIndex; fuelCount--; consumeRegister[fuelId.OptimizedItemIndex]++; if (fuelCount == 0) { fuelId = default(OptimizedItemId); fuelInc = 0; fuelHeat = 0L; } if (fuelEnergy < 0) { fuelEnergy = 0L; } } else { fuelEnergy = 0L; productive = false; } } public void SetNewFuel(OptimizedItemId _itemId, short _count, short _inc) { fuelId = _itemId; fuelCount = _count; fuelInc = _inc; fuelHeat = ((ProtoSet)(object)LDB.items).Select((int)_itemId.ItemIndex)?.HeatValue ?? 0; incUsed = false; } public OptimizedItemId PickFuelFrom(int filter, out int inc) { inc = 0; if (fuelId.ItemIndex > 0 && fuelCount > 5 && (filter == 0 || filter == fuelId.ItemIndex)) { if (fuelInc > 0) { inc = fuelInc / fuelCount; } fuelInc -= (short)inc; fuelCount--; return fuelId; } return default(OptimizedItemId); } public OptimizedItemId PickFuelFrom(int filter, OptimizedItemId[]? fuels, out int inc) { inc = 0; if (fuelId.ItemIndex > 0 && fuelCount > 5 && (filter == 0 || filter == fuelId.ItemIndex)) { for (int i = 0; i < fuels.Length; i++) { if (fuels[i].ItemIndex == fuelId.ItemIndex) { if (fuelInc > 0) { inc = fuelInc / fuelCount; } fuelInc -= (short)inc; fuelCount--; return fuelId; } } } return default(OptimizedItemId); } public readonly void Save(ref PowerGeneratorComponent powerGenerator) { powerGenerator.genEnergyPerTick = genEnergyPerTick; powerGenerator.useFuelPerTick = useFuelPerTick; powerGenerator.fuelMask = fuelMask; powerGenerator.boost = boost; powerGenerator.fuelEnergy = fuelEnergy; powerGenerator.curFuelId = curFuelId; powerGenerator.fuelId = fuelId.ItemIndex; powerGenerator.fuelCount = fuelCount; powerGenerator.fuelInc = fuelInc; powerGenerator.productive = productive; powerGenerator.incUsed = incUsed; powerGenerator.fuelIncLevel = fuelIncLevel; powerGenerator.fuelHeat = fuelHeat; powerGenerator.currentStrength = currentStrength; powerGenerator.capacityCurrentTick = capacityCurrentTick; } } internal record struct OptimizedFuelGeneratorLocation(int SegmentIndex, int Index); [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct OptimizedGammaPowerGenerator { private readonly OptimizedIndexedCargoPath slot0Belt; private readonly int slot0BeltOffset; private readonly bool slot0IsOutput; private readonly OptimizedIndexedCargoPath slot1Belt; private readonly int slot1BeltOffset; private readonly bool slot1IsOutput; private readonly OptimizedItemId catalystId; private readonly OptimizedItemId productId; private readonly long productHeat; private readonly Vector3 position; private readonly float ionEnhance; private readonly long genEnergyPerTick; private float currentStrength; private int catalystPoint; private bool incUsed; private long fuelHeat; private int catalystIncPoint; private float productCount; private float warmup; private float warmupSpeed; private long capacityCurrentTick; public readonly int catalystIncLevel { get { int num = ((catalystPoint != 0) ? (catalystIncPoint / catalystPoint) : 0); if (num >= 10) { return 10; } return num; } } public OptimizedGammaPowerGenerator(OptimizedIndexedCargoPath slot0Belt, int slot0BeltOffset, bool slot0IsOutput, OptimizedIndexedCargoPath slot1Belt, int slot1BeltOffset, bool slot1IsOutput, OptimizedItemId catalystId, OptimizedItemId productId, [In][RequiresLocation] ref PowerGeneratorComponent powerGenerator) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) this.slot0Belt = slot0Belt; this.slot0BeltOffset = slot0BeltOffset; this.slot0IsOutput = slot0IsOutput; this.slot1Belt = slot1Belt; this.slot1BeltOffset = slot1BeltOffset; this.slot1IsOutput = slot1IsOutput; position = new Vector3(powerGenerator.x, powerGenerator.y, powerGenerator.z); ionEnhance = powerGenerator.ionEnhance; genEnergyPerTick = powerGenerator.genEnergyPerTick; currentStrength = powerGenerator.currentStrength; this.catalystId = catalystId; this.productId = productId; productHeat = powerGenerator.productHeat; catalystPoint = powerGenerator.catalystPoint; incUsed = powerGenerator.incUsed; fuelHeat = powerGenerator.fuelHeat; catalystIncPoint = powerGenerator.catalystIncPoint; productCount = powerGenerator.productCount; warmup = powerGenerator.warmup; warmupSpeed = powerGenerator.warmupSpeed; capacityCurrentTick = powerGenerator.capacityCurrentTick; } public long EnergyCap_Gamma_Req(Vector3 normalizedSunDirection, float increase, float eta) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) float num = (Vector3.Dot(normalizedSunDirection, position) + increase * 0.8f + ((catalystPoint > 0) ? ionEnhance : 0f)) * 6f + 0.5f; num = (currentStrength = ((num > 1f) ? 1f : ((num < 0f) ? 0f : num))); float num2 = (float)Cargo.accTableMilli[catalystIncLevel]; capacityCurrentTick = (long)(currentStrength * (1f + warmup * 1.5f) * ((catalystPoint > 0) ? (2f * (1f + num2)) : 1f) * ((productId.ItemIndex > 0) ? 8f : 1f) * (float)genEnergyPerTick); eta = 1f - (1f - eta) * (1f - warmup * warmup * 0.4f); warmupSpeed = (num - 0.75f) * 4f * 1.3888889E-05f; return (long)((double)capacityCurrentTick / (double)eta + 0.49999999); } public long EnergyCap_Gamma(float response) { if (warmupSpeed > 0f && response < 0.25f) { warmupSpeed *= response * 4f; } capacityCurrentTick = (long)((double)capacityCurrentTick * (double)response); if (productId.ItemIndex == 0) { return capacityCurrentTick; } return 0L; } public void GameTick_Gamma(bool useIon, bool useCata, bool keyFrame, int[] productRegister, int[] consumeRegister) { if (catalystPoint > 0) { int num = catalystPoint / 3600; if (useCata) { int num2 = catalystIncPoint / catalystPoint; catalystPoint--; catalystIncPoint -= num2; if (!incUsed) { incUsed = num2 > 0; } if (catalystIncPoint < 0 || catalystPoint <= 0) { catalystIncPoint = 0; } } int num3 = catalystPoint / 3600; consumeRegister[catalystId.OptimizedItemIndex] += num - num3; } if (productId.ItemIndex > 0 && productCount < 20f) { int num4 = (int)productCount; productCount += (float)((double)capacityCurrentTick / (double)productHeat); int num5 = (int)productCount; productRegister[productId.OptimizedItemIndex] += num5 - num4; if (productCount > 20f) { productCount = 20f; } } warmup += warmupSpeed; warmup = ((warmup > 1f) ? 1f : ((warmup < 0f) ? 0f : warmup)); if (!keyFrame && !(productCount < 20f)) { return; } bool flag = productId.ItemIndex > 0 && productCount >= 1f; bool flag2 = keyFrame && useIon && (float)catalystPoint < 72000f; if (!(flag || flag2)) { return; } bool flag3; bool flag4; if (!slot0Belt.HasBelt) { flag3 = false; flag4 = false; } else { flag3 = slot0IsOutput; flag4 = !slot0IsOutput; } bool flag5; bool flag6; if (!slot1Belt.HasBelt) { flag5 = false; flag6 = false; } else { flag5 = slot1IsOutput; flag6 = !slot1IsOutput; } if (flag) { byte remainInc; if (flag3 && flag5) { if (fuelHeat == 0L) { if (InsertInto(ref slot0Belt.Belt, slot0BeltOffset, productId.ItemIndex, 1, 0, out remainInc) == 1) { productCount -= 1f; fuelHeat = 1L; } else if (InsertInto(ref slot1Belt.Belt, slot1BeltOffset, productId.ItemIndex, 1, 0, out remainInc) == 1) { productCount -= 1f; fuelHeat = 0L; } } else if (InsertInto(ref slot1Belt.Belt, slot1BeltOffset, productId.ItemIndex, 1, 0, out remainInc) == 1) { productCount -= 1f; fuelHeat = 0L; } else if (InsertInto(ref slot0Belt.Belt, slot0BeltOffset, productId.ItemIndex, 1, 0, out remainInc) == 1) { productCount -= 1f; fuelHeat = 1L; } } else if (flag3) { if (InsertInto(ref slot0Belt.Belt, slot0BeltOffset, productId.ItemIndex, 1, 0, out remainInc) == 1) { productCount -= 1f; fuelHeat = 1L; } } else if (flag5 && InsertInto(ref slot1Belt.Belt, slot1BeltOffset, productId.ItemIndex, 1, 0, out remainInc) == 1) { productCount -= 1f; fuelHeat = 0L; } } if (!flag2) { return; } if (flag4) { OptimizedCargo optimizedCargo = PickFrom(ref slot0Belt.Belt, slot0BeltOffset, catalystId.ItemIndex, null); if (optimizedCargo.Item == catalystId.ItemIndex) { catalystPoint += 3600 * optimizedCargo.Stack; catalystIncPoint += 3600 * optimizedCargo.Inc; } } if (flag6) { OptimizedCargo optimizedCargo2 = PickFrom(ref slot1Belt.Belt, slot1BeltOffset, catalystId.ItemIndex, null); if (optimizedCargo2.Item == catalystId.ItemIndex) { catalystPoint += 3600 * optimizedCargo2.Stack; catalystIncPoint += 3600 * optimizedCargo2.Inc; } } } public readonly void Save(ref PowerGeneratorComponent powerGenerator) { powerGenerator.currentStrength = currentStrength; powerGenerator.catalystPoint = catalystPoint; powerGenerator.incUsed = incUsed; powerGenerator.fuelHeat = fuelHeat; powerGenerator.catalystIncPoint = catalystIncPoint; powerGenerator.productCount = productCount; powerGenerator.warmup = warmup; powerGenerator.warmupSpeed = warmupSpeed; powerGenerator.capacityCurrentTick = capacityCurrentTick; } private static int InsertInto(ref OptimizedCargoPath belt, int offset, int itemId, byte itemCount, byte itemInc, out byte remainInc) { remainInc = itemInc; if (belt.TryInsertItem(offset, itemId, itemCount, itemInc)) { remainInc = 0; return itemCount; } return 0; } private static OptimizedCargo PickFrom(ref OptimizedCargoPath belt, int offset, int filter, int[]? needs) { if (needs == null) { if (filter != 0) { belt.TryPickItem(offset - 2, 5, filter, out var cargo); return cargo; } return belt.TryPickItem(offset - 2, 5); } return belt.TryPickItem(offset - 2, 5, filter, needs); } } [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct OptimizedGeothermalGenerator { private readonly long genEnergyPerTick; private readonly float warmupSpeed; private readonly float gthStrength; private readonly float gthAffectStrength; private float warmup; public OptimizedGeothermalGenerator([In][RequiresLocation] ref PowerGeneratorComponent powerGenerator) { genEnergyPerTick = powerGenerator.genEnergyPerTick; warmupSpeed = powerGenerator.warmupSpeed; gthStrength = powerGenerator.gthStrength; gthAffectStrength = powerGenerator.gthAffectStrength; warmup = powerGenerator.warmup; } public readonly long EnergyCap_GTH() { float num = gthStrength * gthAffectStrength * warmup; return (long)((float)genEnergyPerTick * num); } public void GeneratePower() { float num = warmup + warmupSpeed; warmup = ((num > 1f) ? 1f : ((num < 0f) ? 0f : num)); } public readonly void Save(ref PowerGeneratorComponent powerGenerator) { powerGenerator.warmup = warmup; } } [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct OptimizedPowerExchanger { private readonly float targetState; private readonly long energyPerTick; private readonly long maxPoolEnergy; private readonly OptimizedItemId emptyId; private readonly OptimizedItemId fullId; private readonly OptimizedIndexedCargoPath belt0; private readonly OptimizedIndexedCargoPath belt1; private readonly OptimizedIndexedCargoPath belt2; private readonly OptimizedIndexedCargoPath belt3; private readonly bool isOutput0; private readonly bool isOutput1; private readonly bool isOutput2; private readonly bool isOutput3; private short emptyCount; private short fullCount; private short emptyInc; private short fullInc; private long currPoolEnergy; private byte poolInc; private int outputSlot; private int inputSlot; private int outputRectify; private int inputRectify; public float state; public long currEnergyPerTick; public long capsCurrentTick; public OptimizedPowerExchanger(OptimizedItemId emptyId, OptimizedItemId fullId, OptimizedIndexedCargoPath belt0, OptimizedIndexedCargoPath belt1, OptimizedIndexedCargoPath belt2, OptimizedIndexedCargoPath belt3, [In][RequiresLocation] ref PowerExchangerComponent powerExchanger) { targetState = powerExchanger.targetState; energyPerTick = powerExchanger.energyPerTick; maxPoolEnergy = powerExchanger.maxPoolEnergy; this.emptyId = emptyId; this.fullId = fullId; this.belt0 = belt0; this.belt1 = belt1; this.belt2 = belt2; this.belt3 = belt3; isOutput0 = powerExchanger.isOutput0; isOutput1 = powerExchanger.isOutput1; isOutput2 = powerExchanger.isOutput2; isOutput3 = powerExchanger.isOutput3; emptyCount = powerExchanger.emptyCount; fullCount = powerExchanger.fullCount; emptyInc = powerExchanger.emptyInc; fullInc = powerExchanger.fullInc; currPoolEnergy = powerExchanger.currPoolEnergy; poolInc = powerExchanger.poolInc; outputSlot = powerExchanger.outputSlot; inputSlot = powerExchanger.inputSlot; outputRectify = powerExchanger.outputRectify; inputRectify = powerExchanger.inputRectify; state = powerExchanger.state; currEnergyPerTick = powerExchanger.currEnergyPerTick; capsCurrentTick = powerExchanger.capsCurrentTick; } public readonly void Save(ref PowerExchangerComponent powerExchanger) { powerExchanger.emptyCount = emptyCount; powerExchanger.fullCount = fullCount; powerExchanger.emptyInc = emptyInc; powerExchanger.fullInc = fullInc; powerExchanger.currPoolEnergy = currPoolEnergy; powerExchanger.poolInc = poolInc; powerExchanger.outputSlot = outputSlot; powerExchanger.inputSlot = inputSlot; powerExchanger.outputRectify = outputRectify; powerExchanger.inputRectify = inputRectify; powerExchanger.state = state; powerExchanger.currEnergyPerTick = currEnergyPerTick; powerExchanger.capsCurrentTick = capsCurrentTick; } public void StateUpdate() { if (state < targetState) { state += 0.00557f; if (state >= targetState) { state = targetState; } } else if (state > targetState) { state -= 0.00557f; if (state <= targetState) { state = targetState; } } } public long InputCaps() { long num = CalculateActualEnergyPerTick(isOutput: false); if (num > maxPoolEnergy - currPoolEnergy) { if (emptyCount > 0 && fullCount < 20) { capsCurrentTick = num; } else { capsCurrentTick = maxPoolEnergy - currPoolEnergy; } } else { capsCurrentTick = num; } return capsCurrentTick; } public long OutputCaps() { long num = CalculateActualEnergyPerTick(isOutput: true); if (currPoolEnergy < num) { if (fullCount > 0 && emptyCount < 20) { capsCurrentTick = num; } else { capsCurrentTick = currPoolEnergy; } } else { capsCurrentTick = num; } return capsCurrentTick; } public long InputUpdate(long remaining, int[] productRegister, int[] consumeRegister) { if (state != 1f) { return 0L; } long num = remaining; long num2 = CalculateActualEnergyPerTick(isOutput: false); num = ((num < num2) ? num : num2); if (num >= maxPoolEnergy - currPoolEnergy) { if (emptyCount > 0 && fullCount < 20) { if (num != remaining) { num = num2; } currPoolEnergy -= maxPoolEnergy; int n = emptyCount; int m = emptyInc; byte b = (byte)split_inc(ref n, ref m, 1); emptyCount = (short)n; emptyInc = (short)m; fullCount++; fullInc += b; productRegister[fullId.OptimizedItemIndex]++; consumeRegister[emptyId.OptimizedItemIndex]++; } else { num = maxPoolEnergy - currPoolEnergy; } } currEnergyPerTick = num; currPoolEnergy += num; return num; } public long OutputUpdate(long energyPay, int[] productRegister, int[] consumeRegister) { if (state != -1f) { return 0L; } long num = energyPay; long num2 = CalculateActualEnergyPerTick(isOutput: true); num = ((num < num2) ? num : num2); if (num >= currPoolEnergy) { if (fullCount > 0 && emptyCount < 20) { if (num != energyPay) { num = num2; } currPoolEnergy += maxPoolEnergy; int n = fullCount; int m = fullInc; byte b = (byte)split_inc(ref n, ref m, 1); fullCount = (short)n; fullInc = (short)m; emptyCount++; emptyInc += b; poolInc = b; productRegister[emptyId.OptimizedItemIndex]++; consumeRegister[fullId.OptimizedItemIndex]++; } else { num = currPoolEnergy; poolInc = 0; } } currEnergyPerTick = -num; currPoolEnergy -= num; return num; } public void BeltUpdate() { int num = 0; int num2 = 0; if (belt0.HasBelt) { if (isOutput0) { num++; } else { num2++; } } if (belt1.HasBelt) { if (isOutput1) { num++; } else { num2++; } } if (belt2.HasBelt) { if (this.isOutput2) { num++; } else { num2++; } } if (belt3.HasBelt) { if (isOutput3) { num++; } else { num2++; } } for (int i = 0; i < num2; i++) { if (i == 0 && inputRectify != inputSlot) { inputSlot = inputRectify; } OptimizedIndexedCargoPath noBelt = OptimizedIndexedCargoPath.NoBelt; bool isOutput = false; if (inputSlot == 0) { if (belt0.HasBelt) { noBelt = belt0; isOutput = isOutput0; } } else if (inputSlot == 1) { if (belt1.HasBelt) { noBelt = belt1; isOutput = isOutput1; } } else if (inputSlot == 2) { if (belt2.HasBelt) { noBelt = belt2; isOutput = this.isOutput2; } } else if (inputSlot == 3 && belt3.HasBelt) { noBelt = belt3; isOutput = isOutput3; } if (noBelt.HasBelt) { inputRectify = (ComputeInsertOrPick(ref noBelt.Belt, isOutput) ? FindTheNextSlot(isOutput) : inputRectify); inputSlot = FindTheNextSlot(isOutput); } } for (int j = 0; j < num; j++) { if (j == 0 && outputRectify != outputSlot) { outputSlot = outputRectify; } OptimizedIndexedCargoPath noBelt2 = OptimizedIndexedCargoPath.NoBelt; bool isOutput2 = false; if (outputSlot == 0) { if (belt0.HasBelt) { noBelt2 = belt0; isOutput2 = isOutput0; } } else if (outputSlot == 1) { if (belt1.HasBelt) { noBelt2 = belt1; isOutput2 = isOutput1; } } else if (outputSlot == 2) { if (belt2.HasBelt) { noBelt2 = belt2; isOutput2 = this.isOutput2; } } else if (outputSlot == 3 && belt3.HasBelt) { noBelt2 = belt3; isOutput2 = isOutput3; } if (noBelt2.HasBelt) { outputRectify = (ComputeInsertOrPick(ref noBelt2.Belt, isOutput2) ? FindTheNextSlot(isOutput2) : outputRectify); outputSlot = FindTheNextSlot(isOutput2); } } } public bool ComputeInsertOrPick(ref OptimizedCargoPath belt, bool isOutput) { if (isOutput) { if (state == 0f) { return InsertItemToBelt(ref belt); } if (state == -1f) { return InsertItemToBelt(ref belt, isEmptyAcc: true); } if (state == 1f) { return InsertItemToBelt(ref belt, isEmptyAcc: false); } } else if (!isOutput) { if (state == 0f) { return PickItemFromBelt(ref belt); } if (state == -1f) { return PickItemFromBelt(ref belt); } if (state == 1f) { return PickItemFromBelt(ref belt); } } return false; } private bool InsertItemToBelt(ref OptimizedCargoPath belt, bool isEmptyAcc) { if (isEmptyAcc) { if (emptyCount > 0) { int n = emptyCount; int m = emptyInc; byte inc = (byte)split_inc(ref n, ref m, 1); if (belt.TryInsertItemAtHead(emptyId.ItemIndex, 1, inc)) { emptyCount = (short)n; emptyInc = (short)m; return true; } } } else if (fullCount > 0) { int n2 = fullCount; int m2 = fullInc; byte inc2 = (byte)split_inc(ref n2, ref m2, 1); if (belt.TryInsertItemAtHead(fullId.ItemIndex, 1, inc2)) { fullCount = (short)n2; fullInc = (short)m2; return true; } } return false; } private bool InsertItemToBelt(ref OptimizedCargoPath belt) { if (emptyCount > 0) { int n = emptyCount; int m = emptyInc; byte inc = (byte)split_inc(ref n, ref m, 1); if (belt.TryInsertItemAtHead(emptyId.ItemIndex, 1, inc)) { emptyCount = (short)n; emptyInc = (short)m; return true; } } if (fullCount > 0) { int n2 = fullCount; int m2 = fullInc; byte inc2 = (byte)split_inc(ref n2, ref m2, 1); if (belt.TryInsertItemAtHead(fullId.ItemIndex, 1, inc2)) { fullCount = (short)n2; fullInc = (short)m2; return true; } } return false; } private bool PickItemFromBelt(ref OptimizedCargoPath beltId) { if (emptyCount < 5) { CargoPathMethods.TryPickItemAtRear(ref beltId, emptyId.ItemIndex, null, out var cargo); if (emptyId.ItemIndex == cargo.Item) { emptyCount += cargo.Stack; emptyInc += cargo.Inc; return true; } } if (fullCount < 5) { CargoPathMethods.TryPickItemAtRear(ref beltId, fullId.ItemIndex, null, out var cargo2); if (fullId.ItemIndex == cargo2.Item) { fullCount += cargo2.Stack; fullInc += cargo2.Inc; return true; } } return false; } private readonly int FindTheNextSlot(bool isOutput) { if (isOutput) { int num = outputSlot; for (int i = 0; i < 4; i++) { num++; num = ((num <= 3) ? num : (num - 4)); if (num == 0 && belt0.HasBelt && isOutput0) { return num; } if (num == 1 && belt1.HasBelt && isOutput1) { return num; } if (num == 2 && belt2.HasBelt && isOutput2) { return num; } if (num == 3 && belt3.HasBelt && isOutput3) { return num; } } } else { int num2 = inputSlot; for (int j = 0; j < 4; j++) { num2++; num2 = ((num2 <= 3) ? num2 : (num2 - 4)); if (num2 == 0 && belt0.HasBelt && !isOutput0) { return num2; } if (num2 == 1 && belt1.HasBelt && !isOutput1) { return num2; } if (num2 == 2 && belt2.HasBelt && !isOutput2) { return num2; } if (num2 == 3 && belt3.HasBelt && !isOutput3) { return num2; } } } return 0; } private readonly long CalculateActualEnergyPerTick(bool isOutput) { int num; if (isOutput) { num = poolInc; } else { int n = emptyCount; int m = emptyInc; num = split_inc(ref n, ref m, 1); } if (num != 0) { return energyPerTick + (long)((double)energyPerTick * Cargo.accTableMilli[num] + 0.1); } return energyPerTick; } private static int split_inc(ref int n, ref int m, int p) { if (n == 0) { return 0; } int num = m / n; int num2 = m - num * n; n -= p; num2 -= n; num = ((num2 > 0) ? (num * p + num2) : (num * p)); m -= num; return num; } } [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct OptimizedSolarGenerator { private readonly long genEnergyPerTick; private readonly Vector3 position; private float currentStrength; private long capacityCurrentTick; public OptimizedSolarGenerator([In][RequiresLocation] ref PowerGeneratorComponent powerGenerator) { //IL_001f: 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) genEnergyPerTick = powerGenerator.genEnergyPerTick; position = new Vector3(powerGenerator.x, powerGenerator.y, powerGenerator.z); currentStrength = powerGenerator.currentStrength; capacityCurrentTick = powerGenerator.capacityCurrentTick; } public long EnergyCap_PV(Vector3 normalized, float lumino) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) float num = Vector3.Dot(normalized, position) * 2.5f + 0.8572445f; num = ((num > 1f) ? 1f : ((num < 0f) ? 0f : num)); currentStrength = num * lumino; capacityCurrentTick = (long)(currentStrength * (float)genEnergyPerTick); return capacityCurrentTick; } public readonly void Save(ref PowerGeneratorComponent powerGenerator) { powerGenerator.currentStrength = currentStrength; powerGenerator.capacityCurrentTick = capacityCurrentTick; } } [StructLayout(LayoutKind.Sequential, Pack = 1)] internal readonly struct OptimizedWindGeneratorGroup { private readonly long _genEnergyPerTick; public readonly int _componentCount; public OptimizedWindGeneratorGroup(long genEnergyPerTick, int componentCount) { _genEnergyPerTick = genEnergyPerTick; _componentCount = componentCount; } public long EnergyCap_Wind(float windStrength) { return (long)(windStrength * (float)_genEnergyPerTick) * _componentCount; } } internal sealed class SolarGeneratorExecutor { private OptimizedSolarGenerator[] _optimizedSolarGenerators; private Dictionary _solarIdToOptimizedIndex; private int _subId; private long? _cachedEnergySum; [MemberNotNullWhen(true, "PrototypeId")] public bool IsUsed { [MemberNotNullWhen(true, "PrototypeId")] get { return GeneratorCount > 0; } } public int GeneratorCount => _optimizedSolarGenerators.Length; public int? PrototypeId { get; private set; } public long TotalCapacityCurrentTick { get; private set; } public Dictionary.KeyCollection OptimizedPowerGeneratorIds => _solarIdToOptimizedIndex.Keys; public long EnergyCap(float luminosity, Vector3 normalized, bool flag2, long[] currentGeneratorCapacities) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) if (_optimizedSolarGenerators.Length == 0) { return 0L; } if (!flag2 && _cachedEnergySum.HasValue) { currentGeneratorCapacities[_subId] += _cachedEnergySum.Value; return _cachedEnergySum.Value; } long num = 0L; OptimizedSolarGenerator[] optimizedSolarGenerators = _optimizedSolarGenerators; for (int i = 0; i < optimizedSolarGenerators.Length; i++) { num += optimizedSolarGenerators[i].EnergyCap_PV(normalized, luminosity); } _cachedEnergySum = num; currentGeneratorCapacities[_subId] += num; TotalCapacityCurrentTick = num; return num; } public void Save(PlanetFactory planet) { PowerGeneratorComponent[] genPool = planet.powerSystem.genPool; OptimizedSolarGenerator[] optimizedSolarGenerators = _optimizedSolarGenerators; for (int i = 1; i < planet.powerSystem.genCursor; i++) { if (_solarIdToOptimizedIndex.TryGetValue(i, out var value)) { optimizedSolarGenerators[value].Save(ref genPool[i]); } } } public void Initialize(PlanetFactory planet, int networkId) { List list = new List(); Dictionary dictionary = new Dictionary(); int? num = null; int? num2 = null; for (int i = 1; i < planet.powerSystem.genCursor; i++) { ref PowerGeneratorComponent reference = ref planet.powerSystem.genPool[i]; if (reference.id == i && reference.networkId == networkId && reference.photovoltaic) { if (num.HasValue && num != reference.subId) { throw new InvalidOperationException("Assumption that subId is the same for all solar machines is incorrect."); } num = reference.subId; int protoId = planet.entityPool[reference.entityId].protoId; if (num2.HasValue && num2 != protoId) { throw new InvalidOperationException("Assumption that protoId is the same for all solar machines is incorrect."); } num2 = protoId; dictionary.Add(reference.id, list.Count); list.Add(new OptimizedSolarGenerator(ref reference)); } } _optimizedSolarGenerators = list.ToArray(); _solarIdToOptimizedIndex = dictionary; _subId = num.GetValueOrDefault(-1); PrototypeId = num2; } } internal sealed class WindGeneratorExecutor { private OptimizedWindGeneratorGroup[] _optimizedWindGeneratorGroups; private int _subId; [MemberNotNullWhen(true, "PrototypeId")] public bool IsUsed { [MemberNotNullWhen(true, "PrototypeId")] get { return GeneratorCount > 0; } } public int GeneratorCount { get; private set; } public int? PrototypeId { get; private set; } public long TotalCapacityCurrentTick { get; private set; } public long EnergyCap(float windStrength, long[] currentGeneratorCapacities) { if (_optimizedWindGeneratorGroups.Length == 0) { return 0L; } long num = 0L; OptimizedWindGeneratorGroup[] optimizedWindGeneratorGroups = _optimizedWindGeneratorGroups; for (int i = 0; i < optimizedWindGeneratorGroups.Length; i++) { num += optimizedWindGeneratorGroups[i].EnergyCap_Wind(windStrength); } currentGeneratorCapacities[_subId] += num; TotalCapacityCurrentTick = num; return num; } public void Save(PlanetFactory planet) { } public void Initialize(PlanetFactory planet, int networkId) { Dictionary dictionary = new Dictionary(); int? num = null; int? num2 = null; for (int i = 1; i < planet.powerSystem.genCursor; i++) { ref PowerGeneratorComponent reference = ref planet.powerSystem.genPool[i]; if (reference.id == i && reference.networkId == networkId && reference.wind) { if (num.HasValue && num != reference.subId) { throw new InvalidOperationException("Assumption that subId is the same for all wind machines is incorrect."); } num = reference.subId; int protoId = planet.entityPool[reference.entityId].protoId; if (num2.HasValue && num2 != protoId) { throw new InvalidOperationException("Assumption that protoId is the same for all wind machines is incorrect."); } num2 = protoId; if (!dictionary.TryGetValue(reference.genEnergyPerTick, out var _)) { dictionary.Add(reference.genEnergyPerTick, 0); } dictionary[reference.genEnergyPerTick]++; } } _optimizedWindGeneratorGroups = dictionary.Select((KeyValuePair x) => new OptimizedWindGeneratorGroup(x.Key, x.Value)).ToArray(); _subId = num.GetValueOrDefault(-1); GeneratorCount = dictionary.Values.Sum(); PrototypeId = num2; } } } namespace Weaver.Optimizations.Pilers { [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct OptimizedPiler { private readonly BeltIndex inputBeltIndex; private readonly BeltIndex outputBeltIndex; private readonly int inputBeltSpeed; private readonly int outputBeltSpeed; private readonly PilerState pilerState; private byte cacheCargoStack1; private byte cacheCargoInc1; private byte cacheCargoStack2; private byte cacheCargoInc2; private byte cacheCdTick; private short cacheItemId1; private short cacheItemId2; private int slowlyBeltSpeed; public OptimizedPiler(BeltIndex inputBeltIndex, BeltIndex outputBeltIndex, int inputBeltSpeed, int outputBeltSpeed, [In][RequiresLocation] ref PilerComponent piler) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) this.inputBeltIndex = inputBeltIndex; this.outputBeltIndex = outputBeltIndex; this.inputBeltSpeed = inputBeltSpeed; this.outputBeltSpeed = outputBeltSpeed; cacheCargoStack1 = piler.cacheCargoStack1; cacheCargoInc1 = piler.cacheCargoInc1; cacheCargoStack2 = piler.cacheCargoStack2; cacheCargoInc2 = piler.cacheCargoInc2; cacheCdTick = piler.cacheCdTick; cacheItemId1 = piler.cacheItemId1; cacheItemId2 = piler.cacheItemId2; pilerState = piler.pilerState; slowlyBeltSpeed = piler.slowlyBeltSpeed; } public uint InternalUpdate(float power, ref int timeSpend, OptimizedCargoPath[] optimizedCargoPaths) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Invalid comparison between Unknown and I4 //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Invalid comparison between Unknown and I4 if (cacheCdTick > 0) { cacheCdTick--; } bool flag = power > 0.1f; slowlyBeltSpeed = ((inputBeltSpeed > outputBeltSpeed) ? outputBeltSpeed : inputBeltSpeed); slowlyBeltSpeed = ((slowlyBeltSpeed > 2) ? 3 : slowlyBeltSpeed); if (timeSpend < 10000) { timeSpend += (flag ? ((((int)pilerState == 1) ? inputBeltSpeed : outputBeltSpeed) * (int)(1000f * power)) : 0); } ref OptimizedCargoPath belt = ref inputBeltIndex.GetBelt(optimizedCargoPaths); ref OptimizedCargoPath belt2 = ref outputBeltIndex.GetBelt(optimizedCargoPaths); bool flag2 = flag && timeSpend >= 10000; if ((int)pilerState == 1) { OptimizedCargo cargo2; if (flag2) { if (cacheItemId2 == 0 && belt.TryPickCargoAtEnd(out var cargo)) { if (cacheItemId1 != 0) { cacheItemId2 = cacheItemId1; cacheCargoStack2 = cacheCargoStack1; cacheCargoInc2 = cacheCargoInc1; } cacheItemId1 = cargo.Item; cacheCargoStack1 = cargo.Stack; cacheCargoInc1 = cargo.Inc; cacheCdTick = (byte)(PilerComponent.cacheCdTickArray[slowlyBeltSpeed - 1] + 1); timeSpend -= 10000; } } else if (cacheItemId1 == 0 && belt.TryPickCargoAtEnd(out cargo2)) { cacheItemId1 = cargo2.Item; cacheCargoStack1 = cargo2.Stack; cacheCargoInc1 = cargo2.Inc; } int num = belt2.TestBlankAtHead(); if (num >= 0) { if (cacheItemId1 != 0 && cacheItemId2 != 0) { if (cacheItemId1 == cacheItemId2) { if (cacheCargoStack1 + cacheCargoStack2 > 4) { int num2 = cacheCargoStack1 + cacheCargoStack2; int num3 = cacheCargoInc1 + cacheCargoInc2; byte b = (byte)((float)num3 / (float)num2 * 4f + 0.5f); OptimizedCargo optimizedCargo = new OptimizedCargo(cacheItemId1, 4, b); belt2.InsertCargoAtHeadDirect(optimizedCargo, num); cacheCargoStack1 = (byte)(num2 - 4); cacheCargoInc1 = (byte)(num3 - b); cacheItemId2 = 0; cacheCargoStack2 = 0; cacheCargoInc2 = 0; } else { OptimizedCargo optimizedCargo2 = new OptimizedCargo(cacheItemId1, (byte)(cacheCargoStack1 + cacheCargoStack2), (byte)(cacheCargoInc1 + cacheCargoInc2)); belt2.InsertCargoAtHeadDirect(optimizedCargo2, num); cacheItemId1 = 0; cacheCargoStack1 = 0; cacheCargoInc1 = 0; cacheItemId2 = 0; cacheCargoStack2 = 0; cacheCargoInc2 = 0; } } else { OptimizedCargo optimizedCargo3 = new OptimizedCargo(cacheItemId2, cacheCargoStack2, cacheCargoInc2); belt2.InsertCargoAtHeadDirect(optimizedCargo3, num); cacheItemId2 = 0; cacheCargoStack2 = 0; cacheCargoInc2 = 0; } } else if (cacheCdTick == 0 && cacheItemId1 != 0) { OptimizedCargo optimizedCargo4 = new OptimizedCargo(cacheItemId1, cacheCargoStack1, cacheCargoInc1); belt2.InsertCargoAtHeadDirect(optimizedCargo4, num); cacheItemId1 = 0; cacheCargoStack1 = 0; cacheCargoInc1 = 0; } } } else { if (cacheItemId1 == 0 && cacheItemId2 == 0) { OptimizedCargo cargo3; bool flag3 = belt.TryPickCargoAtEnd(out cargo3); if (flag2) { if (flag3) { byte b2 = (byte)((float)(int)cargo3.Stack / 2f + 0.5f); byte b3 = (byte)((float)(int)cargo3.Inc / (float)(int)cargo3.Stack * (float)(int)b2 + 0.5f); cacheItemId2 = cargo3.Item; cacheCargoStack2 = b2; cacheCargoInc2 = b3; if (cargo3.Stack > b2) { cacheItemId1 = cargo3.Item; cacheCargoStack1 = (byte)(cargo3.Stack - b2); cacheCargoInc1 = (byte)(cargo3.Inc - b3); cacheCdTick = (byte)(PilerComponent.cacheCdTickArray[slowlyBeltSpeed - 1] * 2 + 1); timeSpend -= 10000; } } } else if (flag3) { cacheItemId2 = cargo3.Item; cacheCargoStack2 = cargo3.Stack; cacheCargoInc2 = cargo3.Inc; } } int num4 = belt2.TestBlankAtHead(); if (cacheItemId2 != 0 && num4 >= 0) { OptimizedCargo optimizedCargo5 = new OptimizedCargo(cacheItemId2, cacheCargoStack2, cacheCargoInc2); belt2.InsertCargoAtHeadDirect(optimizedCargo5, num4); cacheItemId2 = cacheItemId1; cacheCargoStack2 = cacheCargoStack1; cacheCargoInc2 = cacheCargoInc1; cacheItemId1 = 0; cacheCargoStack1 = 0; cacheCargoInc1 = 0; } } if (cacheCdTick < 1) { return 0u; } return 1u; } public readonly void Save(ref PilerComponent piler, int timeSpend) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) piler.cacheCargoStack1 = cacheCargoStack1; piler.cacheCargoInc1 = cacheCargoInc1; piler.cacheCargoStack2 = cacheCargoStack2; piler.cacheCargoInc2 = cacheCargoInc2; piler.cacheCdTick = cacheCdTick; piler.cacheItemId1 = cacheItemId1; piler.cacheItemId2 = cacheItemId2; piler.pilerState = pilerState; piler.timeSpend = timeSpend; piler.slowlyBeltSpeed = slowlyBeltSpeed; } } internal sealed class PilerExecutor { private ReadonlyArray _networkIndices; private OptimizedPiler[] _optimizedPilers; private int[] _timeSpends; private Dictionary _pilerIdToOptimizedIndex; private PrototypePowerConsumptionExecutor _prototypePowerConsumptionExecutor; public int Count => _optimizedPilers.Length; public void GameTick(PlanetFactory planet, ReadonlyArray pilerPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption, OptimizedCargoPath[] optimizedCargoPaths) { float[] networkServes = planet.powerSystem.networkServes; ReadonlyArray networkIndices = _networkIndices; OptimizedPiler[] optimizedPilers = _optimizedPilers; int[] timeSpends = _timeSpends; for (int i = 0; i < optimizedPilers.Length; i++) { short num = networkIndices[i]; float power = networkServes[num]; ref int reference = ref timeSpends[i]; optimizedPilers[i].InternalUpdate(power, ref reference, optimizedCargoPaths); UpdatePower(pilerPowerConsumerIndexes, powerConsumerTypes, thisSubFactoryNetworkPowerConsumption, i, num, reference); } } public void UpdatePower(ReadonlyArray pilerPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption) { ReadonlyArray networkIndices = _networkIndices; int[] timeSpends = _timeSpends; for (int i = 0; i < timeSpends.Length; i++) { short networkIndex = networkIndices[i]; int timeSpend = timeSpends[i]; UpdatePower(pilerPowerConsumerIndexes, powerConsumerTypes, thisSubFactoryNetworkPowerConsumption, i, networkIndex, timeSpend); } } private static void UpdatePower(ReadonlyArray pilerPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption, int pilerIndex, short networkIndex, int timeSpend) { int index = pilerPowerConsumerIndexes[pilerIndex]; PowerConsumerType powerConsumerType = powerConsumerTypes[index]; thisSubFactoryNetworkPowerConsumption[networkIndex] += GetPowerConsumption(powerConsumerType, timeSpend); } public PrototypePowerConsumptions UpdatePowerConsumptionPerPrototype(ReadonlyArray pilerPowerConsumerIndexes, ReadonlyArray powerConsumerTypes) { PrototypePowerConsumptionExecutor prototypePowerConsumptionExecutor = _prototypePowerConsumptionExecutor; prototypePowerConsumptionExecutor.Clear(); int[] timeSpends = _timeSpends; ReadonlyArray prototypeIdIndexes = prototypePowerConsumptionExecutor.PrototypeIdIndexes; long[] prototypeIdPowerConsumption = prototypePowerConsumptionExecutor.PrototypeIdPowerConsumption; for (int i = 0; i < timeSpends.Length; i++) { int timeSpend = timeSpends[i]; UpdatePowerConsumptionPerPrototype(pilerPowerConsumerIndexes, powerConsumerTypes, prototypeIdIndexes, prototypeIdPowerConsumption, i, timeSpend); } return prototypePowerConsumptionExecutor.GetPowerConsumption(); } private static void UpdatePowerConsumptionPerPrototype(ReadonlyArray pilerPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, ReadonlyArray prototypeIdIndexes, long[] prototypeIdPowerConsumption, int pilerIndex, int timeSpend) { int index = pilerPowerConsumerIndexes[pilerIndex]; PowerConsumerType powerConsumerType = powerConsumerTypes[index]; prototypeIdPowerConsumption[prototypeIdIndexes[pilerIndex]] += GetPowerConsumption(powerConsumerType, timeSpend); } public void Save(PlanetFactory planet) { PilerComponent[] pilerPool = planet.cargoTraffic.pilerPool; OptimizedPiler[] optimizedPilers = _optimizedPilers; int[] timeSpends = _timeSpends; for (int i = 1; i < planet.factorySystem.inserterCursor; i++) { if (_pilerIdToOptimizedIndex.TryGetValue(i, out var value)) { optimizedPilers[value].Save(ref pilerPool[i], timeSpends[value]); } } } public void Initialize(PlanetFactory planet, Graph subFactoryGraph, SubFactoryPowerSystemBuilder subFactoryPowerSystemBuilder, BeltExecutor beltExecutor, UniverseStaticDataBuilder universeStaticDataBuilder) { //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) List list = new List(); List list2 = new List(); List list3 = new List(); Dictionary dictionary = new Dictionary(); PrototypePowerConsumptionBuilder prototypePowerConsumptionBuilder = new PrototypePowerConsumptionBuilder(); foreach (int item in from x in subFactoryGraph.GetAllNodes() where x.EntityTypeIndex.EntityType == EntityType.Piler select x.EntityTypeIndex.Index into x orderby x select x) { ref PilerComponent reference = ref planet.cargoTraffic.pilerPool[item]; if (reference.id != item || reference.inputBeltId == 0 || reference.outputBeltId == 0 || (int)reference.pilerState == 0) { continue; } BeltComponent val = planet.cargoTraffic.beltPool[reference.inputBeltId]; if (beltExecutor.TryGetOptimizedCargoPathIndex(planet, reference.inputBeltId, out var beltIndex)) { BeltComponent val2 = planet.cargoTraffic.beltPool[reference.outputBeltId]; if (beltExecutor.TryGetOptimizedCargoPathIndex(planet, reference.outputBeltId, out var beltIndex2)) { int networkId = planet.powerSystem.consumerPool[reference.pcId].networkId; list.Add(ConverterUtilities.ThrowIfNotWithinPositiveShortRange(networkId, "networkIndex")); dictionary.Add(reference.id, list2.Count); list2.Add(new OptimizedPiler(beltIndex, beltIndex2, val.speed, val2.speed, ref reference)); list3.Add(reference.timeSpend); subFactoryPowerSystemBuilder.AddPiler(ref reference, networkId); prototypePowerConsumptionBuilder.AddPowerConsumer(ref planet.entityPool[reference.entityId]); } } } _networkIndices = universeStaticDataBuilder.DeduplicateArrayUnmanaged(list); _optimizedPilers = list2.ToArray(); _timeSpends = list3.ToArray(); _pilerIdToOptimizedIndex = dictionary; _prototypePowerConsumptionExecutor = prototypePowerConsumptionBuilder.Build(universeStaticDataBuilder); } private static long GetPowerConsumption(PowerConsumerType powerConsumerType, int timeSpend) { return powerConsumerType.GetRequiredEnergy(timeSpend < 10000); } } } namespace Weaver.Optimizations.NeedsSystem { internal struct ComponentNeeds { public short PatternIndex { get; } public byte Needs { get; set; } public bool HasAnyNeeds => Needs != 0; public ComponentNeeds(short patternIndex, byte needs) { PatternIndex = patternIndex; Needs = needs; } public readonly bool GetNeeds(int index) { return ((Needs >> index) & 1) == 1; } } internal record struct GroupNeeds(int GroupNeedStartIndex, byte GroupNeedsSize) { public int GetObjectNeedsIndex(int objectIndex) { if (GroupNeedsSize == 0) { return 0; } return GroupNeedStartIndex + objectIndex; } public static void SetIfInRange(int[] copyTo, short[] copyFrom, int copyToIndex, int copyFromIndex) { if (copyTo.Length > copyToIndex) { copyTo[copyToIndex] = copyFrom[copyFromIndex]; } } public static void SetNeedsIfInRange(int[] copyTo, ComponentNeeds componentNeeds, short[] needsPatterns, int copyIndex) { if (copyTo.Length > copyIndex) { copyTo[copyIndex] = (componentNeeds.GetNeeds(copyIndex) ? needsPatterns[componentNeeds.PatternIndex + copyIndex] : 0); } } public static void SetIfInRange(int[] copyTo, int[] copyFrom, int copyToIndex, int copyFromIndex) { if (copyTo.Length > copyToIndex) { copyTo[copyToIndex] = copyFrom[copyFromIndex]; } } public static short GetOrDefaultConvertToShortWithClamping(int[] values, int index, int minAllowedValue, int maxAllowedValue) { if (values.Length <= index) { return 0; } int num = values[index]; if (num > 32767 || num < -32768) { num = Math.Min(Math.Max(num, minAllowedValue), maxAllowedValue); } return (short)num; } } internal sealed class GroupNeedsBuilder { private readonly SubFactoryNeedsBuilder _needsBuilder; private readonly EntityType _entityType; private readonly int _needsStartIndex; private readonly List<(int[] Needs, int[] Pattern)> _needsWithPatterns = new List<(int[], int[])>(); public GroupNeedsBuilder(SubFactoryNeedsBuilder needsBuilder, EntityType entityType, int needsStartIndex) { _needsBuilder = needsBuilder; _entityType = entityType; _needsStartIndex = needsStartIndex; } public void AddNeeds(int[] needs, int[] pattern) { _needsWithPatterns.Add((needs, pattern)); } public void Complete() { int num = 0; foreach (var needsWithPattern in _needsWithPatterns) { num = Math.Max(num, needsWithPattern.Pattern.Length); } foreach (var needsWithPattern2 in _needsWithPatterns) { short patternIndex = AddNeedsPattern(needsWithPattern2.Needs, needsWithPattern2.Pattern, num); _needsBuilder.AddNeeds(patternIndex, needsWithPattern2.Pattern); } _needsBuilder.CompleteGroup(_entityType, new GroupNeeds(_needsStartIndex, (byte)num)); } private short AddNeedsPattern(int[] needs, int[] pattern, int largestPatternSize) { if (pattern.Length > 8) { throw new InvalidOperationException($"Assumption that no needs pattern is larger than {8} was incorrect. Length: {pattern.Length}"); } if (needs.Length > 8) { throw new InvalidOperationException($"Assumption that no needs is larger than {8} was incorrect. Length: {needs.Length}"); } NeedsPattern needsPattern = new NeedsPattern(pattern, largestPatternSize); return _needsBuilder.AddPattern(needsPattern, largestPatternSize); } } internal readonly struct NeedsPattern : IEquatable { private readonly int[] _pattern; private readonly int _length; public int[] Pattern => _pattern; public NeedsPattern(int[] pattern, int length) { _pattern = pattern; _length = length; } public bool Equals(NeedsPattern other) { if (_length == other._length) { return _pattern.SequenceEqual(other._pattern); } return false; } public override bool Equals(object obj) { if (obj is NeedsPattern other) { return Equals(other); } return false; } public override int GetHashCode() { HashCode hashCode = default(HashCode); hashCode.Add(_length); for (int i = 0; i < _pattern.Length; i++) { hashCode.Add(_pattern[i]); } return hashCode.ToHashCode(); } } internal sealed class SubFactoryNeeds { private readonly GroupNeeds[] _groupNeeds; public short[] NeedsPatterns { get; } public ComponentNeeds[] ComponentsNeeds { get; } public SubFactoryNeeds(GroupNeeds[] groupNeeds, short[] needsPatterns, ComponentNeeds[] componentsNeeds) { _groupNeeds = groupNeeds; NeedsPatterns = needsPatterns; ComponentsNeeds = componentsNeeds; } public GroupNeeds GetGroupNeeds(EntityType entityType) { return _groupNeeds[(uint)entityType]; } public int GetTypedObjectNeedsIndex(TypedObjectIndex typedObjectIndex) { return GetGroupNeeds(typedObjectIndex.EntityType).GetObjectNeedsIndex(typedObjectIndex.Index); } } internal sealed class SubFactoryNeedsBuilder { private readonly GroupNeeds[] _groupNeeds = new GroupNeeds[ArrayExtensions.GetEnumValuesEnumerable().Max((EntityType x) => (int)x) + 1]; private readonly Dictionary _needsPatternToNeedsPatternIndex = new Dictionary(); private readonly List _needsPatternsFlat = new List(); private readonly List _needsBits = new List(); public const int MAX_NEEDS_LENGTH = 8; public GroupNeedsBuilder CreateGroupNeedsBuilder(EntityType entityType) { return new GroupNeedsBuilder(this, entityType, _needsBits.Count); } public void AddNeeds(short patternIndex, int[] needs) { _needsBits.Add(new ComponentNeeds(patternIndex, PatternToBits(needs))); } public short AddPattern(NeedsPattern needsPattern, int largestGroupPatternSize) { if (_needsPatternToNeedsPatternIndex.TryGetValue(needsPattern, out var value)) { return value; } int count = _needsPatternsFlat.Count; if (count > 32767 || count < -32768) { throw new InvalidOperationException("Assumption that newPatternIndex fits in a short is not correct."); } for (int i = 0; i < largestGroupPatternSize; i++) { if (i >= needsPattern.Pattern.Length) { _needsPatternsFlat.Add(0); continue; } int num = needsPattern.Pattern[i]; if (num > 32767 || num < -32768) { throw new InvalidOperationException("Assumption that patternValue fits in a short is not correct."); } _needsPatternsFlat.Add((short)num); } _needsPatternToNeedsPatternIndex.Add(needsPattern, (short)count); return (short)count; } public void CompleteGroup(EntityType entityType, GroupNeeds groupNeeds) { _groupNeeds[(uint)entityType] = groupNeeds; } public SubFactoryNeeds Build() { return new SubFactoryNeeds(_groupNeeds, _needsPatternsFlat.ToArray(), _needsBits.ToArray()); } private static byte PatternToBits(int[] needs) { byte b = 0; for (int i = 0; i < needs.Length; i++) { b |= (byte)(((needs[i] != 0) ? 1u : 0u) << i); } return b; } } } namespace Weaver.Optimizations.Monitors { internal sealed class MonitorExecutor { private ReadonlyArray _monitorIndexes; private ReadonlyArray _networkIds; private OptimizedMonitor[] _optimizedMonitors; private PrototypePowerConsumptionExecutor _prototypePowerConsumptionExecutor; public int Count => _optimizedMonitors.Length; public void GameTick(PlanetFactory planet, ReadonlyArray monitorPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption, OptimizedCargoPath[] optimizedCargoPaths) { SpeakerComponent[] speakerPool = planet.digitalSystem.speakerPool; bool sandboxToolsEnabled = GameMain.sandboxToolsEnabled; float[] networkServes = planet.powerSystem.networkServes; MonitorComponent[] monitorPool = planet.cargoTraffic.monitorPool; ReadonlyArray monitorIndexes = _monitorIndexes; ReadonlyArray networkIds = _networkIds; OptimizedMonitor[] optimizedMonitors = _optimizedMonitors; for (int i = 0; i < _monitorIndexes.Length; i++) { int num = monitorIndexes[i]; short num2 = networkIds[i]; float power = networkServes[num2]; optimizedMonitors[i].InternalUpdate(ref monitorPool[num], power, sandboxToolsEnabled, speakerPool, optimizedCargoPaths); UpdatePower(monitorPowerConsumerIndexes, powerConsumerTypes, thisSubFactoryNetworkPowerConsumption, i, num2); } } public void UpdatePower(ReadonlyArray monitorPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption) { ReadonlyArray networkIds = _networkIds; for (int i = 0; i < networkIds.Length; i++) { short networkIndex = networkIds[i]; UpdatePower(monitorPowerConsumerIndexes, powerConsumerTypes, thisSubFactoryNetworkPowerConsumption, i, networkIndex); } } private static void UpdatePower(ReadonlyArray monitorPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption, int monitorIndex, short networkIndex) { int index = monitorPowerConsumerIndexes[monitorIndex]; PowerConsumerType powerConsumerType = powerConsumerTypes[index]; thisSubFactoryNetworkPowerConsumption[networkIndex] += GetPowerConsumption(powerConsumerType); } public PrototypePowerConsumptions UpdatePowerConsumptionPerPrototype(ReadonlyArray monitorPowerConsumerIndexes, ReadonlyArray powerConsumerTypes) { PrototypePowerConsumptionExecutor prototypePowerConsumptionExecutor = _prototypePowerConsumptionExecutor; prototypePowerConsumptionExecutor.Clear(); ReadonlyArray prototypeIdIndexes = prototypePowerConsumptionExecutor.PrototypeIdIndexes; long[] prototypeIdPowerConsumption = prototypePowerConsumptionExecutor.PrototypeIdPowerConsumption; for (int i = 0; i < prototypeIdIndexes.Length; i++) { UpdatePowerConsumptionPerPrototype(monitorPowerConsumerIndexes, powerConsumerTypes, prototypeIdIndexes, prototypeIdPowerConsumption, i); } return prototypePowerConsumptionExecutor.GetPowerConsumption(); } private static void UpdatePowerConsumptionPerPrototype(ReadonlyArray monitorPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, ReadonlyArray prototypeIdIndexes, long[] prototypeIdPowerConsumption, int monitorIndexIndex) { int index = monitorPowerConsumerIndexes[monitorIndexIndex]; PowerConsumerType powerConsumerType = powerConsumerTypes[index]; prototypeIdPowerConsumption[prototypeIdIndexes[monitorIndexIndex]] += GetPowerConsumption(powerConsumerType); } public void Initialize(PlanetFactory planet, Graph subFactoryGraph, SubFactoryPowerSystemBuilder subFactoryPowerSystemBuilder, BeltExecutor beltExecutor, UniverseStaticDataBuilder universeStaticDataBuilder) { //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) List list = new List(); List list2 = new List(); List list3 = new List(); PrototypePowerConsumptionBuilder prototypePowerConsumptionBuilder = new PrototypePowerConsumptionBuilder(); foreach (int item in from x in subFactoryGraph.GetAllNodes() where x.EntityTypeIndex.EntityType == EntityType.Monitor select x.EntityTypeIndex.Index into x orderby x select x) { ref MonitorComponent reference = ref planet.cargoTraffic.monitorPool[item]; if (reference.id == item && beltExecutor.TryGetOptimizedCargoPathIndex(planet, reference.targetBeltId, out var beltIndex)) { BeltComponent val = planet.cargoTraffic.beltPool[reference.targetBeltId]; int targetBeltOffset = val.segIndex + val.segPivotOffset; int networkId = planet.powerSystem.consumerPool[reference.pcId].networkId; subFactoryPowerSystemBuilder.AddMonitor(ref reference, networkId); list.Add(item); list2.Add(ConverterUtilities.ThrowIfNotWithinPositiveShortRange(networkId, "networkIndex")); list3.Add(new OptimizedMonitor(beltIndex, val.speed, targetBeltOffset)); prototypePowerConsumptionBuilder.AddPowerConsumer(ref planet.entityPool[reference.entityId]); } } _monitorIndexes = universeStaticDataBuilder.DeduplicateArrayUnmanaged(list); _networkIds = universeStaticDataBuilder.DeduplicateArrayUnmanaged(list2); _optimizedMonitors = list3.ToArray(); _prototypePowerConsumptionExecutor = prototypePowerConsumptionBuilder.Build(universeStaticDataBuilder); } private static long GetPowerConsumption(PowerConsumerType powerConsumerType) { return powerConsumerType.GetRequiredEnergy(working: true); } } [StructLayout(LayoutKind.Sequential, Pack = 1)] internal readonly struct OptimizedMonitor { private readonly BeltIndex targetBeltIndex; private readonly int targetBeltSpeed; private readonly int targetBeltOffset; public OptimizedMonitor(BeltIndex targetBeltIndex, int targetBeltSpeed, int targetBeltOffset) { this.targetBeltIndex = targetBeltIndex; this.targetBeltSpeed = targetBeltSpeed; this.targetBeltOffset = targetBeltOffset; } public void InternalUpdate(ref MonitorComponent monitor, float power, bool sandbox, SpeakerComponent[] _speakerPool, OptimizedCargoPath[] optimizedCargoPaths) { if (monitor.periodTickCount < 60) { ((MonitorComponent)(ref monitor)).SetPeriodTickCount(60); } int num = 0; monitor.cargoFlow -= monitor.cargoBytesArray[0]; Array.Copy(monitor.cargoBytesArray, 1, monitor.cargoBytesArray, 0, monitor.periodTickCount - 1); if (monitor.periodCargoBytesArray == null || monitor.periodCargoBytesArray.Length != monitor.cargoBytesArray.Length) { ((MonitorComponent)(ref monitor)).SetPeriodTickCount((int)monitor.periodTickCount); } Array.Copy(monitor.periodCargoBytesArray, 1, monitor.periodCargoBytesArray, 0, monitor.periodTickCount - 1); monitor.cargoBytesArray[monitor.periodTickCount - 1] = 0; monitor.periodCargoBytesArray[monitor.periodTickCount - 1] = monitor.cargoFlow; bool flag = power > 0.1f; int num2 = targetBeltOffset + monitor.offset; int num3 = num2 + 10; if (monitor.prewarmSampleTick < monitor.periodTickCount * 2) { monitor.prewarmSampleTick++; } ref OptimizedCargoPath belt = ref targetBeltIndex.GetBelt(optimizedCargoPaths); GetCargoAtIndexByFilter(monitor.cargoFilter, ref belt, num2, out var cargo, out var cargoBufferIndex, out var offset); if (monitor.lastCargoId == -1 && cargoBufferIndex >= 0) { num = ((cargoBufferIndex != monitor.formerCargoId) ? (num + (10 - offset - 1) * cargo.Stack) : (num - (offset + 1) * cargo.Stack)); } else if (monitor.lastCargoId >= 0 && cargoBufferIndex >= 0) { num = ((monitor.lastCargoId == cargoBufferIndex) ? (num + (monitor.lastCargoOffset - offset) * cargo.Stack) : ((monitor.formerCargoId != cargoBufferIndex) ? (num + (monitor.lastCargoOffset + 1) * monitor.lastCargoStack + (10 - offset - 1) * cargo.Stack) : (num + ((monitor.lastCargoOffset + 1) * monitor.lastCargoStack + (10 - offset - 1) * cargo.Stack - 10 * (monitor.lastCargoStack + cargo.Stack))))); } else if (monitor.lastCargoId >= 0 && cargoBufferIndex == -1) { num += (monitor.lastCargoOffset + 1) * monitor.lastCargoStack; } if (num3 < belt.pathLength) { GetCargoAtIndexByFilter(monitor.cargoFilter, ref belt, num3, out var _, out monitor.formerCargoId, out var _); } else { monitor.formerCargoId = -1; } monitor.lastCargoId = cargoBufferIndex; monitor.lastCargoOffset = offset; monitor.lastCargoStack = cargo.Stack; if (sandbox && monitor.spawnItemOperator > 0 && flag) { int num4 = ((targetBeltSpeed == 1) ? 10 : ((targetBeltSpeed != 2) ? 2 : 5)); double num5 = (double)monitor.targetCargoBytes / 10.0; double num6 = (double)power * num5 / (double)(int)monitor.periodTickCount; monitor.spawnItemAccumulator += num6; int num7 = (int)(num6 * (double)num4 + 0.99996); if (num7 < 1) { num7 = 1; } else if (num7 > 4) { num7 = 4; } if (monitor.spawnItemOperator == 2) { num7 = 4; } if (monitor.spawnItemAccumulator >= (double)num7 + 0.99996) { monitor.spawnItemAccumulator = (double)num7 + 0.99996; } int num8 = (int)(monitor.spawnItemAccumulator + 1E-08); if (num8 >= num7) { num8 = num7; } if (num8 > 0) { if (monitor.cargoFilter > 0 && monitor.spawnItemOperator == 1) { int num9 = 0; int index = num2 + 10; int cargoBufferIndex2; OptimizedCargo optimizedCargo = belt.QueryItemAtIndex(index, out cargoBufferIndex2); if (optimizedCargo.Item == monitor.cargoFilter) { int num10 = num7 - optimizedCargo.Stack; if (num10 > 0) { num9 = ((num8 >= num10) ? num10 : num8); optimizedCargo.Stack += (byte)num9; belt.SetCargoInBuffer(cargoBufferIndex2, optimizedCargo); } } else if (belt.TryInsertItem(index, monitor.cargoFilter, (byte)num8, 0)) { num9 = num8; } monitor.spawnItemAccumulator -= num9; num += num9 * 10; } else if (monitor.spawnItemOperator == 2) { int index2 = num2 - 10; int cargoBufferIndex3; OptimizedCargo optimizedCargo2 = belt.QueryItemAtIndex(index2, out cargoBufferIndex3); if (monitor.cargoFilter == 0 || (monitor.cargoFilter > 0 && optimizedCargo2.Item == monitor.cargoFilter)) { int num11; if (num8 >= optimizedCargo2.Stack) { belt.RemoveCargoAtIndex(index2); num11 = optimizedCargo2.Stack; } else { optimizedCargo2.Stack -= (byte)num8; belt.SetCargoInBuffer(cargoBufferIndex3, optimizedCargo2); num11 = num8; } monitor.spawnItemAccumulator -= num11; num += num11 * 10; } } } } monitor.cargoFlow += num; monitor.totalCargoBytes += num; monitor.cargoBytesArray[monitor.periodTickCount - 1] = (sbyte)num; monitor.periodCargoBytesArray[monitor.periodTickCount - 1] = monitor.cargoFlow; monitor.isSpeakerAlarming = Alarming(ref monitor, monitor.alarmMode, ref belt) && flag; monitor.isSystemAlarming = Alarming(ref monitor, monitor.systemWarningMode, ref belt); if (monitor.isSpeakerAlarming) { ((SpeakerComponent)(ref _speakerPool[monitor.speakerId])).Play((ESpeakerPlaybackOrigin)1, 0f); } else { ((SpeakerComponent)(ref _speakerPool[monitor.speakerId])).Stop(); } ((SpeakerComponent)(ref _speakerPool[monitor.speakerId])).SetPowerRatio(power); } private bool Alarming(ref MonitorComponent monitor, int _mode, ref OptimizedCargoPath targetBelt) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Invalid comparison between Unknown and I4 //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Invalid comparison between Unknown and I4 //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Invalid comparison between Unknown and I4 //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Invalid comparison between Unknown and I4 if (monitor.periodTickCount == 0 || _mode == 0) { return false; } ELogicState logicState = ((MonitorComponent)(ref monitor)).GetLogicState(); switch (_mode) { case 1: return (int)logicState == 1; case 2: return (int)logicState == 2; default: { int num = targetBeltOffset; bool flag = true; OptimizedCargo cargo; int offset; for (int i = 0; i < targetBeltSpeed; i++) { GetCargoAtIndexByFilter(monitor.cargoFilter, ref targetBelt, num + i, out cargo, out var cargoBufferIndex, out offset); if (cargoBufferIndex < 0) { flag = false; break; } } switch (_mode) { case 3: return flag; case 4: return !flag; case 5: if (flag) { return (int)logicState == 1; } return false; case 6: { flag = true; int num2 = (targetBelt.closed ? 9 : 0); int pathLength = targetBelt.pathLength; for (int j = -25; j < 26; j++) { int num3 = num + j; num3 = ((num3 < num2) ? num2 : num3); num3 = ((num3 >= pathLength) ? (pathLength - 1) : num3); GetCargoAtIndexByFilter(monitor.cargoFilter, ref targetBelt, num3, out cargo, out var cargoBufferIndex2, out offset); if (cargoBufferIndex2 < 0) { flag = false; break; } } if (!flag) { return (int)logicState == 1; } return false; } default: return false; } } } } private static void GetCargoAtIndexByFilter(int filter, ref OptimizedCargoPath targetBelt, int index, out OptimizedCargo cargo, out int cargoBufferIndex, out int offset) { targetBelt.GetCargoAtIndex(index, out cargo, out cargoBufferIndex, out offset); if (cargoBufferIndex >= 0 && cargo.Item != filter && filter != 0) { cargo.Item = 0; cargoBufferIndex = -1; offset = -1; } } } } namespace Weaver.Optimizations.Miners { internal readonly struct BeltMinerOutput : IMinerOutput { private readonly BeltIndex outputBeltIndex; private readonly int beltOffset; public BeltMinerOutput(BeltIndex outputBeltIndex, int beltOffset) { this.outputBeltIndex = outputBeltIndex; this.beltOffset = beltOffset; } public int InsertInto(int itemId, byte itemCount, OptimizedCargoPath[] optimizedCargoPaths) { if (!outputBeltIndex.GetBelt(optimizedCargoPaths).TryInsertItem(beltOffset, itemId, itemCount, 0)) { return 0; } return itemCount; } public void PrePowerUpdate(ref T miner) where T : IMiner { float num = (float)miner.ProductCount / 50f; num = ((num > 1f) ? 1f : num); float num2 = -2.45f * num + 2.47f; num2 = ((num2 > 1f) ? 1f : num2); miner.SpeedDamper = num2; } public bool TryGetMinerOutput(PlanetFactory planet, BeltExecutor beltExecutor, [In][RequiresLocation] ref MinerComponent miner, out BeltMinerOutput minerOutput) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) if (miner.insertTarget <= 0) { minerOutput = default(BeltMinerOutput); return false; } int beltId = planet.entityPool[miner.insertTarget].beltId; if (!beltExecutor.TryGetOptimizedCargoPathIndex(planet, beltId, out var beltIndex)) { minerOutput = default(BeltMinerOutput); return false; } BeltComponent val = planet.cargoTraffic.beltPool[beltId]; minerOutput = new BeltMinerOutput(beltIndex, ((BeltComponent)(ref val)).pivotOnPath); return true; } bool IMinerOutput.TryGetMinerOutput(PlanetFactory planet, BeltExecutor beltExecutor, [In][RequiresLocation] ref MinerComponent miner, out BeltMinerOutput minerOutput) { return TryGetMinerOutput(planet, beltExecutor, ref miner, out minerOutput); } } internal interface IMiner { int ProductCount { get; set; } float SpeedDamper { get; set; } } internal interface IMinerOutput where T : IMinerOutput { int InsertInto(int itemId, byte itemCount, OptimizedCargoPath[] optimizedCargoPaths); void PrePowerUpdate(ref TMiner miner) where TMiner : IMiner; bool TryGetMinerOutput(PlanetFactory planet, BeltExecutor beltExecutor, [In][RequiresLocation] ref MinerComponent miner, out T minerOutput); } internal struct MiningFlags { public int MiningFlag; public int VeinMiningFlag; public MiningFlags() { MiningFlag = 0; VeinMiningFlag = 0; } public void AddMiningFlagUnsafe(EVeinType addVeinType) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) MiningFlag |= 1 << (int)addVeinType; } public void AddVeinMiningFlagUnsafe(EVeinType addVeinType) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) VeinMiningFlag |= 1 << (int)addVeinType; } } internal sealed class OilMinerExecutor { private ReadonlyArray _networkIds; private OptimizedOilMiner[] _optimizedMiners; public Dictionary _minerIdToOptimizedIndex; private PrototypePowerConsumptionExecutor _prototypePowerConsumptionExecutor; public int Count => _optimizedMiners.Length; public void GameTick(PlanetFactory planet, ReadonlyArray oilMinerPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption, int[] productRegister, OptimizedCargoPath[] optimizedCargoPaths) { GameHistoryData history = GameMain.history; float[] networkServes = planet.powerSystem.networkServes; float miningSpeedScale = history.miningSpeedScale; VeinData[] veinPool = planet.veinPool; ReadonlyArray networkIds = _networkIds; OptimizedOilMiner[] optimizedMiners = _optimizedMiners; float num; float num2 = (num = planet.gameData.gameDesc.resourceMultiplier); if (num < 5f / 12f) { num = 5f / 12f; } float miningRate = history.miningCostRate * 0.40111667f / num; if (num2 > 99.5f) { miningRate = 0f; } for (int i = 0; i < optimizedMiners.Length; i++) { short num3 = networkIds[i]; float power = networkServes[num3]; ref OptimizedOilMiner reference = ref optimizedMiners[i]; reference.InternalUpdate(planet, veinPool, power, miningRate, miningSpeedScale, productRegister, optimizedCargoPaths); UpdatePower(oilMinerPowerConsumerIndexes, powerConsumerTypes, thisSubFactoryNetworkPowerConsumption, i, num3, ref reference); } } public void UpdatePower(ReadonlyArray oilMinerPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption) { ReadonlyArray networkIds = _networkIds; OptimizedOilMiner[] optimizedMiners = _optimizedMiners; for (int i = 0; i < optimizedMiners.Length; i++) { short networkIndex = networkIds[i]; UpdatePower(oilMinerPowerConsumerIndexes, powerConsumerTypes, thisSubFactoryNetworkPowerConsumption, i, networkIndex, ref optimizedMiners[i]); } } private static void UpdatePower(ReadonlyArray oilMinerPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption, int minerIndex, short networkIndex, ref OptimizedOilMiner miner) { float num = (float)miner.productCount / 50f; num = ((num > 1f) ? 1f : num); float num2 = -2.45f * num + 2.47f; num2 = ((num2 > 1f) ? 1f : num2); miner.speedDamper = num2; int index = oilMinerPowerConsumerIndexes[minerIndex]; PowerConsumerType powerConsumerType = powerConsumerTypes[index]; thisSubFactoryNetworkPowerConsumption[networkIndex] += GetPowerConsumption(powerConsumerType, ref miner); } public PrototypePowerConsumptions UpdatePowerConsumptionPerPrototype(ReadonlyArray oilMinerPowerConsumerIndexes, ReadonlyArray powerConsumerTypes) { PrototypePowerConsumptionExecutor prototypePowerConsumptionExecutor = _prototypePowerConsumptionExecutor; prototypePowerConsumptionExecutor.Clear(); OptimizedOilMiner[] optimizedMiners = _optimizedMiners; ReadonlyArray prototypeIdIndexes = prototypePowerConsumptionExecutor.PrototypeIdIndexes; long[] prototypeIdPowerConsumption = prototypePowerConsumptionExecutor.PrototypeIdPowerConsumption; for (int i = 0; i < optimizedMiners.Length; i++) { UpdatePowerConsumptionPerPrototype(oilMinerPowerConsumerIndexes, powerConsumerTypes, prototypeIdIndexes, prototypeIdPowerConsumption, i, ref optimizedMiners[i]); } return prototypePowerConsumptionExecutor.GetPowerConsumption(); } private static void UpdatePowerConsumptionPerPrototype(ReadonlyArray oilMinerPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, ReadonlyArray prototypeIdIndexes, long[] prototypeIdPowerConsumption, int minerIndex, [In][RequiresLocation] ref OptimizedOilMiner miner) { int index = oilMinerPowerConsumerIndexes[minerIndex]; PowerConsumerType powerConsumerType = powerConsumerTypes[index]; prototypeIdPowerConsumption[prototypeIdIndexes[minerIndex]] += GetPowerConsumption(powerConsumerType, ref miner); } public void Save(PlanetFactory planet) { MinerComponent[] minerPool = planet.factorySystem.minerPool; OptimizedOilMiner[] optimizedMiners = _optimizedMiners; for (int i = 1; i < planet.factorySystem.minerCursor; i++) { if (_minerIdToOptimizedIndex.TryGetValue(i, out var value)) { optimizedMiners[value].Save(ref minerPool[i]); } } } public void Initialize(PlanetFactory planet, Graph subFactoryGraph, SubFactoryPowerSystemBuilder subFactoryPowerSystemBuilder, SubFactoryProductionRegisterBuilder subFactoryProductionRegisterBuilder, BeltExecutor beltExecutor, UniverseStaticDataBuilder universeStaticDataBuilder) { //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Invalid comparison between Unknown and I4 List list = new List(); List list2 = new List(); Dictionary dictionary = new Dictionary(); PrototypePowerConsumptionBuilder prototypePowerConsumptionBuilder = new PrototypePowerConsumptionBuilder(); foreach (int item in from x in subFactoryGraph.GetAllNodes() where x.EntityTypeIndex.EntityType == EntityType.Miner select x.EntityTypeIndex.Index into x orderby x select x) { ref MinerComponent reference = ref planet.factorySystem.minerPool[item]; if (reference.id != item || (int)reference.type != 3 || reference.veinCount == 0 || reference.insertTarget <= 0) { continue; } int beltId = planet.entityPool[reference.insertTarget].beltId; if (beltExecutor.TryGetOptimizedCargoPathIndex(planet, beltId, out var beltIndex)) { int pivotOnPath = ((BeltComponent)(ref planet.cargoTraffic.beltPool[beltId])).pivotOnPath; int productId = planet.veinPool[reference.veins[0]].productId; OptimizedItemId productId2 = default(OptimizedItemId); if (productId > 0) { productId2 = subFactoryProductionRegisterBuilder.AddProduct(productId); } int networkId = planet.powerSystem.consumerPool[reference.pcId].networkId; subFactoryPowerSystemBuilder.AddOilMiner(ref reference, networkId); dictionary.Add(item, list2.Count); list.Add(ConverterUtilities.ThrowIfNotWithinPositiveShortRange(networkId, "networkIndex")); list2.Add(new OptimizedOilMiner(beltIndex, pivotOnPath, productId2, ref reference)); prototypePowerConsumptionBuilder.AddPowerConsumer(ref planet.entityPool[reference.entityId]); } } _networkIds = universeStaticDataBuilder.DeduplicateArrayUnmanaged(list); _optimizedMiners = list2.ToArray(); _minerIdToOptimizedIndex = dictionary; _prototypePowerConsumptionExecutor = prototypePowerConsumptionBuilder.Build(universeStaticDataBuilder); } private static long GetPowerConsumption(PowerConsumerType powerConsumerType, [In][RequiresLocation] ref OptimizedOilMiner miner) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 EWorkState val = miner.DetermineState(); return powerConsumerType.GetRequiredEnergy(((int)val > 0) ? ((double)(miner.speedDamper * (float)miner.speed * (float)miner.speed) / 100000000.0) : 0.0); } } [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct OptimizedOilMiner { private readonly BeltIndex outputBeltIndex; private readonly int outputBeltOffset; public readonly int speed; private readonly int period; private readonly int insertTarget; private readonly int veinIndex; private readonly OptimizedItemId productId; private int time; public float speedDamper; public int productCount; private double costFrac; public OptimizedOilMiner(BeltIndex outputBeltIndex, int outputBeltOffset, OptimizedItemId productId, [In][RequiresLocation] ref MinerComponent miner) { this.outputBeltIndex = outputBeltIndex; this.outputBeltOffset = outputBeltOffset; speed = miner.speed; speedDamper = miner.speedDamper; period = miner.period; insertTarget = miner.insertTarget; veinIndex = miner.veins[0]; time = miner.time; this.productId = productId; productCount = miner.productCount; costFrac = miner.costFrac; } public void InternalUpdate(PlanetFactory factory, VeinData[] veinPool, float power, float miningRate, float miningSpeed, int[] productRegister, OptimizedCargoPath[] optimizedCargoPaths) { //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Expected I4, but got Unknown if (power < 0.1f) { return; } ref VeinData reference = ref veinPool[veinIndex]; if (time < period) { float num = (float)reference.amount * VeinData.oilSpeedMultiplier; time += (int)(power * speedDamper * (float)speed * miningSpeed * num + 0.5f); } if (time >= period && productCount < 50) { int num2 = time / period; if (miningRate > 0f && reference.amount > 2500) { costFrac += (double)miningRate * (double)num2; int num3 = (int)costFrac; costFrac -= num3; int num4 = reference.amount - 2500; if (num3 > 0) { if (num3 > num4) { num3 = num4; } reference.amount -= num3; factory.veinGroups[reference.groupIndex].amount -= num3; if (reference.amount <= 2500) { lock (veinPool) { factory.NotifyVeinExhausted((int)reference.type, (int)reference.groupIndex, reference.pos); } } } } productCount += num2; productRegister[productId.OptimizedItemIndex] += num2; time -= period * num2; } if (productCount > 0 && insertTarget > 0 && productId.ItemIndex > 0) { int num5 = (int)(36000000.0 / (double)period * (double)miningSpeed * (double)((float)veinPool[veinIndex].amount * VeinData.oilSpeedMultiplier) - 0.009999999776482582) / 1800 + 1; num5 = ((num5 >= 4) ? 4 : ((num5 < 1) ? 1 : num5)); int num6 = ((productCount < num5) ? productCount : num5); int num7 = (outputBeltIndex.GetBelt(optimizedCargoPaths).TryInsertItem(outputBeltOffset, productId.ItemIndex, (byte)num6, 0) ? ((byte)num6) : 0); productCount -= num7; } } public readonly EWorkState DetermineState() { if (time >= period) { return (EWorkState)(-2); } return (EWorkState)1; } public readonly void Save(ref MinerComponent miner) { miner.time = time; miner.speedDamper = speedDamper; miner.productCount = productCount; miner.costFrac = costFrac; } } [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct OptimizedVeinMiner : IMiner where T : struct, IMinerOutput { public readonly T output; public readonly int speed; private readonly int period; private readonly int[] veins; private readonly OptimizedItemId[] veinProducts; private int time; private int veinCount; private int currentVeinIndex; private int minimumVeinAmount; public OptimizedItemId productId; private double costFrac; public int ProductCount { get; set; } public float SpeedDamper { get; set; } public OptimizedVeinMiner(T output, OptimizedItemId[] veinProducts, OptimizedItemId productId, [In][RequiresLocation] ref MinerComponent miner) { this.output = output; this.veinProducts = veinProducts; speed = miner.speed; SpeedDamper = miner.speedDamper; period = miner.period; veins = miner.veins; time = miner.time; veinCount = miner.veinCount; currentVeinIndex = miner.currentVeinIndex; minimumVeinAmount = miner.minimumVeinAmount; this.productId = productId; ProductCount = miner.productCount; costFrac = miner.costFrac; } public uint InternalUpdate(PlanetFactory factory, VeinData[] veinPool, float power, float miningRate, float miningSpeed, int[] productRegister, ref MiningFlags miningFlags, OptimizedCargoPath[] optimizedCargoPaths) { //IL_0350: Unknown result type (might be due to invalid IL or missing references) //IL_0363: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Expected I4, but got Unknown //IL_02bf: Unknown result type (might be due to invalid IL or missing references) //IL_02c4: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Unknown result type (might be due to invalid IL or missing references) if (power < 0.1f) { return 0u; } uint result = 0u; if (veinCount > 0) { if (time <= period) { time += (int)(power * SpeedDamper * (float)speed * miningSpeed * (float)veinCount); if (time < -2000000000) { time = int.MaxValue; } else if (time < 0) { time = 0; } result = 1u; } if (time >= period && veinCount > 0) { int num = veins[currentVeinIndex]; OptimizedItemId optimizedItemId = veinProducts[currentVeinIndex]; Assert.Positive(num); if (veinPool[num].id == 0) { RemoveVeinFromArray(currentVeinIndex); GetMinimumVeinAmount(veinPool); if (veinCount > 1) { currentVeinIndex %= veinCount; } else { currentVeinIndex = 0; } time += (int)(power * SpeedDamper * (float)speed * miningSpeed * (float)veinCount); return 0u; } if (ProductCount < 50 && (productId.ItemIndex == 0 || productId.ItemIndex == veinPool[num].productId)) { productId = optimizedItemId; int num2 = time / period; int num3 = 0; if (veinPool[num].amount > 0) { if (miningRate > 0f) { double num4 = (double)miningRate * (double)num2; costFrac += num4; int num5; if (costFrac < (double)veinPool[num].amount) { num3 = num2; num5 = (int)costFrac; costFrac -= num5; } else { num5 = veinPool[num].amount; double num6 = costFrac - num4; double num7 = ((double)num5 - num6) / num4; double num8 = (double)num2 * num7; num3 = (int)(Math.Ceiling(num8) + 0.01); costFrac = (double)miningRate * ((double)num3 - num8); } if (num5 > 0) { int groupIndex = veinPool[num].groupIndex; veinPool[num].amount -= num5; if (veinPool[num].amount < minimumVeinAmount) { minimumVeinAmount = veinPool[num].amount; } factory.veinGroups[groupIndex].amount -= num5; if (veinPool[num].amount <= 0) { int num9 = (int)veinPool[num].type; Vector3 pos = veinPool[num].pos; lock (veinPool) { factory.RemoveVeinWithComponents(num); factory.RecalculateVeinGroup(groupIndex); factory.NotifyVeinExhausted(num9, groupIndex, pos); } } else { currentVeinIndex++; } } } else { num3 = num2; costFrac = 0.0; } ProductCount += num3; productRegister[productId.OptimizedItemIndex] += num3; miningFlags.AddMiningFlagUnsafe(veinPool[num].type); miningFlags.AddVeinMiningFlagUnsafe(veinPool[num].type); } else { RemoveVeinFromArray(currentVeinIndex); GetMinimumVeinAmount(veinPool); } time -= period * num3; if (veinCount > 1) { currentVeinIndex %= veinCount; } else { currentVeinIndex = 0; } } } } if (ProductCount > 0 && productId.ItemIndex > 0) { int num10 = (int)(36000000.0 / (double)period * (double)miningSpeed * (double)veinCount - 0.009999999776482582) / 1800 + 1; num10 = ((num10 >= 4) ? 4 : ((num10 < 1) ? 1 : num10)); int num11 = ((ProductCount < num10) ? ProductCount : num10); int num12 = output.InsertInto(productId.ItemIndex, (byte)num11, optimizedCargoPaths); ProductCount -= num12; if (ProductCount == 0) { productId = default(OptimizedItemId); } } return result; } public readonly void Save(ref MinerComponent miner) { miner.time = time; miner.veinCount = veinCount; miner.currentVeinIndex = currentVeinIndex; miner.minimumVeinAmount = minimumVeinAmount; miner.productId = productId.ItemIndex; miner.costFrac = costFrac; miner.productCount = ProductCount; miner.speedDamper = SpeedDamper; } public readonly EWorkState DetermineState() { if (time >= period) { return (EWorkState)(-2); } return (EWorkState)1; } private void RemoveVeinFromArray(int index) { if (veins != null) { veins[index] = 0; veinProducts[index] = default(OptimizedItemId); veinCount--; if (veinCount - index > 0) { Array.Copy(veins, index + 1, veins, index, veinCount - index); Array.Copy(veinProducts, index + 1, veinProducts, index, veinCount - index); } if (veins.Length - veinCount > 0) { Array.Clear(veins, veinCount, veins.Length - veinCount); Array.Clear(veinProducts, veinCount, veinProducts.Length - veinCount); } } } private void GetMinimumVeinAmount(VeinData[] veinPool) { minimumVeinAmount = int.MaxValue; if (veinCount > 0) { for (int i = 0; i < veinCount; i++) { int num = veins[i]; if (num > 0 && veinPool[num].id == num && veinPool[num].amount > 0 && veinPool[num].amount < minimumVeinAmount) { minimumVeinAmount = veinPool[num].amount; } } } else { minimumVeinAmount = 0; } } } [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct OptimizedWaterMiner { private readonly BeltIndex outputBeltIndex; private readonly int outputBeltOffset; private readonly int period; private readonly OptimizedItemId productId; public readonly int speed; private int time; public float speedDamper; public int productCount; public OptimizedWaterMiner(BeltIndex outputBeltIndex, int outputBeltOffset, OptimizedItemId productId, [In][RequiresLocation] ref MinerComponent miner) { this.outputBeltIndex = outputBeltIndex; this.outputBeltOffset = outputBeltOffset; speed = miner.speed; speedDamper = miner.speedDamper; period = miner.period; time = miner.time; this.productId = productId; productCount = miner.productCount; } public uint InternalUpdate(float power, float miningSpeed, int[] productRegister, OptimizedCargoPath[] optimizedCargoPaths) { if (power < 0.1f) { return 0u; } uint result = 0u; if (time < period) { time += (int)(power * speedDamper * (float)speed * miningSpeed); result = 1u; } if (time >= period) { int num = time / period; if (productCount < 50) { productCount += num; productRegister[productId.OptimizedItemIndex] += num; time -= period * num; } } if (productCount > 0) { int num2 = (int)(36000000.0 / (double)period * (double)miningSpeed - 0.009999999776482582) / 1800 + 1; num2 = ((num2 >= 4) ? 4 : ((num2 < 1) ? 1 : num2)); int num3 = ((productCount < num2) ? productCount : num2); int num4 = (outputBeltIndex.GetBelt(optimizedCargoPaths).TryInsertItem(outputBeltOffset, productId.ItemIndex, (byte)num3, 0) ? ((byte)num3) : 0); productCount -= num4; } return result; } public readonly EWorkState DetermineState() { if (time >= period) { return (EWorkState)(-2); } return (EWorkState)1; } public readonly void Save(ref MinerComponent miner) { miner.time = time; miner.speedDamper = speedDamper; miner.productCount = productCount; } } internal readonly struct StationMinerOutput : IMinerOutput { private readonly StationComponent _outputStation; public StationMinerOutput(StationComponent outputStation) { _outputStation = outputStation; } public int InsertInto(int itemId, byte itemCount, OptimizedCargoPath[] optimizedCargoPaths) { return 0; } public void PrePowerUpdate(ref T miner) where T : IMiner { StationStore[] storage = _outputStation.storage; int num = storage[0].count; if (storage[0].localOrder < -4000) { num += storage[0].localOrder + 4000; } int max = storage[0].max; max = ((max < 3000) ? 3000 : max); float num2 = (float)num / (float)max; num2 = ((num2 > 1f) ? 1f : num2); float num3 = -2.45f * num2 + 2.47f; num3 = ((num3 > 1f) ? 1f : num3); miner.SpeedDamper = num3; } public bool TryGetMinerOutput(PlanetFactory planet, BeltExecutor beltExecutor, [In][RequiresLocation] ref MinerComponent miner, out StationMinerOutput minerOutput) { int stationId = planet.entityPool[miner.entityId].stationId; if (stationId <= 0) { minerOutput = default(StationMinerOutput); return false; } if (miner.insertTarget > 0) { throw new InvalidOperationException("Current code does not use insertTarget to move items into the station. Instead the station pulls from the miner.\r\nThe miner knows the station id because the miners entity also contains the station id.\r\nIf insertTarget suddenly start containing something for station miners then the logic has changed and the code\r\nneed to be changed."); } StationComponent outputStation = planet.transport.stationPool[stationId]; minerOutput = new StationMinerOutput(outputStation); return true; } bool IMinerOutput.TryGetMinerOutput(PlanetFactory planet, BeltExecutor beltExecutor, [In][RequiresLocation] ref MinerComponent miner, out StationMinerOutput minerOutput) { return TryGetMinerOutput(planet, beltExecutor, ref miner, out minerOutput); } } internal sealed class VeinMinerExecutor where TMinerOutput : struct, IMinerOutput { private ReadonlyArray _networkIds; public OptimizedVeinMiner[] _optimizedMiners; public Dictionary _minerIdToOptimizedIndex; private PrototypePowerConsumptionExecutor _prototypePowerConsumptionExecutor; public int Count => _optimizedMiners.Length; public int GetOptimizedMinerIndexFromMinerId(int minerId) { return _minerIdToOptimizedIndex[minerId]; } public void GameTick(PlanetFactory planet, ReadonlyArray veinMinerPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption, int[] productRegister, ref MiningFlags miningFlags, OptimizedCargoPath[] optimizedCargoPaths) { GameHistoryData history = GameMain.history; float[] networkServes = planet.powerSystem.networkServes; VeinData[] veinPool = planet.veinPool; ReadonlyArray networkIds = _networkIds; OptimizedVeinMiner[] optimizedMiners = _optimizedMiners; float resourceMultiplier = planet.gameData.gameDesc.resourceMultiplier; float miningRate = history.miningCostRate; float miningSpeedScale = history.miningSpeedScale; if (resourceMultiplier > 99.5f) { miningRate = 0f; } for (int i = 0; i < optimizedMiners.Length; i++) { short num = networkIds[i]; float power = networkServes[num]; ref OptimizedVeinMiner reference = ref optimizedMiners[i]; reference.InternalUpdate(planet, veinPool, power, miningRate, miningSpeedScale, productRegister, ref miningFlags, optimizedCargoPaths); UpdatePower(veinMinerPowerConsumerIndexes, powerConsumerTypes, thisSubFactoryNetworkPowerConsumption, i, num, ref reference); } } public void UpdatePower(ReadonlyArray veinMinerPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption) { ReadonlyArray networkIds = _networkIds; OptimizedVeinMiner[] optimizedMiners = _optimizedMiners; for (int i = 0; i < optimizedMiners.Length; i++) { short networkIndex = networkIds[i]; UpdatePower(veinMinerPowerConsumerIndexes, powerConsumerTypes, thisSubFactoryNetworkPowerConsumption, i, networkIndex, ref optimizedMiners[i]); } } private static void UpdatePower(ReadonlyArray veinMinerPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption, int minerIndex, short networkIndex, ref OptimizedVeinMiner miner) { miner.output.PrePowerUpdate(ref miner); int index = veinMinerPowerConsumerIndexes[minerIndex]; PowerConsumerType powerConsumerType = powerConsumerTypes[index]; thisSubFactoryNetworkPowerConsumption[networkIndex] += GetPowerConsumption(powerConsumerType, ref miner); } public PrototypePowerConsumptions UpdatePowerConsumptionPerPrototype(ReadonlyArray veinMinerPowerConsumerIndexes, ReadonlyArray powerConsumerTypes) { PrototypePowerConsumptionExecutor prototypePowerConsumptionExecutor = _prototypePowerConsumptionExecutor; prototypePowerConsumptionExecutor.Clear(); OptimizedVeinMiner[] optimizedMiners = _optimizedMiners; ReadonlyArray prototypeIdIndexes = prototypePowerConsumptionExecutor.PrototypeIdIndexes; long[] prototypeIdPowerConsumption = prototypePowerConsumptionExecutor.PrototypeIdPowerConsumption; for (int i = 0; i < optimizedMiners.Length; i++) { UpdatePowerConsumptionPerPrototype(veinMinerPowerConsumerIndexes, powerConsumerTypes, prototypeIdIndexes, prototypeIdPowerConsumption, i, ref optimizedMiners[i]); } return prototypePowerConsumptionExecutor.GetPowerConsumption(); } private static void UpdatePowerConsumptionPerPrototype(ReadonlyArray veinMinerPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, ReadonlyArray prototypeIdIndexes, long[] prototypeIdPowerConsumption, int minerIndex, [In][RequiresLocation] ref OptimizedVeinMiner miner) { int index = veinMinerPowerConsumerIndexes[minerIndex]; PowerConsumerType powerConsumerType = powerConsumerTypes[index]; prototypeIdPowerConsumption[prototypeIdIndexes[minerIndex]] += GetPowerConsumption(powerConsumerType, ref miner); } public void Save(PlanetFactory planet) { MinerComponent[] minerPool = planet.factorySystem.minerPool; OptimizedVeinMiner[] optimizedMiners = _optimizedMiners; for (int i = 1; i < planet.factorySystem.minerCursor; i++) { if (_minerIdToOptimizedIndex.TryGetValue(i, out var value)) { optimizedMiners[value].Save(ref minerPool[i]); } } } public void Initialize(PlanetFactory planet, Graph subFactoryGraph, OptimizedPowerSystemVeinMinerBuilder optimizedPowerSystemVeinMinerBuilder, SubFactoryProductionRegisterBuilder subFactoryProductionRegisterBuilder, BeltExecutor beltExecutor, UniverseStaticDataBuilder universeStaticDataBuilder) { //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Invalid comparison between Unknown and I4 List list = new List(); List> list2 = new List>(); Dictionary dictionary = new Dictionary(); TMinerOutput val = new TMinerOutput(); PrototypePowerConsumptionBuilder prototypePowerConsumptionBuilder = new PrototypePowerConsumptionBuilder(); foreach (int item in from x in subFactoryGraph.GetAllNodes() where x.EntityTypeIndex.EntityType == EntityType.Miner select x.EntityTypeIndex.Index into x orderby x select x) { ref MinerComponent reference = ref planet.factorySystem.minerPool[item]; if (reference.id == item && (int)reference.type == 2 && val.TryGetMinerOutput(planet, beltExecutor, ref reference, out var minerOutput)) { OptimizedItemId[] array = new OptimizedItemId[reference.veinCount]; for (int i = 0; i < array.Length; i++) { array[i] = subFactoryProductionRegisterBuilder.AddProduct(planet.veinPool[reference.veins[i]].productId); } OptimizedItemId productId = default(OptimizedItemId); if (reference.productId > 0) { productId = subFactoryProductionRegisterBuilder.AddProduct(reference.productId); } int networkId = planet.powerSystem.consumerPool[reference.pcId].networkId; optimizedPowerSystemVeinMinerBuilder.AddMiner(ref reference, networkId); dictionary.Add(item, list2.Count); list.Add(ConverterUtilities.ThrowIfNotWithinPositiveShortRange(networkId, "networkIndex")); list2.Add(new OptimizedVeinMiner(minerOutput, array, productId, ref reference)); prototypePowerConsumptionBuilder.AddPowerConsumer(ref planet.entityPool[reference.entityId]); } } _networkIds = universeStaticDataBuilder.DeduplicateArrayUnmanaged(list); _optimizedMiners = list2.ToArray(); _minerIdToOptimizedIndex = dictionary; _prototypePowerConsumptionExecutor = prototypePowerConsumptionBuilder.Build(universeStaticDataBuilder); } private static long GetPowerConsumption(PowerConsumerType powerConsumerType, [In][RequiresLocation] ref OptimizedVeinMiner miner) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 EWorkState val = miner.DetermineState(); return powerConsumerType.GetRequiredEnergy(((int)val > 0) ? ((double)(miner.SpeedDamper * (float)miner.speed * (float)miner.speed) / 100000000.0) : 0.0); } } internal sealed class WaterMinerExecutor { private ReadonlyArray _networkIds; private OptimizedWaterMiner[] _optimizedMiners; public Dictionary _minerIdToOptimizedIndex; private PrototypePowerConsumptionExecutor _prototypePowerConsumptionExecutor; public int Count => _optimizedMiners.Length; public void GameTick(PlanetFactory planet, ReadonlyArray waterMinerPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption, int[] productRegister, OptimizedCargoPath[] optimizedCargoPaths) { GameHistoryData history = GameMain.history; float[] networkServes = planet.powerSystem.networkServes; float miningSpeedScale = history.miningSpeedScale; ReadonlyArray networkIds = _networkIds; OptimizedWaterMiner[] optimizedMiners = _optimizedMiners; for (int i = 0; i < optimizedMiners.Length; i++) { short num = networkIds[i]; float power = networkServes[num]; ref OptimizedWaterMiner reference = ref optimizedMiners[i]; reference.InternalUpdate(power, miningSpeedScale, productRegister, optimizedCargoPaths); UpdatePower(waterMinerPowerConsumerIndexes, powerConsumerTypes, thisSubFactoryNetworkPowerConsumption, i, num, ref reference); } } public void UpdatePower(ReadonlyArray waterMinerPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption) { ReadonlyArray networkIds = _networkIds; OptimizedWaterMiner[] optimizedMiners = _optimizedMiners; for (int i = 0; i < optimizedMiners.Length; i++) { short networkIndex = networkIds[i]; UpdatePower(waterMinerPowerConsumerIndexes, powerConsumerTypes, thisSubFactoryNetworkPowerConsumption, i, networkIndex, ref optimizedMiners[i]); } } private static void UpdatePower(ReadonlyArray waterMinerPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption, int minerIndex, short networkIndex, ref OptimizedWaterMiner miner) { float num = (float)miner.productCount / 50f; num = ((num > 1f) ? 1f : num); float num2 = -2.45f * num + 2.47f; num2 = ((num2 > 1f) ? 1f : num2); miner.speedDamper = num2; int index = waterMinerPowerConsumerIndexes[minerIndex]; PowerConsumerType powerConsumerType = powerConsumerTypes[index]; thisSubFactoryNetworkPowerConsumption[networkIndex] += GetPowerConsumption(powerConsumerType, ref miner); } public PrototypePowerConsumptions UpdatePowerConsumptionPerPrototype(ReadonlyArray waterMinerPowerConsumerIndexes, ReadonlyArray powerConsumerTypes) { PrototypePowerConsumptionExecutor prototypePowerConsumptionExecutor = _prototypePowerConsumptionExecutor; prototypePowerConsumptionExecutor.Clear(); OptimizedWaterMiner[] optimizedMiners = _optimizedMiners; ReadonlyArray prototypeIdIndexes = prototypePowerConsumptionExecutor.PrototypeIdIndexes; long[] prototypeIdPowerConsumption = prototypePowerConsumptionExecutor.PrototypeIdPowerConsumption; for (int i = 0; i < optimizedMiners.Length; i++) { UpdatePowerConsumptionPerPrototype(waterMinerPowerConsumerIndexes, powerConsumerTypes, prototypeIdIndexes, prototypeIdPowerConsumption, i, ref optimizedMiners[i]); } return prototypePowerConsumptionExecutor.GetPowerConsumption(); } private static void UpdatePowerConsumptionPerPrototype(ReadonlyArray waterMinerPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, ReadonlyArray prototypeIdIndexes, long[] prototypeIdPowerConsumption, int minerIndex, [In][RequiresLocation] ref OptimizedWaterMiner miner) { int index = waterMinerPowerConsumerIndexes[minerIndex]; PowerConsumerType powerConsumerType = powerConsumerTypes[index]; prototypeIdPowerConsumption[prototypeIdIndexes[minerIndex]] += GetPowerConsumption(powerConsumerType, ref miner); } public void Save(PlanetFactory planet) { MinerComponent[] minerPool = planet.factorySystem.minerPool; OptimizedWaterMiner[] optimizedMiners = _optimizedMiners; for (int i = 1; i < planet.factorySystem.minerCursor; i++) { if (_minerIdToOptimizedIndex.TryGetValue(i, out var value)) { optimizedMiners[value].Save(ref minerPool[i]); } } } public void Initialize(PlanetFactory planet, Graph subFactoryGraph, SubFactoryPowerSystemBuilder subFactoryPowerSystemBuilder, SubFactoryProductionRegisterBuilder subFactoryProductionRegisterBuilder, BeltExecutor beltExecutor, UniverseStaticDataBuilder universeStaticDataBuilder) { //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Invalid comparison between Unknown and I4 List list = new List(); List list2 = new List(); Dictionary dictionary = new Dictionary(); PrototypePowerConsumptionBuilder prototypePowerConsumptionBuilder = new PrototypePowerConsumptionBuilder(); foreach (int item in from x in subFactoryGraph.GetAllNodes() where x.EntityTypeIndex.EntityType == EntityType.Miner select x.EntityTypeIndex.Index into x orderby x select x) { ref MinerComponent reference = ref planet.factorySystem.minerPool[item]; if (reference.id == item && (int)reference.type == 1 && planet.planet.waterItemId > 0 && reference.insertTarget > 0) { int beltId = planet.entityPool[reference.insertTarget].beltId; if (beltExecutor.TryGetOptimizedCargoPathIndex(planet, beltId, out var beltIndex)) { int pivotOnPath = ((BeltComponent)(ref planet.cargoTraffic.beltPool[beltId])).pivotOnPath; OptimizedItemId productId = subFactoryProductionRegisterBuilder.AddProduct(planet.planet.waterItemId); int networkId = planet.powerSystem.consumerPool[reference.pcId].networkId; subFactoryPowerSystemBuilder.AddWaterMiner(ref reference, networkId); dictionary.Add(item, list2.Count); list.Add(ConverterUtilities.ThrowIfNotWithinPositiveShortRange(networkId, "networkIndex")); list2.Add(new OptimizedWaterMiner(beltIndex, pivotOnPath, productId, ref reference)); prototypePowerConsumptionBuilder.AddPowerConsumer(ref planet.entityPool[reference.entityId]); } } } _networkIds = universeStaticDataBuilder.DeduplicateArrayUnmanaged(list); _optimizedMiners = list2.ToArray(); _minerIdToOptimizedIndex = dictionary; _prototypePowerConsumptionExecutor = prototypePowerConsumptionBuilder.Build(universeStaticDataBuilder); } private static long GetPowerConsumption(PowerConsumerType powerConsumerType, [In][RequiresLocation] ref OptimizedWaterMiner miner) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 EWorkState val = miner.DetermineState(); return powerConsumerType.GetRequiredEnergy(((int)val > 0) ? ((double)(miner.speedDamper * (float)miner.speed * (float)miner.speed) / 100000000.0) : 0.0); } } } namespace Weaver.Optimizations.Labs { internal struct LabPowerFields { public bool replicating; public int extraPowerRatio; public LabPowerFields([In][RequiresLocation] ref LabComponent labComponent) { replicating = labComponent.replicating; extraPowerRatio = labComponent.extraPowerRatio; } } [Flags] internal enum LabState : byte { Active = 0, Inactive = 4, InactiveOutputFull = 5, InactiveInputMissing = 6 } internal record struct ResearchedTech(int ResearchTechId, int PreviousTechLevel, TechState State, TechProto Proto) { [CompilerGenerated] private readonly bool PrintMembers(StringBuilder builder) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) builder.Append("ResearchTechId = "); builder.Append(ResearchTechId.ToString()); builder.Append(", PreviousTechLevel = "); builder.Append(PreviousTechLevel.ToString()); builder.Append(", State = "); TechState state = State; builder.Append(((object)(TechState)(ref state)).ToString()); builder.Append(", Proto = "); builder.Append(Proto); return true; } } internal sealed class StarClusterResearchManager { private readonly Queue _tickResearchedTech = new Queue(); public void AddResearchedTech(int researchTechId, int previousTechLevel, TechState state, TechProto proto) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) lock (_tickResearchedTech) { _tickResearchedTech.Enqueue(new ResearchedTech(researchTechId, previousTechLevel, state, proto)); } } public void UIThreadUnlockResearchedTechnologies(GameHistoryData history) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) bool flag = false; try { foreach (ResearchedTech item in _tickResearchedTech) { if (item.State.unlocked) { flag = true; history.techStates[item.ResearchTechId] = item.State; for (int i = 0; i < item.Proto.UnlockRecipes.Length; i++) { history.UnlockRecipe(item.Proto.UnlockRecipes[i]); } for (int j = 0; j < item.Proto.UnlockFunctions.Length; j++) { history.UnlockTechFunction(item.Proto.UnlockFunctions[j], item.Proto.UnlockValues[j], item.PreviousTechLevel); } for (int k = 0; k < item.Proto.AddItems.Length; k++) { history.GainTechAwards(item.Proto.AddItems[k], item.Proto.AddItemCounts[k]); } history.NotifyTechUnlock(item.ResearchTechId, item.PreviousTechLevel, false); } if (item.State.curLevel > item.PreviousTechLevel) { flag = true; history.techStates[item.ResearchTechId] = item.State; for (int l = 0; l < item.Proto.UnlockFunctions.Length; l++) { history.UnlockTechFunction(item.Proto.UnlockFunctions[l], item.Proto.UnlockValues[l], item.PreviousTechLevel); } for (int m = 0; m < item.Proto.AddItems.Length; m++) { history.GainTechAwards(item.Proto.AddItems[m], item.Proto.AddItemCounts[m]); } history.NotifyTechUnlock(item.ResearchTechId, item.PreviousTechLevel, false); } } } finally { _tickResearchedTech.Clear(); } if (flag) { OptimizedStarCluster.ReOptimizeAllPlanets(); } } } } namespace Weaver.Optimizations.Labs.Researching { [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct OptimizedResearchingLab { public const int NO_NEXT_LAB = -1; public readonly int nextLabIndex; public bool incUsed; public int hashBytes; public int extraHashBytes; public OptimizedResearchingLab(int? nextLabIndex, [In][RequiresLocation] ref LabComponent lab) { this.nextLabIndex = (nextLabIndex.HasValue ? nextLabIndex.Value : (-1)); incUsed = lab.incUsed; hashBytes = lab.hashBytes; extraHashBytes = lab.extraHashBytes; } public OptimizedResearchingLab(int nextLabIndex, [In][RequiresLocation] ref OptimizedResearchingLab lab) { this.nextLabIndex = nextLabIndex; incUsed = lab.incUsed; hashBytes = lab.hashBytes; extraHashBytes = lab.extraHashBytes; } public void SetFunction(int entityId, int techId, SignData[] signPool, ref LabPowerFields labPowerFields, GroupNeeds groupNeeds, ComponentNeeds[] componentsNeeds, int labIndex) { hashBytes = 0; extraHashBytes = 0; labPowerFields.extraPowerRatio = 0; incUsed = false; int objectNeedsIndex = groupNeeds.GetObjectNeedsIndex(labIndex); byte b = 0; for (int i = 0; i < LabComponent.matrixIds.Length; i++) { b |= (byte)(((LabComponent.matrixIds[i] > 0) ? 1u : 0u) << i); } componentsNeeds[objectNeedsIndex].Needs = b; signPool[entityId].iconId0 = (uint)techId; signPool[entityId].iconType = ((techId != 0) ? 3u : 0u); } public static void UpdateNeedsResearch(GroupNeeds groupNeeds, ComponentNeeds[] componentsNeeds, int[] matrixServed, int labIndex) { int objectNeedsIndex = groupNeeds.GetObjectNeedsIndex(labIndex); int num = groupNeeds.GroupNeedsSize * labIndex; byte b = 0; for (int i = 0; i < groupNeeds.GroupNeedsSize; i++) { b |= (byte)(((matrixServed[num + i] < 36000) ? 1u : 0u) << i); } componentsNeeds[objectNeedsIndex].Needs = b; } public LabState InternalUpdateResearch(float power, float research_speed, int techId, OptimizedItemId[] matrixIds, int[] consumeRegister, ref TechState ts, ref int techHashedThisFrame, ref long uMatrixPoint, ref long hashRegister, ref LabPowerFields labPowerFields, GroupNeeds groupNeeds, int[] matrixServed, int[] matrixIncServed, int labIndex) { if (power < 0.1f) { return LabState.Active; } int num = (int)(research_speed + 2f); int num2 = groupNeeds.GroupNeedsSize * labIndex; for (int i = 0; i < groupNeeds.GroupNeedsSize; i++) { if (LabComponent.matrixPoints[i] <= 0) { continue; } int num3 = matrixServed[num2 + i] / LabComponent.matrixPoints[i]; if (num3 < num) { num = num3; if (num == 0) { labPowerFields.replicating = false; return LabState.InactiveInputMissing; } } } labPowerFields.replicating = true; research_speed = ((research_speed < (float)num) ? research_speed : ((float)num)); int num4 = (int)(power * 10000f * research_speed + 0.5f); hashBytes += num4; long num5 = hashBytes / 10000; hashBytes -= (int)num5 * 10000; long num6 = ts.hashNeeded - ts.hashUploaded; num5 = ((num5 < num6) ? num5 : num6); num5 = ((num5 < num) ? num5 : num); int num7 = (int)num5; if (num7 > 0) { int groupNeedsSize = groupNeeds.GroupNeedsSize; int num8 = ((groupNeedsSize != 0) ? 10 : 0); for (int j = 0; j < groupNeedsSize; j++) { if (LabComponent.matrixPoints[j] > 0) { int num9 = matrixServed[num2 + j] / 3600; int num10 = split_inc_level(ref matrixServed[num2 + j], ref matrixIncServed[num2 + j], LabComponent.matrixPoints[j] * num7); num8 = ((num8 < num10) ? num8 : num10); int num11 = matrixServed[num2 + j] / 3600; if (matrixServed[num2 + j] <= 0 || matrixIncServed[num2 + j] < 0) { matrixIncServed[num2 + j] = 0; } int num12 = num9 - num11; if (num12 > 0 && !incUsed) { incUsed = num8 > 0; } consumeRegister[matrixIds[j].OptimizedItemIndex] += num12; } } if (num8 < 0) { num8 = 0; } int num13 = (int)(10000.0 * Cargo.incTableMilli[num8] * 10.0 + 0.1); labPowerFields.extraPowerRatio = Cargo.powerTable[num8]; extraHashBytes += (int)(power * (float)num13 * research_speed + 0.5f); long num14 = extraHashBytes / 100000; extraHashBytes -= (int)num14 * 100000; num14 = ((num14 < 0) ? 0 : num14); int num15 = (int)num14; ts.hashUploaded += num5 + num14; hashRegister += num5 + num14; uMatrixPoint += ts.uPointPerHash * num5; techHashedThisFrame += num7 + num15; if (ts.hashUploaded >= ts.hashNeeded) { TechProto val = ((ProtoSet)(object)LDB.techs).Select(techId); if (ts.curLevel >= ts.maxLevel) { ts.curLevel = ts.maxLevel; ts.hashUploaded = ts.hashNeeded; ts.unlocked = true; ts.unlockTick = GameMain.gameTick; } else { ts.curLevel++; ts.hashUploaded = 0L; ts.hashNeeded = val.GetHashNeeded(ts.curLevel); } } } else { labPowerFields.extraPowerRatio = 0; } return LabState.Active; } public readonly void UpdateOutputToNext(int labIndex, OptimizedResearchingLab[] labPool, LabState[] labStates, GroupNeeds groupNeeds, ComponentNeeds[] componentsNeeds, int[] matrixServed, int[] matrixIncServed) { if (nextLabIndex == -1) { return; } int num = groupNeeds.GroupNeedsSize * labIndex; int num2 = groupNeeds.GroupNeedsSize * nextLabIndex; bool flag = false; int objectNeedsIndex = groupNeeds.GetObjectNeedsIndex(nextLabIndex); ComponentNeeds componentNeeds = componentsNeeds[objectNeedsIndex]; for (int i = 0; i < groupNeeds.GroupNeedsSize; i++) { if (componentNeeds.GetNeeds(i) && matrixServed[num + i] >= 7200) { int num3 = (matrixServed[num + i] - 7200) / 3600 * 3600; if (num3 > 36000) { num3 = 36000; } int num4 = split_inc(ref matrixServed[num + i], ref matrixIncServed[num + i], num3); matrixIncServed[num2 + i] += num4; matrixServed[num2 + i] += num3; flag = true; } } if (flag) { labStates[labIndex] = LabState.Active; labStates[nextLabIndex] = LabState.Active; } } public readonly void Save(ref LabComponent lab, LabPowerFields labPowerFields, int researchTechId, GroupNeeds groupNeeds, ComponentNeeds[] componentsNeeds, short[] needsPatterns, int[] matrixServed, int[] matrixIncServed, int labIndex) { int objectNeedsIndex = groupNeeds.GetObjectNeedsIndex(labIndex); int num = groupNeeds.GroupNeedsSize * labIndex; ComponentNeeds componentNeeds = componentsNeeds[objectNeedsIndex]; for (int i = 0; i < groupNeeds.GroupNeedsSize; i++) { GroupNeeds.SetIfInRange(lab.matrixServed, matrixServed, i, num + i); GroupNeeds.SetNeedsIfInRange(lab.needs, componentNeeds, needsPatterns, i); GroupNeeds.SetIfInRange(lab.matrixIncServed, matrixIncServed, i, num + i); } lab.replicating = labPowerFields.replicating; lab.incUsed = incUsed; lab.hashBytes = hashBytes; lab.extraHashBytes = extraHashBytes; lab.extraPowerRatio = labPowerFields.extraPowerRatio; lab.techId = researchTechId; } private static int split_inc(ref int n, ref int m, int p) { int num = m / n; int num2 = m - num * n; n -= p; num2 -= n; num = ((num2 > 0) ? (num * p + num2) : (num * p)); m -= num; return num; } private static int split_inc_level(ref int n, ref int m, int p) { int num = m / n; int num2 = m - num * n; n -= p; num2 -= n; m -= ((num2 > 0) ? (num * p + num2) : (num * p)); return num; } } internal sealed class ResearchingLabExecutor { private readonly StarClusterResearchManager _starClusterResearchManager; private OptimizedItemId[]? _matrixIds; private ReadonlyArray _labNetworkIds; public LabState[] _labStates; public OptimizedResearchingLab[] _optimizedLabs; public LabPowerFields[] _labsPowerFields; public ReadonlyArray _entityIds; public Dictionary _labIdToOptimizedLabIndex; public HashSet _unOptimizedLabIds; private PrototypePowerConsumptionExecutor _prototypePowerConsumptionExecutor; public int[] _matrixServed; public int[] _matrixIncServed; public int Count => _optimizedLabs.Length; public ResearchingLabExecutor(StarClusterResearchManager starClusterResearchManager) { _starClusterResearchManager = starClusterResearchManager; } public void GameTickLabResearchMode(PlanetFactory planet, ReadonlyArray researchingLabPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption, int[] consumeRegister, SubFactoryNeeds subFactoryNeeds) { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_034d: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_02a2: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Unknown result type (might be due to invalid IL or missing references) //IL_02b7: Unknown result type (might be due to invalid IL or missing references) //IL_02cc: Unknown result type (might be due to invalid IL or missing references) //IL_02f5: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) lock (_starClusterResearchManager) { FactorySystem factorySystem = planet.factorySystem; GameHistoryData history = GameMain.history; GameStatData statistics = GameMain.statistics; FactoryProductionStat val = statistics.production.factoryStatPool[planet.index]; SignData[] entitySignPool = planet.entitySignPool; float[] networkServes = planet.powerSystem.networkServes; ReadonlyArray labNetworkIds = _labNetworkIds; LabState[] labStates = _labStates; OptimizedResearchingLab[] optimizedLabs = _optimizedLabs; LabPowerFields[] labsPowerFields = _labsPowerFields; int num = history.currentTech; TechProto val2 = ((ProtoSet)(object)LDB.techs).Select(num); TechState ts = default(TechState); bool flag = false; float research_speed = history.techSpeed; int techHashedThisFrame = statistics.techHashedThisFrame; long uMatrixPoint = history.universeMatrixPointUploaded; long hashRegister = val.hashRegister; if (num > 0 && val2 != null && val2.IsLabTech && GameMain.history.techStates.ContainsKey(num)) { ts = history.techStates[num]; flag = true; } if (!flag) { num = 0; } if ((flag && optimizedLabs.Length != 0) || factorySystem.researchTechId != num) { Array.Clear(LabComponent.matrixPoints, 0, LabComponent.matrixPoints.Length); if (val2 != null && val2.IsLabTech) { for (int i = 0; i < val2.Items.Length; i++) { int num2 = val2.Items[i] - LabComponent.matrixIds[0]; if (num2 >= 0 && num2 < LabComponent.matrixPoints.Length) { LabComponent.matrixPoints[num2] = val2.ItemPoints[i]; } } } } GroupNeeds groupNeeds = subFactoryNeeds.GetGroupNeeds(EntityType.ResearchingLab); ComponentNeeds[] componentsNeeds = subFactoryNeeds.ComponentsNeeds; if (factorySystem.researchTechId != num) { factorySystem.researchTechId = num; ReadonlyArray entityIds = _entityIds; for (int j = 0; j < optimizedLabs.Length; j++) { optimizedLabs[j].SetFunction(entityIds[j], factorySystem.researchTechId, entitySignPool, ref labsPowerFields[j], groupNeeds, componentsNeeds, j); } } if (_matrixIds == null) { return; } int[] matrixServed = _matrixServed; int[] matrixIncServed = _matrixIncServed; for (int k = 0; k < optimizedLabs.Length; k++) { short num3 = labNetworkIds[k]; ref LabState reference = ref labStates[k]; ref LabPowerFields reference2 = ref labsPowerFields[k]; if (reference != 0) { UpdatePower(researchingLabPowerConsumerIndexes, powerConsumerTypes, thisSubFactoryNetworkPowerConsumption, k, num3, reference2); continue; } ref OptimizedResearchingLab reference3 = ref optimizedLabs[k]; OptimizedResearchingLab.UpdateNeedsResearch(groupNeeds, componentsNeeds, matrixServed, k); if (flag) { int curLevel = ts.curLevel; float power = networkServes[num3]; reference = reference3.InternalUpdateResearch(power, research_speed, factorySystem.researchTechId, _matrixIds, consumeRegister, ref ts, ref techHashedThisFrame, ref uMatrixPoint, ref hashRegister, ref reference2, groupNeeds, matrixServed, matrixIncServed, k); if (ts.unlocked) { history.techStates[factorySystem.researchTechId] = ts; _starClusterResearchManager.AddResearchedTech(factorySystem.researchTechId, curLevel, ts, val2); history.DequeueTech(); flag = false; } if (ts.curLevel > curLevel) { history.techStates[factorySystem.researchTechId] = ts; _starClusterResearchManager.AddResearchedTech(factorySystem.researchTechId, curLevel, ts, val2); history.DequeueTech(); flag = false; } } UpdatePower(researchingLabPowerConsumerIndexes, powerConsumerTypes, thisSubFactoryNetworkPowerConsumption, k, num3, reference2); } history.techStates[factorySystem.researchTechId] = ts; statistics.techHashedThisFrame = techHashedThisFrame; history.universeMatrixPointUploaded = uMatrixPoint; val.hashRegister = hashRegister; } } public void GameTickLabOutputToNext(long time, SubFactoryNeeds subFactoryNeeds) { GroupNeeds groupNeeds = subFactoryNeeds.GetGroupNeeds(EntityType.ResearchingLab); ComponentNeeds[] componentsNeeds = subFactoryNeeds.ComponentsNeeds; int[] matrixServed = _matrixServed; int[] matrixIncServed = _matrixIncServed; LabState[] labStates = _labStates; OptimizedResearchingLab[] optimizedLabs = _optimizedLabs; int num = (int)(time & 3); for (int i = 0; i < optimizedLabs.Length; i++) { if ((i & 3) == num) { optimizedLabs[i].UpdateOutputToNext(i, optimizedLabs, labStates, groupNeeds, componentsNeeds, matrixServed, matrixIncServed); } } } public void UpdatePower(ReadonlyArray researchingLabPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption) { ReadonlyArray labNetworkIds = _labNetworkIds; LabPowerFields[] labsPowerFields = _labsPowerFields; for (int i = 0; i < labNetworkIds.Length; i++) { short networkIndex = labNetworkIds[i]; LabPowerFields labPowerFields = labsPowerFields[i]; UpdatePower(researchingLabPowerConsumerIndexes, powerConsumerTypes, thisSubFactoryNetworkPowerConsumption, i, networkIndex, labPowerFields); } } private static void UpdatePower(ReadonlyArray researchingLabPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption, int labIndex, short networkIndex, LabPowerFields labPowerFields) { int index = researchingLabPowerConsumerIndexes[labIndex]; PowerConsumerType powerConsumerType = powerConsumerTypes[index]; thisSubFactoryNetworkPowerConsumption[networkIndex] += GetPowerConsumption(powerConsumerType, labPowerFields); } public PrototypePowerConsumptions UpdatePowerConsumptionPerPrototype(ReadonlyArray researchingLabPowerConsumerIndexes, ReadonlyArray powerConsumerTypes) { PrototypePowerConsumptionExecutor prototypePowerConsumptionExecutor = _prototypePowerConsumptionExecutor; prototypePowerConsumptionExecutor.Clear(); LabPowerFields[] labsPowerFields = _labsPowerFields; ReadonlyArray prototypeIdIndexes = prototypePowerConsumptionExecutor.PrototypeIdIndexes; long[] prototypeIdPowerConsumption = prototypePowerConsumptionExecutor.PrototypeIdPowerConsumption; for (int i = 0; i < labsPowerFields.Length; i++) { LabPowerFields labPowerFields = labsPowerFields[i]; UpdatePowerConsumptionPerPrototype(researchingLabPowerConsumerIndexes, powerConsumerTypes, prototypeIdIndexes, prototypeIdPowerConsumption, i, labPowerFields); } return prototypePowerConsumptionExecutor.GetPowerConsumption(); } private static void UpdatePowerConsumptionPerPrototype(ReadonlyArray researchingLabPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, ReadonlyArray prototypeIdIndexes, long[] prototypeIdPowerConsumption, int labIndex, LabPowerFields labPowerFields) { int index = researchingLabPowerConsumerIndexes[labIndex]; PowerConsumerType powerConsumerType = powerConsumerTypes[index]; prototypeIdPowerConsumption[prototypeIdIndexes[labIndex]] += GetPowerConsumption(powerConsumerType, labPowerFields); } public void Save(PlanetFactory planet, SubFactoryNeeds subFactoryNeeds) { SignData[] entitySignPool = planet.entitySignPool; LabComponent[] labPool = planet.factorySystem.labPool; OptimizedResearchingLab[] optimizedLabs = _optimizedLabs; LabPowerFields[] labsPowerFields = _labsPowerFields; int researchTechId = planet.factorySystem.researchTechId; GroupNeeds groupNeeds = subFactoryNeeds.GetGroupNeeds(EntityType.ResearchingLab); ComponentNeeds[] componentsNeeds = subFactoryNeeds.ComponentsNeeds; short[] needsPatterns = subFactoryNeeds.NeedsPatterns; int[] matrixServed = _matrixServed; int[] matrixIncServed = _matrixIncServed; for (int i = 1; i < planet.factorySystem.labCursor; i++) { if (_labIdToOptimizedLabIndex.TryGetValue(i, out var value)) { ref LabComponent reference = ref labPool[i]; optimizedLabs[value].Save(ref reference, labsPowerFields[value], researchTechId, groupNeeds, componentsNeeds, needsPatterns, matrixServed, matrixIncServed, value); entitySignPool[reference.entityId].iconId0 = (uint)researchTechId; entitySignPool[reference.entityId].iconType = ((researchTechId != 0) ? 3u : 0u); } } } public void Initialize(PlanetFactory planet, Graph subFactoryGraph, SubFactoryPowerSystemBuilder subFactoryPowerSystemBuilder, SubFactoryProductionRegisterBuilder subFactoryProductionRegisterBuilder, SubFactoryNeedsBuilder subFactoryNeedsBuilder, UniverseStaticDataBuilder universeStaticDataBuilder) { List list = new List(); List list2 = new List(); List list3 = new List(); List list4 = new List(); List list5 = new List(); Dictionary dictionary = new Dictionary(); HashSet unOptimizedLabIds = new HashSet(); List list6 = new List(); List list7 = new List(); PrototypePowerConsumptionBuilder prototypePowerConsumptionBuilder = new PrototypePowerConsumptionBuilder(); GroupNeedsBuilder groupNeedsBuilder = subFactoryNeedsBuilder.CreateGroupNeedsBuilder(EntityType.ResearchingLab); foreach (int item in from x in subFactoryGraph.GetAllNodes() where x.EntityTypeIndex.EntityType == EntityType.ResearchingLab select x.EntityTypeIndex.Index into x orderby x select x) { ref LabComponent reference = ref planet.factorySystem.labPool[item]; int? nextLabIndex = null; if (planet.factorySystem.labPool[reference.nextLabId].id != 0 && planet.factorySystem.labPool[reference.nextLabId].id == reference.nextLabId) { nextLabIndex = reference.nextLabId; } dictionary.Add(item, list3.Count); list3.Add(new OptimizedResearchingLab(nextLabIndex, ref reference)); list4.Add(new LabPowerFields(ref reference)); int networkId = planet.powerSystem.consumerPool[reference.pcId].networkId; list.Add(ConverterUtilities.ThrowIfNotWithinPositiveShortRange(networkId, "networkIndex")); list2.Add(LabState.Active); list5.Add(reference.entityId); list6.Add(reference.matrixServed); list7.Add(reference.matrixIncServed); subFactoryPowerSystemBuilder.AddResearchingLab(ref reference, networkId); prototypePowerConsumptionBuilder.AddPowerConsumer(ref planet.entityPool[reference.entityId]); planet.entityNeeds[reference.entityId] = reference.needs; groupNeedsBuilder.AddNeeds(reference.needs, LabComponent.matrixIds); } for (int i = 0; i < list3.Count; i++) { OptimizedResearchingLab lab = list3[i]; if (lab.nextLabIndex != -1) { if (!dictionary.TryGetValue(lab.nextLabIndex, out var value)) { throw new InvalidOperationException("Next lab index was not part of the converted research labs."); } list3[i] = new OptimizedResearchingLab(value, ref lab); } } _matrixIds = null; if (list3.Count > 0) { _matrixIds = subFactoryProductionRegisterBuilder.AddConsume(LabComponent.matrixIds); } if (list3.Count > 0) { int num = LabComponent.matrixIds.Length; List list8 = new List(); List list9 = new List(); for (int j = 0; j < list3.Count; j++) { for (int k = 0; k < num; k++) { list8.Add(GetOrDefault(list6[j], k)); list9.Add(GetOrDefault(list7[j], k)); } } _matrixServed = list8.ToArray(); _matrixIncServed = list9.ToArray(); } _labNetworkIds = universeStaticDataBuilder.DeduplicateArrayUnmanaged(list); _labStates = list2.ToArray(); _optimizedLabs = list3.ToArray(); _labsPowerFields = list4.ToArray(); _entityIds = universeStaticDataBuilder.DeduplicateArrayUnmanaged(list5); _labIdToOptimizedLabIndex = dictionary; _unOptimizedLabIds = unOptimizedLabIds; _prototypePowerConsumptionExecutor = prototypePowerConsumptionBuilder.Build(universeStaticDataBuilder); groupNeedsBuilder.Complete(); } private static long GetPowerConsumption(PowerConsumerType powerConsumerType, LabPowerFields producingLabPowerFields) { return powerConsumerType.GetRequiredEnergy(producingLabPowerFields.replicating, 1000 + producingLabPowerFields.extraPowerRatio); } private static int GetOrDefault(int[] values, int index) { if (values.Length <= index) { return 0; } return values[index]; } } } namespace Weaver.Optimizations.Labs.Producing { internal struct ProducingLabTimingData { public int Time; public int ExtraTime; public int SpeedOverride; public int ExtraSpeed; public ProducingLabTimingData([In][RequiresLocation] ref LabComponent lab) { Time = lab.time; ExtraTime = lab.extraTime; SpeedOverride = lab.speedOverride; ExtraSpeed = lab.extraSpeed; } public bool UpdateTimings(float power, bool replicating, [In][RequiresLocation] ref ProducingLabRecipe producingLabRecipe) { if (replicating && Time < producingLabRecipe.TimeSpend && ExtraTime < producingLabRecipe.ExtraTimeSpend) { Time += (int)(power * (float)SpeedOverride); ExtraTime += (int)(power * (float)ExtraSpeed); return false; } return true; } } [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct OptimizedProducingLab { public const int NO_NEXT_LAB = -1; public readonly bool forceAccMode; public readonly int nextLabIndex; public bool incUsed; public OptimizedProducingLab(int? nextLabIndex, [In][RequiresLocation] ref LabComponent lab) { forceAccMode = lab.forceAccMode; this.nextLabIndex = (nextLabIndex.HasValue ? nextLabIndex.Value : (-1)); incUsed = lab.incUsed; } public OptimizedProducingLab(int nextLabIndex, [In][RequiresLocation] ref OptimizedProducingLab lab) { forceAccMode = lab.forceAccMode; this.nextLabIndex = nextLabIndex; incUsed = lab.incUsed; } public static void UpdateNeedsAssemble([In][RequiresLocation] ref ProducingLabRecipe producingLabRecipe, [In][RequiresLocation] ref ProducingLabTimingData producingLabTimingData, GroupNeeds groupNeeds, short[] served, ComponentNeeds[] componentsNeeds, int labIndex) { int num = ((producingLabRecipe.TimeSpend > 5400000) ? 6 : (3 * ((producingLabTimingData.SpeedOverride + 5001) / 10000) + 3)); int objectNeedsIndex = groupNeeds.GetObjectNeedsIndex(labIndex); int num2 = groupNeeds.GroupNeedsSize * labIndex; OptimizedItemId[] requires = producingLabRecipe.Requires; byte b = 0; for (int i = 0; i < requires.Length; i++) { b |= (byte)(((served[num2 + i] < num) ? 1u : 0u) << i); } componentsNeeds[objectNeedsIndex].Needs = b; } public LabState InternalUpdateAssemble(float power, int[] productRegister, int[] consumeRegister, [In][RequiresLocation] ref ProducingLabRecipe producingLabRecipe, ref LabPowerFields labPowerFields, ref ProducingLabTimingData producingLabTimingData, int servedOffset, int producedOffset, short[] served, short[] incServed, short[] produced) { if (producingLabTimingData.ExtraTime >= producingLabRecipe.ExtraTimeSpend) { for (int i = 0; i < producingLabRecipe.ProductCounts.Length; i++) { produced[producedOffset + i] += producingLabRecipe.ProductCounts[i]; productRegister[producingLabRecipe.Products[i].OptimizedItemIndex] += producingLabRecipe.ProductCounts[i]; } producingLabTimingData.ExtraTime -= producingLabRecipe.ExtraTimeSpend; } if (producingLabTimingData.Time >= producingLabRecipe.TimeSpend) { labPowerFields.replicating = false; for (int j = 0; j < producingLabRecipe.Products.Length; j++) { if (produced[producedOffset + j] + producingLabRecipe.ProductCounts[j] > 10 * ((producingLabTimingData.SpeedOverride + 9999) / 10000)) { return LabState.InactiveOutputFull; } } for (int k = 0; k < producingLabRecipe.Products.Length; k++) { produced[producedOffset + k] += producingLabRecipe.ProductCounts[k]; productRegister[producingLabRecipe.Products[k].OptimizedItemIndex] += producingLabRecipe.ProductCounts[k]; } producingLabTimingData.ExtraSpeed = 0; producingLabTimingData.SpeedOverride = producingLabRecipe.Speed; labPowerFields.extraPowerRatio = 0; producingLabTimingData.Time -= producingLabRecipe.TimeSpend; } if (!labPowerFields.replicating) { int length = producingLabRecipe.RequireCounts.Length; for (int l = 0; l < length; l++) { if (incServed[servedOffset + l] <= 0) { incServed[servedOffset + l] = 0; } if (served[servedOffset + l] < producingLabRecipe.RequireCounts[l] || served[servedOffset + l] == 0) { producingLabTimingData.Time = 0; return LabState.InactiveInputMissing; } } int num = ((length > 0) ? 10 : 0); for (int m = 0; m < length; m++) { int num2 = split_inc_level(ref served[servedOffset + m], ref incServed[servedOffset + m], producingLabRecipe.RequireCounts[m]); num = ((num < num2) ? num : num2); if (!incUsed) { incUsed = num2 > 0; } if (served[servedOffset + m] == 0) { incServed[servedOffset + m] = 0; } consumeRegister[producingLabRecipe.Requires[m].OptimizedItemIndex] += producingLabRecipe.RequireCounts[m]; } if (num < 0) { num = 0; } if (producingLabRecipe.Productive && !forceAccMode) { producingLabTimingData.ExtraSpeed = (int)((double)producingLabRecipe.Speed * Cargo.incTableMilli[num] * 10.0 + 0.1); producingLabTimingData.SpeedOverride = producingLabRecipe.Speed; labPowerFields.extraPowerRatio = Cargo.powerTable[num]; } else { producingLabTimingData.ExtraSpeed = 0; producingLabTimingData.SpeedOverride = (int)((double)producingLabRecipe.Speed * (1.0 + Cargo.accTableMilli[num]) + 0.1); labPowerFields.extraPowerRatio = Cargo.powerTable[num]; } labPowerFields.replicating = true; } producingLabTimingData.UpdateTimings(power, labPowerFields.replicating, ref producingLabRecipe); if (!labPowerFields.replicating) { throw new InvalidOperationException("I do not think this is possible. Not sure why it is in the game."); } return LabState.Active; } public readonly void UpdateOutputToNext(int labIndex, OptimizedProducingLab[] labPool, LabState[] labStates, bool[] needToUpdateNeeds, [In][RequiresLocation] ref ProducingLabRecipe producingLabRecipe, [In][RequiresLocation] ref ProducingLabTimingData producingLabTimingData, GroupNeeds groupNeeds, ComponentNeeds[] componentsNeeds, int serveOffset, int producedSize, short[] served, short[] incServed, short[] produced) { if (nextLabIndex == -1) { return; } bool flag = false; int num = ((producingLabRecipe.TimeSpend > 5400000) ? 1 : (1 + producingLabTimingData.SpeedOverride / 20000)); int objectNeedsIndex = groupNeeds.GetObjectNeedsIndex(nextLabIndex); int num2 = groupNeeds.GroupNeedsSize * nextLabIndex; int length = producingLabRecipe.RequireCounts.Length; ComponentNeeds componentNeeds = componentsNeeds[objectNeedsIndex]; for (int i = 0; i < length; i++) { int num3 = producingLabRecipe.RequireCounts[i] + num; if (componentNeeds.GetNeeds(i) && served[serveOffset + i] >= num3) { int num4 = served[serveOffset + i] - num3; if (num4 > 5) { num4 = 5; } int num5 = num4 * incServed[serveOffset + i] / served[serveOffset + i]; served[serveOffset + i] -= (short)num4; incServed[serveOffset + i] -= (short)num5; served[num2 + i] += (short)num4; incServed[num2 + i] += (short)num5; flag = true; } } int num6 = producedSize * labIndex; int num7 = producedSize * nextLabIndex; int num8 = 10 * ((producingLabTimingData.SpeedOverride + 9999) / 10000) - 2; if (produced[num6] < num8 && produced[num7] > 0) { int num9 = ((num8 - produced[num6] < produced[num7]) ? (num8 - produced[num6]) : produced[num7]); produced[num6] += (short)num9; produced[num7] -= (short)num9; flag = true; } if (flag) { labStates[labIndex] = LabState.Active; labStates[nextLabIndex] = LabState.Active; needToUpdateNeeds[labIndex] = true; needToUpdateNeeds[nextLabIndex] = true; } } public readonly void Save(ref LabComponent lab, LabPowerFields labPowerFields, ProducingLabTimingData producingLabTimingData, GroupNeeds groupNeeds, ComponentNeeds[] componentsNeeds, short[] needsPatterns, int producedSize, short[] served, short[] incServed, short[] produced, int labIndex) { int objectNeedsIndex = groupNeeds.GetObjectNeedsIndex(labIndex); int num = groupNeeds.GroupNeedsSize * labIndex; ComponentNeeds componentNeeds = componentsNeeds[objectNeedsIndex]; for (int i = 0; i < groupNeeds.GroupNeedsSize; i++) { GroupNeeds.SetIfInRange(lab.served, served, i, num + i); GroupNeeds.SetNeedsIfInRange(lab.needs, componentNeeds, needsPatterns, i); GroupNeeds.SetIfInRange(lab.incServed, incServed, i, num + i); } int num2 = labIndex * producedSize; for (int j = 0; j < producedSize; j++) { GroupNeeds.SetIfInRange(lab.produced, produced, j, num2 + j); } lab.incUsed = incUsed; lab.replicating = labPowerFields.replicating; lab.extraPowerRatio = labPowerFields.extraPowerRatio; lab.time = producingLabTimingData.Time; lab.extraTime = producingLabTimingData.ExtraTime; lab.extraSpeed = producingLabTimingData.ExtraSpeed; lab.speedOverride = producingLabTimingData.SpeedOverride; } private static int split_inc_level(ref short n, ref short m, short p) { int num = m / n; int num2 = m - num * n; n -= p; num2 -= n; m -= (short)((num2 > 0) ? (num * p + num2) : (num * p)); return num; } } internal sealed class ProducingLabExecutor { private ReadonlyArray _labNetworkIds; public LabState[] _labStates; public OptimizedProducingLab[] _optimizedLabs; public LabPowerFields[] _labsPowerFields; private ProducingLabTimingData[] _labsTimingData; public ReadonlyArray _labRecipeIndexes; public ReadonlyArray _entityIds; public Dictionary _labIdToOptimizedLabIndex; public HashSet _unOptimizedLabIds; private PrototypePowerConsumptionExecutor _prototypePowerConsumptionExecutor; private long[]? _previousPowerConsumptions; public int _producedSize = -1; public short[] _served; public short[] _incServed; public short[] _produced; public bool[] _needToUpdateNeeds; public int Count => _optimizedLabs.Length; public void GameTickLabProduceMode(PlanetFactory planet, ReadonlyArray producingLabPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption, int[] productRegister, int[] consumeRegister, SubFactoryNeeds subFactoryNeeds, UniverseStaticData universeStaticData) { float[] networkServes = planet.powerSystem.networkServes; ReadonlyArray labNetworkIds = _labNetworkIds; LabState[] labStates = _labStates; OptimizedProducingLab[] optimizedLabs = _optimizedLabs; LabPowerFields[] labsPowerFields = _labsPowerFields; ProducingLabTimingData[] labsTimingData = _labsTimingData; ReadonlyArray producingLabRecipes = universeStaticData.ProducingLabRecipes; GroupNeeds groupNeeds = subFactoryNeeds.GetGroupNeeds(EntityType.ProducingLab); ComponentNeeds[] componentsNeeds = subFactoryNeeds.ComponentsNeeds; int producedSize = _producedSize; short[] served = _served; short[] incServed = _incServed; short[] produced = _produced; ReadonlyArray labRecipeIndexes = _labRecipeIndexes; bool[] needToUpdateNeeds = _needToUpdateNeeds; long[] previousPowerConsumptions = _previousPowerConsumptions; if (previousPowerConsumptions == null) { _previousPowerConsumptions = new long[optimizedLabs.Length]; previousPowerConsumptions = _previousPowerConsumptions; for (int i = 0; i < optimizedLabs.Length; i++) { previousPowerConsumptions[i] = UpdatePower(producingLabPowerConsumerIndexes, powerConsumerTypes, i, labsPowerFields[i]); } } for (int j = 0; j < optimizedLabs.Length; j++) { short num = labNetworkIds[j]; ref LabState reference = ref labStates[j]; if (reference != 0) { thisSubFactoryNetworkPowerConsumption[num] += previousPowerConsumptions[j]; continue; } ref readonly ProducingLabRecipe producingLabRecipe = ref producingLabRecipes[labRecipeIndexes[j]]; ref ProducingLabTimingData reference2 = ref labsTimingData[j]; if (needToUpdateNeeds[j]) { OptimizedProducingLab.UpdateNeedsAssemble(ref producingLabRecipe, ref reference2, groupNeeds, served, componentsNeeds, j); needToUpdateNeeds[j] = false; } float num2 = networkServes[num]; if (num2 < 0.1f) { thisSubFactoryNetworkPowerConsumption[num] += previousPowerConsumptions[j]; continue; } ref LabPowerFields reference3 = ref labsPowerFields[j]; if (!reference2.UpdateTimings(num2, reference3.replicating, ref producingLabRecipe)) { thisSubFactoryNetworkPowerConsumption[num] += previousPowerConsumptions[j]; continue; } ref OptimizedProducingLab reference4 = ref optimizedLabs[j]; int servedOffset = j * groupNeeds.GroupNeedsSize; int producedOffset = j * producedSize; reference = reference4.InternalUpdateAssemble(num2, productRegister, consumeRegister, ref producingLabRecipe, ref reference3, ref reference2, servedOffset, producedOffset, served, incServed, produced); if (reference3.replicating) { needToUpdateNeeds[j] = true; } previousPowerConsumptions[j] = UpdatePower(producingLabPowerConsumerIndexes, powerConsumerTypes, j, reference3); thisSubFactoryNetworkPowerConsumption[num] += previousPowerConsumptions[j]; } } public void GameTickLabOutputToNext(long time, SubFactoryNeeds subFactoryNeeds, UniverseStaticData universeStaticData) { GroupNeeds groupNeeds = subFactoryNeeds.GetGroupNeeds(EntityType.ProducingLab); ComponentNeeds[] componentsNeeds = subFactoryNeeds.ComponentsNeeds; int producedSize = _producedSize; short[] served = _served; short[] incServed = _incServed; short[] produced = _produced; bool[] needToUpdateNeeds = _needToUpdateNeeds; ReadonlyArray labRecipeIndexes = _labRecipeIndexes; LabState[] labStates = _labStates; OptimizedProducingLab[] optimizedLabs = _optimizedLabs; ReadonlyArray producingLabRecipes = universeStaticData.ProducingLabRecipes; ProducingLabTimingData[] labsTimingData = _labsTimingData; int num = (int)(time & 3); for (int i = 0; i < optimizedLabs.Length; i++) { if ((i & 3) == num) { int serveOffset = i * groupNeeds.GroupNeedsSize; optimizedLabs[i].UpdateOutputToNext(i, optimizedLabs, labStates, needToUpdateNeeds, ref producingLabRecipes[labRecipeIndexes[i]], ref labsTimingData[i], groupNeeds, componentsNeeds, serveOffset, producedSize, served, incServed, produced); } } } public void UpdatePower(ReadonlyArray producingLabPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption) { ReadonlyArray labNetworkIds = _labNetworkIds; LabPowerFields[] labsPowerFields = _labsPowerFields; for (int i = 0; i < _optimizedLabs.Length; i++) { short num = labNetworkIds[i]; LabPowerFields labPowerFields = labsPowerFields[i]; thisSubFactoryNetworkPowerConsumption[num] += UpdatePower(producingLabPowerConsumerIndexes, powerConsumerTypes, i, labPowerFields); } } private static long UpdatePower(ReadonlyArray producingLabPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, int labIndex, LabPowerFields labPowerFields) { int index = producingLabPowerConsumerIndexes[labIndex]; return GetPowerConsumption(powerConsumerTypes[index], labPowerFields); } public PrototypePowerConsumptions UpdatePowerConsumptionPerPrototype(ReadonlyArray producingLabPowerConsumerIndexes, ReadonlyArray powerConsumerTypes) { PrototypePowerConsumptionExecutor prototypePowerConsumptionExecutor = _prototypePowerConsumptionExecutor; prototypePowerConsumptionExecutor.Clear(); LabPowerFields[] labsPowerFields = _labsPowerFields; ReadonlyArray prototypeIdIndexes = prototypePowerConsumptionExecutor.PrototypeIdIndexes; long[] prototypeIdPowerConsumption = prototypePowerConsumptionExecutor.PrototypeIdPowerConsumption; for (int i = 0; i < labsPowerFields.Length; i++) { LabPowerFields labPowerFields = labsPowerFields[i]; UpdatePowerConsumptionPerPrototype(producingLabPowerConsumerIndexes, powerConsumerTypes, prototypeIdIndexes, prototypeIdPowerConsumption, i, labPowerFields); } return prototypePowerConsumptionExecutor.GetPowerConsumption(); } private static void UpdatePowerConsumptionPerPrototype(ReadonlyArray producingLabPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, ReadonlyArray prototypeIdIndexes, long[] prototypeIdPowerConsumption, int labIndex, LabPowerFields labPowerFields) { int index = producingLabPowerConsumerIndexes[labIndex]; PowerConsumerType powerConsumerType = powerConsumerTypes[index]; prototypeIdPowerConsumption[prototypeIdIndexes[labIndex]] += GetPowerConsumption(powerConsumerType, labPowerFields); } public void Save(PlanetFactory planet, SubFactoryNeeds subFactoryNeeds) { LabComponent[] labPool = planet.factorySystem.labPool; OptimizedProducingLab[] optimizedLabs = _optimizedLabs; LabPowerFields[] labsPowerFields = _labsPowerFields; ProducingLabTimingData[] labsTimingData = _labsTimingData; GroupNeeds groupNeeds = subFactoryNeeds.GetGroupNeeds(EntityType.ProducingLab); ComponentNeeds[] componentsNeeds = subFactoryNeeds.ComponentsNeeds; short[] needsPatterns = subFactoryNeeds.NeedsPatterns; int producedSize = _producedSize; short[] served = _served; short[] incServed = _incServed; short[] produced = _produced; for (int i = 1; i < planet.factorySystem.labCursor; i++) { if (_labIdToOptimizedLabIndex.TryGetValue(i, out var value)) { optimizedLabs[value].Save(ref labPool[i], labsPowerFields[value], labsTimingData[value], groupNeeds, componentsNeeds, needsPatterns, producedSize, served, incServed, produced, value); } } } public void Initialize(PlanetFactory planet, Graph subFactoryGraph, SubFactoryPowerSystemBuilder subFactoryPowerSystemBuilder, SubFactoryProductionRegisterBuilder subFactoryProductionRegisterBuilder, SubFactoryNeedsBuilder subFactoryNeedsBuilder, UniverseStaticDataBuilder universeStaticDataBuilder) { List list = new List(); List list2 = new List(); List list3 = new List(); List list4 = new List(); List list5 = new List(); HashSet hashSet = new HashSet(); List list6 = new List(); List list7 = new List(); Dictionary dictionary = new Dictionary(); HashSet hashSet2 = new HashSet(); List list8 = new List(); List list9 = new List(); List list10 = new List(); GameHistoryData history = planet.gameData.history; PrototypePowerConsumptionBuilder prototypePowerConsumptionBuilder = new PrototypePowerConsumptionBuilder(); GroupNeedsBuilder groupNeedsBuilder = subFactoryNeedsBuilder.CreateGroupNeedsBuilder(EntityType.ProducingLab); HashSet hashSet3 = new HashSet(from x in subFactoryGraph.GetAllNodes() where x.EntityTypeIndex.EntityType == EntityType.ProducingLab select x.EntityTypeIndex.Index); foreach (int item in hashSet3.OrderByDescending((int x) => x)) { ref LabComponent reference = ref planet.factorySystem.labPool[item]; if (reference.id != item) { hashSet2.Add(item); continue; } if (reference.researchMode) { hashSet2.Add(item); continue; } if (reference.recipeId == 0) { hashSet2.Add(item); continue; } if (!history.RecipeUnlocked(reference.recipeId)) { hashSet2.Add(item); continue; } int? nextLabIndex = null; if (planet.factorySystem.labPool[reference.nextLabId].id != 0 && planet.factorySystem.labPool[reference.nextLabId].id == reference.nextLabId) { nextLabIndex = reference.nextLabId; if (!hashSet3.Contains(nextLabIndex.Value)) { throw new InvalidOperationException(string.Format("Labs next lab index is not part of the current sub factory. {0}: {1}", "nextLabIndex", nextLabIndex.Value)); } } ProducingLabRecipe producingLabRecipe = new ProducingLabRecipe(ref reference, subFactoryProductionRegisterBuilder.AddConsume(reference.recipeExecuteData.requires), universeStaticDataBuilder.DeduplicateArrayUnmanaged(ConverterUtilities.ConvertToShortArrayOrThrow(reference.recipeExecuteData.requireCounts, "requireCounts")), subFactoryProductionRegisterBuilder.AddProduct(reference.recipeExecuteData.products), universeStaticDataBuilder.DeduplicateArrayUnmanaged(ConverterUtilities.ConvertToShortArrayOrThrow(reference.recipeExecuteData.productCounts, "productCounts"))); hashSet.Add(producingLabRecipe); int num = universeStaticDataBuilder.AddProducingLabRecipe(ref producingLabRecipe); dictionary.Add(item, list3.Count); list3.Add(new OptimizedProducingLab(nextLabIndex, ref reference)); list4.Add(new LabPowerFields(ref reference)); list5.Add(new ProducingLabTimingData(ref reference)); int networkId = planet.powerSystem.consumerPool[reference.pcId].networkId; list.Add(ConverterUtilities.ThrowIfNotWithinPositiveShortRange(networkId, "networkIndex")); list2.Add(LabState.Active); list6.Add(reference.entityId); list8.Add(reference.served); list9.Add(reference.incServed); list10.Add(reference.produced); list7.Add((short)num); subFactoryPowerSystemBuilder.AddProducingLab(ref reference, networkId); prototypePowerConsumptionBuilder.AddPowerConsumer(ref planet.entityPool[reference.entityId]); planet.entityNeeds[reference.entityId] = reference.needs; groupNeedsBuilder.AddNeeds(reference.needs, reference.recipeExecuteData.requires); } for (int i = 0; i < list3.Count; i++) { OptimizedProducingLab lab = list3[i]; if (lab.nextLabIndex != -1) { if (!dictionary.TryGetValue(lab.nextLabIndex, out var value)) { throw new InvalidOperationException("Next lab index was not part of the converted research labs."); } list3[i] = new OptimizedProducingLab(value, ref lab); } } if (hashSet.Count > 0) { int num2 = hashSet.Max((ProducingLabRecipe x) => x.Requires.Length); int num3 = hashSet.Max((ProducingLabRecipe x) => x.Products.Length); List list11 = new List(); List list12 = new List(); List list13 = new List(); for (int j = 0; j < list3.Count; j++) { for (int k = 0; k < num2; k++) { list11.Add(GroupNeeds.GetOrDefaultConvertToShortWithClamping(list8[j], k, -5000, 5000)); list12.Add(GroupNeeds.GetOrDefaultConvertToShortWithClamping(list9[j], k, -5000, 5000)); } for (int l = 0; l < num3; l++) { list13.Add(GroupNeeds.GetOrDefaultConvertToShortWithClamping(list10[j], l, -5000, 5000)); } } _producedSize = num3; _served = list11.ToArray(); _incServed = list12.ToArray(); _produced = list13.ToArray(); _needToUpdateNeeds = new bool[list3.Count]; _needToUpdateNeeds.Fill(value: true); } _labNetworkIds = universeStaticDataBuilder.DeduplicateArrayUnmanaged(list); _labStates = list2.ToArray(); _optimizedLabs = list3.ToArray(); _labsPowerFields = list4.ToArray(); _labsTimingData = list5.ToArray(); _entityIds = universeStaticDataBuilder.DeduplicateArrayUnmanaged(list6); _labRecipeIndexes = universeStaticDataBuilder.DeduplicateArrayUnmanaged(list7); _labIdToOptimizedLabIndex = dictionary; _unOptimizedLabIds = hashSet2; _prototypePowerConsumptionExecutor = prototypePowerConsumptionBuilder.Build(universeStaticDataBuilder); groupNeedsBuilder.Complete(); } private static long GetPowerConsumption(PowerConsumerType powerConsumerType, LabPowerFields producingLabPowerFields) { return powerConsumerType.GetRequiredEnergy(producingLabPowerFields.replicating, 1000 + producingLabPowerFields.extraPowerRatio); } } [StructLayout(LayoutKind.Sequential, Pack = 1)] internal readonly struct ProducingLabRecipe : IEquatable, IMemorySize { public readonly int RecipeId; public readonly int TimeSpend; public readonly int ExtraTimeSpend; public readonly int Speed; public readonly bool Productive; public readonly OptimizedItemId[] Requires; public readonly ReadonlyArray RequireCounts; public readonly OptimizedItemId[] Products; public readonly ReadonlyArray ProductCounts; public ProducingLabRecipe([In][RequiresLocation] ref LabComponent lab, OptimizedItemId[] requires, ReadonlyArray requireCounts, OptimizedItemId[] products, ReadonlyArray productCounts) { RecipeId = lab.recipeId; TimeSpend = lab.recipeExecuteData.timeSpend; ExtraTimeSpend = lab.recipeExecuteData.extraTimeSpend; Speed = lab.speed; Productive = lab.recipeExecuteData.productive; Requires = requires; RequireCounts = requireCounts; Products = products; ProductCounts = productCounts; } public int GetSize() { return Marshal.SizeOf() + Marshal.SizeOf() * Requires.Length + Marshal.SizeOf() * RequireCounts.Length + Marshal.SizeOf() * Products.Length + Marshal.SizeOf() * ProductCounts.Length; } public bool Equals(ProducingLabRecipe other) { if (RecipeId == other.RecipeId && TimeSpend == other.TimeSpend && ExtraTimeSpend == other.ExtraTimeSpend && Speed == other.Speed && Productive == other.Productive && Requires.SequenceEqual(other.Requires) && RequireCounts.SequenceEqual(other.RequireCounts) && Products.SequenceEqual(other.Products)) { return ProductCounts.SequenceEqual(other.ProductCounts); } return false; } public override bool Equals(object obj) { if (obj is ProducingLabRecipe other) { return Equals(other); } return false; } public override int GetHashCode() { HashCode hashCode = default(HashCode); hashCode.Add(RecipeId); hashCode.Add(TimeSpend); hashCode.Add(ExtraTimeSpend); hashCode.Add(Speed); hashCode.Add(Productive); for (int i = 0; i < Requires.Length; i++) { hashCode.Add(Requires[i]); } for (int j = 0; j < RequireCounts.Length; j++) { hashCode.Add(RequireCounts[j]); } for (int k = 0; k < Products.Length; k++) { hashCode.Add(Products[k]); } for (int l = 0; l < ProductCounts.Length; l++) { hashCode.Add(ProductCounts[l]); } return hashCode.ToHashCode(); } } } namespace Weaver.Optimizations.Inserters { internal interface IInserterGrade : IEquatable where T : IInserterGrade { T Create(ref InserterComponent inserter); } internal readonly struct InserterConnections : IEquatable, IMemorySize { public readonly TypedObjectIndex PickFrom; public readonly TypedObjectIndex InsertInto; public InserterConnections(TypedObjectIndex pickFrom, TypedObjectIndex insertInto) { PickFrom = pickFrom; InsertInto = insertInto; } public int GetSize() { return Marshal.SizeOf(); } public bool Equals(InserterConnections other) { if (PickFrom == other.PickFrom) { return InsertInto == other.InsertInto; } return false; } public override bool Equals(object obj) { if (obj is InserterConnections other) { return Equals(other); } return false; } public override int GetHashCode() { return HashCode.Combine(PickFrom, InsertInto); } public override string ToString() { return string.Format("InserterConnections\r\n\\t{0}: {1}\r\n\\t{2}: {3}", "PickFrom", PickFrom, "InsertInto", InsertInto); } } internal static class CargoPathMethods { public static bool TryPickItemAtRear(ref OptimizedCargoPath cargoPath, int filter, int[]? needs, out OptimizedCargo cargo) { if (!cargoPath.TryGetCargoIdAtRear(out cargo)) { cargo = default(OptimizedCargo); return false; } int item = cargo.Item; if (filter != 0) { if (item == filter) { cargoPath.TryRemoveItemAtRear(); return true; } } else { if (needs == null) { cargoPath.TryRemoveItemAtRear(); return true; } for (int i = 0; i < needs.Length; i++) { if (needs[i] == item) { cargoPath.TryRemoveItemAtRear(); return true; } } } cargo = default(OptimizedCargo); return false; } } internal sealed class InserterExecutor where TInserter : struct, IInserter where TInserterGrade : struct, IInserterGrade, IMemorySize { private TInserter[] _optimizedInserters; private OptimizedInserterStage[] _optimizedInserterStages; private ReadonlyArray _inserterNetworkIds; private InserterState[] _inserterStates; private ReadonlyArray _inserterConnections; private Dictionary _inserterIdToOptimizedIndex; private PrototypePowerConsumptionExecutor _prototypePowerConsumptionExecutor; private readonly AssemblerState[] _assemblerStates; private readonly LabState[] _producingLabStates; private readonly LabState[] _researchingLabStates; private readonly OptimizedFuelGenerator[][] _generatorSegmentToOptimizedFuelGenerators; private readonly OptimizedItemId[]?[]? _fuelNeeds; private readonly SubFactoryNeeds _subFactoryNeeds; private readonly int _assemblerProducedSize; private readonly short[] _assemblerServed; private readonly short[] _assemblerIncServed; private readonly short[] _assemblerProduced; private readonly ReadonlyArray _assemblerRecipeIndexes; private readonly bool[] _assemblerNeedToUpdateNeeds; private readonly int _producingLabProducedSize; private readonly short[] _producingLabServed; private readonly short[] _producingLabIncServed; private readonly short[] _producingLabProduced; private readonly ReadonlyArray _producingLabRecipeIndexes; private readonly bool[] _producingLabNeedToUpdateNeeds; private readonly int[] _researchingLabMatrixServed; private readonly int[] _researchingLabMatrixIncServed; private readonly ReadonlyArray _siloIndexes; private readonly EjectorBulletData[] _ejectorBulletDatas; private readonly UniverseStaticData _universeStaticData; public int Count => _optimizedInserters.Length; public InserterExecutor(AssemblerState[] assemblerStates, LabState[] producingLabStates, LabState[] researchingLabStates, OptimizedFuelGenerator[][] generatorSegmentToOptimizedFuelGenerators, OptimizedItemId[]?[]? fuelNeeds, SubFactoryNeeds subFactoryNeeds, int assemblerProducedSize, short[] assemblerServed, short[] assemblerIncServed, short[] assemblerProduced, ReadonlyArray assemblerRecipeIndexes, bool[] assemblerNeedToUpdateNeeds, int producingLabProducedSize, short[] producingLabServed, short[] producingLabIncServed, short[] producingLabProduced, ReadonlyArray producingLabRecipeIndexes, bool[] producingLabNeedToUpdateNeeds, int[] researchingLabMatrixServed, int[] researchingLabMatrixIncServed, ReadonlyArray siloIndexes, EjectorBulletData[] ejectorBulletDatas, UniverseStaticData universeStaticData) { _assemblerStates = assemblerStates; _producingLabStates = producingLabStates; _researchingLabStates = researchingLabStates; _generatorSegmentToOptimizedFuelGenerators = generatorSegmentToOptimizedFuelGenerators; _fuelNeeds = fuelNeeds; _subFactoryNeeds = subFactoryNeeds; _assemblerProducedSize = assemblerProducedSize; _assemblerServed = assemblerServed; _assemblerIncServed = assemblerIncServed; _assemblerProduced = assemblerProduced; _assemblerRecipeIndexes = assemblerRecipeIndexes; _assemblerNeedToUpdateNeeds = assemblerNeedToUpdateNeeds; _producingLabProducedSize = producingLabProducedSize; _producingLabServed = producingLabServed; _producingLabIncServed = producingLabIncServed; _producingLabProduced = producingLabProduced; _producingLabRecipeIndexes = producingLabRecipeIndexes; _producingLabNeedToUpdateNeeds = producingLabNeedToUpdateNeeds; _researchingLabMatrixServed = researchingLabMatrixServed; _researchingLabMatrixIncServed = researchingLabMatrixIncServed; _siloIndexes = siloIndexes; _ejectorBulletDatas = ejectorBulletDatas; _universeStaticData = universeStaticData; } public void GameTickInserters(PlanetFactory planet, ReadonlyArray inserterPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption, OptimizedCargoPath[] optimizedCargoPaths, UniverseStaticData universeStaticData) { float[] networkServes = planet.powerSystem.networkServes; OptimizedInserterStage[] optimizedInserterStages = _optimizedInserterStages; ReadonlyArray inserterNetworkIds = _inserterNetworkIds; InserterState[] inserterStates = _inserterStates; TInserter[] optimizedInserters = _optimizedInserters; ReadonlyArray inserterGrades = default(TInserter).GetInserterGrades(universeStaticData); for (int i = 0; i < optimizedInserterStages.Length; i++) { ref OptimizedInserterStage reference = ref optimizedInserterStages[i]; short num = inserterNetworkIds[i]; ref InserterState reference2 = ref inserterStates[i]; if (reference2 != 0) { if (reference2 == InserterState.InactivePickFrom) { if (!IsObjectPickFromActive(i)) { UpdatePower(inserterPowerConsumerIndexes, powerConsumerTypes, thisSubFactoryNetworkPowerConsumption, i, num, reference); continue; } reference2 = InserterState.Active; } else if (reference2 == InserterState.InactiveInsertInto) { if (!IsObjectInsertIntoActive(i)) { UpdatePower(inserterPowerConsumerIndexes, powerConsumerTypes, thisSubFactoryNetworkPowerConsumption, i, num, reference); continue; } reference2 = InserterState.Active; } } float power = networkServes[num]; ref TInserter reference3 = ref optimizedInserters[i]; reference3.Update(planet, this, power, i, ref reference2, ref inserterGrades[reference3.grade], ref reference, _inserterConnections, _subFactoryNeeds, optimizedCargoPaths); UpdatePower(inserterPowerConsumerIndexes, powerConsumerTypes, thisSubFactoryNetworkPowerConsumption, i, num, reference); } } public void UpdatePower(ReadonlyArray inserterPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption) { ReadonlyArray inserterNetworkIds = _inserterNetworkIds; for (int i = 0; i < _optimizedInserters.Length; i++) { short networkIndex = inserterNetworkIds[i]; OptimizedInserterStage optimizedInserterStage = _optimizedInserterStages[i]; UpdatePower(inserterPowerConsumerIndexes, powerConsumerTypes, thisSubFactoryNetworkPowerConsumption, i, networkIndex, optimizedInserterStage); } } private static void UpdatePower(ReadonlyArray inserterPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption, int inserterIndex, short networkIndex, OptimizedInserterStage optimizedInserterStage) { int index = inserterPowerConsumerIndexes[inserterIndex]; PowerConsumerType powerConsumerType = powerConsumerTypes[index]; thisSubFactoryNetworkPowerConsumption[networkIndex] += GetPowerConsumption(powerConsumerType, optimizedInserterStage); } public PrototypePowerConsumptions UpdatePowerConsumptionPerPrototype(ReadonlyArray inserterPowerConsumerIndexes, ReadonlyArray powerConsumerTypes) { PrototypePowerConsumptionExecutor prototypePowerConsumptionExecutor = _prototypePowerConsumptionExecutor; prototypePowerConsumptionExecutor.Clear(); ReadonlyArray prototypeIdIndexes = prototypePowerConsumptionExecutor.PrototypeIdIndexes; long[] prototypeIdPowerConsumption = prototypePowerConsumptionExecutor.PrototypeIdPowerConsumption; for (int i = 0; i < _optimizedInserters.Length; i++) { OptimizedInserterStage optimizedInserterStage = _optimizedInserterStages[i]; UpdatePowerConsumptionPerPrototype(inserterPowerConsumerIndexes, powerConsumerTypes, prototypeIdIndexes, prototypeIdPowerConsumption, i, optimizedInserterStage); } return prototypePowerConsumptionExecutor.GetPowerConsumption(); } private static void UpdatePowerConsumptionPerPrototype(ReadonlyArray inserterPowerConsumerIndexes, ReadonlyArray powerConsumerTypes, ReadonlyArray prototypeIdIndexes, long[] prototypeIdPowerConsumption, int inserterIndex, OptimizedInserterStage optimizedInserterStage) { int index = inserterPowerConsumerIndexes[inserterIndex]; PowerConsumerType powerConsumerType = powerConsumerTypes[index]; prototypeIdPowerConsumption[prototypeIdIndexes[inserterIndex]] += GetPowerConsumption(powerConsumerType, optimizedInserterStage); } private static long GetPowerConsumption(PowerConsumerType powerConsumerType, OptimizedInserterStage stage) { return powerConsumerType.GetRequiredEnergy(stage == OptimizedInserterStage.Sending || stage == OptimizedInserterStage.Returning); } private bool IsObjectPickFromActive(int inserterIndex) { TypedObjectIndex pickFrom = _inserterConnections[inserterIndex].PickFrom; if (pickFrom.EntityType == EntityType.Assembler) { return _assemblerStates[pickFrom.Index] == AssemblerState.Active; } if (pickFrom.EntityType == EntityType.ProducingLab) { return _producingLabStates[pickFrom.Index] == LabState.Active; } throw new InvalidOperationException($"Check if pick from is active does currently not support entity type of type: {pickFrom.EntityType}"); } private bool IsObjectInsertIntoActive(int inserterIndex) { TypedObjectIndex insertInto = _inserterConnections[inserterIndex].InsertInto; if (insertInto.EntityType == EntityType.Assembler) { return _assemblerStates[insertInto.Index] == AssemblerState.Active; } if (insertInto.EntityType == EntityType.ProducingLab) { return _producingLabStates[insertInto.Index] == LabState.Active; } if (insertInto.EntityType == EntityType.ResearchingLab) { return _researchingLabStates[insertInto.Index] == LabState.Active; } throw new InvalidOperationException($"Check if insert into is active does currently not support entity type of type: {insertInto.EntityType}"); } private static bool IsInNeed(short productItemIndex, ComponentNeeds componentNeeds, short[] needsPatterns, int needsSize) { if (needsSize == 0) { return true; } for (int i = 0; i < needsSize; i++) { if (componentNeeds.GetNeeds(i) && needsPatterns[componentNeeds.PatternIndex + i] == productItemIndex) { return true; } } return false; } public short PickFuelForPowerGenFrom(PlanetFactory planet, ref InserterState inserterState, int pickOffset, int insertOffset, int filter, InserterConnections inserterConnections, out byte stack, out byte inc, out bool fuelFull, OptimizedCargoPath[] optimizedCargoPaths) { stack = 1; inc = 0; fuelFull = false; TypedObjectIndex pickFrom = inserterConnections.PickFrom; int index = pickFrom.Index; ref OptimizedFuelGenerator reference = ref _generatorSegmentToOptimizedFuelGenerators[insertOffset][inserterConnections.InsertInto.Index]; if (_fuelNeeds == null) { throw new InvalidOperationException("_fuelNeeds was null when inserter attempted to insert into FuelPowerGenerator."); } OptimizedItemId fuelId = reference.fuelId; if (fuelId.ItemIndex > 0 && filter > 0 && fuelId.ItemIndex != filter) { return 0; } OptimizedItemId[] array = _fuelNeeds[reference.fuelMask]; if (pickFrom.EntityType == EntityType.Belt) { ref OptimizedCargoPath reference2 = ref optimizedCargoPaths[index]; if (fuelId.ItemIndex > 0) { reference2.TryPickItem(pickOffset - 2, 5, fuelId.ItemIndex, out var cargo); stack = cargo.Stack; inc = cargo.Inc; return cargo.Item; } reference2.TryPickFuel(pickOffset - 2, 5, filter, array, out var optimizedCargo); stack = optimizedCargo.Stack; inc = optimizedCargo.Inc; return optimizedCargo.Item; } if (pickFrom.EntityType == EntityType.Assembler) { AssemblerState assemblerState = _assemblerStates[index]; if (assemblerState != 0 && assemblerState != AssemblerState.InactiveOutputFull) { inserterState = InserterState.InactivePickFrom; return 0; } OptimizedItemId[] products = _universeStaticData.AssemblerRecipes[_assemblerRecipeIndexes[index]].Products; short[] assemblerProduced = _assemblerProduced; int num = _assemblerProducedSize * index; if (fuelId.ItemIndex > 0) { for (int i = 0; i < products.Length; i++) { short itemIndex = products[i].ItemIndex; if (assemblerProduced[num + i] > 0 && itemIndex > 0 && itemIndex == fuelId.ItemIndex) { assemblerProduced[num + i]--; _assemblerStates[index] = AssemblerState.Active; return itemIndex; } } } else { for (int j = 0; j < products.Length; j++) { short itemIndex2 = products[j].ItemIndex; if (assemblerProduced[num + j] <= 0 || itemIndex2 <= 0 || (filter != 0 && filter != itemIndex2)) { continue; } for (int k = 0; k < array.Length; k++) { if (array[k].ItemIndex == itemIndex2) { assemblerProduced[num + j]--; _assemblerStates[index] = AssemblerState.Active; return itemIndex2; } } } } return 0; } if (pickFrom.EntityType == EntityType.Storage) { StorageComponent val = planet.factoryStorage.storagePool[index]; StorageComponent val2 = val; if (val != null) { int inc2 = default(int); for (val = val.topStorage; val != null; val = val.previousStorage) { if (val.lastEmptyItem != 0 && val.lastEmptyItem != filter) { int itemId = ((fuelId.ItemIndex > 0) ? fuelId.ItemIndex : filter); int count = 1; bool flag; if (fuelId.ItemIndex > 0) { val.TakeTailItems(ref itemId, ref count, ref inc2, planet.entityPool[val.entityId].battleBaseId > 0); inc = (byte)inc2; flag = count == 1; } else { bool flag2 = OptimizedStorage.TakeTailFuel(val, ref itemId, ref count, array, out inc2, planet.entityPool[val.entityId].battleBaseId > 0); inc = (byte)inc2; flag = count == 1 || flag2; } if (count == 1) { val.lastEmptyItem = -1; return (short)itemId; } if (!flag) { val.lastEmptyItem = filter; } } if (val == val2) { break; } } } return 0; } if (pickFrom.EntityType == EntityType.FuelPowerGenerator) { if (reference.fuelCount <= 8) { ref OptimizedFuelGenerator reference3 = ref _generatorSegmentToOptimizedFuelGenerators[pickOffset][index]; short itemIndex3; int inc3; if (fuelId.ItemIndex > 0) { itemIndex3 = reference3.PickFuelFrom(fuelId.ItemIndex, out inc3).ItemIndex; } else { OptimizedItemId obj = (((reference3.fuelMask & reference.fuelMask) != reference3.fuelMask) ? reference3.PickFuelFrom(filter, array, out inc3) : reference3.PickFuelFrom(filter, out inc3)); itemIndex3 = obj.ItemIndex; } inc = (byte)inc3; return itemIndex3; } fuelFull = true; } return 0; } public short PickFrom(PlanetFactory planet, ref InserterState inserterState, int inserterIndex, int offset, int filter, InserterConnections inserterConnections, GroupNeeds groupNeeds, out byte stack, out byte inc, OptimizedCargoPath[] optimizedCargoPaths) { stack = 1; inc = 0; TypedObjectIndex pickFrom = inserterConnections.PickFrom; int index = pickFrom.Index; if (pickFrom.EntityType == EntityType.Belt) { ref OptimizedCargoPath reference = ref optimizedCargoPaths[index]; if (groupNeeds.GroupNeedsSize == 0) { if (filter != 0) { reference.TryPickItem(offset - 2, 5, filter, out var cargo); stack = cargo.Stack; inc = cargo.Inc; return cargo.Item; } OptimizedCargo optimizedCargo = reference.TryPickItem(offset - 2, 5); stack = optimizedCargo.Stack; inc = optimizedCargo.Inc; return optimizedCargo.Item; } int groupNeedsSize = groupNeeds.GroupNeedsSize; int objectNeedsIndex = groupNeeds.GetObjectNeedsIndex(inserterConnections.InsertInto.Index); ComponentNeeds componentNeeds = _subFactoryNeeds.ComponentsNeeds[objectNeedsIndex]; short[] needsPatterns = _subFactoryNeeds.NeedsPatterns; OptimizedCargo optimizedCargo2 = reference.TryPickItem(offset - 2, 5, filter, componentNeeds, needsPatterns, groupNeedsSize); stack = optimizedCargo2.Stack; inc = optimizedCargo2.Inc; return optimizedCargo2.Item; } if (pickFrom.EntityType == EntityType.Assembler) { AssemblerState assemblerState = _assemblerStates[index]; if (assemblerState != 0 && assemblerState != AssemblerState.InactiveOutputFull) { inserterState = InserterState.InactivePickFrom; return 0; } int groupNeedsSize2 = groupNeeds.GroupNeedsSize; int objectNeedsIndex2 = groupNeeds.GetObjectNeedsIndex(inserterConnections.InsertInto.Index); ComponentNeeds componentNeeds2 = _subFactoryNeeds.ComponentsNeeds[objectNeedsIndex2]; short[] needsPatterns2 = _subFactoryNeeds.NeedsPatterns; OptimizedItemId[] products = _universeStaticData.AssemblerRecipes[_assemblerRecipeIndexes[index]].Products; short[] assemblerProduced = _assemblerProduced; int num = _assemblerProducedSize * index; for (int i = 0; i < products.Length; i++) { short itemIndex = products[i].ItemIndex; if ((filter == itemIndex || filter == 0) && assemblerProduced[num + i] > 0 && itemIndex > 0 && IsInNeed(itemIndex, componentNeeds2, needsPatterns2, groupNeedsSize2)) { assemblerProduced[num + i]--; _assemblerStates[index] = AssemblerState.Active; return products[i].ItemIndex; } } return 0; } if (pickFrom.EntityType == EntityType.Ejector) { ref EjectorBulletData reference2 = ref _ejectorBulletDatas[index]; int objectNeedsIndex3 = groupNeeds.GetObjectNeedsIndex(inserterConnections.InsertInto.Index); ComponentNeeds componentNeeds3 = _subFactoryNeeds.ComponentsNeeds[objectNeedsIndex3]; short[] needsPatterns3 = _subFactoryNeeds.NeedsPatterns; if (reference2.BulletId > 0 && reference2.BulletCount > 5 && (filter == 0 || filter == reference2.BulletId) && IsInNeed(reference2.BulletId, componentNeeds3, needsPatterns3, groupNeeds.GroupNeedsSize)) { return reference2.TakeOneBulletUnsafe(out inc); } return 0; } if (pickFrom.EntityType == EntityType.Silo) { int num2 = _siloIndexes[index]; int objectNeedsIndex4 = groupNeeds.GetObjectNeedsIndex(inserterConnections.InsertInto.Index); ComponentNeeds componentNeeds4 = _subFactoryNeeds.ComponentsNeeds[objectNeedsIndex4]; short[] needsPatterns4 = _subFactoryNeeds.NeedsPatterns; ref SiloComponent reference3 = ref planet.factorySystem.siloPool[num2]; int bulletId = reference3.bulletId; int bulletCount = reference3.bulletCount; if (bulletId > 0 && bulletCount > 1 && (filter == 0 || filter == bulletId) && IsInNeed((short)bulletId, componentNeeds4, needsPatterns4, groupNeeds.GroupNeedsSize)) { ((SiloComponent)(ref reference3)).TakeOneBulletUnsafe(ref inc); return (short)bulletId; } return 0; } if (pickFrom.EntityType == EntityType.Storage) { StorageComponent val = planet.factoryStorage.storagePool[index]; StorageComponent val2 = val; if (val != null) { short[] needsPatterns5 = _subFactoryNeeds.NeedsPatterns; int inc2 = default(int); for (val = val.topStorage; val != null; val = val.previousStorage) { if (val.lastEmptyItem != 0 && val.lastEmptyItem != filter) { int itemId = filter; int count = 1; bool flag; if (groupNeeds.GroupNeedsSize == 0) { val.TakeTailItems(ref itemId, ref count, ref inc2, planet.entityPool[val.entityId].battleBaseId > 0); inc = (byte)inc2; flag = count == 1; } else { int objectNeedsIndex5 = groupNeeds.GetObjectNeedsIndex(inserterConnections.InsertInto.Index); ComponentNeeds componentNeeds5 = _subFactoryNeeds.ComponentsNeeds[objectNeedsIndex5]; bool flag2 = OptimizedStorage.TakeTailItems(val, ref itemId, ref count, componentNeeds5, needsPatterns5, groupNeeds.GroupNeedsSize, out inc2, planet.entityPool[val.entityId].battleBaseId > 0); inc = (byte)inc2; flag = count == 1 || flag2; } if (count == 1) { val.lastEmptyItem = -1; return (short)itemId; } if (!flag) { val.lastEmptyItem = filter; } } if (val == val2) { break; } } } return 0; } if (pickFrom.EntityType == EntityType.Station) { throw new InvalidOperationException("Assumption that sorters can not interact with stations is incorrect."); } if (pickFrom.EntityType == EntityType.ProducingLab) { LabState labState = _producingLabStates[index]; if (labState != 0 && labState != LabState.InactiveOutputFull) { inserterState = InserterState.InactivePickFrom; return 0; } OptimizedItemId[] products2 = _universeStaticData.ProducingLabRecipes[_producingLabRecipeIndexes[index]].Products; short[] producingLabProduced = _producingLabProduced; int num3 = _producingLabProducedSize * index; int groupNeedsSize3 = groupNeeds.GroupNeedsSize; int objectNeedsIndex6 = groupNeeds.GetObjectNeedsIndex(inserterConnections.InsertInto.Index); ComponentNeeds componentNeeds6 = _subFactoryNeeds.ComponentsNeeds[objectNeedsIndex6]; short[] needsPatterns6 = _subFactoryNeeds.NeedsPatterns; for (int j = 0; j < products2.Length; j++) { short itemIndex2 = products2[j].ItemIndex; if (producingLabProduced[num3 + j] > 0 && itemIndex2 > 0 && (filter == 0 || filter == itemIndex2) && IsInNeed(itemIndex2, componentNeeds6, needsPatterns6, groupNeedsSize3)) { producingLabProduced[num3 + j]--; _producingLabStates[index] = LabState.Active; return products2[j].ItemIndex; } } return 0; } if (pickFrom.EntityType == EntityType.FuelPowerGenerator) { ref OptimizedFuelGenerator reference4 = ref _generatorSegmentToOptimizedFuelGenerators[offset][index]; if (reference4.fuelCount <= 8) { int inc3; short itemIndex3 = reference4.PickFuelFrom(filter, out inc3).ItemIndex; inc = (byte)inc3; return itemIndex3; } return 0; } return 0; } public short InsertInto(PlanetFactory planet, ref InserterState inserterState, int inserterIndex, InserterConnections inserterConnections, GroupNeeds groupNeeds, int offset, int itemId, byte itemCount, byte itemInc, out byte remainInc, OptimizedCargoPath[] optimizedCargoPaths) { remainInc = itemInc; TypedObjectIndex insertInto = inserterConnections.InsertInto; int index = insertInto.Index; if (insertInto.EntityType == EntityType.Belt) { if (optimizedCargoPaths[index].TryInsertItem(offset, itemId, itemCount, itemInc)) { remainInc = 0; return itemCount; } return 0; } if (insertInto.EntityType == EntityType.Assembler) { AssemblerState assemblerState = _assemblerStates[index]; if (assemblerState != 0 && assemblerState != AssemblerState.InactiveInputMissing) { inserterState = InserterState.InactiveInsertInto; return 0; } if (groupNeeds.GroupNeedsSize == 0) { throw new InvalidOperationException("Needs should only be null if assembler is inactive which the above if statement should have caught."); } OptimizedItemId[] requires = _universeStaticData.AssemblerRecipes[_assemblerRecipeIndexes[index]].Requires; short[] assemblerServed = _assemblerServed; short[] assemblerIncServed = _assemblerIncServed; int num = groupNeeds.GroupNeedsSize * index; for (int i = 0; i < requires.Length; i++) { if (requires[i].ItemIndex == itemId) { ref short reference = ref assemblerServed[num + i]; reference += itemCount; ref short reference2 = ref assemblerIncServed[num + i]; reference2 += itemInc; remainInc = 0; _assemblerStates[index] = AssemblerState.Active; _assemblerNeedToUpdateNeeds[index] = true; return itemCount; } } return 0; } if (insertInto.EntityType == EntityType.Ejector) { if (groupNeeds.GroupNeedsSize == 0) { throw new InvalidOperationException("Need was null for active ejector."); } ref EjectorBulletData reference3 = ref _ejectorBulletDatas[index]; int objectNeedsIndex = groupNeeds.GetObjectNeedsIndex(index); ComponentNeeds componentNeeds = _subFactoryNeeds.ComponentsNeeds[objectNeedsIndex]; if (_subFactoryNeeds.NeedsPatterns[componentNeeds.PatternIndex] == itemId && reference3.BulletId == itemId) { reference3.BulletCount += itemCount; reference3.BulletInc += itemInc; remainInc = 0; return itemCount; } return 0; } if (insertInto.EntityType == EntityType.Silo) { if (groupNeeds.GroupNeedsSize == 0) { throw new InvalidOperationException("Need was null for active silo."); } int num2 = _siloIndexes[index]; int objectNeedsIndex2 = groupNeeds.GetObjectNeedsIndex(index); ComponentNeeds componentNeeds2 = _subFactoryNeeds.ComponentsNeeds[objectNeedsIndex2]; if (_subFactoryNeeds.NeedsPatterns[componentNeeds2.PatternIndex] == itemId && planet.factorySystem.siloPool[num2].bulletId == itemId) { planet.factorySystem.siloPool[num2].bulletCount += itemCount; planet.factorySystem.siloPool[num2].bulletInc += itemInc; remainInc = 0; return itemCount; } return 0; } if (insertInto.EntityType == EntityType.ProducingLab) { LabState labState = _producingLabStates[index]; if (labState != 0 && labState != LabState.InactiveInputMissing) { inserterState = InserterState.InactiveInsertInto; return 0; } if (groupNeeds.GroupNeedsSize == 0) { throw new InvalidOperationException("Needs should only be null if producing lab is inactive which the above if statement should have caught."); } OptimizedItemId[] requires2 = _universeStaticData.ProducingLabRecipes[_producingLabRecipeIndexes[index]].Requires; short[] producingLabServed = _producingLabServed; short[] producingLabIncServed = _producingLabIncServed; int num3 = groupNeeds.GroupNeedsSize * index; for (int j = 0; j < requires2.Length; j++) { if (requires2[j].ItemIndex == itemId) { ref short reference4 = ref producingLabServed[num3 + j]; reference4 += itemCount; ref short reference5 = ref producingLabIncServed[num3 + j]; reference5 += itemInc; remainInc = 0; _producingLabStates[index] = LabState.Active; _producingLabNeedToUpdateNeeds[index] = true; return itemCount; } } return 0; } if (insertInto.EntityType == EntityType.ResearchingLab) { LabState labState2 = _researchingLabStates[index]; if (labState2 != 0 && labState2 != LabState.InactiveInputMissing) { inserterState = InserterState.InactiveInsertInto; return 0; } if (groupNeeds.GroupNeedsSize == 0) { throw new InvalidOperationException("Needs should only be null if researching lab is inactive which the above if statement should have caught."); } int num4 = groupNeeds.GroupNeedsSize * index; int[] researchingLabMatrixServed = _researchingLabMatrixServed; int[] researchingLabMatrixIncServed = _researchingLabMatrixIncServed; int num5 = itemId - 6001; if (num5 >= 0 && num5 < 6) { researchingLabMatrixServed[num4 + num5] += 3600 * itemCount; researchingLabMatrixIncServed[num4 + num5] += 3600 * itemInc; remainInc = 0; _researchingLabStates[index] = LabState.Active; return itemCount; } return 0; } if (insertInto.EntityType == EntityType.Storage) { int num6 = default(int); for (StorageComponent val = planet.factoryStorage.storagePool[index]; val != null; val = val.nextStorage) { if (val.lastFullItem != itemId) { int num7 = ((planet.entityPool[val.entityId].battleBaseId != 0) ? val.AddItemFilteredBanOnly(itemId, (int)itemCount, (int)itemInc, ref num6) : val.AddItem(itemId, (int)itemCount, (int)itemInc, ref num6, true)); remainInc = (byte)num6; if (num7 == itemCount) { val.lastFullItem = -1; } else { val.lastFullItem = itemId; } if (num7 != 0 || val.nextStorage == null) { return (short)num7; } } } return 0; } if (insertInto.EntityType == EntityType.Station) { throw new InvalidOperationException("Assumption that sorters can not interact with stations is incorrect."); } if (insertInto.EntityType == EntityType.FuelPowerGenerator) { ref OptimizedFuelGenerator reference6 = ref _generatorSegmentToOptimizedFuelGenerators[offset][index]; if (itemId == reference6.fuelId.ItemIndex) { if (reference6.fuelCount < 10) { ref short fuelCount = ref reference6.fuelCount; fuelCount += itemCount; ref short fuelInc = ref reference6.fuelInc; fuelInc += itemInc; remainInc = 0; return itemCount; } return 0; } if (reference6.fuelId.ItemIndex == 0) { if (_fuelNeeds == null) { throw new InvalidOperationException("_fuelNeeds was null when inserter attempted to insert into FuelPowerGenerator."); } OptimizedItemId[] array = _fuelNeeds[reference6.fuelMask]; if (array == null || array.Length == 0) { return 0; } for (int k = 0; k < array.Length; k++) { if (array[k].ItemIndex == itemId) { reference6.SetNewFuel(array[k], itemCount, itemInc); remainInc = 0; return itemCount; } } return 0; } return 0; } if (insertInto.EntityType == EntityType.Splitter) { throw new InvalidOperationException("Assumption that sorters can not interact with splitters is incorrect."); } return 0; } public void Save(PlanetFactory planet) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) InserterComponent[] inserterPool = planet.factorySystem.inserterPool; TInserter[] optimizedInserters = _optimizedInserters; OptimizedInserterStage[] optimizedInserterStages = _optimizedInserterStages; for (int i = 1; i < planet.factorySystem.inserterCursor; i++) { if (_inserterIdToOptimizedIndex.TryGetValue(i, out var value)) { optimizedInserters[value].Save(ref inserterPool[i], ToEInserterStage(optimizedInserterStages[value])); } } } public void Initialize(PlanetFactory planet, OptimizedSubFactory subFactory, Graph subFactoryGraph, Func inserterSelector, OptimizedPowerSystemInserterBuilder optimizedPowerSystemInserterBuilder, BeltExecutor beltExecutor, UniverseStaticDataBuilder universeStaticDataBuilder, UniverseInserterStaticDataBuilder universeInserterStaticDataBuilder) { //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_030d: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_03c6: Unknown result type (might be due to invalid IL or missing references) //IL_03cb: Unknown result type (might be due to invalid IL or missing references) //IL_049d: Unknown result type (might be due to invalid IL or missing references) List inserterNetworkIds = new List(); List inserterStates = new List(); List inserterConnections = new List(); List optimizedInserters = new List(); List optimizedInserterStages = new List(); Dictionary dictionary = new Dictionary(); PrototypePowerConsumptionBuilder prototypePowerConsumptionBuilder = new PrototypePowerConsumptionBuilder(); foreach (int item in from x in subFactoryGraph.GetAllNodes() where x.EntityTypeIndex.EntityType == EntityType.Inserter select x.EntityTypeIndex.Index into x orderby x select x) { ref InserterComponent reference = ref planet.factorySystem.inserterPool[item]; if (!inserterSelector(reference)) { continue; } TypedObjectIndex typedObjectIndex = new TypedObjectIndex(EntityType.None, 0); if (reference.pickTarget != 0) { typedObjectIndex = subFactory.GetAsGranularTypedObjectIndex(reference.pickTarget, planet); if (typedObjectIndex.EntityType == EntityType.None) { continue; } TypedObjectIndex typedObjectIndex2 = new TypedObjectIndex(EntityType.None, 0); if (reference.insertTarget != 0) { typedObjectIndex2 = subFactory.GetAsGranularTypedObjectIndex(reference.insertTarget, planet); if (typedObjectIndex2.EntityType == EntityType.None || typedObjectIndex.EntityType == EntityType.None || typedObjectIndex2.EntityType == EntityType.None) { continue; } if (typedObjectIndex.EntityType == EntityType.FuelPowerGenerator && typedObjectIndex2.EntityType == EntityType.FuelPowerGenerator && planet.powerSystem.genPool[typedObjectIndex2.Index].id != typedObjectIndex2.Index) { WeaverFixes.Logger.LogMessage((object)"Power generator did not exist."); continue; } if (typedObjectIndex.EntityType == EntityType.FuelPowerGenerator && typedObjectIndex2.EntityType == EntityType.FuelPowerGenerator && (planet.powerSystem.genPool[typedObjectIndex.Index].fuelMask & planet.powerSystem.genPool[typedObjectIndex2.Index].fuelMask) == 0) { WeaverFixes.Logger.LogMessage((object)"Power generator masks did not match at all."); continue; } dictionary.Add(item, optimizedInserters.Count); int networkId = planet.powerSystem.consumerPool[reference.pcId].networkId; inserterNetworkIds.Add(ConverterUtilities.ThrowIfNotWithinPositiveShortRange(networkId, "networkIndex")); inserterStates.Add(InserterState.Active); optimizedPowerSystemInserterBuilder.AddInserter(ref reference, networkId); TInserterGrade inserterGrade = default(TInserterGrade).Create(ref reference); int grade = universeInserterStaticDataBuilder.AddInserterGrade(ref inserterGrade); int num = reference.pickOffset; if (typedObjectIndex.EntityType == EntityType.Belt) { BeltComponent belt = planet.cargoTraffic.beltPool[typedObjectIndex.Index]; if (beltExecutor.TryGetOptimizedCargoPathIndex(planet, typedObjectIndex.Index, out var beltIndex)) { num = GetCorrectedPickOffset(reference.pickOffset, ref belt, ref beltIndex.GetBelt(beltExecutor.OptimizedCargoPaths)); typedObjectIndex = new TypedObjectIndex(typedObjectIndex.EntityType, beltIndex.GetIndex()); } num += ((BeltComponent)(ref belt)).pivotOnPath; } else if (typedObjectIndex.EntityType == EntityType.FuelPowerGenerator) { OptimizedFuelGeneratorLocation optimizedFuelGeneratorLocation = optimizedPowerSystemInserterBuilder.GetOptimizedFuelGeneratorLocation(typedObjectIndex.Index); num = optimizedFuelGeneratorLocation.SegmentIndex; typedObjectIndex = new TypedObjectIndex(typedObjectIndex.EntityType, optimizedFuelGeneratorLocation.Index); } int num2 = reference.insertOffset; if (typedObjectIndex2.EntityType == EntityType.Belt) { BeltComponent belt2 = planet.cargoTraffic.beltPool[typedObjectIndex2.Index]; if (beltExecutor.TryGetOptimizedCargoPathIndex(planet, typedObjectIndex2.Index, out var beltIndex2)) { num2 = GetCorrectedInsertOffset(reference.insertOffset, ref belt2, ref beltIndex2.GetBelt(beltExecutor.OptimizedCargoPaths)); typedObjectIndex2 = new TypedObjectIndex(typedObjectIndex2.EntityType, beltIndex2.GetIndex()); } num2 += ((BeltComponent)(ref belt2)).pivotOnPath; } else if (typedObjectIndex2.EntityType == EntityType.FuelPowerGenerator) { OptimizedFuelGeneratorLocation optimizedFuelGeneratorLocation2 = optimizedPowerSystemInserterBuilder.GetOptimizedFuelGeneratorLocation(typedObjectIndex2.Index); num2 = optimizedFuelGeneratorLocation2.SegmentIndex; typedObjectIndex2 = new TypedObjectIndex(typedObjectIndex2.EntityType, optimizedFuelGeneratorLocation2.Index); } inserterConnections.Add(new InserterConnections(typedObjectIndex, typedObjectIndex2)); optimizedInserters.Add(default(TInserter).Create(ref reference, num, num2, grade)); optimizedInserterStages.Add(ToOptimizedInserterStage(reference.stage)); prototypePowerConsumptionBuilder.AddPowerConsumer(ref planet.entityPool[reference.entityId]); } else { planet.entitySignPool[reference.entityId].signType = 10u; } } else { planet.entitySignPool[reference.entityId].signType = 10u; } } int[] array = (from x in inserterConnections.Select((InserterConnections x, int i) => (x, i)) orderby _subFactoryNeeds.GetTypedObjectNeedsIndex(x.x.InsertInto) select x.i).ToArray(); int[] oldIndexToNewIndex = new int[array.Length]; for (int j = 0; j < array.Length; j++) { oldIndexToNewIndex[array[j]] = j; } _inserterNetworkIds = universeStaticDataBuilder.DeduplicateArrayUnmanaged(array.Select((int x) => inserterNetworkIds[x]).ToArray()); _inserterStates = array.Select((int x) => inserterStates[x]).ToArray(); _inserterConnections = universeStaticDataBuilder.DeduplicateArray(array.Select((int x) => inserterConnections[x]).ToArray()); _optimizedInserters = array.Select((int x) => optimizedInserters[x]).ToArray(); _optimizedInserterStages = array.Select((int x) => optimizedInserterStages[x]).ToArray(); _inserterIdToOptimizedIndex = dictionary.ToDictionary((KeyValuePair x) => x.Key, (KeyValuePair x) => oldIndexToNewIndex[x.Value]); _prototypePowerConsumptionExecutor = prototypePowerConsumptionBuilder.Build(universeStaticDataBuilder, array); } private void Print(int inserterIndex) { WeaverFixes.Logger.LogMessage((object)_optimizedInserters[inserterIndex].ToString()); ManualLogSource logger = WeaverFixes.Logger; short num = _inserterNetworkIds[inserterIndex]; logger.LogMessage((object)num.ToString(CultureInfo.InvariantCulture)); WeaverFixes.Logger.LogMessage((object)_inserterStates[inserterIndex].ToString()); WeaverFixes.Logger.LogMessage((object)_inserterConnections[inserterIndex].ToString()); } private static OptimizedInserterStage ToOptimizedInserterStage(EInserterStage inserterStage) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected I4, but got Unknown return (int)inserterStage switch { 0 => OptimizedInserterStage.Picking, 1 => OptimizedInserterStage.Sending, 2 => OptimizedInserterStage.Inserting, 3 => OptimizedInserterStage.Returning, _ => throw new ArgumentOutOfRangeException("inserterStage"), }; } private static EInserterStage ToEInserterStage(OptimizedInserterStage inserterStage) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) return (EInserterStage)(inserterStage switch { OptimizedInserterStage.Picking => 0, OptimizedInserterStage.Sending => 1, OptimizedInserterStage.Inserting => 2, OptimizedInserterStage.Returning => 3, _ => throw new ArgumentOutOfRangeException("inserterStage"), }); } private static int GetCorrectedPickOffset(int pickOffset, [In][RequiresLocation] ref BeltComponent belt, [In][RequiresLocation] ref OptimizedCargoPath cargoPath) { int num = belt.segPivotOffset + belt.segIndex; int num2 = num + pickOffset; if (num2 < 4) { num2 = 4; } if (num2 + 5 >= cargoPath.pathLength) { num2 = cargoPath.pathLength - 5 - 1; } return num2 - num; } private static int GetCorrectedInsertOffset(int insertOffset, [In][RequiresLocation] ref BeltComponent belt, [In][RequiresLocation] ref OptimizedCargoPath cargoPath) { int num = belt.segPivotOffset + belt.segIndex; int num2 = num + insertOffset; if (num2 < 4) { num2 = 4; } if (num2 + 5 >= cargoPath.pathLength) { num2 = cargoPath.pathLength - 5 - 1; } return num2 - num; } } [Flags] internal enum InserterState : byte { Active = 0, Inactive = 4, InactivePickFrom = 5, InactiveInsertInto = 6 } public enum OptimizedInserterStage : byte { Picking, Sending, Inserting, Returning } } namespace Weaver.Optimizations.Inserters.Types { internal interface IInserter where TInserter : struct, IInserter where TInserterGrade : struct, IInserterGrade, IMemorySize { short grade { get; } int pickOffset { get; } int insertOffset { get; } TInserter Create([In][RequiresLocation] ref InserterComponent inserter, int pickFromOffset, int insertIntoOffset, int grade); ReadonlyArray GetInserterGrades(UniverseStaticData universeStaticData); void Update(PlanetFactory planet, InserterExecutor inserterExecutor, float power, int inserterIndex, ref InserterState inserterState, [In][RequiresLocation] ref TInserterGrade inserterGrade, ref OptimizedInserterStage stage, ReadonlyArray insertersConnections, SubFactoryNeeds subFactoryNeeds, OptimizedCargoPath[] optimizedCargoPaths); void Save(ref InserterComponent inserter, EInserterStage inserterStage); } [StructLayout(LayoutKind.Sequential, Pack = 1)] internal readonly struct BiInserterGrade : IInserterGrade, IEquatable, IMemorySize { public readonly short Filter; public readonly byte StackInput; public readonly byte StackOutput; public readonly bool CareNeeds; public BiInserterGrade(byte stackInput, byte stackOutput, bool careNeeds, int filter) { if (filter < 0 || filter > 32767) { throw new ArgumentOutOfRangeException("filter", string.Format("{0} was not within the bounds of a short. Value: {1}", "filter", filter)); } StackInput = stackInput; StackOutput = stackOutput; CareNeeds = careNeeds; Filter = (short)filter; } public BiInserterGrade Create(ref InserterComponent inserter) { byte stackInput = (byte)GameMain.history.inserterStackCountObsolete; byte stackInput2 = (byte)GameMain.history.inserterStackInput; byte stackOutput = (byte)GameMain.history.inserterStackOutput; if (inserter.grade == 3) { return new BiInserterGrade(stackInput, 1, inserter.careNeeds, inserter.filter); } if (inserter.grade == 4) { return new BiInserterGrade(stackInput2, stackOutput, inserter.careNeeds, inserter.filter); } return new BiInserterGrade(1, 1, inserter.careNeeds, inserter.filter); } public int GetSize() { return Marshal.SizeOf(); } public bool Equals(BiInserterGrade other) { if (StackInput == other.StackInput && StackOutput == other.StackOutput && CareNeeds == other.CareNeeds) { return Filter == other.Filter; } return false; } public override bool Equals(object obj) { if (obj is BiInserterGrade other) { return Equals(other); } return false; } public override int GetHashCode() { return HashCode.Combine(StackInput, StackOutput, CareNeeds, Filter); } } [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct OptimizedBiInserter : IInserter { private short itemId; private short itemCount; private short itemInc; private int stackCount; private int idleTick; public short grade { get; } public int pickOffset { get; } public int insertOffset { get; } public OptimizedBiInserter([In][RequiresLocation] ref InserterComponent inserter, int pickFromOffset, int insertIntoOffset, int grade) { if (grade < 0 || grade > 32767) { throw new ArgumentOutOfRangeException("grade", string.Format("{0} was not within the bounds of a short. Value: {1}", "grade", grade)); } if (inserter.itemId < 0 || inserter.itemId > 32767) { throw new ArgumentOutOfRangeException("itemId", string.Format("{0} was not within the bounds of a short. Value: {1}", "itemId", inserter.itemId)); } this.grade = (short)grade; pickOffset = pickFromOffset; insertOffset = insertIntoOffset; itemId = (short)inserter.itemId; itemCount = inserter.itemCount; itemInc = inserter.itemInc; stackCount = inserter.stackCount; idleTick = inserter.idleTick; } public readonly OptimizedBiInserter Create([In][RequiresLocation] ref InserterComponent inserter, int pickFromOffset, int insertIntoOffset, int grade) { return new OptimizedBiInserter(ref inserter, pickFromOffset, insertIntoOffset, grade); } public readonly ReadonlyArray GetInserterGrades(UniverseStaticData universeStaticData) { return universeStaticData.BiInserterGrades; } internal static bool IsNeedsNotEmpty(ReadonlyArray insertersConnections, SubFactoryNeeds subFactoryNeeds, int inserterIndex, InserterConnections inserterConnections, out GroupNeeds groupNeeds) { inserterConnections = insertersConnections[inserterIndex]; groupNeeds = subFactoryNeeds.GetGroupNeeds(inserterConnections.InsertInto.EntityType); if (groupNeeds.GroupNeedsSize == 0 || inserterConnections.InsertInto.EntityType == EntityType.FuelPowerGenerator) { return true; } int objectNeedsIndex = groupNeeds.GetObjectNeedsIndex(inserterConnections.InsertInto.Index); return subFactoryNeeds.ComponentsNeeds[objectNeedsIndex].Needs != 0; } internal static bool IsNeedsEmpty(SubFactoryNeeds subFactoryNeeds, InserterConnections inserterConnections, out GroupNeeds groupNeeds) { groupNeeds = subFactoryNeeds.GetGroupNeeds(inserterConnections.InsertInto.EntityType); if (groupNeeds.GroupNeedsSize == 0 || inserterConnections.InsertInto.EntityType == EntityType.FuelPowerGenerator) { return false; } int objectNeedsIndex = groupNeeds.GetObjectNeedsIndex(inserterConnections.InsertInto.Index); return subFactoryNeeds.ComponentsNeeds[objectNeedsIndex].Needs == 0; } public void Update(PlanetFactory planet, InserterExecutor inserterExecutor, float power, int inserterIndex, ref InserterState inserterState, [In][RequiresLocation] ref BiInserterGrade inserterGrade, ref OptimizedInserterStage stage, ReadonlyArray insertersConnections, SubFactoryNeeds subFactoryNeeds, OptimizedCargoPath[] optimizedCargoPaths) { if (power < 0.1f) { inserterState = InserterState.Active; return; } bool flag = false; int num = 1; do { InserterConnections inserterConnections = insertersConnections[inserterIndex]; GroupNeeds groupNeeds = default(GroupNeeds); int filter; if (itemId == 0) { if (inserterGrade.CareNeeds) { if (idleTick-- >= 1) { break; } if (!IsNeedsNotEmpty(insertersConnections, subFactoryNeeds, inserterIndex, inserterConnections, out groupNeeds)) { idleTick = 9; break; } } else if (inserterConnections.InsertInto.EntityType == EntityType.FuelPowerGenerator) { if (idleTick-- >= 1) { continue; } byte stack; byte inc; bool fuelFull; short num2 = inserterExecutor.PickFuelForPowerGenFrom(planet, ref inserterState, pickOffset, insertOffset, inserterGrade.Filter, inserterConnections, out stack, out inc, out fuelFull, optimizedCargoPaths); if (num2 <= 0) { if (fuelFull) { idleTick = 9; } break; } itemId = num2; itemCount += stack; itemInc += inc; stackCount++; flag = true; } filter = inserterGrade.Filter; } else { if (stackCount >= inserterGrade.StackInput || (inserterGrade.Filter != 0 && inserterGrade.Filter != itemId)) { break; } if (inserterGrade.CareNeeds) { if (idleTick-- >= 1) { break; } if (!IsNeedsNotEmpty(insertersConnections, subFactoryNeeds, inserterIndex, inserterConnections, out groupNeeds)) { idleTick = 10; break; } } filter = itemId; } byte stack2; byte inc2; short num3 = inserterExecutor.PickFrom(planet, ref inserterState, inserterIndex, pickOffset, filter, inserterConnections, groupNeeds, out stack2, out inc2, optimizedCargoPaths); if (num3 <= 0) { break; } itemId = num3; itemCount += stack2; itemInc += inc2; stackCount++; flag = true; } while (num-- > 0); num = 1; int num4 = 0; do { if (itemId == 0 || stackCount == 0) { itemId = 0; stackCount = 0; itemCount = 0; itemInc = 0; break; } if (idleTick-- >= 1) { break; } InserterConnections inserterConnections2 = insertersConnections[inserterIndex]; TypedObjectIndex typedObjectIndex = ((inserterGrade.StackOutput > 1) ? inserterConnections2.InsertInto : default(TypedObjectIndex)); if (typedObjectIndex.EntityType == EntityType.Belt) { int count = itemCount; int inc3 = itemInc; optimizedCargoPaths[typedObjectIndex.Index].TryInsertItemWithStackIncreasement(insertOffset, itemId, inserterGrade.StackOutput, ref count, ref inc3); if (count < itemCount) { num4 = itemId; } itemCount = (short)count; itemInc = (short)inc3; stackCount = ((itemCount > 0) ? ((itemCount - 1) / 4 + 1) : 0); if (stackCount == 0) { itemId = 0; itemCount = 0; itemInc = 0; break; } num = 0; continue; } GroupNeeds groupNeeds2 = default(GroupNeeds); if (inserterGrade.CareNeeds && IsNeedsEmpty(subFactoryNeeds, inserterConnections2, out groupNeeds2)) { idleTick = 10; break; } int num5 = itemCount / stackCount; int num6 = (int)((float)itemInc / (float)itemCount * (float)num5 + 0.5f); byte remainInc; int num7 = inserterExecutor.InsertInto(planet, ref inserterState, inserterIndex, inserterConnections2, groupNeeds2, insertOffset, itemId, (byte)num5, (byte)num6, out remainInc, optimizedCargoPaths); if (inserterConnections2.InsertInto.EntityType == EntityType.FuelPowerGenerator && num7 == 0) { idleTick = 10; break; } if (num7 <= 0) { break; } if (remainInc == 0 && num7 == num5) { stackCount--; } itemCount -= (short)num7; itemInc -= (short)(num6 - remainInc); num4 = itemId; if (stackCount == 0) { itemId = 0; itemCount = 0; itemInc = 0; break; } } while (num-- > 0); if (flag || num4 > 0) { stage = OptimizedInserterStage.Sending; } else if (itemId > 0) { stage = OptimizedInserterStage.Inserting; } else { stage = ((stage == OptimizedInserterStage.Sending) ? OptimizedInserterStage.Returning : OptimizedInserterStage.Picking); } } public readonly void Save(ref InserterComponent inserter, EInserterStage inserterStage) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) inserter.itemId = itemId; inserter.itemCount = itemCount; inserter.itemInc = itemInc; inserter.stackCount = stackCount; inserter.idleTick = idleTick; inserter.stage = inserterStage; } public override readonly string ToString() { return string.Format("Bi Inserter\r\n\\t{0}: {1:N0}\r\n\\t{2}: {3:N0}\r\n\\t{4}: {5:N0}\r\n\\t{6}: {7:N0}\r\n\\t{8}: {9:N0}\r\n\\t{10}: {11:N0}\r\n\\t{12}: {13:N0}\r\n\\t{14}: {15:N0}", "grade", grade, "pickOffset", pickOffset, "insertOffset", insertOffset, "itemId", itemId, "itemCount", itemCount, "itemInc", itemInc, "stackCount", stackCount, "idleTick", idleTick); } OptimizedBiInserter IInserter.Create([In][RequiresLocation] ref InserterComponent inserter, int pickFromOffset, int insertIntoOffset, int grade) { return Create(ref inserter, pickFromOffset, insertIntoOffset, grade); } void IInserter.Update(PlanetFactory planet, InserterExecutor inserterExecutor, float power, int inserterIndex, ref InserterState inserterState, [In][RequiresLocation] ref BiInserterGrade inserterGrade, ref OptimizedInserterStage stage, ReadonlyArray insertersConnections, SubFactoryNeeds subFactoryNeeds, OptimizedCargoPath[] optimizedCargoPaths) { Update(planet, inserterExecutor, power, inserterIndex, ref inserterState, ref inserterGrade, ref stage, insertersConnections, subFactoryNeeds, optimizedCargoPaths); } } [StructLayout(LayoutKind.Sequential, Pack = 1)] internal readonly struct InserterGrade : IInserterGrade, IEquatable, IMemorySize { public readonly int Delay; public readonly int Stt; public readonly short Filter; public readonly byte StackInput; public readonly byte StackOutput; public readonly bool CareNeeds; public InserterGrade(int delay, byte stackInput, byte stackOutput, bool careNeeds, int filter, int stt) { if (filter < 0 || filter > 32767) { throw new ArgumentOutOfRangeException("filter", string.Format("{0} was not within the bounds of a short. Value: {1}", "filter", filter)); } Delay = delay; StackInput = stackInput; StackOutput = stackOutput; CareNeeds = careNeeds; Filter = (short)filter; Stt = stt; } public InserterGrade Create(ref InserterComponent inserter) { byte b = (byte)GameMain.history.inserterStackCountObsolete; byte b2 = (byte)GameMain.history.inserterStackInput; byte stackOutput = (byte)GameMain.history.inserterStackOutput; int delay = ((b > 1) ? 110000 : 0); int delay2 = ((b2 > 1) ? 40000 : 0); if (inserter.grade == 3) { return new InserterGrade(delay, b, 1, inserter.careNeeds, inserter.filter, inserter.stt); } if (inserter.grade == 4) { return new InserterGrade(delay2, b2, stackOutput, inserter.careNeeds, inserter.filter, inserter.stt); } return new InserterGrade(0, 1, 1, inserter.careNeeds, inserter.filter, inserter.stt); } public int GetSize() { return Marshal.SizeOf(); } public bool Equals(InserterGrade other) { if (Delay == other.Delay && StackInput == other.StackInput && StackOutput == other.StackOutput && CareNeeds == other.CareNeeds && Filter == other.Filter) { return Stt == other.Stt; } return false; } public override bool Equals(object obj) { if (obj is InserterGrade other) { return Equals(other); } return false; } public override int GetHashCode() { return HashCode.Combine(Delay, StackInput, StackOutput, CareNeeds, Filter, Stt); } } [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct OptimizedInserter : IInserter { private int time; private short itemId; private short itemCount; private short itemInc; private int stackCount; private int idleTick; public short grade { get; } public int pickOffset { get; } public int insertOffset { get; } public OptimizedInserter([In][RequiresLocation] ref InserterComponent inserter, int pickFromOffset, int insertIntoOffset, int grade) { if (grade < 0 || grade > 32767) { throw new ArgumentOutOfRangeException("grade", string.Format("{0} was not within the bounds of a short. Value: {1}", "grade", grade)); } if (inserter.itemId < 0 || inserter.itemId > 32767) { throw new ArgumentOutOfRangeException("itemId", string.Format("{0} was not within the bounds of a short. Value: {1}", "itemId", inserter.itemId)); } this.grade = (short)grade; pickOffset = pickFromOffset; insertOffset = insertIntoOffset; time = inserter.time; itemId = (short)inserter.itemId; itemCount = inserter.itemCount; itemInc = inserter.itemInc; stackCount = inserter.stackCount; idleTick = inserter.idleTick; } public readonly OptimizedInserter Create([In][RequiresLocation] ref InserterComponent inserter, int pickFromOffset, int insertIntoOffset, int grade) { return new OptimizedInserter(ref inserter, pickFromOffset, insertIntoOffset, grade); } public readonly ReadonlyArray GetInserterGrades(UniverseStaticData universeStaticData) { return universeStaticData.InserterGrades; } public void Update(PlanetFactory planet, InserterExecutor inserterExecutor, float power, int inserterIndex, ref InserterState inserterState, [In][RequiresLocation] ref InserterGrade inserterGrade, ref OptimizedInserterStage stage, ReadonlyArray insertersConnections, SubFactoryNeeds subFactoryNeeds, OptimizedCargoPath[] optimizedCargoPaths) { if (power < 0.1f) { return; } InserterConnections inserterConnections2; GroupNeeds groupNeeds2; int filter; short num4; byte stack; byte inc2; switch (stage) { case OptimizedInserterStage.Picking: inserterConnections2 = insertersConnections[inserterIndex]; groupNeeds2 = default(GroupNeeds); if (itemId == 0) { if (inserterGrade.CareNeeds) { if (idleTick-- <= 0) { if (OptimizedBiInserter.IsNeedsNotEmpty(insertersConnections, subFactoryNeeds, inserterIndex, inserterConnections2, out groupNeeds2)) { goto IL_0138; } idleTick = 9; } } else { if (inserterConnections2.InsertInto.EntityType != EntityType.FuelPowerGenerator) { goto IL_0138; } if (idleTick-- <= 0) { byte stack2; byte inc3; bool fuelFull; short num5 = inserterExecutor.PickFuelForPowerGenFrom(planet, ref inserterState, pickOffset, insertOffset, inserterGrade.Filter, inserterConnections2, out stack2, out inc3, out fuelFull, optimizedCargoPaths); if (num5 > 0) { itemId = num5; itemCount += stack2; itemInc += inc3; stackCount++; time = 0; } else if (fuelFull) { idleTick = 9; } } } } else if (stackCount < inserterGrade.StackInput) { if (!inserterGrade.CareNeeds) { goto IL_018e; } if (idleTick-- <= 0) { if (OptimizedBiInserter.IsNeedsNotEmpty(insertersConnections, subFactoryNeeds, inserterIndex, inserterConnections2, out groupNeeds2)) { goto IL_018e; } idleTick = 10; } } goto IL_01f3; case OptimizedInserterStage.Sending: time += (int)(power * 10000f); if (time >= inserterGrade.Stt) { stage = OptimizedInserterStage.Inserting; time -= inserterGrade.Stt; } if (itemId == 0) { stage = OptimizedInserterStage.Returning; time = inserterGrade.Stt - time; } break; case OptimizedInserterStage.Inserting: if (itemId == 0 || stackCount == 0) { itemId = 0; stackCount = 0; itemCount = 0; itemInc = 0; time += (int)(power * 10000f); stage = OptimizedInserterStage.Returning; } else { if (idleTick-- >= 1) { break; } InserterConnections inserterConnections = insertersConnections[inserterIndex]; TypedObjectIndex typedObjectIndex = ((inserterGrade.StackOutput > 1) ? inserterConnections.InsertInto : default(TypedObjectIndex)); if (typedObjectIndex.EntityType == EntityType.Belt) { int count = itemCount; int inc = itemInc; optimizedCargoPaths[typedObjectIndex.Index].TryInsertItemWithStackIncreasement(insertOffset, itemId, inserterGrade.StackOutput, ref count, ref inc); itemCount = (short)count; itemInc = (short)inc; stackCount = ((itemCount > 0) ? ((itemCount - 1) / 4 + 1) : 0); if (stackCount == 0) { itemId = 0; time += (int)(power * 10000f); stage = OptimizedInserterStage.Returning; itemCount = 0; itemInc = 0; } break; } GroupNeeds groupNeeds = default(GroupNeeds); if (inserterGrade.CareNeeds && OptimizedBiInserter.IsNeedsEmpty(subFactoryNeeds, inserterConnections, out groupNeeds)) { idleTick = 10; break; } int num = itemCount / stackCount; int num2 = (int)((float)itemInc / (float)itemCount * (float)num + 0.5f); byte remainInc; int num3 = inserterExecutor.InsertInto(planet, ref inserterState, inserterIndex, inserterConnections, groupNeeds, insertOffset, itemId, (byte)num, (byte)num2, out remainInc, optimizedCargoPaths); if (inserterConnections.InsertInto.EntityType == EntityType.FuelPowerGenerator && num3 == 0) { idleTick = 10; } else if (num3 > 0) { if (remainInc == 0 && num3 == num) { stackCount--; } itemCount -= (short)num3; itemInc -= (short)(num2 - remainInc); if (stackCount == 0) { itemId = 0; time += (int)(power * 10000f); stage = OptimizedInserterStage.Returning; itemCount = 0; itemInc = 0; } } } break; case OptimizedInserterStage.Returning: { time += (int)(power * 10000f); if (time >= inserterGrade.Stt) { stage = OptimizedInserterStage.Picking; time = 0; } break; } IL_018e: filter = itemId; goto IL_0195; IL_01f3: if (itemId > 0) { time += 10000; if (stackCount == inserterGrade.StackInput || time >= inserterGrade.Delay) { time = (int)(power * 10000f); stage = OptimizedInserterStage.Sending; } } else { time = 0; } break; IL_0138: filter = inserterGrade.Filter; goto IL_0195; IL_0195: num4 = inserterExecutor.PickFrom(planet, ref inserterState, inserterIndex, pickOffset, filter, inserterConnections2, groupNeeds2, out stack, out inc2, optimizedCargoPaths); if (num4 > 0) { itemId = num4; itemCount += stack; itemInc += inc2; stackCount++; time = 0; } goto IL_01f3; } } public readonly void Save(ref InserterComponent inserter, EInserterStage inserterStage) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) inserter.time = time; inserter.itemId = itemId; inserter.itemCount = itemCount; inserter.itemInc = itemInc; inserter.stackCount = stackCount; inserter.idleTick = idleTick; inserter.stage = inserterStage; } OptimizedInserter IInserter.Create([In][RequiresLocation] ref InserterComponent inserter, int pickFromOffset, int insertIntoOffset, int grade) { return Create(ref inserter, pickFromOffset, insertIntoOffset, grade); } void IInserter.Update(PlanetFactory planet, InserterExecutor inserterExecutor, float power, int inserterIndex, ref InserterState inserterState, [In][RequiresLocation] ref InserterGrade inserterGrade, ref OptimizedInserterStage stage, ReadonlyArray insertersConnections, SubFactoryNeeds subFactoryNeeds, OptimizedCargoPath[] optimizedCargoPaths) { Update(planet, inserterExecutor, power, inserterIndex, ref inserterState, ref inserterGrade, ref stage, insertersConnections, subFactoryNeeds, optimizedCargoPaths); } } } namespace Weaver.Optimizations.Fractionators { [StructLayout(LayoutKind.Sequential, Pack = 1)] internal readonly struct FractionatorConfiguration : IEquatable, IMemorySize { public readonly int FluidInputMax; public readonly int FluidOutputMax; public readonly int ProductOutputMax; public readonly bool IsOutput0; public readonly bool IsOutput1; public readonly bool IsOutput2; public FractionatorConfiguration(bool isOutput0, bool isOutput1, bool isOutput2, int fluidInputMax, int fluidOutputMax, int productOutputMax) { IsOutput0 = isOutput0; IsOutput1 = isOutput1; IsOutput2 = isOutput2; FluidInputMax = fluidInputMax; FluidOutputMax = fluidOutputMax; ProductOutputMax = productOutputMax; } public int GetSize() { return Marshal.SizeOf(); } public bool Equals(FractionatorConfiguration other) { if (IsOutput0 == other.IsOutput0 && IsOutput1 == other.IsOutput1 && IsOutput2 == other.IsOutput2 && FluidInputMax == other.FluidInputMax && FluidOutputMax == other.FluidOutputMax) { return ProductOutputMax == other.ProductOutputMax; } return false; } public override bool Equals(object obj) { if (obj is FractionatorConfiguration other) { return Equals(other); } return false; } public override int GetHashCode() { return HashCode.Combine(IsOutput0, IsOutput1, IsOutput2, FluidInputMax, FluidOutputMax, ProductOutputMax); } } internal sealed class FractionatorExecutor { private ReadonlyArray _fractionatorNetworkId; private OptimizedFractionator[] _optimizedFractionators; private FractionatorPowerFields[] _fractionatorsPowerFields; private FractionatorRecipeProduct[] _fractionatorRecipeProducts; public Dictionary _fractionatorIdToOptimizedIndex; private PrototypePowerConsumptionExecutor _prototypePowerConsumptionExecutor; public int Count => _optimizedFractionators.Length; public void GameTick(PlanetFactory planet, ReadonlyArray fractionatorPowerConsumerTypeIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption, int[] productRegister, int[] consumeRegister, OptimizedCargoPath[] optimizedCargoPaths, UniverseStaticData universeStaticData) { float[] networkServes = planet.powerSystem.networkServes; ReadonlyArray fractionatorNetworkId = _fractionatorNetworkId; OptimizedFractionator[] optimizedFractionators = _optimizedFractionators; FractionatorPowerFields[] fractionatorsPowerFields = _fractionatorsPowerFields; ReadonlyArray fractionatorConfigurations = universeStaticData.FractionatorConfigurations; FractionatorRecipeProduct[] fractionatorRecipeProducts = _fractionatorRecipeProducts; for (int i = 0; i < optimizedFractionators.Length; i++) { short num = fractionatorNetworkId[i]; float power = networkServes[num]; ref OptimizedFractionator reference = ref optimizedFractionators[i]; ref readonly FractionatorConfiguration configuration = ref fractionatorConfigurations[reference.configurationIndex]; ref FractionatorPowerFields fractionatorPowerFields = ref fractionatorsPowerFields[i]; reference.InternalUpdate(power, ref configuration, ref fractionatorPowerFields, fractionatorRecipeProducts, productRegister, consumeRegister, optimizedCargoPaths); UpdatePower(fractionatorPowerConsumerTypeIndexes, powerConsumerTypes, thisSubFactoryNetworkPowerConsumption, i, num, ref fractionatorPowerFields); } } public void UpdatePower(ReadonlyArray fractionatorPowerConsumerTypeIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption) { ReadonlyArray fractionatorNetworkId = _fractionatorNetworkId; FractionatorPowerFields[] fractionatorsPowerFields = _fractionatorsPowerFields; for (int i = 0; i < fractionatorsPowerFields.Length; i++) { short networkIndex = fractionatorNetworkId[i]; UpdatePower(fractionatorPowerConsumerTypeIndexes, powerConsumerTypes, thisSubFactoryNetworkPowerConsumption, i, networkIndex, ref fractionatorsPowerFields[i]); } } private static void UpdatePower(ReadonlyArray fractionatorPowerConsumerTypeIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption, int fractionatorIndex, short networkIndex, [In][RequiresLocation] ref FractionatorPowerFields fractionatorPowerFields) { int index = fractionatorPowerConsumerTypeIndexes[fractionatorIndex]; PowerConsumerType powerConsumerType = powerConsumerTypes[index]; thisSubFactoryNetworkPowerConsumption[networkIndex] += GetPowerConsumption(powerConsumerType, ref fractionatorPowerFields); } public PrototypePowerConsumptions UpdatePowerConsumptionPerPrototype(ReadonlyArray fractionatorPowerConsumerTypeIndexes, ReadonlyArray powerConsumerTypes) { PrototypePowerConsumptionExecutor prototypePowerConsumptionExecutor = _prototypePowerConsumptionExecutor; prototypePowerConsumptionExecutor.Clear(); FractionatorPowerFields[] fractionatorsPowerFields = _fractionatorsPowerFields; ReadonlyArray prototypeIdIndexes = prototypePowerConsumptionExecutor.PrototypeIdIndexes; long[] prototypeIdPowerConsumption = prototypePowerConsumptionExecutor.PrototypeIdPowerConsumption; for (int i = 0; i < fractionatorsPowerFields.Length; i++) { UpdatePowerConsumptionPerPrototype(fractionatorPowerConsumerTypeIndexes, powerConsumerTypes, prototypeIdIndexes, prototypeIdPowerConsumption, i, ref fractionatorsPowerFields[i]); } return prototypePowerConsumptionExecutor.GetPowerConsumption(); } private static void UpdatePowerConsumptionPerPrototype(ReadonlyArray fractionatorPowerConsumerTypeIndexes, ReadonlyArray powerConsumerTypes, ReadonlyArray prototypeIdIndexes, long[] prototypeIdPowerConsumption, int fractionatorIndex, [In][RequiresLocation] ref FractionatorPowerFields fractionatorPowerFields) { int index = fractionatorPowerConsumerTypeIndexes[fractionatorIndex]; PowerConsumerType powerConsumerType = powerConsumerTypes[index]; prototypeIdPowerConsumption[prototypeIdIndexes[fractionatorIndex]] += GetPowerConsumption(powerConsumerType, ref fractionatorPowerFields); } public void Save(PlanetFactory planet) { SignData[] entitySignPool = planet.entitySignPool; FractionatorComponent[] fractionatorPool = planet.factorySystem.fractionatorPool; OptimizedFractionator[] optimizedFractionators = _optimizedFractionators; FractionatorPowerFields[] fractionatorsPowerFields = _fractionatorsPowerFields; for (int i = 1; i < planet.factorySystem.fractionatorCursor; i++) { if (_fractionatorIdToOptimizedIndex.TryGetValue(i, out var value)) { ref FractionatorPowerFields fractionatorPowerFields = ref fractionatorsPowerFields[value]; optimizedFractionators[value].Save(ref fractionatorPool[i], ref fractionatorPowerFields, entitySignPool); } } } public void Initialize(PlanetFactory planet, Graph subFactoryGraph, SubFactoryPowerSystemBuilder subFactoryPowerSystemBuilder, SubFactoryProductionRegisterBuilder subFactoryProductionRegisterBuilder, BeltExecutor beltExecutor, UniverseStaticDataBuilder universeStaticDataBuilder) { List list = new List(); List list2 = new List(); List list3 = new List(); Dictionary dictionary = new Dictionary(); HashSet hashSet = new HashSet(); PrototypePowerConsumptionBuilder prototypePowerConsumptionBuilder = new PrototypePowerConsumptionBuilder(); foreach (int item2 in from x in subFactoryGraph.GetAllNodes() where x.EntityTypeIndex.EntityType == EntityType.Fractionator select x.EntityTypeIndex.Index into x orderby x select x) { ref FractionatorComponent reference = ref planet.factorySystem.fractionatorPool[item2]; if (reference.id == item2) { FractionatorConfiguration fractionatorConfiguration = new FractionatorConfiguration(reference.isOutput0, reference.isOutput1, reference.isOutput2, reference.fluidInputMax, reference.fluidOutputMax, reference.productOutputMax); int configurationIndex = universeStaticDataBuilder.AddFractionatorConfiguration(ref fractionatorConfiguration); beltExecutor.TryGetOptimizedCargoPathIndex(planet, reference.belt0, out var beltIndex); beltExecutor.TryGetOptimizedCargoPathIndex(planet, reference.belt1, out var beltIndex2); beltExecutor.TryGetOptimizedCargoPathIndex(planet, reference.belt2, out var beltIndex3); OptimizedItemId fluidId = default(OptimizedItemId); if (reference.fluidId > 0) { fluidId = subFactoryProductionRegisterBuilder.AddConsume(reference.fluidId); } OptimizedItemId productId = default(OptimizedItemId); if (reference.productId > 0) { productId = subFactoryProductionRegisterBuilder.AddProduct(reference.productId); } dictionary.Add(reference.id, list2.Count); int networkId = planet.powerSystem.consumerPool[reference.pcId].networkId; list.Add(ConverterUtilities.ThrowIfNotWithinPositiveShortRange(networkId, "networkIndex")); list2.Add(new OptimizedFractionator(beltIndex, beltIndex2, beltIndex3, configurationIndex, fluidId, productId, ref reference)); list3.Add(new FractionatorPowerFields(ref reference)); subFactoryPowerSystemBuilder.AddFractionator(ref reference, networkId); prototypePowerConsumptionBuilder.AddPowerConsumer(ref planet.entityPool[reference.entityId]); } } if (list2.Count > 0) { RecipeProto[] fractionatorRecipes = RecipeProto.fractionatorRecipes; foreach (RecipeProto val in fractionatorRecipes) { FractionatorRecipeProduct item = new FractionatorRecipeProduct(val.Items[0], subFactoryProductionRegisterBuilder.AddConsume(val.Items[0]), subFactoryProductionRegisterBuilder.AddProduct(val.Results[0]), (float)val.ResultCounts[0] / (float)val.ItemCounts[0]); hashSet.Add(item); } } _fractionatorNetworkId = universeStaticDataBuilder.DeduplicateArrayUnmanaged(list); _optimizedFractionators = list2.ToArray(); _fractionatorsPowerFields = list3.ToArray(); _fractionatorIdToOptimizedIndex = dictionary; _fractionatorRecipeProducts = hashSet.ToArray(); _prototypePowerConsumptionExecutor = prototypePowerConsumptionBuilder.Build(universeStaticDataBuilder); } private static long GetPowerConsumption(PowerConsumerType powerConsumerType, [In][RequiresLocation] ref FractionatorPowerFields fractionatorPowerFields) { double num = (((double)fractionatorPowerFields.fluidInputCargoCount > 0.0001) ? ((float)fractionatorPowerFields.fluidInputCount / fractionatorPowerFields.fluidInputCargoCount) : 4f); double num2 = (double)((fractionatorPowerFields.fluidInputCargoCount < 30f) ? fractionatorPowerFields.fluidInputCargoCount : 30f) * num - 30.0; if (num2 < 0.0) { num2 = 0.0; } int permillage = (int)((num2 * 50.0 + 1000.0) * Cargo.powerTableRatio[fractionatorPowerFields.incLevel] + 0.5); return powerConsumerType.GetRequiredEnergy(fractionatorPowerFields.isWorking, permillage); } } [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct FractionatorPowerFields { public bool isWorking; public int fluidInputCount; public float fluidInputCargoCount; public int fluidInputInc; public readonly int incLevel { get { if (fluidInputCount <= 0 || fluidInputInc <= 0) { return 0; } int num = fluidInputInc / fluidInputCount; if (num >= 10) { return 10; } return num; } } public FractionatorPowerFields([In][RequiresLocation] ref FractionatorComponent fractionator) { isWorking = fractionator.isWorking; fluidInputCount = fractionator.fluidInputCount; fluidInputCargoCount = fractionator.fluidInputCargoCount; fluidInputInc = fractionator.fluidInputInc; } } internal readonly struct FractionatorRecipeProduct : IEquatable { public readonly int GameFluidId; public readonly OptimizedItemId Fluid; public readonly OptimizedItemId Product; public readonly float ProduceProbability; public FractionatorRecipeProduct(int gameFluidId, OptimizedItemId fluid, OptimizedItemId product, float produceProbability) { GameFluidId = gameFluidId; Fluid = fluid; Product = product; ProduceProbability = produceProbability; } public bool Equals(FractionatorRecipeProduct other) { if (GameFluidId == other.GameFluidId && Fluid.Equals(other.Fluid) && Product.Equals(other.Product)) { return ProduceProbability == other.ProduceProbability; } return false; } public override bool Equals(object obj) { if (obj is FractionatorRecipeProduct other) { return Equals(other); } return false; } public override int GetHashCode() { return HashCode.Combine(GameFluidId, Fluid, Product, ProduceProbability); } } [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct OptimizedFractionator { public readonly BeltIndex belt0Index; public readonly BeltIndex belt1Index; public readonly BeltIndex belt2Index; public readonly int configurationIndex; public OptimizedItemId fluidId; public OptimizedItemId productId; public float produceProb; public int productOutputCount; public int fluidOutputCount; public int fluidOutputInc; public int progress; public bool fractionSuccess; public bool incUsed; public int fluidOutputTotal; public int productOutputTotal; public uint seed; public OptimizedFractionator(BeltIndex belt0Index, BeltIndex belt1Index, BeltIndex belt2Index, int configurationIndex, OptimizedItemId fluidId, OptimizedItemId productId, [In][RequiresLocation] ref FractionatorComponent fractionator) { this.belt0Index = belt0Index; this.belt1Index = belt1Index; this.belt2Index = belt2Index; this.configurationIndex = configurationIndex; this.fluidId = fluidId; this.productId = productId; produceProb = fractionator.produceProb; productOutputCount = fractionator.productOutputCount; fluidOutputCount = fractionator.fluidOutputCount; fluidOutputInc = fractionator.fluidOutputInc; progress = fractionator.progress; fractionSuccess = fractionator.fractionSuccess; incUsed = fractionator.incUsed; fluidOutputTotal = fractionator.fluidOutputTotal; productOutputTotal = fractionator.productOutputTotal; seed = fractionator.seed; } public void SetRecipe(int needId, FractionatorRecipeProduct[] fractionatorRecipeProducts) { incUsed = false; for (int i = 0; i < fractionatorRecipeProducts.Length; i++) { if (needId == fractionatorRecipeProducts[i].GameFluidId) { fluidId = fractionatorRecipeProducts[i].Fluid; productId = fractionatorRecipeProducts[i].Product; produceProb = fractionatorRecipeProducts[i].ProduceProbability; break; } } } public uint InternalUpdate(float power, [In][RequiresLocation] ref FractionatorConfiguration configuration, ref FractionatorPowerFields fractionatorPowerFields, FractionatorRecipeProduct[] fractionatorRecipeProducts, int[] productRegister, int[] consumeRegister, OptimizedCargoPath[] optimizedCargoPaths) { if (power < 0.1f) { return 0u; } double num = 1.0; if (fractionatorPowerFields.fluidInputCount == 0) { fractionatorPowerFields.fluidInputCargoCount = 0f; } else { num = (((double)fractionatorPowerFields.fluidInputCargoCount > 0.0001) ? ((float)fractionatorPowerFields.fluidInputCount / fractionatorPowerFields.fluidInputCargoCount) : 4f); } if (fractionatorPowerFields.fluidInputCount > 0 && productOutputCount < configuration.ProductOutputMax && fluidOutputCount < configuration.FluidOutputMax) { int num2 = (int)((double)power * 166.66666666666666 * (double)((fractionatorPowerFields.fluidInputCargoCount < 30f) ? fractionatorPowerFields.fluidInputCargoCount : 30f) * num + 0.75); progress += num2; if (progress > 100000) { progress = 100000; } while (progress >= 10000) { int num3 = ((fractionatorPowerFields.fluidInputInc > 0 && fractionatorPowerFields.fluidInputCount > 0) ? (fractionatorPowerFields.fluidInputInc / fractionatorPowerFields.fluidInputCount) : 0); if (!incUsed) { incUsed = num3 > 0; } seed = (uint)((int)((ulong)((long)(seed % 2147483646 + 1) * 48271L) % 2147483647uL) - 1); fractionSuccess = (double)seed / 2147483646.0 < (double)produceProb * (1.0 + Cargo.accTableMilli[(num3 < 10) ? num3 : 10]); if (fractionSuccess) { productOutputCount++; productOutputTotal++; productRegister[productId.OptimizedItemIndex]++; consumeRegister[fluidId.OptimizedItemIndex]++; } else { fluidOutputCount++; fluidOutputTotal++; fluidOutputInc += num3; } fractionatorPowerFields.fluidInputCount--; fractionatorPowerFields.fluidInputInc -= num3; fractionatorPowerFields.fluidInputCargoCount -= (float)(1.0 / num); if (fractionatorPowerFields.fluidInputCargoCount < 0f) { fractionatorPowerFields.fluidInputCargoCount = 0f; } progress -= 10000; } } else { fractionSuccess = false; } if (belt1Index.HasValue) { ref OptimizedCargoPath belt = ref belt1Index.GetBelt(optimizedCargoPaths); if (configuration.IsOutput1) { if (fluidOutputCount > 0) { int num4 = fluidOutputInc / fluidOutputCount; if (belt.TryUpdateItemAtHeadAndFillBlank(fluidId.ItemIndex, Mathf.CeilToInt((float)(num - 0.1)), 1, (byte)num4)) { fluidOutputCount--; fluidOutputInc -= num4; if (fluidOutputCount > 0) { num4 = fluidOutputInc / fluidOutputCount; if (belt.TryUpdateItemAtHeadAndFillBlank(fluidId.ItemIndex, Mathf.CeilToInt((float)(num - 0.1)), 1, (byte)num4)) { fluidOutputCount--; fluidOutputInc -= num4; } } } } } else if (!configuration.IsOutput1 && fractionatorPowerFields.fluidInputCargoCount < (float)configuration.FluidInputMax) { OptimizedCargo cargo2; if (fluidId.ItemIndex > 0) { if (CargoPathMethods.TryPickItemAtRear(ref belt, fluidId.ItemIndex, null, out var cargo)) { fractionatorPowerFields.fluidInputCount += cargo.Stack; fractionatorPowerFields.fluidInputInc += cargo.Inc; fractionatorPowerFields.fluidInputCargoCount += 1f; } } else if (CargoPathMethods.TryPickItemAtRear(ref belt, 0, RecipeProto.fractionatorNeeds, out cargo2)) { fractionatorPowerFields.fluidInputCount += cargo2.Stack; fractionatorPowerFields.fluidInputInc += cargo2.Inc; fractionatorPowerFields.fluidInputCargoCount += 1f; SetRecipe(cargo2.Item, fractionatorRecipeProducts); } } } if (belt2Index.HasValue) { ref OptimizedCargoPath belt2 = ref belt2Index.GetBelt(optimizedCargoPaths); if (configuration.IsOutput2) { if (fluidOutputCount > 0) { int num5 = fluidOutputInc / fluidOutputCount; if (belt2.TryUpdateItemAtHeadAndFillBlank(fluidId.ItemIndex, Mathf.CeilToInt((float)(num - 0.1)), 1, (byte)num5)) { fluidOutputCount--; fluidOutputInc -= num5; if (fluidOutputCount > 0) { num5 = fluidOutputInc / fluidOutputCount; if (belt2.TryUpdateItemAtHeadAndFillBlank(fluidId.ItemIndex, Mathf.CeilToInt((float)(num - 0.1)), 1, (byte)num5)) { fluidOutputCount--; fluidOutputInc -= num5; } } } } } else if (!configuration.IsOutput2 && fractionatorPowerFields.fluidInputCargoCount < (float)configuration.FluidInputMax) { OptimizedCargo cargo4; if (fluidId.ItemIndex > 0) { if (CargoPathMethods.TryPickItemAtRear(ref belt2, fluidId.ItemIndex, null, out var cargo3)) { fractionatorPowerFields.fluidInputCount += cargo3.Stack; fractionatorPowerFields.fluidInputInc += cargo3.Inc; fractionatorPowerFields.fluidInputCargoCount += 1f; } } else if (CargoPathMethods.TryPickItemAtRear(ref belt2, 0, RecipeProto.fractionatorNeeds, out cargo4)) { fractionatorPowerFields.fluidInputCount += cargo4.Stack; fractionatorPowerFields.fluidInputInc += cargo4.Inc; fractionatorPowerFields.fluidInputCargoCount += 1f; SetRecipe(cargo4.Item, fractionatorRecipeProducts); } } } if (belt0Index.HasValue && configuration.IsOutput0 && productOutputCount > 0 && belt0Index.GetBelt(optimizedCargoPaths).TryInsertItemAtHeadAndFillBlank(productId.ItemIndex, 1, 0)) { productOutputCount--; } if (fractionatorPowerFields.fluidInputCount == 0 && fluidOutputCount == 0 && productOutputCount == 0) { fluidId = default(OptimizedItemId); } fractionatorPowerFields.isWorking = fractionatorPowerFields.fluidInputCount > 0 && productOutputCount < configuration.ProductOutputMax && fluidOutputCount < configuration.FluidOutputMax; if (!fractionatorPowerFields.isWorking) { return 0u; } return 1u; } public readonly void Save(ref FractionatorComponent fractionator, [In][RequiresLocation] ref FractionatorPowerFields fractionatorPowerFields, SignData[] signPool) { fractionator.fluidId = fluidId.ItemIndex; fractionator.productId = productId.ItemIndex; fractionator.produceProb = produceProb; fractionator.isWorking = fractionatorPowerFields.isWorking; fractionator.fluidInputCount = fractionatorPowerFields.fluidInputCount; fractionator.fluidInputCargoCount = fractionatorPowerFields.fluidInputCargoCount; fractionator.fluidInputInc = fractionatorPowerFields.fluidInputInc; fractionator.productOutputCount = productOutputCount; fractionator.fluidOutputCount = fluidOutputCount; fractionator.fluidOutputInc = fluidOutputInc; fractionator.progress = progress; fractionator.fractionSuccess = fractionSuccess; fractionator.incUsed = incUsed; fractionator.fluidOutputTotal = fluidOutputTotal; fractionator.productOutputTotal = productOutputTotal; fractionator.seed = seed; SaveRecipeSignData(ref fractionator, signPool); } private static void SaveRecipeSignData(ref FractionatorComponent fractionator, SignData[] signPool) { RecipeProto[] fractionatorRecipes = RecipeProto.fractionatorRecipes; for (int i = 0; i < fractionatorRecipes.Length; i++) { if (fractionator.fluidId == fractionatorRecipes[i].Items[0]) { signPool[fractionator.entityId].iconId0 = (uint)fractionatorRecipes[i].Results[0]; signPool[fractionator.entityId].iconType = ((fractionatorRecipes[i].Results[0] != 0) ? 1u : 0u); break; } } } } } namespace Weaver.Optimizations.Ejectors { internal sealed class EjectorExecutor { public OptimizedEjector[] _optimizedEjectors; private ReadonlyArray _optimizedBulletItemId; private ReadonlyArray _ejectorNetworkIds; public EjectorBulletData[] _ejectorBulletDatas; private int[] _directions; private ReadonlyArray _incLevels; private Dictionary _ejectorIdToOptimizedEjectorIndex; private PrototypePowerConsumptionExecutor _prototypePowerConsumptionExecutor; public const int SoleEjectorNeedsIndex = 0; public int Count => _optimizedEjectors.Length; public int GetOptimizedEjectorIndex(int ejectorId) { return _ejectorIdToOptimizedEjectorIndex[ejectorId]; } public void GameTick(PlanetFactory planet, long time, ReadonlyArray ejectorPowerConsumerTypeIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption, int[] consumeRegister, SubFactoryNeeds subFactoryNeeds) { float[] networkServes = planet.powerSystem.networkServes; AstroData[] astrosData = planet.factorySystem.planet.galaxy.astrosData; OptimizedEjector[] optimizedEjectors = _optimizedEjectors; EjectorBulletData[] ejectorBulletDatas = _ejectorBulletDatas; int[] directions = _directions; ReadonlyArray incLevels = _incLevels; ReadonlyArray optimizedBulletItemId = _optimizedBulletItemId; GroupNeeds groupNeeds = subFactoryNeeds.GetGroupNeeds(EntityType.Ejector); ComponentNeeds[] componentsNeeds = subFactoryNeeds.ComponentsNeeds; DysonSwarm val = null; if (planet.factorySystem.factory.dysonSphere != null) { val = planet.factorySystem.factory.dysonSphere.swarm; } bool flag = false; if (val != null) { for (int i = 0; i < val.orbitCursor; i++) { if (val.orbits[i].enabled) { flag = true; break; } } } ReadonlyArray ejectorNetworkIds = _ejectorNetworkIds; for (int j = 0; j < optimizedEjectors.Length; j++) { short num = ejectorNetworkIds[j]; ref int reference = ref directions[j]; int incLevel = incLevels[j]; if (flag) { ref EjectorBulletData bulletData = ref ejectorBulletDatas[j]; short optimizedBulletId = optimizedBulletItemId[j]; int objectNeedsIndex = groupNeeds.GetObjectNeedsIndex(j); float power = networkServes[num]; optimizedEjectors[j].InternalUpdate(power, time, val, astrosData, optimizedBulletId, consumeRegister, componentsNeeds, objectNeedsIndex, ref bulletData, ref reference, incLevel); } UpdatePower(ejectorPowerConsumerTypeIndexes, powerConsumerTypes, thisSubFactoryNetworkPowerConsumption, j, num, reference, incLevel); } } public void UpdatePower(PlanetFactory planet, ReadonlyArray ejectorPowerConsumerTypeIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption) { ReadonlyArray ejectorNetworkIds = _ejectorNetworkIds; int[] directions = _directions; ReadonlyArray incLevels = _incLevels; for (int i = 0; i < directions.Length; i++) { short networkIndex = ejectorNetworkIds[i]; int direction = directions[i]; int incLevel = incLevels[i]; UpdatePower(ejectorPowerConsumerTypeIndexes, powerConsumerTypes, thisSubFactoryNetworkPowerConsumption, i, networkIndex, direction, incLevel); } } private static void UpdatePower(ReadonlyArray ejectorPowerConsumerTypeIndexes, ReadonlyArray powerConsumerTypes, long[] thisSubFactoryNetworkPowerConsumption, int ejectorIndex, short networkIndex, int direction, int incLevel) { int index = ejectorPowerConsumerTypeIndexes[ejectorIndex]; PowerConsumerType powerConsumerType = powerConsumerTypes[index]; thisSubFactoryNetworkPowerConsumption[networkIndex] += GetPowerConsumption(powerConsumerType, direction, incLevel); } public PrototypePowerConsumptions UpdatePowerConsumptionPerPrototype(ReadonlyArray ejectorPowerConsumerTypeIndexes, ReadonlyArray powerConsumerTypes) { PrototypePowerConsumptionExecutor prototypePowerConsumptionExecutor = _prototypePowerConsumptionExecutor; prototypePowerConsumptionExecutor.Clear(); int[] directions = _directions; ReadonlyArray incLevels = _incLevels; ReadonlyArray prototypeIdIndexes = prototypePowerConsumptionExecutor.PrototypeIdIndexes; long[] prototypeIdPowerConsumption = prototypePowerConsumptionExecutor.PrototypeIdPowerConsumption; for (int i = 0; i < directions.Length; i++) { int direction = directions[i]; int incLevel = incLevels[i]; UpdatePowerConsumptionPerPrototype(ejectorPowerConsumerTypeIndexes, powerConsumerTypes, prototypeIdIndexes, prototypeIdPowerConsumption, i, direction, incLevel); } return prototypePowerConsumptionExecutor.GetPowerConsumption(); } private static void UpdatePowerConsumptionPerPrototype(ReadonlyArray ejectorPowerConsumerTypeIndexes, ReadonlyArray powerConsumerTypes, ReadonlyArray prototypeIdIndexes, long[] prototypeIdPowerConsumption, int ejectorIndex, int direction, int incLevel) { int index = ejectorPowerConsumerTypeIndexes[ejectorIndex]; PowerConsumerType powerConsumerType = powerConsumerTypes[index]; prototypeIdPowerConsumption[prototypeIdIndexes[ejectorIndex]] += GetPowerConsumption(powerConsumerType, direction, incLevel); } public void Save(PlanetFactory planet, SubFactoryNeeds subFactoryNeeds) { OptimizedEjector[] optimizedEjectors = _optimizedEjectors; EjectorBulletData[] ejectorBulletDatas = _ejectorBulletDatas; int[] directions = _directions; EjectorComponent[] ejectorPool = planet.factorySystem.ejectorPool; GroupNeeds groupNeeds = subFactoryNeeds.GetGroupNeeds(EntityType.Ejector); ComponentNeeds[] componentsNeeds = subFactoryNeeds.ComponentsNeeds; short[] needsPatterns = subFactoryNeeds.NeedsPatterns; for (int i = 1; i < planet.factorySystem.ejectorCursor; i++) { if (_ejectorIdToOptimizedEjectorIndex.TryGetValue(i, out var value)) { EjectorBulletData ejectorBulletData = ejectorBulletDatas[value]; int direction = directions[value]; optimizedEjectors[value].Save(ref ejectorPool[i], groupNeeds, componentsNeeds, needsPatterns, value, ejectorBulletData, direction); } } } public void Initialize(PlanetFactory planet, Graph subFactoryGraph, SubFactoryPowerSystemBuilder subFactoryPowerSystemBuilder, SubFactoryProductionRegisterBuilder subFactoryProductionRegisterBuilder, SubFactoryNeedsBuilder subFactoryNeedsBuilder, UniverseStaticDataBuilder universeStaticDataBuilder) { List list = new List(); List list2 = new List(); List list3 = new List(); List list4 = new List(); List list5 = new List(); List list6 = new List(); Dictionary dictionary = new Dictionary(); PrototypePowerConsumptionBuilder prototypePowerConsumptionBuilder = new PrototypePowerConsumptionBuilder(); GroupNeedsBuilder groupNeedsBuilder = subFactoryNeedsBuilder.CreateGroupNeedsBuilder(EntityType.Ejector); foreach (int item in from x in subFactoryGraph.GetAllNodes() where x.EntityTypeIndex.EntityType == EntityType.Ejector select x.EntityTypeIndex.Index into x orderby x select x) { ref EjectorComponent reference = ref planet.factorySystem.ejectorPool[item]; list.Add(subFactoryProductionRegisterBuilder.AddConsume(reference.bulletId).OptimizedItemIndex); int networkId = planet.powerSystem.consumerPool[reference.pcId].networkId; list2.Add(ConverterUtilities.ThrowIfNotWithinPositiveShortRange(networkId, "networkIndex")); list3.Add(new EjectorBulletData(reference.bulletId, reference.bulletCount, reference.bulletInc)); list4.Add(reference.direction); list5.Add(((EjectorComponent)(ref reference)).incLevel); dictionary.Add(reference.id, list6.Count); list6.Add(new OptimizedEjector(ref reference)); ref int[] needs = ref reference.needs; if (needs == null) { needs = new int[6]; } planet.entityNeeds[reference.entityId] = reference.needs; groupNeedsBuilder.AddNeeds(reference.needs, new int[1] { reference.bulletId }); subFactoryPowerSystemBuilder.AddEjector(ref reference, networkId); prototypePowerConsumptionBuilder.AddPowerConsumer(ref planet.entityPool[reference.entityId]); } _optimizedBulletItemId = universeStaticDataBuilder.DeduplicateArrayUnmanaged(list); _ejectorNetworkIds = universeStaticDataBuilder.DeduplicateArrayUnmanaged(list2); _ejectorBulletDatas = list3.ToArray(); _directions = list4.ToArray(); _incLevels = universeStaticDataBuilder.DeduplicateArrayUnmanaged(list5); _optimizedEjectors = list6.ToArray(); _ejectorIdToOptimizedEjectorIndex = dictionary; _prototypePowerConsumptionExecutor = prototypePowerConsumptionBuilder.Build(universeStaticDataBuilder); groupNeedsBuilder.Complete(); } private static long GetPowerConsumption(PowerConsumerType powerConsumerType, int direction, int incLevel) { return powerConsumerType.GetRequiredEnergy(direction != 0, 1000 + Cargo.powerTable[incLevel]); } } internal struct EjectorBulletData { public readonly short BulletId; public byte BulletCount; public byte BulletInc; public EjectorBulletData(int bulletId, int bulletCount, int bulletInc) { if (bulletId < 0 || bulletId > 32767) { throw new ArgumentOutOfRangeException("bulletId", string.Format("{0} was not within the bounds of a short. Value: {1}", "bulletId", bulletId)); } if (bulletCount < 0 || bulletCount > 255) { throw new ArgumentOutOfRangeException("bulletCount", string.Format("{0} was not within the bounds of a byte. Value: {1}", "bulletCount", bulletCount)); } if (bulletInc < 0 || bulletInc > 255) { throw new ArgumentOutOfRangeException("bulletInc", string.Format("{0} was not within the bounds of a byte. Value: {1}", "bulletInc", bulletInc)); } BulletId = (short)bulletId; BulletCount = (byte)bulletCount; BulletInc = (byte)bulletInc; } public short TakeOneBulletUnsafe(out byte inc) { inc = (byte)((BulletInc >= 0) ? ((uint)(BulletInc / BulletCount)) : 0u); BulletCount--; BulletInc -= inc; return BulletId; } } [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct OptimizedEjector { private readonly int id; private readonly int planetId; private readonly int chargeSpend; private readonly int coldSpend; private readonly float pivotY; private readonly float muzzleY; private readonly bool boost; private readonly bool autoOrbit; private readonly float localAlt; private readonly Vector3 localPosN; private readonly Quaternion localRot; private int time; private int orbitId; private int findingOrbitId; private int runtimeOrbitId; private bool incUsed; private Vector3 localDir; private double targetDist; private bool needFindNextOrbit; public OptimizedEjector([In][RequiresLocation] ref EjectorComponent ejector) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) id = ejector.id; planetId = ejector.planetId; chargeSpend = ejector.chargeSpend; coldSpend = ejector.coldSpend; pivotY = ejector.pivotY; muzzleY = ejector.muzzleY; boost = ejector.boost; autoOrbit = ejector.autoOrbit; localAlt = ejector.localAlt; localPosN = ejector.localPosN; localRot = ejector.localRot; time = ejector.time; orbitId = ejector.orbitId; findingOrbitId = ejector.findingOrbitId; runtimeOrbitId = ejector.runtimeOrbitId; incUsed = ejector.incUsed; localDir = ejector.localDir; targetDist = ejector.targetDist; needFindNextOrbit = ejector.needFindNextOrbit; } public uint InternalUpdate(float power, long tick, DysonSwarm? swarm, AstroData[] astroPoses, short optimizedBulletId, int[] consumeRegister, ComponentNeeds[] componentsNeeds, int needsOffset, ref EjectorBulletData bulletData, ref int direction, int incLevel) { //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: Unknown result type (might be due to invalid IL or missing references) //IL_02f8: Unknown result type (might be due to invalid IL or missing references) //IL_02fa: Unknown result type (might be due to invalid IL or missing references) //IL_02ff: Unknown result type (might be due to invalid IL or missing references) //IL_0304: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Unknown result type (might be due to invalid IL or missing references) //IL_0318: Unknown result type (might be due to invalid IL or missing references) //IL_031e: Unknown result type (might be due to invalid IL or missing references) //IL_0323: Unknown result type (might be due to invalid IL or missing references) //IL_0328: Unknown result type (might be due to invalid IL or missing references) //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_0337: Unknown result type (might be due to invalid IL or missing references) //IL_0339: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Unknown result type (might be due to invalid IL or missing references) //IL_033d: Unknown result type (might be due to invalid IL or missing references) //IL_0342: Unknown result type (might be due to invalid IL or missing references) //IL_05c8: Unknown result type (might be due to invalid IL or missing references) //IL_05db: Unknown result type (might be due to invalid IL or missing references) //IL_05e0: Unknown result type (might be due to invalid IL or missing references) //IL_05e5: Unknown result type (might be due to invalid IL or missing references) //IL_05e7: Unknown result type (might be due to invalid IL or missing references) //IL_05ec: Unknown result type (might be due to invalid IL or missing references) //IL_05f0: Unknown result type (might be due to invalid IL or missing references) //IL_060c: Unknown result type (might be due to invalid IL or missing references) //IL_0611: Unknown result type (might be due to invalid IL or missing references) //IL_0616: Unknown result type (might be due to invalid IL or missing references) //IL_0618: Unknown result type (might be due to invalid IL or missing references) //IL_061a: Unknown result type (might be due to invalid IL or missing references) //IL_061c: Unknown result type (might be due to invalid IL or missing references) //IL_0621: Unknown result type (might be due to invalid IL or missing references) //IL_0663: Unknown result type (might be due to invalid IL or missing references) //IL_0665: Unknown result type (might be due to invalid IL or missing references) //IL_0667: Unknown result type (might be due to invalid IL or missing references) //IL_066c: Unknown result type (might be due to invalid IL or missing references) //IL_0671: Unknown result type (might be due to invalid IL or missing references) //IL_0673: Unknown result type (might be due to invalid IL or missing references) //IL_0686: Unknown result type (might be due to invalid IL or missing references) //IL_03fe: Unknown result type (might be due to invalid IL or missing references) //IL_040d: Unknown result type (might be due to invalid IL or missing references) //IL_0412: Unknown result type (might be due to invalid IL or missing references) //IL_0417: Unknown result type (might be due to invalid IL or missing references) //IL_0419: Unknown result type (might be due to invalid IL or missing references) //IL_041e: Unknown result type (might be due to invalid IL or missing references) //IL_0422: Unknown result type (might be due to invalid IL or missing references) //IL_043a: Unknown result type (might be due to invalid IL or missing references) //IL_043f: Unknown result type (might be due to invalid IL or missing references) //IL_0444: Unknown result type (might be due to invalid IL or missing references) //IL_0446: Unknown result type (might be due to invalid IL or missing references) //IL_044b: Unknown result type (might be due to invalid IL or missing references) //IL_048d: Unknown result type (might be due to invalid IL or missing references) //IL_048f: Unknown result type (might be due to invalid IL or missing references) //IL_0491: Unknown result type (might be due to invalid IL or missing references) //IL_0496: Unknown result type (might be due to invalid IL or missing references) //IL_049b: Unknown result type (might be due to invalid IL or missing references) //IL_049d: Unknown result type (might be due to invalid IL or missing references) //IL_088a: Unknown result type (might be due to invalid IL or missing references) //IL_08b4: Unknown result type (might be due to invalid IL or missing references) //IL_08de: Unknown result type (might be due to invalid IL or missing references) //IL_04b3: Unknown result type (might be due to invalid IL or missing references) //IL_06ec: Unknown result type (might be due to invalid IL or missing references) //IL_06f1: Unknown result type (might be due to invalid IL or missing references) //IL_06f3: Unknown result type (might be due to invalid IL or missing references) //IL_06f8: Unknown result type (might be due to invalid IL or missing references) //IL_06fa: Unknown result type (might be due to invalid IL or missing references) //IL_0701: Unknown result type (might be due to invalid IL or missing references) //IL_0709: Unknown result type (might be due to invalid IL or missing references) //IL_0710: Unknown result type (might be due to invalid IL or missing references) //IL_0719: Unknown result type (might be due to invalid IL or missing references) //IL_0720: Unknown result type (might be due to invalid IL or missing references) //IL_072b: Unknown result type (might be due to invalid IL or missing references) //IL_0732: Unknown result type (might be due to invalid IL or missing references) //IL_073a: Unknown result type (might be due to invalid IL or missing references) //IL_0741: Unknown result type (might be due to invalid IL or missing references) //IL_074a: Unknown result type (might be due to invalid IL or missing references) //IL_0751: Unknown result type (might be due to invalid IL or missing references) //IL_0508: Unknown result type (might be due to invalid IL or missing references) //IL_050d: Unknown result type (might be due to invalid IL or missing references) //IL_050f: Unknown result type (might be due to invalid IL or missing references) //IL_0514: Unknown result type (might be due to invalid IL or missing references) //IL_0516: Unknown result type (might be due to invalid IL or missing references) //IL_051d: Unknown result type (might be due to invalid IL or missing references) //IL_0525: Unknown result type (might be due to invalid IL or missing references) //IL_052c: Unknown result type (might be due to invalid IL or missing references) //IL_0535: Unknown result type (might be due to invalid IL or missing references) //IL_053c: Unknown result type (might be due to invalid IL or missing references) //IL_0547: Unknown result type (might be due to invalid IL or missing references) //IL_054e: Unknown result type (might be due to invalid IL or missing references) //IL_0556: Unknown result type (might be due to invalid IL or missing references) //IL_055d: Unknown result type (might be due to invalid IL or missing references) //IL_0566: Unknown result type (might be due to invalid IL or missing references) //IL_056d: Unknown result type (might be due to invalid IL or missing references) //IL_096c: Unknown result type (might be due to invalid IL or missing references) //IL_098c: Unknown result type (might be due to invalid IL or missing references) //IL_098e: Unknown result type (might be due to invalid IL or missing references) //IL_0995: Unknown result type (might be due to invalid IL or missing references) //IL_0997: Unknown result type (might be due to invalid IL or missing references) //IL_0999: Unknown result type (might be due to invalid IL or missing references) //IL_09af: Unknown result type (might be due to invalid IL or missing references) //IL_09b4: Unknown result type (might be due to invalid IL or missing references) //IL_09b9: Unknown result type (might be due to invalid IL or missing references) //IL_09be: Unknown result type (might be due to invalid IL or missing references) //IL_09c2: Unknown result type (might be due to invalid IL or missing references) //IL_09ef: Unknown result type (might be due to invalid IL or missing references) //IL_09f4: Unknown result type (might be due to invalid IL or missing references) //IL_09f9: Unknown result type (might be due to invalid IL or missing references) //IL_0a00: Unknown result type (might be due to invalid IL or missing references) //IL_0a02: Unknown result type (might be due to invalid IL or missing references) //IL_0a09: Unknown result type (might be due to invalid IL or missing references) //IL_0a0b: Unknown result type (might be due to invalid IL or missing references) //IL_0a11: Unknown result type (might be due to invalid IL or missing references) if (swarm == null) { throw new InvalidOperationException("I am very confused about why this ever worked to begin with. Swarm was null for ejector which is possible. The game ignores it but it will cause a crash."); } componentsNeeds[needsOffset].Needs = ((bulletData.BulletCount < 20) ? ((byte)1) : ((byte)0)); if (bulletData.BulletCount == 0) { return 0u; } if (!autoOrbit) { runtimeOrbitId = orbitId; } if (orbitId < 0 || orbitId >= swarm.orbitCursor || swarm.orbits[orbitId].id != orbitId || !swarm.orbits[orbitId].enabled) { orbitId = 0; } if (swarm.orbits[runtimeOrbitId].id != runtimeOrbitId || !swarm.orbits[runtimeOrbitId].enabled) { runtimeOrbitId = orbitId; } if (swarm.orbits[findingOrbitId].id != findingOrbitId || !swarm.orbits[findingOrbitId].enabled) { findingOrbitId = orbitId; } float num = (float)Cargo.accTableMilli[incLevel]; int num2 = (int)(power * 10000f * (1f + num) + 0.1f); if (boost) { num2 *= 10; } if (runtimeOrbitId == 0 && !needFindNextOrbit) { if (autoOrbit) { needFindNextOrbit = true; } if (direction == 1) { time = (int)((long)time * (long)coldSpend / chargeSpend); direction = -1; } if (direction == -1) { time -= num2; if (time <= 0) { time = 0; direction = 0; } } if (power >= 0.1f) { localDir.x *= 0.9f; localDir.y *= 0.9f; localDir.z = localDir.z * 0.9f + 0.1f; return 1u; } return 0u; } if (power < 0.1f) { if (direction == 1) { time = (int)((long)time * (long)coldSpend / chargeSpend); direction = -1; } return 0u; } bool flag = true; int num3 = planetId / 100 * 100; float num4 = localAlt + pivotY + (muzzleY - pivotY) / Mathf.Max(0.1f, Mathf.Sqrt(1f - localDir.y * localDir.y)); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(localPosN.x * num4, localPosN.y * num4, localPosN.z * num4); VectorLF3 val2 = astroPoses[planetId].uPos + Maths.QRotateLF(astroPoses[planetId].uRot, VectorLF3.op_Implicit(val)); Quaternion val3 = astroPoses[planetId].uRot * localRot; VectorLF3 uPos = astroPoses[num3].uPos; VectorLF3 val4 = uPos - val2; VectorLF3 val5; if (needFindNextOrbit) { int num5 = 0; long num6 = tick % 30; long num7 = id % 30; if (num6 == num7 && orbitId != 0) { num5 = orbitId; } else if ((num6 + 15) % 30 == num7) { int num8 = findingOrbitId + 1; if (num8 >= swarm.orbitCursor) { num8 = 1; } while (swarm.orbits[num8].id != num8 || !swarm.orbits[num8].enabled) { num8++; if (num8 >= swarm.orbitCursor) { num8 = 1; } if (num8 == runtimeOrbitId) { break; } } num5 = num8; findingOrbitId = num8; } if (num5 != 0) { val5 = VectorLF3.Cross(VectorLF3.op_Implicit(swarm.orbits[num5].up), val4); VectorLF3 val6 = uPos + ((VectorLF3)(ref val5)).normalized * (double)swarm.orbits[num5].radius - val2; targetDist = ((VectorLF3)(ref val6)).magnitude; val6.x /= targetDist; val6.y /= targetDist; val6.z /= targetDist; Vector3 val7 = Maths.QInvRotate(val3, VectorLF3.op_Implicit(val6)); if ((double)val7.y >= 0.08715574 && val7.y <= 0.8660254f) { bool flag2 = false; for (int i = num3 + 1; i <= planetId + 2; i++) { if (i == planetId) { continue; } double num9 = astroPoses[i].uRadius; if (!(num9 > 1.0)) { continue; } VectorLF3 val8 = astroPoses[i].uPos - val2; double num10 = val8.x * val8.x + val8.y * val8.y + val8.z * val8.z; double num11 = val8.x * val6.x + val8.y * val6.y + val8.z * val6.z; if (num11 > 0.0) { double num12 = num10 - num11 * num11; num9 += 120.0; if (num12 < num9 * num9) { flag2 = true; break; } } } if (!flag2) { runtimeOrbitId = num5; } } } } val5 = VectorLF3.Cross(VectorLF3.op_Implicit(swarm.orbits[runtimeOrbitId].up), val4); VectorLF3 val9 = uPos + ((VectorLF3)(ref val5)).normalized * (double)swarm.orbits[runtimeOrbitId].radius; VectorLF3 val10 = val9 - val2; targetDist = ((VectorLF3)(ref val10)).magnitude; val10.x /= targetDist; val10.y /= targetDist; val10.z /= targetDist; Vector3 val11 = Maths.QInvRotate(val3, VectorLF3.op_Implicit(val10)); if ((double)val11.y < 0.08715574 || val11.y > 0.8660254f) { flag = false; } bool flag3 = bulletData.BulletCount > 0; if (flag3 && flag) { for (int j = num3 + 1; j <= planetId + 2; j++) { if (j == planetId) { continue; } double num13 = astroPoses[j].uRadius; if (!(num13 > 1.0)) { continue; } VectorLF3 val12 = astroPoses[j].uPos - val2; double num14 = val12.x * val12.x + val12.y * val12.y + val12.z * val12.z; double num15 = val12.x * val10.x + val12.y * val10.y + val12.z * val10.z; if (num15 > 0.0) { double num16 = num14 - num15 * num15; num13 += 120.0; if (num16 < num13 * num13) { flag = false; break; } } } } if (autoOrbit && (!flag || runtimeOrbitId == 0)) { needFindNextOrbit = true; runtimeOrbitId = 0; if (direction == 1) { time = (int)((long)time * (long)coldSpend / chargeSpend); direction = -1; } if (direction == -1) { time -= num2; if (time <= 0) { time = 0; direction = 0; } } if (power >= 0.1f) { localDir.x *= 0.9f; localDir.y *= 0.9f; localDir.z = localDir.z * 0.9f + 0.1f; return 1u; } return 0u; } needFindNextOrbit = false; localDir.x = localDir.x * 0.9f + val11.x * 0.1f; localDir.y = localDir.y * 0.9f + val11.y * 0.1f; localDir.z = localDir.z * 0.9f + val11.z * 0.1f; bool flag4 = flag && flag3; int result = ((!flag3) ? 2 : (flag ? 4 : 3)); if (direction == 1) { if (!flag4) { time = (int)((long)time * (long)coldSpend / chargeSpend); direction = -1; } } else if (direction == 0 && flag4) { direction = 1; } if (direction == 1) { time += num2; if (time >= chargeSpend) { SailBullet val13 = new SailBullet { maxt = (float)(targetDist / 5000.0), lBegin = val }; val5 = VectorLF3.Cross(val9 - uPos, VectorLF3.op_Implicit(swarm.orbits[runtimeOrbitId].up)); val13.uEndVel = VectorLF3.op_Implicit(((VectorLF3)(ref val5)).normalized * Math.Sqrt(swarm.dysonSphere.gravity / swarm.orbits[runtimeOrbitId].radius)); val13.uBegin = val2; val13.uEnd = val9; swarm.AddBullet(val13, runtimeOrbitId); int num17 = bulletData.BulletInc / bulletData.BulletCount; if (!incUsed) { incUsed = num17 > 0; } bulletData.BulletInc -= (byte)num17; bulletData.BulletCount--; if (bulletData.BulletCount == 0) { bulletData.BulletInc = 0; } consumeRegister[optimizedBulletId]++; time = coldSpend; direction = -1; return (uint)result; } } else if (direction == -1) { time -= num2; if (time <= 0) { time = 0; direction = (flag4 ? 1 : 0); return (uint)result; } } else { time = 0; } return (uint)result; } public readonly void Save(ref EjectorComponent ejector, GroupNeeds groupNeeds, ComponentNeeds[] componentsNeeds, short[] needsPatterns, int ejectorIndex, EjectorBulletData ejectorBulletData, int direction) { //IL_0071: 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) int objectNeedsIndex = groupNeeds.GetObjectNeedsIndex(ejectorIndex); ComponentNeeds componentNeeds = componentsNeeds[objectNeedsIndex]; for (int i = 0; i < groupNeeds.GroupNeedsSize; i++) { GroupNeeds.SetNeedsIfInRange(ejector.needs, componentNeeds, needsPatterns, i); } ejector.time = time; ejector.orbitId = orbitId; ejector.findingOrbitId = findingOrbitId; ejector.runtimeOrbitId = runtimeOrbitId; ejector.incUsed = incUsed; ejector.localDir = localDir; ejector.targetDist = targetDist; ejector.needFindNextOrbit = needFindNextOrbit; ejector.direction = direction; ejector.bulletCount = ejectorBulletData.BulletCount; ejector.bulletInc = ejectorBulletData.BulletInc; } } } namespace Weaver.Optimizations.Belts { internal sealed class BeltExecutor { private OptimizedCargoPath[] _optimizedCargoPaths; private Dictionary _cargoPathToOptimizedCargoPathIndex; public Dictionary CargoPathToOptimizedCargoPathIndex => _cargoPathToOptimizedCargoPathIndex; public int Count => _optimizedCargoPaths.Length; public OptimizedCargoPath[] OptimizedCargoPaths => _optimizedCargoPaths; public bool TryGetOptimizedCargoPathIndex(PlanetFactory planet, int beltId, [NotNullWhen(true)] out BeltIndex beltIndex) { if (!TryGetCargoPath(planet, beltId, out CargoPath belt)) { beltIndex = BeltIndex.NoBelt; return false; } beltIndex = _cargoPathToOptimizedCargoPathIndex[belt]; return true; } public void GameTick() { OptimizedCargoPath[] optimizedCargoPaths = _optimizedCargoPaths; for (int i = 0; i < optimizedCargoPaths.Length; i++) { optimizedCargoPaths[i].Update(optimizedCargoPaths); } } public void Save(CargoContainer cargoContainer) { OptimizedCargoPath[] optimizedCargoPaths = _optimizedCargoPaths; foreach (KeyValuePair item in _cargoPathToOptimizedCargoPathIndex) { ref OptimizedCargoPath belt = ref item.Value.GetBelt(optimizedCargoPaths); CopyToBufferWithUpdatedCargoIndexes(item.Key.buffer, ref belt, cargoContainer); belt.Save(item.Key); } } public void Initialize(PlanetFactory planet, Graph subFactoryGraph, UniverseStaticDataBuilder universeStaticDataBuilder) { List list = new List(); Dictionary dictionary = new Dictionary(); foreach (int item2 in from x in subFactoryGraph.GetAllNodes() where x.EntityTypeIndex.EntityType == EntityType.Belt select x.EntityTypeIndex.Index into x orderby x select x) { CargoPath val = planet.cargoTraffic.pathPool[item2]; if (val != null && val.id == item2) { byte[] bufferWithUpdatedCargoIndexes = GetBufferWithUpdatedCargoIndexes(val); OptimizedCargoPath item = new OptimizedCargoPath(bufferWithUpdatedCargoIndexes, val, universeStaticDataBuilder); dictionary.Add(val, new BeltIndex(list.Count)); list.Add(item); } } _optimizedCargoPaths = list.ToArray(); foreach (KeyValuePair item3 in dictionary) { if (item3.Key.outputPath != null) { item3.Value.GetBelt(_optimizedCargoPaths).SetOutputPath(dictionary[item3.Key.outputPath]); } } _cargoPathToOptimizedCargoPathIndex = dictionary; } private static byte[] GetBufferWithUpdatedCargoIndexes(CargoPath cargoPath) { //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: 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_00e5: Unknown result type (might be due to invalid IL or missing references) byte[] array = new byte[cargoPath.buffer.Length]; Array.Copy(cargoPath.buffer, array, cargoPath.buffer.Length); Cargo[] cargoPool = cargoPath.cargoContainer.cargoPool; int num = 5; int num2 = 10; int num3 = 0; while (num3 < cargoPath.bufferLength) { if (cargoPath.buffer[num3] == 0) { num3 += num; continue; } if (cargoPath.buffer[num3] == 250) { int num4 = cargoPath.buffer[num3 + 1] - 1 + (cargoPath.buffer[num3 + 2] - 1) * 100 + (cargoPath.buffer[num3 + 3] - 1) * 10000 + (cargoPath.buffer[num3 + 4] - 1) * 1000000; if (num4 >= cargoPool.Length || num4 < 0 || num3 >= cargoPath.pointPos.Length) { Assert.CannotBeReached(); } else { Cargo val = cargoPool[num4]; OptimizedCargo optimizedCargo = new OptimizedCargo(val.item, val.stack, val.inc); SetCargoInBuffer(array, num3 + 1, optimizedCargo); } num3 += num2; continue; } if (246 <= cargoPath.buffer[num3] && cargoPath.buffer[num3] < 250) { num3 += 250 - cargoPath.buffer[num3]; int num5 = cargoPath.buffer[num3 + 1] - 1 + (cargoPath.buffer[num3 + 2] - 1) * 100 + (cargoPath.buffer[num3 + 3] - 1) * 10000 + (cargoPath.buffer[num3 + 4] - 1) * 1000000; Cargo val2 = cargoPool[num5]; OptimizedCargo optimizedCargo2 = new OptimizedCargo(val2.item, val2.stack, val2.inc); SetCargoInBuffer(array, num3 + 1, optimizedCargo2); num3 += num2; continue; } Assert.CannotBeReached("断言失败:buffer数据有误"); break; } return array; } private static void CopyToBufferWithUpdatedCargoIndexes(byte[] bufferCopy, ref OptimizedCargoPath optimizedCargoPath, CargoContainer cargoContainer) { if (bufferCopy.Length != optimizedCargoPath.buffer.Length) { throw new ArgumentOutOfRangeException("bufferCopy", "bufferCopy did not have the same length as optimizedCargoPath.buffer."); } Array.Copy(optimizedCargoPath.buffer, bufferCopy, optimizedCargoPath.buffer.Length); int num = 5; int num2 = 10; int num3 = 0; while (num3 < optimizedCargoPath.bufferLength) { if (optimizedCargoPath.buffer[num3] == 0) { num3 += num; continue; } if (optimizedCargoPath.buffer[num3] == 250) { OptimizedCargo cargo = GetCargo(optimizedCargoPath.buffer, num3 + 1); int cargoIndex = cargoContainer.AddCargo(cargo.Item, cargo.Stack, cargo.Inc); SetCargoIndexInBufferDefaultGameWay(bufferCopy, num3 + 1, cargoIndex); num3 += num2; continue; } if (246 <= optimizedCargoPath.buffer[num3] && optimizedCargoPath.buffer[num3] < 250) { num3 += 250 - optimizedCargoPath.buffer[num3]; OptimizedCargo cargo2 = GetCargo(optimizedCargoPath.buffer, num3 + 1); int cargoIndex2 = cargoContainer.AddCargo(cargo2.Item, cargo2.Stack, cargo2.Inc); SetCargoIndexInBufferDefaultGameWay(bufferCopy, num3 + 1, cargoIndex2); num3 += num2; continue; } Assert.CannotBeReached("断言失败:buffer数据有误"); break; } } internal static void SetCargoInBuffer(byte[] buffer, int bufferIndex, OptimizedCargo optimizedCargo) { buffer[bufferIndex] = (byte)((optimizedCargo.Item & 0x7F) + 1); buffer[bufferIndex + 1] = (byte)((optimizedCargo.Item >> 7) + 1); buffer[bufferIndex + 2] = (byte)(optimizedCargo.Stack + 1); buffer[bufferIndex + 3] = (byte)(optimizedCargo.Inc + 1); } internal static OptimizedCargo GetCargo(byte[] buffer, int index) { return new OptimizedCargo((short)(buffer[index] - 1 + (buffer[index + 1] - 1 << 7)), (byte)(buffer[index + 2] - 1), (byte)(buffer[index + 3] - 1)); } internal static void SetCargoIndexInBufferDefaultGameWay(byte[] buffer, int bufferIndex, int cargoIndex) { buffer[bufferIndex] = (byte)(cargoIndex % 100 + 1); cargoIndex /= 100; buffer[bufferIndex + 1] = (byte)(cargoIndex % 100 + 1); cargoIndex /= 100; buffer[bufferIndex + 2] = (byte)(cargoIndex % 100 + 1); cargoIndex /= 100; buffer[bufferIndex + 3] = (byte)(cargoIndex % 100 + 1); } private static bool TryGetCargoPath(PlanetFactory planet, int beltId, [NotNullWhen(true)] out CargoPath? belt) { if (beltId <= 0) { belt = null; return false; } belt = planet.cargoTraffic.GetCargoPath(planet.cargoTraffic.beltPool[beltId].segPathId); return belt != null; } } internal readonly struct BeltIndex : IEquatable, IMemorySize { private const int NO_BELT_INDEX = -1; private readonly int _index; public static readonly BeltIndex NoBelt = new BeltIndex(-1); public bool HasValue => _index != -1; public BeltIndex(int index) { _index = index; } public ref OptimizedCargoPath GetBelt(OptimizedCargoPath[] belts) { return ref belts[_index]; } public int GetIndex() { if (!HasValue) { throw new InvalidOperationException("Attempted to get index of empty belt index."); } return _index; } public int GetSize() { return Marshal.SizeOf(); } public static bool operator ==(BeltIndex left, BeltIndex right) { return left._index == right._index; } public static bool operator !=(BeltIndex left, BeltIndex right) { return left._index != right._index; } public bool Equals(BeltIndex other) { return this == other; } public override bool Equals(object obj) { if (obj is BeltIndex other) { return Equals(other); } return false; } public override int GetHashCode() { HashCode hashCode = default(HashCode); hashCode.Add(_index); return hashCode.ToHashCode(); } } internal struct OptimizedCargo { public short Item; public byte Stack; public byte Inc; private const uint _itemMask_ = 16383u; private const uint _stackMask = 245760u; private const uint _incMask__ = 16515072u; private const int _itemOffset = 0; private const int _stackOffset = 14; private const int _incOffset = 18; public OptimizedCargo(short item, byte stack, byte inc) { Item = item; Stack = stack; Inc = inc; } } [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct OptimizedCargoPath { public readonly byte[] buffer; private readonly ReadonlyArray chunks; public readonly int outputIndex; public readonly bool closed; public readonly int bufferLength; public readonly int chunkCount; public BeltIndex outputCargoPathIndex; private int outputChunk; private bool lastUpdateFrameOdd; public int updateLen; public readonly int pathLength => bufferLength; public OptimizedCargoPath(byte[] buffer, CargoPath cargoPath, UniverseStaticDataBuilder universeStaticDataBuilder) { outputIndex = -1; this.buffer = buffer; chunks = universeStaticDataBuilder.DeduplicateArrayUnmanaged(cargoPath.chunks); outputIndex = cargoPath.outputIndex; closed = cargoPath.closed; bufferLength = cargoPath.bufferLength; chunkCount = cargoPath.chunkCount; outputCargoPathIndex = BeltIndex.NoBelt; outputChunk = cargoPath.outputChunk; lastUpdateFrameOdd = cargoPath.lastUpdateFrameOdd; updateLen = cargoPath.updateLen; } public readonly void Save(CargoPath cargoPath) { cargoPath.outputChunk = outputChunk; cargoPath.lastUpdateFrameOdd = lastUpdateFrameOdd; cargoPath.updateLen = updateLen; } public void SetOutputPath(BeltIndex cargoPathIndex) { outputCargoPathIndex = cargoPathIndex; } public readonly bool TryInsertCargo(int index, OptimizedCargo optimizedCargo) { int num = index + 5; int num2 = index - 5; if (index < 4) { return false; } if (num >= bufferLength) { return false; } bool flag = false; while (index > num2) { if (buffer[num] != 0) { index--; num--; continue; } flag = true; break; } if (!flag) { return false; } if (num + 6 < bufferLength) { if (buffer[++num] != 0) { index = num - 1 - 5; } else if (buffer[++num] != 0) { index = num - 1 - 5; } else if (buffer[++num] != 0) { index = num - 1 - 5; } else if (buffer[++num] != 0) { index = num - 1 - 5; } else if (buffer[++num] != 0) { index = num - 1 - 5; } } if (index < 4) { return false; } int num3 = index + 5; int num4 = 0; int num5 = 0; bool flag2 = false; bool flag3 = false; int num6 = num3; while (num6 >= num3 - 2880 && num6 >= 0) { if (buffer[num6] == 0) { num5++; if (!flag2) { num4++; } if (num4 == 10 && (!closed || num6 >= 10)) { InsertCargoDirect(index, optimizedCargo); return true; } if (num5 == 10 && (!closed || num6 >= 10)) { flag3 = true; break; } } else { flag2 = true; if (num4 < 1) { return false; } if (buffer[num6] == byte.MaxValue) { num6 -= 9; } } num6--; } if (closed && !flag3 && num5 >= 10 && num5 < 20 && num3 < 2880) { num5 -= 10; if (num4 > 10) { num4 = 10; } int num7 = bufferLength - 1; while (num7 > num3 && num7 > bufferLength + num3 - 2880) { if (buffer[num7] == 0) { num5++; } else if (buffer[num7] == byte.MaxValue) { num7 -= 9; } if (num5 >= 10) { if (num4 == 10) { InsertCargoDirect(index, optimizedCargo); return true; } flag3 = true; break; } num7--; } } if (flag3) { int num8 = 10 - num4; int num9 = num3 - num4 + 1; int num10 = index - 4; while (num10 >= num3 - 2880 && num10 >= 0) { if (buffer[num10] == 246) { int num11 = 0; int num12 = num10 - 1; while (num12 >= num3 - 2880 && num12 >= 0 && num11 < num8 && buffer[num12] == 0) { num11++; num12--; } if (num11 > 0) { Array.Copy(buffer, num10, buffer, num10 - num11, num9 - num10); num8 -= num11; num9 -= num11; num10 -= num11; } } num10--; } if (num8 == 0) { InsertCargoDirect(index, optimizedCargo); return true; } Assert.CannotBeReached("断言失败:插入货物逻辑有误"); } return false; } public readonly bool TryInsertItem(int index, int itemId, byte stack, byte inc) { int num = index + 5; int num2 = index - 5; if (index < 4) { return false; } if (num >= bufferLength) { return false; } bool flag = false; while (index > num2) { if (buffer[num] != 0) { index--; num--; continue; } flag = true; break; } if (!flag) { return false; } if (num + 6 < bufferLength) { if (buffer[++num] != 0) { index = num - 1 - 5; } else if (buffer[++num] != 0) { index = num - 1 - 5; } else if (buffer[++num] != 0) { index = num - 1 - 5; } else if (buffer[++num] != 0) { index = num - 1 - 5; } else if (buffer[++num] != 0) { index = num - 1 - 5; } } if (index < 4) { return false; } int num3 = index + 5; int num4 = index - 4; if (buffer[num4] == 0 && (!closed || num4 >= 10)) { InsertItemDirect(index, itemId, stack, inc); return true; } int num5 = num3 - 2880; if (num5 < 0) { num5 = 0; } int num6 = 0; int num7 = 0; bool flag2 = false; bool flag3 = false; for (int num8 = num3; num8 >= num5; num8--) { if (buffer[num8] == 0) { num7++; if (!flag2) { num6++; } if (num6 == 10 && (!closed || num8 >= 10)) { InsertItemDirect(index, itemId, stack, inc); return true; } if (num7 == 10 && (!closed || num8 >= 10)) { flag3 = true; break; } } else { flag2 = true; if (num6 < 1) { return false; } if (buffer[num8] == byte.MaxValue) { num8 -= 9; } } } if (closed && !flag3 && num7 >= 10 && num7 < 20 && num3 < 2880) { num7 -= 10; if (num6 > 10) { num6 = 10; } int num9 = bufferLength - 1; while (num9 > num3 && num9 > bufferLength + num3 - 2880) { if (buffer[num9] == 0) { num7++; } else if (buffer[num9] == byte.MaxValue) { num9 -= 9; } if (num7 >= 10) { if (num6 == 10) { InsertItemDirect(index, itemId, stack, inc); return true; } flag3 = true; break; } num9--; } } if (flag3) { int num10 = 10 - num6; int num11 = num3 - num6 + 1; for (int num12 = num4; num12 >= num5; num12--) { if (buffer[num12] == 246) { int num13 = 0; int num14 = num12 - 1; while (num14 >= num5 && num13 < num10 && buffer[num14] == 0) { num13++; num14--; } if (num13 > 0) { Array.Copy(buffer, num12, buffer, num12 - num13, num11 - num12); num10 -= num13; num11 -= num13; num12 -= num13; } } } if (num10 == 0) { InsertItemDirect(index, itemId, stack, inc); return true; } Assert.CannotBeReached("断言失败:插入货物逻辑有误"); } return false; } public void TryInsertItemWithStackIncreasement(int index, int itemId, int maxStack, ref int count, ref int inc) { int num = index + 5; if (num >= 0 && num < bufferLength) { int num2 = buffer[num]; if (num2 > 0) { int num3 = num; num3 = ((num2 < 246) ? (num3 + (246 - buffer[num - 4])) : (num3 + (250 - num2))); OptimizedCargo cargo = GetCargo(num3 + 1); cargo = AddItemStackToCargo(cargo, itemId, maxStack, ref count, ref inc); SetCargoInBuffer(num3 + 1, cargo); } } if (count == 0) { return; } int num4 = index - 4; if (num4 >= 0 && num4 < bufferLength) { int num5 = buffer[num4]; if (num5 > 0) { int num6 = num4; num6 = ((num5 < 246) ? (num6 + (246 - buffer[num4 - 4])) : (num6 + (250 - num5))); OptimizedCargo cargo2 = GetCargo(num6 + 1); cargo2 = AddItemStackToCargo(cargo2, itemId, maxStack, ref count, ref inc); SetCargoInBuffer(num6 + 1, cargo2); } } if (count == 0) { return; } int num7 = index - 5; if (index < 4 || num >= bufferLength) { return; } bool flag = false; while (index > num7) { if (buffer[num] != 0) { index--; num--; continue; } flag = true; break; } if (!flag) { return; } if (num + 6 < bufferLength) { if (buffer[++num] != 0) { index = num - 1 - 5; } else if (buffer[++num] != 0) { index = num - 1 - 5; } else if (buffer[++num] != 0) { index = num - 1 - 5; } else if (buffer[++num] != 0) { index = num - 1 - 5; } else if (buffer[++num] != 0) { index = num - 1 - 5; } } if (index < 4) { return; } int num8 = index + 5; int num9 = index - 4; if (buffer[num9] == 0 && (!closed || num9 >= 10)) { int num10 = count; int num11 = inc; if (count > maxStack) { num10 = maxStack; num11 = inc / count; int num12 = inc - num11 * count; count -= num10; num12 -= count; num11 = ((num12 > 0) ? (num11 * num10 + num12) : (num11 * num10)); inc -= num11; } else { count = 0; inc = 0; } InsertItemDirect(index, itemId, (byte)num10, (byte)num11); return; } int num13 = num8 - 2880; if (num13 < 0) { num13 = 0; } int num14 = 0; int num15 = 0; bool flag2 = false; bool flag3 = false; for (int num16 = num8; num16 >= num13; num16--) { if (buffer[num16] == 0) { num15++; if (!flag2) { num14++; } if (num14 == 10 && (!closed || num16 >= 10)) { int num17 = count; int num18 = inc; if (count > maxStack) { num17 = maxStack; num18 = inc / count; int num19 = inc - num18 * count; count -= num17; num19 -= count; num18 = ((num19 > 0) ? (num18 * num17 + num19) : (num18 * num17)); inc -= num18; } else { count = 0; inc = 0; } InsertItemDirect(index, itemId, (byte)num17, (byte)num18); return; } if (num15 == 10 && (!closed || num16 >= 10)) { flag3 = true; break; } } else { flag2 = true; if (num14 < 1) { return; } if (buffer[num16] == byte.MaxValue) { num16 -= 9; } } } if (closed && !flag3 && num15 >= 10 && num15 < 20 && num8 < 2880) { num15 -= 10; if (num14 > 10) { num14 = 10; } int num20 = bufferLength - 1; while (num20 > num8 && num20 > bufferLength + num8 - 2880) { if (buffer[num20] == 0) { num15++; } else if (buffer[num20] == byte.MaxValue) { num20 -= 9; } if (num15 >= 10) { if (num14 == 10) { int num21 = count; int num22 = inc; if (count > maxStack) { num21 = maxStack; num22 = inc / count; int num23 = inc - num22 * count; count -= num21; num23 -= count; num22 = ((num23 > 0) ? (num22 * num21 + num23) : (num22 * num21)); inc -= num22; } else { count = 0; inc = 0; } InsertItemDirect(index, itemId, (byte)num21, (byte)num22); return; } flag3 = true; break; } num20--; } } if (!flag3) { return; } int num24 = 10 - num14; int num25 = num8 - num14 + 1; for (int num26 = num9; num26 >= num13; num26--) { if (buffer[num26] == 246) { int num27 = 0; int num28 = num26 - 1; while (num28 >= num13 && num27 < num24 && buffer[num28] == 0) { num27++; num28--; } if (num27 > 0) { Array.Copy(buffer, num26, buffer, num26 - num27, num25 - num26); num24 -= num27; num25 -= num27; num26 -= num27; } } } if (num24 == 0) { int num29 = count; int num30 = inc; if (count > maxStack) { num29 = maxStack; num30 = inc / count; int num31 = inc - num30 * count; count -= num29; num31 -= count; num30 = ((num31 > 0) ? (num30 * num29 + num31) : (num30 * num29)); inc -= num30; } else { count = 0; inc = 0; } InsertItemDirect(index, itemId, (byte)num29, (byte)num30); } else { Assert.CannotBeReached("断言失败:插入货物逻辑有误"); } } public readonly bool TryInsertCargoNoSqueeze(int index, OptimizedCargo optimizedCargo) { if (index < 4 || index + 5 >= bufferLength) { return false; } if (buffer[index + 5] != 0) { return false; } int num = index - 4; int num2 = index + 5; for (int i = num; i < num2; i++) { if (buffer[i] != 0) { return false; } } InsertCargoDirect(index, optimizedCargo); return true; } public readonly void InsertCargoAtHeadDirect(OptimizedCargo optimizedCargo, int headIndex) { SetCargo(headIndex, optimizedCargo); } private readonly void InsertCargoDirect(int index, OptimizedCargo optimizedCargo) { SetCargo(index - 4, optimizedCargo); } public readonly void InsertItemDirect(int index, int itemId, byte stack, byte inc) { SetCargo(index - 4, new OptimizedCargo((short)itemId, stack, inc)); } public readonly bool TryInsertItemAtHead(int itemId, byte stack, byte inc) { if (buffer[0] != 0 || buffer[9] != 0) { return false; } SetCargo(0, new OptimizedCargo((short)itemId, stack, inc)); return true; } public readonly bool TryInsertItemAtHeadAndFillBlank(int itemId, byte stack, byte inc) { int num = TestBlankAtHead(); if (num < 0) { return false; } int num2 = num + 9; if (bufferLength <= num2) { return false; } SetCargo(num, new OptimizedCargo((short)itemId, stack, inc)); return true; } public readonly bool TryUpdateItemAtHeadAndFillBlank(int itemId, int maxStack, byte stack, byte inc) { int num = TestBlankAtHead(); if (num < 0) { if (!TryGetCargoIdAtIndex(0, 10, out var cargo, out var cargoBufferIndex)) { return false; } int stack2 = cargo.Stack; if (cargo.Item == itemId && stack2 + stack <= maxStack) { cargo.Stack += stack; cargo.Inc += inc; SetCargoInBuffer(cargoBufferIndex, cargo); return true; } return false; } int num2 = num + 9; if (bufferLength <= num2) { return false; } SetCargo(num, new OptimizedCargo((short)itemId, stack, inc)); return true; } public readonly OptimizedCargo QueryItemAtIndex(int index, out int cargoBufferIndex) { if (index < 0) { cargoBufferIndex = -1; return default(OptimizedCargo); } if (index >= bufferLength) { cargoBufferIndex = -1; return default(OptimizedCargo); } if (buffer[index] == 0) { cargoBufferIndex = -1; return default(OptimizedCargo); } int num = index + 10 - 1; if (num >= bufferLength) { num = bufferLength - 1; } for (int i = index; i <= num; i++) { if (buffer[i] >= 246) { i += 250 - buffer[i]; cargoBufferIndex = i + 1; return GetCargo(i + 1); } } Assert.CannotBeReached(); cargoBufferIndex = -1; return default(OptimizedCargo); } public bool RemoveCargoAtIndex(int index) { if (index < 0) { return false; } if (index >= bufferLength) { return false; } if (buffer[index] == 0) { return false; } int num = index + 10 - 1; if (num >= bufferLength) { num = bufferLength - 1; } for (int i = index; i <= num; i++) { if (buffer[i] >= 246) { i += 250 - buffer[i]; Array.Clear(buffer, i - 4, 10); int num2 = i + 5 + 1; if (updateLen < num2) { updateLen = num2; } return true; } } Assert.CannotBeReached(); return false; } public bool TryPickFuel(int index, int length, int filter, OptimizedItemId[]? fuelMask, out OptimizedCargo optimizedCargo) { if (index < 0) { index = 0; } else if (index >= bufferLength) { index = bufferLength - 1; } int num = index + length; if (num > bufferLength) { num = bufferLength; } for (int i = index; i < num; i++) { if (buffer[i] < 246) { continue; } i += 250 - buffer[i]; optimizedCargo = GetCargo(i + 1); if (filter == 0 || optimizedCargo.Item == filter) { for (int j = 0; j < fuelMask.Length; j++) { if (fuelMask[j].ItemIndex == optimizedCargo.Item) { Array.Clear(buffer, i - 4, 10); int num2 = i + 5 + 1; if (updateLen < num2) { updateLen = num2; } return true; } } } optimizedCargo = default(OptimizedCargo); return false; } optimizedCargo = default(OptimizedCargo); return false; } public OptimizedCargo TryPickItem(int index, int length) { if (index < 0) { index = 0; } else if (index >= bufferLength) { index = bufferLength - 1; } int num = index + length; if (num > bufferLength) { num = bufferLength; } for (int i = index; i < num; i++) { if (buffer[i] >= 246) { i += 250 - buffer[i]; OptimizedCargo cargo = GetCargo(i + 1); Array.Clear(buffer, i - 4, 10); int num2 = i + 5 + 1; if (updateLen < num2) { updateLen = num2; } return cargo; } } return default(OptimizedCargo); } public bool TryPickItem(int index, int length, int filter, out OptimizedCargo cargo) { if (index < 0) { index = 0; } else if (index >= bufferLength) { index = bufferLength - 1; } int num = index + length; if (num > bufferLength) { num = bufferLength; } for (int i = index; i < num; i++) { if (buffer[i] < 246) { continue; } i += 250 - buffer[i]; OptimizedCargo cargo2 = GetCargo(i + 1); if (filter == 0 || cargo2.Item == filter) { Array.Clear(buffer, i - 4, 10); int num2 = i + 5 + 1; if (updateLen < num2) { updateLen = num2; } cargo = cargo2; return true; } cargo = default(OptimizedCargo); return false; } cargo = default(OptimizedCargo); return false; } public OptimizedCargo TryPickItem(int index, int length, int filter, int[] needs) { if (index < 0) { index = 0; } else if (index >= bufferLength) { index = bufferLength - 1; } int num = index + length; if (num > bufferLength) { num = bufferLength; } for (int i = index; i < num; i++) { if (buffer[i] < 246) { continue; } i += 250 - buffer[i]; OptimizedCargo cargo = GetCargo(i + 1); int item = cargo.Item; if ((filter == 0 || item == filter) && (item == needs[0] || item == needs[1] || item == needs[2] || item == needs[3] || item == needs[4] || item == needs[5])) { Array.Clear(buffer, i - 4, 10); int num2 = i + 5 + 1; if (updateLen < num2) { updateLen = num2; } return cargo; } return default(OptimizedCargo); } return default(OptimizedCargo); } public bool TryPickItem(int index, int length, int filter, int[] needs, out OptimizedCargo cargo) { if (index < 0) { index = 0; } else if (index >= bufferLength) { index = bufferLength - 1; } int num = index + length; if (num > bufferLength) { num = bufferLength; } for (int i = index; i < num; i++) { if (buffer[i] < 246) { continue; } i += 250 - buffer[i]; OptimizedCargo cargo2 = GetCargo(i + 1); int item = cargo2.Item; if ((filter == 0 || item == filter) && (item == needs[0] || item == needs[1] || item == needs[2] || item == needs[3] || item == needs[4] || item == needs[5])) { Array.Clear(buffer, i - 4, 10); int num2 = i + 5 + 1; if (updateLen < num2) { updateLen = num2; } cargo = cargo2; return true; } cargo = default(OptimizedCargo); return false; } cargo = default(OptimizedCargo); return false; } public OptimizedCargo TryPickItem(int index, int length, int filter, ComponentNeeds componentNeeds, short[] needsPatterns, int needsSize) { if (index < 0) { index = 0; } else if (index >= bufferLength) { index = bufferLength - 1; } int num = index + length; if (num > bufferLength) { num = bufferLength; } for (int i = index; i < num; i++) { if (buffer[i] < 246) { continue; } i += 250 - buffer[i]; OptimizedCargo cargo = GetCargo(i + 1); int item = cargo.Item; if ((filter == 0 || item == filter) && AnyMatch(componentNeeds, needsPatterns, needsSize, item)) { Array.Clear(buffer, i - 4, 10); int num2 = i + 5 + 1; if (updateLen < num2) { updateLen = num2; } return cargo; } return default(OptimizedCargo); } return default(OptimizedCargo); } public void TryRemoveItemAtRear() { int num = bufferLength - 5 - 1; if (buffer[num] == 250) { Array.Clear(buffer, num - 4, 10); int num2 = num + 5 + 1; if (updateLen < num2) { updateLen = num2; } } } public readonly int TestBlankAtHead() { int num = 9; if (buffer[num] != 0) { return -1; } if (bufferLength < 20) { return 0; } if (buffer[++num] != 0) { return 0; } if (buffer[++num] != 0) { return 1; } if (buffer[++num] != 0) { return 2; } if (buffer[++num] != 0) { return 3; } if (buffer[++num] != 0) { return 4; } if (buffer[++num] != 0) { return 5; } if (buffer[++num] != 0) { return 6; } if (buffer[++num] != 0) { return 7; } if (buffer[++num] != 0) { return 8; } if (buffer[++num] != 0) { return 9; } return 0; } public readonly bool TryGetCargoIdAtRear(out OptimizedCargo cargo) { int num = bufferLength - 5 - 1; if (buffer[num] == 250) { cargo = GetCargo(num + 1); return true; } cargo = default(OptimizedCargo); return false; } public OptimizedCargo TryPickItemAtRear(int[] needs, out int needIdx) { needIdx = -1; if (buffer[bufferLength - 5 - 1] == 250) { int num = bufferLength - 5 - 1; OptimizedCargo cargo = GetCargo(num + 1); int item = cargo.Item; if (item == needs[0]) { Array.Clear(buffer, num - 4, 10); int num2 = num + 5 + 1; if (updateLen < num2) { updateLen = num2; } needIdx = 0; return cargo; } if (item == needs[1]) { Array.Clear(buffer, num - 4, 10); int num3 = num + 5 + 1; if (updateLen < num3) { updateLen = num3; } needIdx = 1; return cargo; } if (item == needs[2]) { Array.Clear(buffer, num - 4, 10); int num4 = num + 5 + 1; if (updateLen < num4) { updateLen = num4; } needIdx = 2; return cargo; } if (item == needs[3]) { Array.Clear(buffer, num - 4, 10); int num5 = num + 5 + 1; if (updateLen < num5) { updateLen = num5; } needIdx = 3; return cargo; } if (item == needs[4]) { Array.Clear(buffer, num - 4, 10); int num6 = num + 5 + 1; if (updateLen < num6) { updateLen = num6; } needIdx = 4; return cargo; } if (item == needs[5]) { Array.Clear(buffer, num - 4, 10); int num7 = num + 5 + 1; if (updateLen < num7) { updateLen = num7; } needIdx = 5; return cargo; } } return default(OptimizedCargo); } public bool TryPickCargoAtEnd(out OptimizedCargo cargo) { int num = bufferLength - 5 - 1; if (buffer[num] == 250) { OptimizedCargo cargo2 = GetCargo(num + 1); Array.Clear(buffer, num - 4, 10); int num2 = num + 5 + 1; if (updateLen < num2) { updateLen = num2; } cargo = cargo2; return true; } cargo = default(OptimizedCargo); return false; } public readonly bool GetCargoAtIndex(int index, out OptimizedCargo cargo, out int cargoBufferIndex, out int offset) { cargo = new OptimizedCargo(0, 1, 0); offset = -1; byte b = buffer[index]; if (b == 0) { cargoBufferIndex = -1; return false; } int num = -1; if (b >= 246) { num = index - (b - 250); } else { for (int num2 = index; num2 >= index - 5; num2--) { if (buffer[num2] == 250) { num = num2; break; } } } if (num >= 0 && buffer[num] == 250) { cargoBufferIndex = num + 1; cargo = GetCargo(num + 1); offset = index - num + 4; return true; } cargoBufferIndex = -1; return false; } public readonly bool TryGetCargoIdAtIndex(int index, int length, out OptimizedCargo cargo, out int cargoBufferIndex) { if (index < 0) { index = 0; } else if (index >= bufferLength) { index = bufferLength - 1; } int num = index + length; if (num > bufferLength) { num = bufferLength; } for (int i = index; i < num; i++) { if (buffer[i] >= 246) { i += 250 - buffer[i]; cargo = GetCargo(i + 1); cargoBufferIndex = i + 1; return true; } } cargo = default(OptimizedCargo); cargoBufferIndex = -1; return false; } public void Update(OptimizedCargoPath[] optimizedCargoPaths) { if (outputCargoPathIndex.HasValue) { ref OptimizedCargoPath belt = ref outputCargoPathIndex.GetBelt(optimizedCargoPaths); int num; if (belt.chunkCount == 1) { num = belt.chunks[2]; outputChunk = 0; } else { int num2 = belt.chunkCount - 1; if (outputChunk > num2) { outputChunk = num2; } int num3 = 0; while (true) { if (outputIndex < belt.chunks[outputChunk * 3]) { num2 = outputChunk - 1; outputChunk = (num3 + num2) / 2; continue; } if (outputIndex < belt.chunks[outputChunk * 3] + belt.chunks[outputChunk * 3 + 1]) { break; } num3 = outputChunk + 1; outputChunk = (num3 + num2) / 2; } num = belt.chunks[outputChunk * 3 + 2]; } int num4 = bufferLength - 5 - 1; if (buffer[num4] == 250) { OptimizedCargo cargo = GetCargo(num4 + 1); if (closed) { if (belt.TryInsertCargoNoSqueeze(outputIndex, cargo)) { Array.Clear(buffer, num4 - 4, 10); updateLen = bufferLength; } } else if (belt.TryInsertCargo((lastUpdateFrameOdd == belt.lastUpdateFrameOdd) ? outputIndex : ((outputIndex + num > belt.bufferLength - 6) ? (belt.bufferLength - 6) : (outputIndex + num)), cargo)) { Array.Clear(buffer, num4 - 4, 10); updateLen = bufferLength; } } } else if (bufferLength <= 10) { return; } lastUpdateFrameOdd = (GameMain.gameTick & 1) == 1; int num5 = updateLen - 1; while (num5 >= 0 && buffer[num5] != 0) { updateLen--; num5--; } if (updateLen == 0) { return; } int num6 = updateLen; for (int num7 = chunkCount - 1; num7 >= 0; num7--) { int num8 = chunks[num7 * 3]; int num9 = chunks[num7 * 3 + 2]; if (num8 < num6) { if (buffer[num8] != 0) { for (int i = num8 - 5; i < num8 + 4; i++) { if (i >= 0 && buffer[i] == 250) { num8 = ((i >= num8) ? (i - 4) : (i + 5 + 1)); break; } } } int num10 = 0; while (num10 < num9) { int num11 = num6 - num8; if (num11 < 10) { num10 = ((num9 < num11) ? num9 : num11); break; } int num12 = 0; for (int j = 0; j < num9 - num10; j++) { int num13 = num6 - 1 - j; if (buffer[num13] != 0) { break; } num12++; } if (num12 > 0) { Array.Copy(buffer, num8, buffer, num8 + num12, num11 - num12); Array.Clear(buffer, num8, num12); num10 += num12; } int num14 = num6 - 1; while (num14 >= 0 && buffer[num14] != 0) { num6--; num14--; } } int num15 = num8 + ((num10 == 0) ? 1 : num10); if (num6 > num15) { num6 = num15; } } } } private static bool AnyMatch(ComponentNeeds componentNeeds, short[] needsPatterns, int needsSize, int match) { for (int i = 0; i < needsSize; i++) { if (componentNeeds.GetNeeds(i) && needsPatterns[componentNeeds.PatternIndex + i] == match) { return true; } } return false; } internal readonly void SetCargoInBuffer(int bufferIndex, OptimizedCargo optimizedCargo) { SetCargoInBuffer(buffer, bufferIndex, optimizedCargo); } internal static void SetCargoInBuffer(byte[] buffer, int bufferIndex, OptimizedCargo optimizedCargo) { BeltExecutor.SetCargoInBuffer(buffer, bufferIndex, optimizedCargo); } private readonly OptimizedCargo GetCargo(int index) { return BeltExecutor.GetCargo(buffer, index); } private readonly void SetCargo(int index, OptimizedCargo optimizedCargo) { buffer[index] = 246; buffer[index + 1] = 247; buffer[index + 2] = 248; buffer[index + 3] = 249; buffer[index + 4] = 250; SetCargoInBuffer(index + 5, optimizedCargo); buffer[index + 9] = byte.MaxValue; } private static OptimizedCargo AddItemStackToCargo(OptimizedCargo cargo, int itemId, int maxStack, ref int count, ref int inc) { if (cargo.Item == itemId && cargo.Stack < maxStack) { int num = maxStack - cargo.Stack; int num2 = inc; if (num < count) { num2 = inc / count; int num3 = inc - num2 * count; count -= num; num3 -= count; num2 = ((num3 > 0) ? (num2 * num + num3) : (num2 * num)); inc -= num2; } else { num = count; count = 0; inc = 0; } cargo.Stack += (byte)num; cargo.Inc += (byte)num2; } return cargo; } } internal readonly struct OptimizedIndexedCargoPath { private readonly OptimizedCargoPath[]? _optimizedCargoPaths; private readonly BeltIndex _index; public static readonly OptimizedIndexedCargoPath NoBelt = new OptimizedIndexedCargoPath(null, BeltIndex.NoBelt); [MemberNotNullWhen(true, "_optimizedCargoPaths")] public bool HasBelt { [MemberNotNullWhen(true, "_optimizedCargoPaths")] get { return _optimizedCargoPaths != null; } } public BeltIndex BeltIndex => _index; public ref OptimizedCargoPath Belt => ref _index.GetBelt(_optimizedCargoPaths); public OptimizedIndexedCargoPath(OptimizedCargoPath[]? optimizedCargoPaths, BeltIndex index) { _optimizedCargoPaths = optimizedCargoPaths; _index = index; } } internal sealed class PlanetWideBeltExecutor { private readonly Dictionary _cargoPathToOptimizedCargoPath = new Dictionary(); public OptimizedIndexedCargoPath GetOptimizedCargoPath(CargoPath cargoPath) { return _cargoPathToOptimizedCargoPath[cargoPath]; } public void AddBeltExecutor(BeltExecutor beltExecutor) { foreach (KeyValuePair item in beltExecutor.CargoPathToOptimizedCargoPathIndex) { _cargoPathToOptimizedCargoPath.Add(item.Key, new OptimizedIndexedCargoPath(beltExecutor.OptimizedCargoPaths, item.Value)); } } } } namespace Weaver.Optimizations.Assemblers { internal sealed class AssemblerExecutor { private ReadonlyArray _assemblerNetworkIds; public AssemblerState[] _assemblerStates; public OptimizedAssembler[] _optimizedAssemblers; private bool[] _assemblerReplicatings; private int[] _assemblerExtraPowerRatios; private AssemblerTimingData[] _assemblersTimingData; public ReadonlyArray _assemblerRecipeIndexes; public Dictionary _assemblerIdToOptimizedIndex; public HashSet _unOptimizedAssemblerIds; private PrototypePowerConsumptionExecutor _prototypePowerConsumptionExecutor; private long[]? _previousPowerConsumptions; public int _producedSize = -1; public short[] _served; public short[] _incServed; public short[] _produced; public bool[] _needToUpdateNeeds; public int Count => _optimizedAssemblers.Length; public void GameTick(PlanetFactory planet, ReadonlyArray assemblerPowerConsumerTypeIndexes, ReadonlyArray powerConsumerTypes, long[] networksPowerConsumption, int[] productRegister, int[] consumeRegister, SubFactoryNeeds subFactoryNeeds, UniverseStaticData universeStaticData) { float[] networkServes = planet.powerSystem.networkServes; ReadonlyArray assemblerNetworkIds = _assemblerNetworkIds; AssemblerState[] assemblerStates = _assemblerStates; OptimizedAssembler[] optimizedAssemblers = _optimizedAssemblers; ReadonlyArray assemblerRecipes = universeStaticData.AssemblerRecipes; bool[] assemblerReplicatings = _assemblerReplicatings; int[] assemblerExtraPowerRatios = _assemblerExtraPowerRatios; AssemblerTimingData[] assemblersTimingData = _assemblersTimingData; GroupNeeds groupNeeds = subFactoryNeeds.GetGroupNeeds(EntityType.Assembler); ComponentNeeds[] componentsNeeds = subFactoryNeeds.ComponentsNeeds; int producedSize = _producedSize; short[] served = _served; short[] incServed = _incServed; short[] produced = _produced; ReadonlyArray assemblerRecipeIndexes = _assemblerRecipeIndexes; bool[] needToUpdateNeeds = _needToUpdateNeeds; long[] previousPowerConsumptions = _previousPowerConsumptions; if (previousPowerConsumptions == null) { _previousPowerConsumptions = new long[optimizedAssemblers.Length]; previousPowerConsumptions = _previousPowerConsumptions; for (int i = 0; i < optimizedAssemblers.Length; i++) { ref bool reference = ref assemblerReplicatings[i]; ref int reference2 = ref assemblerExtraPowerRatios[i]; previousPowerConsumptions[i] = UpdatePower(assemblerPowerConsumerTypeIndexes, powerConsumerTypes, i, reference, reference2); } } for (int j = 0; j < optimizedAssemblers.Length; j++) { short num = assemblerNetworkIds[j]; ref AssemblerState reference3 = ref assemblerStates[j]; if (reference3 != 0) { networksPowerConsumption[num] += previousPowerConsumptions[j]; continue; } ref readonly AssemblerRecipe assemblerRecipeData = ref assemblerRecipes[assemblerRecipeIndexes[j]]; ref AssemblerTimingData reference4 = ref assemblersTimingData[j]; if (needToUpdateNeeds[j]) { OptimizedAssembler.UpdateNeeds(ref assemblerRecipeData, ref reference4, groupNeeds, served, componentsNeeds, j); needToUpdateNeeds[j] = false; } float num2 = networkServes[num]; if (num2 < 0.1f) { networksPowerConsumption[num] += previousPowerConsumptions[j]; continue; } ref bool reference5 = ref assemblerReplicatings[j]; ref int reference6 = ref assemblerExtraPowerRatios[j]; if (!reference4.UpdateTimings(num2, reference5, ref assemblerRecipeData)) { networksPowerConsumption[num] += previousPowerConsumptions[j]; continue; } int servedOffset = j * groupNeeds.GroupNeedsSize; int producedOffset = j * producedSize; reference3 = optimizedAssemblers[j].Update(num2, productRegister, consumeRegister, ref assemblerRecipeData, ref reference5, ref reference6, ref reference4, servedOffset, producedOffset, served, incServed, produced); if (reference5) { needToUpdateNeeds[j] = true; } previousPowerConsumptions[j] = UpdatePower(assemblerPowerConsumerTypeIndexes, powerConsumerTypes, j, reference5, reference6); networksPowerConsumption[num] += previousPowerConsumptions[j]; } } public void UpdatePower(ReadonlyArray assemblerPowerConsumerTypeIndexes, ReadonlyArray powerConsumerTypes, long[] networksPowerConsumption) { OptimizedAssembler[] optimizedAssemblers = _optimizedAssemblers; ReadonlyArray assemblerNetworkIds = _assemblerNetworkIds; bool[] assemblerReplicatings = _assemblerReplicatings; int[] assemblerExtraPowerRatios = _assemblerExtraPowerRatios; for (int i = 0; i < optimizedAssemblers.Length; i++) { short num = assemblerNetworkIds[i]; bool replicating = assemblerReplicatings[i]; int extraPowerRatios = assemblerExtraPowerRatios[i]; networksPowerConsumption[num] += UpdatePower(assemblerPowerConsumerTypeIndexes, powerConsumerTypes, i, replicating, extraPowerRatios); } } private static long UpdatePower(ReadonlyArray assemblerPowerConsumerTypeIndexes, ReadonlyArray powerConsumerTypes, int assemblerIndex, bool replicating, int extraPowerRatios) { int index = assemblerPowerConsumerTypeIndexes[assemblerIndex]; return GetPowerConsumption(powerConsumerTypes[index], replicating, extraPowerRatios); } public PrototypePowerConsumptions UpdatePowerConsumptionPerPrototype(ReadonlyArray assemblerPowerConsumerTypeIndexes, ReadonlyArray powerConsumerTypes) { PrototypePowerConsumptionExecutor prototypePowerConsumptionExecutor = _prototypePowerConsumptionExecutor; prototypePowerConsumptionExecutor.Clear(); bool[] assemblerReplicatings = _assemblerReplicatings; int[] assemblerExtraPowerRatios = _assemblerExtraPowerRatios; ReadonlyArray prototypeIdIndexes = prototypePowerConsumptionExecutor.PrototypeIdIndexes; long[] prototypeIdPowerConsumption = prototypePowerConsumptionExecutor.PrototypeIdPowerConsumption; for (int i = 0; i < assemblerReplicatings.Length; i++) { bool replicating = assemblerReplicatings[i]; int extraPowerRatio = assemblerExtraPowerRatios[i]; UpdatePowerConsumptionPerPrototype(assemblerPowerConsumerTypeIndexes, powerConsumerTypes, prototypeIdIndexes, prototypeIdPowerConsumption, i, replicating, extraPowerRatio); } return prototypePowerConsumptionExecutor.GetPowerConsumption(); } private static void UpdatePowerConsumptionPerPrototype(ReadonlyArray assemblerPowerConsumerTypeIndexes, ReadonlyArray powerConsumerTypes, ReadonlyArray prototypeIdIndexes, long[] prototypeIdPowerConsumption, int assemblerIndex, bool replicating, int extraPowerRatio) { int index = assemblerPowerConsumerTypeIndexes[assemblerIndex]; PowerConsumerType powerConsumerType = powerConsumerTypes[index]; prototypeIdPowerConsumption[prototypeIdIndexes[assemblerIndex]] += GetPowerConsumption(powerConsumerType, replicating, extraPowerRatio); } public void Save(PlanetFactory planet, SubFactoryNeeds subFactoryNeeds) { AssemblerComponent[] assemblerPool = planet.factorySystem.assemblerPool; OptimizedAssembler[] optimizedAssemblers = _optimizedAssemblers; bool[] assemblerReplicatings = _assemblerReplicatings; int[] assemblerExtraPowerRatios = _assemblerExtraPowerRatios; AssemblerTimingData[] assemblersTimingData = _assemblersTimingData; GroupNeeds groupNeeds = subFactoryNeeds.GetGroupNeeds(EntityType.Assembler); ComponentNeeds[] componentsNeeds = subFactoryNeeds.ComponentsNeeds; short[] needsPatterns = subFactoryNeeds.NeedsPatterns; int producedSize = _producedSize; short[] served = _served; short[] incServed = _incServed; short[] produced = _produced; for (int i = 1; i < planet.factorySystem.assemblerCursor; i++) { if (_assemblerIdToOptimizedIndex.TryGetValue(i, out var value)) { optimizedAssemblers[value].Save(ref assemblerPool[i], assemblerReplicatings[value], assemblerExtraPowerRatios[value], ref assemblersTimingData[value], groupNeeds, componentsNeeds, needsPatterns, producedSize, served, incServed, produced, value); } } } public void InitializeAssemblers(PlanetFactory planet, Graph subFactoryGraph, SubFactoryPowerSystemBuilder subFactoryPowerSystemBuilder, SubFactoryProductionRegisterBuilder subFactoryProductionRegisterBuilder, SubFactoryNeedsBuilder subFactoryNeedsBuilder, UniverseStaticDataBuilder universeStaticDataBuilder) { //IL_0184: Unknown result type (might be due to invalid IL or missing references) List list = new List(); List list2 = new List(); List list3 = new List(); List list4 = new List(); List list5 = new List(); List list6 = new List(); List list7 = new List(); HashSet hashSet = new HashSet(); Dictionary dictionary = new Dictionary(); HashSet hashSet2 = new HashSet(); List list8 = new List(); List list9 = new List(); List list10 = new List(); PrototypePowerConsumptionBuilder prototypePowerConsumptionBuilder = new PrototypePowerConsumptionBuilder(); GroupNeedsBuilder groupNeedsBuilder = subFactoryNeedsBuilder.CreateGroupNeedsBuilder(EntityType.Assembler); GameHistoryData history = planet.gameData.history; foreach (int item in from x in subFactoryGraph.GetAllNodes() where x.EntityTypeIndex.EntityType == EntityType.Assembler select x.EntityTypeIndex.Index into x orderby x select x) { ref AssemblerComponent reference = ref planet.factorySystem.assemblerPool[item]; if (reference.id != item) { hashSet2.Add(item); continue; } if (reference.recipeId == 0) { hashSet2.Add(item); continue; } if (reference.needs == null) { hashSet2.Add(item); continue; } if (!history.RecipeUnlocked(reference.recipeId)) { hashSet2.Add(item); continue; } AssemblerRecipe assemblerRecipe = new AssemblerRecipe(reference.recipeId, reference.recipeType, reference.recipeExecuteData.timeSpend, reference.recipeExecuteData.extraTimeSpend, reference.speed, reference.recipeExecuteData.productive, subFactoryProductionRegisterBuilder.AddConsume(reference.recipeExecuteData.requires), universeStaticDataBuilder.DeduplicateArrayUnmanaged(ConverterUtilities.ConvertToShortArrayOrThrow(reference.recipeExecuteData.requireCounts, "requireCounts")), subFactoryProductionRegisterBuilder.AddProduct(reference.recipeExecuteData.products), universeStaticDataBuilder.DeduplicateArrayUnmanaged(ConverterUtilities.ConvertToShortArrayOrThrow(reference.recipeExecuteData.productCounts, "productCounts"))); hashSet.Add(assemblerRecipe); int num = universeStaticDataBuilder.AddAssemblerRecipe(ref assemblerRecipe); dictionary.Add(reference.id, list3.Count); int networkId = planet.powerSystem.consumerPool[reference.pcId].networkId; list.Add(ConverterUtilities.ThrowIfNotWithinPositiveShortRange(networkId, "networkIndex")); list2.Add(AssemblerState.Active); list3.Add(new OptimizedAssembler(ref reference)); list4.Add(reference.replicating); list5.Add(reference.extraPowerRatio); list6.Add(new AssemblerTimingData(ref reference)); list8.Add(reference.served); list9.Add(reference.incServed); list10.Add(reference.produced); list7.Add((short)num); subFactoryPowerSystemBuilder.AddAssembler(ref reference, networkId); prototypePowerConsumptionBuilder.AddPowerConsumer(ref planet.entityPool[reference.entityId]); planet.entityNeeds[reference.entityId] = reference.needs; groupNeedsBuilder.AddNeeds(reference.needs, reference.recipeExecuteData.requires); } if (hashSet.Count > 0) { int num2 = hashSet.Max((AssemblerRecipe x) => x.Requires.Length); int num3 = hashSet.Max((AssemblerRecipe x) => x.Products.Length); List list11 = new List(); List list12 = new List(); List list13 = new List(); for (int i = 0; i < list3.Count; i++) { for (int j = 0; j < num2; j++) { list11.Add(GroupNeeds.GetOrDefaultConvertToShortWithClamping(list8[i], j, -5000, 5000)); list12.Add(GroupNeeds.GetOrDefaultConvertToShortWithClamping(list9[i], j, -5000, 5000)); } for (int k = 0; k < num3; k++) { list13.Add(GroupNeeds.GetOrDefaultConvertToShortWithClamping(list10[i], k, -5000, 5000)); } } _producedSize = num3; _served = list11.ToArray(); _incServed = list12.ToArray(); _produced = list13.ToArray(); _needToUpdateNeeds = new bool[list3.Count]; _needToUpdateNeeds.Fill(value: true); } _assemblerNetworkIds = universeStaticDataBuilder.DeduplicateArrayUnmanaged(list); _assemblerStates = list2.ToArray(); _optimizedAssemblers = list3.ToArray(); _assemblerReplicatings = list4.ToArray(); _assemblerExtraPowerRatios = list5.ToArray(); _assemblersTimingData = list6.ToArray(); _assemblerRecipeIndexes = universeStaticDataBuilder.DeduplicateArrayUnmanaged(list7); _assemblerIdToOptimizedIndex = dictionary; _unOptimizedAssemblerIds = hashSet2; _prototypePowerConsumptionExecutor = prototypePowerConsumptionBuilder.Build(universeStaticDataBuilder); groupNeedsBuilder.Complete(); } private static long GetPowerConsumption(PowerConsumerType powerConsumerType, bool assemblerReplicating, int assemblerExtraPowerRatio) { return powerConsumerType.GetRequiredEnergy(assemblerReplicating, 1000 + assemblerExtraPowerRatio); } } [StructLayout(LayoutKind.Sequential, Pack = 1)] internal readonly struct AssemblerRecipe : IEquatable, IMemorySize { public readonly int RecipeId; public readonly ERecipeType RecipeType; public readonly int TimeSpend; public readonly int ExtraTimeSpend; public readonly int Speed; public readonly bool Productive; public readonly OptimizedItemId[] Requires; public readonly ReadonlyArray RequireCounts; public readonly OptimizedItemId[] Products; public readonly ReadonlyArray ProductCounts; public AssemblerRecipe(int recipeId, ERecipeType recipeType, int timeSpend, int extraTimeSpend, int speed, bool productive, OptimizedItemId[] requires, ReadonlyArray requireCounts, OptimizedItemId[] products, ReadonlyArray productCounts) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) RecipeId = recipeId; RecipeType = recipeType; TimeSpend = timeSpend; ExtraTimeSpend = extraTimeSpend; Speed = speed; Productive = productive; Requires = requires; RequireCounts = requireCounts; Products = products; ProductCounts = productCounts; } public int GetSize() { return Marshal.SizeOf() + Marshal.SizeOf() * Requires.Length + Marshal.SizeOf() * RequireCounts.Length + Marshal.SizeOf() * Products.Length + Marshal.SizeOf() * ProductCounts.Length; } public bool Equals(AssemblerRecipe other) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) if (RecipeId == other.RecipeId && RecipeType == other.RecipeType && TimeSpend == other.TimeSpend && ExtraTimeSpend == other.ExtraTimeSpend && Speed == other.Speed && Productive == other.Productive && Requires.SequenceEqual(other.Requires) && RequireCounts.SequenceEqual(other.RequireCounts) && Products.SequenceEqual(other.Products)) { return ProductCounts.SequenceEqual(other.ProductCounts); } return false; } public override bool Equals(object obj) { if (obj is AssemblerRecipe other) { return Equals(other); } return false; } public override int GetHashCode() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) HashCode hashCode = default(HashCode); hashCode.Add(RecipeId); hashCode.Add(RecipeType); hashCode.Add(TimeSpend); hashCode.Add(ExtraTimeSpend); hashCode.Add(Speed); hashCode.Add(Productive); for (int i = 0; i < Requires.Length; i++) { hashCode.Add(Requires[i]); } for (int j = 0; j < RequireCounts.Length; j++) { hashCode.Add(RequireCounts[j]); } for (int k = 0; k < Products.Length; k++) { hashCode.Add(Products[k]); } for (int l = 0; l < ProductCounts.Length; l++) { hashCode.Add(ProductCounts[l]); } return hashCode.ToHashCode(); } public void Print() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) WeaverFixes.Logger.LogInfo((object)string.Format("{0}: {1}", "RecipeId", RecipeId)); WeaverFixes.Logger.LogInfo((object)string.Format("{0}: {1}", "RecipeType", RecipeType)); WeaverFixes.Logger.LogInfo((object)string.Format("{0}: {1}", "TimeSpend", TimeSpend)); WeaverFixes.Logger.LogInfo((object)string.Format("{0}: {1}", "ExtraTimeSpend", ExtraTimeSpend)); WeaverFixes.Logger.LogInfo((object)string.Format("{0}: {1}", "Speed", Speed)); WeaverFixes.Logger.LogInfo((object)string.Format("{0}: {1}", "Productive", Productive)); WeaverFixes.Logger.LogInfo((object)("Requires: [" + ((Requires != null) ? string.Join(", ", Requires) : null) + "]")); WeaverFixes.Logger.LogInfo((object)("RequireCounts: [" + string.Join(", ", RequireCounts) + "]")); WeaverFixes.Logger.LogInfo((object)("Products: [" + ((Products != null) ? string.Join(", ", Products) : null) + "]")); WeaverFixes.Logger.LogInfo((object)("ProductCounts: [" + string.Join(", ", ProductCounts) + "]")); WeaverFixes.Logger.LogInfo((object)string.Format("{0}: {1}", "GetHashCode", GetHashCode())); } } [Flags] internal enum AssemblerState : byte { Active = 0, Inactive = 4, InactiveOutputFull = 5, InactiveInputMissing = 6 } internal struct AssemblerTimingData { public int Time; public int ExtraTime; public int ExtraSpeed; public int SpeedOverride; public AssemblerTimingData([In][RequiresLocation] ref AssemblerComponent assembler) { Time = assembler.time; ExtraTime = assembler.extraTime; SpeedOverride = assembler.speedOverride; ExtraSpeed = assembler.extraSpeed; } public bool UpdateTimings(float power, bool replicating, [In][RequiresLocation] ref AssemblerRecipe assemblerRecipeData) { if (replicating && Time < assemblerRecipeData.TimeSpend && ExtraTime < assemblerRecipeData.ExtraTimeSpend) { Time += (int)(power * (float)SpeedOverride); ExtraTime += (int)(power * (float)ExtraSpeed); return false; } return true; } } [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct OptimizedAssembler { public readonly bool forceAccMode; public bool incUsed; public int cycleCount; public int extraCycleCount; public OptimizedAssembler([In][RequiresLocation] ref AssemblerComponent assembler) { forceAccMode = assembler.forceAccMode; incUsed = assembler.incUsed; cycleCount = assembler.cycleCount; extraCycleCount = assembler.extraCycleCount; } public static void UpdateNeeds([In][RequiresLocation] ref AssemblerRecipe assemblerRecipeData, [In][RequiresLocation] ref AssemblerTimingData assemblerTimingData, GroupNeeds groupNeeds, short[] served, ComponentNeeds[] componentsNeeds, int assemblerIndex) { int num = assemblerTimingData.SpeedOverride * 180 / assemblerRecipeData.TimeSpend + 1; if (num < 2) { num = 2; } int objectNeedsIndex = groupNeeds.GetObjectNeedsIndex(assemblerIndex); int num2 = groupNeeds.GroupNeedsSize * assemblerIndex; ReadonlyArray requireCounts = assemblerRecipeData.RequireCounts; byte b = 0; for (int i = 0; i < requireCounts.Length; i++) { b |= (byte)(((served[num2 + i] < requireCounts[i] * num) ? 1u : 0u) << i); } componentsNeeds[objectNeedsIndex].Needs = b; } public AssemblerState Update(float power, int[] productRegister, int[] consumeRegister, [In][RequiresLocation] ref AssemblerRecipe assemblerRecipeData, ref bool replicating, ref int extraPowerRatio, ref AssemblerTimingData assemblerTimingData, int servedOffset, int producedOffset, short[] served, short[] incServed, short[] produced) { //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Invalid comparison between Unknown and I4 //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Invalid comparison between Unknown and I4 //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Invalid comparison between Unknown and I4 //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Invalid comparison between Unknown and I4 //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Invalid comparison between Unknown and I4 //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Invalid comparison between Unknown and I4 //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Invalid comparison between Unknown and I4 if (assemblerTimingData.ExtraTime >= assemblerRecipeData.ExtraTimeSpend) { for (int i = 0; i < assemblerRecipeData.ProductCounts.Length; i++) { produced[producedOffset + i] += assemblerRecipeData.ProductCounts[i]; productRegister[assemblerRecipeData.Products[i].OptimizedItemIndex] += assemblerRecipeData.ProductCounts[i]; } extraCycleCount++; assemblerTimingData.ExtraTime -= assemblerRecipeData.ExtraTimeSpend; } if (assemblerTimingData.Time >= assemblerRecipeData.TimeSpend) { replicating = false; if (assemblerRecipeData.Products.Length == 1) { ERecipeType recipeType = assemblerRecipeData.RecipeType; if ((int)recipeType != 1) { if ((int)recipeType == 4) { if (produced[producedOffset] > assemblerRecipeData.ProductCounts[0] * 9) { return AssemblerState.InactiveOutputFull; } } else if (produced[producedOffset] > assemblerRecipeData.ProductCounts[0] * 19) { return AssemblerState.InactiveOutputFull; } } else if (produced[producedOffset] + assemblerRecipeData.ProductCounts[0] > 100) { return AssemblerState.InactiveOutputFull; } produced[producedOffset] += assemblerRecipeData.ProductCounts[0]; productRegister[assemblerRecipeData.Products[0].OptimizedItemIndex] += assemblerRecipeData.ProductCounts[0]; } else { int num = assemblerRecipeData.Products.Length; if ((int)assemblerRecipeData.RecipeType == 3) { for (int j = 0; j < num; j++) { if (produced[producedOffset + j] > assemblerRecipeData.ProductCounts[j] * 19) { return AssemblerState.InactiveOutputFull; } } } else if ((int)assemblerRecipeData.RecipeType == 5) { for (int k = 0; k < num; k++) { if (produced[producedOffset + k] > assemblerRecipeData.ProductCounts[k] * 19) { return AssemblerState.InactiveOutputFull; } } } else if ((int)assemblerRecipeData.RecipeType == 2) { for (int l = 0; l < num; l++) { if (produced[producedOffset + l] > assemblerRecipeData.ProductCounts[l] * 19) { return AssemblerState.InactiveOutputFull; } } } else if ((int)assemblerRecipeData.RecipeType == 1) { for (int m = 0; m < num; m++) { if (produced[producedOffset + m] + assemblerRecipeData.ProductCounts[m] > 100) { return AssemblerState.InactiveOutputFull; } } } else if ((int)assemblerRecipeData.RecipeType == 4) { for (int n = 0; n < num; n++) { if (produced[producedOffset + n] > assemblerRecipeData.ProductCounts[n] * 9) { return AssemblerState.InactiveOutputFull; } } } else { for (int num2 = 0; num2 < num; num2++) { if (produced[producedOffset + num2] > assemblerRecipeData.ProductCounts[num2] * 19) { return AssemblerState.InactiveOutputFull; } } } for (int num3 = 0; num3 < num; num3++) { produced[producedOffset + num3] += assemblerRecipeData.ProductCounts[num3]; productRegister[assemblerRecipeData.Products[num3].OptimizedItemIndex] += assemblerRecipeData.ProductCounts[num3]; } } assemblerTimingData.ExtraSpeed = 0; assemblerTimingData.SpeedOverride = assemblerRecipeData.Speed; extraPowerRatio = 0; cycleCount++; assemblerTimingData.Time -= assemblerRecipeData.TimeSpend; } if (!replicating) { int length = assemblerRecipeData.RequireCounts.Length; for (int num4 = 0; num4 < length; num4++) { if (incServed[servedOffset + num4] <= 0) { incServed[servedOffset + num4] = 0; } if (served[servedOffset + num4] < assemblerRecipeData.RequireCounts[num4] || served[servedOffset + num4] == 0) { assemblerTimingData.Time = 0; return AssemblerState.InactiveInputMissing; } } int num5 = ((length > 0) ? 10 : 0); for (int num6 = 0; num6 < length; num6++) { int num7 = split_inc_level(ref served[servedOffset + num6], ref incServed[servedOffset + num6], assemblerRecipeData.RequireCounts[num6]); num5 = ((num5 < num7) ? num5 : num7); if (!incUsed) { incUsed = num7 > 0; } if (served[servedOffset + num6] == 0) { incServed[servedOffset + num6] = 0; } consumeRegister[assemblerRecipeData.Requires[num6].OptimizedItemIndex] += assemblerRecipeData.RequireCounts[num6]; } if (num5 < 0) { num5 = 0; } if (assemblerRecipeData.Productive && !forceAccMode) { assemblerTimingData.ExtraSpeed = (int)((double)assemblerRecipeData.Speed * Cargo.incTableMilli[num5] * 10.0 + 0.1); assemblerTimingData.SpeedOverride = assemblerRecipeData.Speed; extraPowerRatio = Cargo.powerTable[num5]; } else { assemblerTimingData.ExtraSpeed = 0; assemblerTimingData.SpeedOverride = (int)((double)assemblerRecipeData.Speed * (1.0 + Cargo.accTableMilli[num5]) + 0.1); extraPowerRatio = Cargo.powerTable[num5]; } replicating = true; } assemblerTimingData.UpdateTimings(power, replicating, ref assemblerRecipeData); if (!replicating) { throw new InvalidOperationException("I do not think this is possible. Not sure why it is in the game."); } return AssemblerState.Active; } public readonly void Save(ref AssemblerComponent assembler, bool replicating, int extraPowerRatio, [In][RequiresLocation] ref AssemblerTimingData assemblerTimingData, GroupNeeds groupNeeds, ComponentNeeds[] componentsNeeds, short[] needsPatterns, int producedSize, short[] served, short[] incServed, short[] produced, int assemblerIndex) { int objectNeedsIndex = groupNeeds.GetObjectNeedsIndex(assemblerIndex); int num = groupNeeds.GroupNeedsSize * assemblerIndex; ComponentNeeds componentNeeds = componentsNeeds[objectNeedsIndex]; for (int i = 0; i < groupNeeds.GroupNeedsSize; i++) { GroupNeeds.SetIfInRange(assembler.served, served, i, num + i); GroupNeeds.SetNeedsIfInRange(assembler.needs, componentNeeds, needsPatterns, i); GroupNeeds.SetIfInRange(assembler.incServed, incServed, i, num + i); } int num2 = assemblerIndex * producedSize; for (int j = 0; j < producedSize; j++) { GroupNeeds.SetIfInRange(assembler.produced, produced, j, num2 + j); } assembler.incUsed = incUsed; assembler.speedOverride = assemblerTimingData.SpeedOverride; assembler.time = assemblerTimingData.Time; assembler.extraTime = assemblerTimingData.ExtraTime; assembler.cycleCount = cycleCount; assembler.extraCycleCount = extraCycleCount; assembler.extraSpeed = assemblerTimingData.ExtraSpeed; assembler.replicating = replicating; assembler.extraPowerRatio = extraPowerRatio; } private static int split_inc_level(ref short n, ref short m, short p) { int num = m / n; int num2 = m - num * n; n -= p; num2 -= n; m -= (short)((num2 > 0) ? (num * p + num2) : (num * p)); return num; } } } namespace Weaver.GameStatistics { internal static class MemoryStatistics { public static void EnableGameStatistics(Harmony harmony) { harmony.PatchAll(typeof(MemoryStatistics)); } [HarmonyPostfix] [HarmonyPatch(typeof(GameSave), "LoadCurrentGame")] private static void LoadCurrentGame_Postfix() { long num = 0L; long num2 = 0L; long num3 = 0L; long num4 = 0L; for (int i = 0; i < GameMain.data.factoryCount; i++) { FactorySystem factorySystem = GameMain.data.factories[i].factorySystem; if (factorySystem == null) { continue; } num += factorySystem.traffic.container.cargoPool.Length * Marshal.SizeOf(); num4 += factorySystem.traffic.beltPool.Length * Marshal.SizeOf(); CargoPath[] pathPool = factorySystem.traffic.pathPool; foreach (CargoPath val in pathPool) { if (val != null) { num2 += val.pointPos.Length * Marshal.SizeOf(); num3 += val.pointRot.Length * Marshal.SizeOf(); } } } long num5 = num + num2 + num3 + num4; WeaverFixes.Logger.LogMessage((object)$"Total cargo memory: {num:N0}"); WeaverFixes.Logger.LogMessage((object)$"Total cargo path position memory: {num2:N0}"); WeaverFixes.Logger.LogMessage((object)$"Total cargo path rotation memory: {num3:N0}"); WeaverFixes.Logger.LogMessage((object)$"Total belt struct memory: {num4:N0}"); WeaverFixes.Logger.LogMessage((object)$"Total belt memory: {num5:N0}"); } } } namespace Weaver.FatoryGraphs { internal enum EntityType : byte { None, Belt, Assembler, Ejector, Silo, ProducingLab, ResearchingLab, Storage, Tank, Station, PowerGenerator, FuelPowerGenerator, PowerExchanger, Splitter, Inserter, Monitor, SprayCoater, Piler, Miner, Fractionator, Dispenser, Turret, FieldGenerator, BattleBase, Marker, VeinGroup } internal record struct EntityTypeIndex(EntityType EntityType, int Index); internal sealed class Graph { private readonly Dictionary _entityTypeIndexToNode = new Dictionary(); public int NodeCount => _entityTypeIndexToNode.Count; public void AddNode(Node node) { _entityTypeIndexToNode.Add(node.EntityTypeIndex, node); } public IEnumerable GetAllNodes() { return _entityTypeIndexToNode.Values; } } internal static class Graphifier { private const int minNodePerGraph = 200; private const int maxCombinedGraphSize = 1000; public static List ToGraphs(PlanetFactory planet) { Dictionary dictionary = new Dictionary(); AddInsertersToGraph(planet, dictionary); AddAssemblersToGraph(planet, dictionary); AddMonitorsToGraph(planet, dictionary); AddSpraycoatersToGraph(planet, dictionary); AddPilersToGraph(planet, dictionary); AddMinersToGraph(planet, dictionary); AddFractionatorsToGraph(planet, dictionary); AddEjectorsToGraph(planet, dictionary); AddSilosToGraph(planet, dictionary); AddLabsToGraph(planet, dictionary); AddStationsToGraph(planet, dictionary); AddDispensersToGraph(planet, dictionary); AddStoragesToGraph(planet, dictionary); AddTanksToGraph(planet, dictionary); AddSplittersToGraph(planet, dictionary); AddBeltsToGraph(planet, dictionary); AddTurretsToGraph(planet, dictionary); AddPowerExchangers(planet, dictionary); AddPowerGenerators(planet, dictionary); HashSet hashSet = new HashSet(dictionary.Values); List list = new List(); while (hashSet.Count > 0) { Node item = hashSet.First(); Queue queue = new Queue(); HashSet hashSet2 = new HashSet(); queue.Enqueue(item); hashSet2.Add(item); hashSet.Remove(item); while (queue.Count > 0) { foreach (Node node in queue.Dequeue().Nodes) { if (hashSet2.Add(node)) { queue.Enqueue(node); hashSet.Remove(node); } } } Graph graph = new Graph(); foreach (Node item2 in hashSet2) { graph.AddNode(item2); } list.Add(graph); } return list.OrderBy(GraphOrder).ToList(); } public static void CombineSmallGraphs(List graphs) { List list = new List(); Graph graph = null; foreach (Graph item in graphs.Where((Graph x) => x.NodeCount < 1000).OrderBy(GraphOrder)) { if (graph == null) { graph = new Graph(); } foreach (Node allNode in item.GetAllNodes()) { graph.AddNode(allNode); } if (graph.NodeCount >= 1000) { list.Add(graph); graph = null; } } if (graph != null) { list.Add(graph); graph = null; } graphs.RemoveAll((Graph x) => x.NodeCount < 1000); graphs.AddRange(list); List source = graphs.ToList(); graphs.Clear(); graphs.AddRange(source.OrderBy(GraphOrder)); } private static int GraphOrder(Graph graph) { Node[] array = (from x in graph.GetAllNodes() where x.EntityTypeIndex.EntityType == EntityType.Inserter select x).ToArray(); if (array.Length == 0) { return int.MaxValue; } return array.Min((Node x) => x.EntityTypeIndex.Index); } private static void AddInsertersToGraph(PlanetFactory planet, Dictionary entityTypeIndexToNode) { for (int i = 1; i < planet.factorySystem.inserterCursor; i++) { ref InserterComponent reference = ref planet.factorySystem.inserterPool[i]; if (reference.id != i) { continue; } Node orCreateNode = GetOrCreateNode(entityTypeIndexToNode, new EntityTypeIndex(EntityType.Inserter, i)); if (reference.pickTarget != 0) { if (!TryGetEntityTypeIndex(reference.pickTarget, planet.factorySystem, out var entityTypeIndex)) { entityTypeIndexToNode.Remove(orCreateNode.EntityTypeIndex); continue; } ConnectReceiveFrom(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } if (reference.insertTarget != 0) { if (!TryGetEntityTypeIndex(reference.insertTarget, planet.factorySystem, out var entityTypeIndex2)) { entityTypeIndexToNode.Remove(orCreateNode.EntityTypeIndex); } else { ConnectSendTo(entityTypeIndexToNode, orCreateNode, entityTypeIndex2.Value); } } } } private static void AddAssemblersToGraph(PlanetFactory planet, Dictionary entityTypeIndexToNode) { for (int i = 1; i < planet.factorySystem.assemblerCursor; i++) { if (planet.factorySystem.assemblerPool[i].id == i) { GetOrCreateNode(entityTypeIndexToNode, new EntityTypeIndex(EntityType.Assembler, i)); } } } private static void AddMonitorsToGraph(PlanetFactory planet, Dictionary entityTypeIndexToNode) { for (int i = 1; i < planet.cargoTraffic.monitorCursor; i++) { ref MonitorComponent reference = ref planet.cargoTraffic.monitorPool[i]; if (reference.id == i && reference.pcId != 0) { Node orCreateNode = GetOrCreateNode(entityTypeIndexToNode, new EntityTypeIndex(EntityType.Monitor, i)); if (TryGetBeltSegmentTypeIndex(reference.targetBeltId, planet, out var entityTypeIndex)) { ConnectReceiveFrom(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } } } } private static void AddSpraycoatersToGraph(PlanetFactory planet, Dictionary entityTypeIndexToNode) { for (int i = 1; i < planet.cargoTraffic.spraycoaterCursor; i++) { ref SpraycoaterComponent reference = ref planet.cargoTraffic.spraycoaterPool[i]; if (reference.id == i && reference.pcId != 0) { Node orCreateNode = GetOrCreateNode(entityTypeIndexToNode, new EntityTypeIndex(EntityType.SprayCoater, i)); if (TryGetBeltSegmentTypeIndex(reference.incBeltId, planet, out var entityTypeIndex)) { ConnectReceiveFrom(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } if (TryGetBeltSegmentTypeIndex(reference.cargoBeltId, planet, out var entityTypeIndex2)) { ConnectSendTo(entityTypeIndexToNode, orCreateNode, entityTypeIndex2.Value); } } } } private static void AddPilersToGraph(PlanetFactory planet, Dictionary entityTypeIndexToNode) { for (int i = 1; i < planet.cargoTraffic.pilerCursor; i++) { ref PilerComponent reference = ref planet.cargoTraffic.pilerPool[i]; if (reference.id == i && reference.pcId != 0) { Node orCreateNode = GetOrCreateNode(entityTypeIndexToNode, new EntityTypeIndex(EntityType.Piler, i)); if (TryGetBeltSegmentTypeIndex(reference.inputBeltId, planet, out var entityTypeIndex)) { ConnectReceiveFrom(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } if (TryGetBeltSegmentTypeIndex(reference.outputBeltId, planet, out var entityTypeIndex2)) { ConnectSendTo(entityTypeIndexToNode, orCreateNode, entityTypeIndex2.Value); } } } } private static void AddMinersToGraph(PlanetFactory planet, Dictionary entityTypeIndexToNode) { for (int i = 1; i < planet.factorySystem.minerCursor; i++) { ref MinerComponent reference = ref planet.factorySystem.minerPool[i]; if (reference.id != i || reference.pcId == 0) { continue; } Node orCreateNode = GetOrCreateNode(entityTypeIndexToNode, new EntityTypeIndex(EntityType.Miner, i)); if (reference.insertTarget > 0) { if (!TryGetEntityTypeIndex(reference.insertTarget, planet.factorySystem, out var entityTypeIndex)) { entityTypeIndexToNode.Remove(orCreateNode.EntityTypeIndex); continue; } ConnectSendTo(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } int stationId = planet.entityPool[reference.entityId].stationId; if (stationId > 0) { EntityTypeIndex receiverTypeIndex = new EntityTypeIndex(EntityType.Station, stationId); ConnectSendTo(entityTypeIndexToNode, orCreateNode, receiverTypeIndex); } for (int j = 0; j < reference.veinCount; j++) { int groupIndex = planet.veinPool[reference.veins[j]].groupIndex; EntityTypeIndex senderTypeIndex = new EntityTypeIndex(EntityType.VeinGroup, groupIndex); ConnectReceiveFrom(entityTypeIndexToNode, orCreateNode, senderTypeIndex); } } } private static void AddFractionatorsToGraph(PlanetFactory planet, Dictionary entityTypeIndexToNode) { for (int i = 1; i < planet.factorySystem.fractionatorCursor; i++) { ref FractionatorComponent reference = ref planet.factorySystem.fractionatorPool[i]; if (reference.id != i || reference.pcId == 0) { continue; } Node orCreateNode = GetOrCreateNode(entityTypeIndexToNode, new EntityTypeIndex(EntityType.Fractionator, i)); if (TryGetBeltSegmentTypeIndex(reference.belt0, planet, out var entityTypeIndex)) { if (reference.isOutput0) { ConnectSendTo(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } else { ConnectReceiveFrom(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } } if (TryGetBeltSegmentTypeIndex(reference.belt1, planet, out entityTypeIndex)) { if (reference.isOutput1) { ConnectSendTo(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } else { ConnectReceiveFrom(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } } if (TryGetBeltSegmentTypeIndex(reference.belt2, planet, out entityTypeIndex)) { if (reference.isOutput2) { ConnectSendTo(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } else { ConnectReceiveFrom(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } } } } private static void AddEjectorsToGraph(PlanetFactory planet, Dictionary entityTypeIndexToNode) { for (int i = 1; i < planet.factorySystem.ejectorCursor; i++) { ref EjectorComponent reference = ref planet.factorySystem.ejectorPool[i]; if (reference.id == i && reference.pcId != 0) { GetOrCreateNode(entityTypeIndexToNode, new EntityTypeIndex(EntityType.Ejector, i)); } } } private static void AddSilosToGraph(PlanetFactory planet, Dictionary entityTypeIndexToNode) { for (int i = 1; i < planet.factorySystem.siloCursor; i++) { ref SiloComponent reference = ref planet.factorySystem.siloPool[i]; if (reference.id == i && reference.pcId != 0) { GetOrCreateNode(entityTypeIndexToNode, new EntityTypeIndex(EntityType.Silo, i)); } } } private static void AddLabsToGraph(PlanetFactory planet, Dictionary entityTypeIndexToNode) { for (int i = 1; i < planet.factorySystem.labCursor; i++) { ref LabComponent reference = ref planet.factorySystem.labPool[i]; if (reference.id == i && reference.pcId != 0 && !reference.researchMode) { Node orCreateNode = GetOrCreateNode(entityTypeIndexToNode, new EntityTypeIndex(EntityType.ProducingLab, i)); if (reference.nextLabId > 0) { EntityTypeIndex b = new EntityTypeIndex(EntityType.ProducingLab, reference.nextLabId); BiDirectionConnection(entityTypeIndexToNode, orCreateNode, b); } } } for (int j = 1; j < planet.factorySystem.labCursor; j++) { ref LabComponent reference2 = ref planet.factorySystem.labPool[j]; if (reference2.id == j && reference2.pcId != 0 && reference2.researchMode) { Node orCreateNode2 = GetOrCreateNode(entityTypeIndexToNode, new EntityTypeIndex(EntityType.ResearchingLab, j)); if (reference2.nextLabId > 0) { EntityTypeIndex b2 = new EntityTypeIndex(EntityType.ResearchingLab, reference2.nextLabId); BiDirectionConnection(entityTypeIndexToNode, orCreateNode2, b2); } } } } private static void AddStationsToGraph(PlanetFactory planet, Dictionary entityTypeIndexToNode) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Invalid comparison between Unknown and I4 //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Invalid comparison between Unknown and I4 for (int i = 1; i < planet.transport.stationCursor; i++) { StationComponent val = planet.transport.stationPool[i]; if (val == null || val.id != i) { continue; } Node orCreateNode = GetOrCreateNode(entityTypeIndexToNode, new EntityTypeIndex(EntityType.Station, i)); SlotData[] slots = val.slots; foreach (SlotData val2 in slots) { if (TryGetBeltSegmentTypeIndex(val2.beltId, planet, out var entityTypeIndex)) { if ((int)val2.dir == 1) { ConnectSendTo(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } else if ((int)val2.dir == 2) { ConnectReceiveFrom(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } } } } } private static void AddDispensersToGraph(PlanetFactory planet, Dictionary entityTypeIndexToNode) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Invalid comparison between Unknown and I4 //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Invalid comparison between Unknown and I4 //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Invalid comparison between Unknown and I4 //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Invalid comparison between Unknown and I4 //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Invalid comparison between Unknown and I4 //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Invalid comparison between Unknown and I4 for (int i = 1; i < planet.transport.dispenserCursor; i++) { DispenserComponent val = planet.transport.dispenserPool[i]; if (val == null || val.id != i || val.pcId == 0) { continue; } Node orCreateNode = GetOrCreateNode(entityTypeIndexToNode, new EntityTypeIndex(EntityType.Dispenser, i)); if (val.storage != null) { EntityTypeIndex entityTypeIndex = new EntityTypeIndex(EntityType.Dispenser, val.storage.id); if ((int)val.playerMode == 3 || (int)val.playerMode == 2 || (int)val.storageMode == 1) { ConnectReceiveFrom(entityTypeIndexToNode, orCreateNode, entityTypeIndex); } if ((int)val.playerMode == 1 || (int)val.playerMode == 2 || (int)val.storageMode == 2) { ConnectSendTo(entityTypeIndexToNode, orCreateNode, entityTypeIndex); } } } } private static void AddStoragesToGraph(PlanetFactory planet, Dictionary entityTypeIndexToNode) { for (int i = 1; i < planet.factoryStorage.storageCursor; i++) { StorageComponent val = planet.factoryStorage.storagePool[i]; if (val != null && val.id == i) { Node orCreateNode = GetOrCreateNode(entityTypeIndexToNode, new EntityTypeIndex(EntityType.Storage, i)); if (val.previousStorage != null && val.previousStorage.id != 0) { EntityTypeIndex b = new EntityTypeIndex(EntityType.Storage, val.previousStorage.id); BiDirectionConnection(entityTypeIndexToNode, orCreateNode, b); } if (val.nextStorage != null && val.nextStorage.id != 0) { EntityTypeIndex b2 = new EntityTypeIndex(EntityType.Storage, val.nextStorage.id); BiDirectionConnection(entityTypeIndexToNode, orCreateNode, b2); } } } } private static void AddTanksToGraph(PlanetFactory planet, Dictionary entityTypeIndexToNode) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) for (int i = 1; i < planet.factoryStorage.tankCursor; i++) { TankComponent val = planet.factoryStorage.tankPool[i]; if (val.id != i) { continue; } Node orCreateNode = GetOrCreateNode(entityTypeIndexToNode, new EntityTypeIndex(EntityType.Tank, i)); if (val.lastTankId != 0 && planet.factoryStorage.tankPool[val.lastTankId].id == val.lastTankId) { EntityTypeIndex b = new EntityTypeIndex(EntityType.Tank, val.lastTankId); BiDirectionConnection(entityTypeIndexToNode, orCreateNode, b); } if (val.nextTankId != 0 && planet.factoryStorage.tankPool[val.nextTankId].id == val.nextTankId) { EntityTypeIndex b2 = new EntityTypeIndex(EntityType.Tank, val.nextTankId); BiDirectionConnection(entityTypeIndexToNode, orCreateNode, b2); } if (TryGetBeltSegmentTypeIndex(val.belt0, planet, out var entityTypeIndex)) { if (val.isOutput0) { ConnectSendTo(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } else { ConnectReceiveFrom(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } } if (TryGetBeltSegmentTypeIndex(val.belt1, planet, out entityTypeIndex)) { if (val.isOutput1) { ConnectSendTo(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } else { ConnectReceiveFrom(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } } if (TryGetBeltSegmentTypeIndex(val.belt2, planet, out entityTypeIndex)) { if (val.isOutput2) { ConnectSendTo(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } else { ConnectReceiveFrom(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } } if (TryGetBeltSegmentTypeIndex(val.belt3, planet, out entityTypeIndex)) { if (val.isOutput3) { ConnectSendTo(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } else { ConnectReceiveFrom(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } } } } private static void AddSplittersToGraph(PlanetFactory planet, Dictionary entityTypeIndexToNode) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) for (int i = 1; i < planet.cargoTraffic.splitterCursor; i++) { SplitterComponent val = planet.cargoTraffic.splitterPool[i]; if (val.id == i) { Node orCreateNode = GetOrCreateNode(entityTypeIndexToNode, new EntityTypeIndex(EntityType.Splitter, i)); if (TryGetBeltSegmentTypeIndex(val.input0, planet, out var entityTypeIndex)) { ConnectReceiveFrom(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } if (TryGetBeltSegmentTypeIndex(val.input1, planet, out entityTypeIndex)) { ConnectReceiveFrom(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } if (TryGetBeltSegmentTypeIndex(val.input2, planet, out entityTypeIndex)) { ConnectReceiveFrom(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } if (TryGetBeltSegmentTypeIndex(val.input3, planet, out entityTypeIndex)) { ConnectReceiveFrom(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } if (TryGetBeltSegmentTypeIndex(val.output0, planet, out entityTypeIndex)) { ConnectSendTo(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } if (TryGetBeltSegmentTypeIndex(val.output1, planet, out entityTypeIndex)) { ConnectSendTo(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } if (TryGetBeltSegmentTypeIndex(val.output2, planet, out entityTypeIndex)) { ConnectSendTo(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } if (TryGetBeltSegmentTypeIndex(val.output3, planet, out entityTypeIndex)) { ConnectSendTo(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } } } } private static void AddBeltsToGraph(PlanetFactory planet, Dictionary entityTypeIndexToNode) { for (int i = 1; i < planet.cargoTraffic.pathCursor; i++) { CargoPath val = planet.cargoTraffic.pathPool[i]; if (val != null && val.id == i) { Node orCreateNode = GetOrCreateNode(entityTypeIndexToNode, new EntityTypeIndex(EntityType.Belt, i)); if (val.outputPath != null) { EntityTypeIndex receiverTypeIndex = new EntityTypeIndex(EntityType.Belt, val.outputPath.id); ConnectSendTo(entityTypeIndexToNode, orCreateNode, receiverTypeIndex); } } } } private static void AddTurretsToGraph(PlanetFactory planet, Dictionary entityTypeIndexToNode) { for (int i = 1; i < planet.defenseSystem.turrets.cursor; i++) { ref TurretComponent reference = ref planet.defenseSystem.turrets.buffer[i]; if (reference.id == i) { Node orCreateNode = GetOrCreateNode(entityTypeIndexToNode, new EntityTypeIndex(EntityType.Turret, i)); if (TryGetBeltSegmentTypeIndex(reference.targetBeltId, planet, out var entityTypeIndex)) { ConnectReceiveFrom(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } } } } private static void AddPowerExchangers(PlanetFactory planet, Dictionary entityTypeIndexToNode) { for (int i = 1; i < planet.powerSystem.excCursor; i++) { ref PowerExchangerComponent reference = ref planet.powerSystem.excPool[i]; if (reference.id != i) { continue; } Node orCreateNode = GetOrCreateNode(entityTypeIndexToNode, new EntityTypeIndex(EntityType.PowerExchanger, i)); if (TryGetBeltSegmentTypeIndex(reference.belt0, planet, out var entityTypeIndex)) { if (reference.isOutput0) { ConnectSendTo(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } else { ConnectReceiveFrom(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } } if (TryGetBeltSegmentTypeIndex(reference.belt1, planet, out entityTypeIndex)) { if (reference.isOutput1) { ConnectSendTo(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } else { ConnectReceiveFrom(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } } if (TryGetBeltSegmentTypeIndex(reference.belt2, planet, out entityTypeIndex)) { if (reference.isOutput2) { ConnectSendTo(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } else { ConnectReceiveFrom(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } } if (TryGetBeltSegmentTypeIndex(reference.belt3, planet, out entityTypeIndex)) { if (reference.isOutput3) { ConnectSendTo(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } else { ConnectReceiveFrom(entityTypeIndexToNode, orCreateNode, entityTypeIndex.Value); } } } } private static void AddPowerGenerators(PlanetFactory planet, Dictionary entityTypeIndexToNode) { for (int i = 1; i < planet.powerSystem.genCursor; i++) { ref PowerGeneratorComponent reference = ref planet.powerSystem.genPool[i]; if (reference.id == i) { EntityType entityType = ((!reference.wind && !reference.photovoltaic && !reference.gamma && !reference.geothermal) ? EntityType.FuelPowerGenerator : EntityType.PowerGenerator); GetOrCreateNode(entityTypeIndexToNode, new EntityTypeIndex(entityType, i)); } } } private static void BiDirectionConnection(Dictionary entityTypeIndexToNode, Node a, EntityTypeIndex b) { ConnectReceiveFrom(entityTypeIndexToNode, a, b); ConnectSendTo(entityTypeIndexToNode, a, b); } private static void ConnectReceiveFrom(Dictionary entityTypeIndexToNode, Node receiverNode, EntityTypeIndex senderTypeIndex) { Node orCreateNode = GetOrCreateNode(entityTypeIndexToNode, senderTypeIndex); receiverNode.ReceivingFrom.Add(orCreateNode); orCreateNode.SendingTo.Add(receiverNode); } private static void ConnectSendTo(Dictionary entityTypeIndexToNode, Node senderNode, EntityTypeIndex receiverTypeIndex) { Node orCreateNode = GetOrCreateNode(entityTypeIndexToNode, receiverTypeIndex); senderNode.SendingTo.Add(orCreateNode); orCreateNode.ReceivingFrom.Add(senderNode); } private static Node GetOrCreateNode(Dictionary entityTypeIndexToNode, EntityTypeIndex entityTypeIndex) { if (!entityTypeIndexToNode.TryGetValue(entityTypeIndex, out Node value)) { value = new Node(entityTypeIndex); entityTypeIndexToNode.Add(entityTypeIndex, value); } return value; } public static bool TryGetEntityTypeIndex(int index, FactorySystem factory, [NotNullWhen(true)] out EntityTypeIndex? entityTypeIndex) { ref EntityData reference = ref factory.factory.entityPool[index]; if (TryGetBeltSegmentTypeIndex(reference.beltId, factory.factory, out var entityTypeIndex2)) { entityTypeIndex = entityTypeIndex2.Value; return true; } if (reference.assemblerId != 0) { entityTypeIndex = new EntityTypeIndex(EntityType.Assembler, reference.assemblerId); return true; } if (reference.ejectorId != 0) { entityTypeIndex = new EntityTypeIndex(EntityType.Ejector, reference.ejectorId); return true; } if (reference.siloId != 0) { entityTypeIndex = new EntityTypeIndex(EntityType.Silo, reference.siloId); return true; } if (reference.labId != 0) { entityTypeIndex = new EntityTypeIndex(factory.labPool[reference.labId].researchMode ? EntityType.ResearchingLab : EntityType.ProducingLab, reference.labId); return true; } if (reference.storageId != 0) { entityTypeIndex = new EntityTypeIndex(EntityType.Storage, reference.storageId); return true; } if (reference.stationId != 0) { entityTypeIndex = new EntityTypeIndex(EntityType.Station, reference.stationId); return true; } if (reference.powerGenId != 0) { ref PowerGeneratorComponent reference2 = ref factory.factory.powerSystem.genPool[reference.powerGenId]; EntityType entityType = ((!reference2.wind && !reference2.photovoltaic && !reference2.gamma && !reference2.geothermal) ? EntityType.FuelPowerGenerator : EntityType.PowerGenerator); entityTypeIndex = new EntityTypeIndex(entityType, reference.powerGenId); return true; } if (reference.splitterId != 0) { entityTypeIndex = new EntityTypeIndex(EntityType.Splitter, reference.splitterId); return true; } if (reference.inserterId != 0) { entityTypeIndex = new EntityTypeIndex(EntityType.Inserter, reference.inserterId); return true; } entityTypeIndex = null; return false; } private static bool TryGetBeltSegmentTypeIndex(int beltId, PlanetFactory planet, [NotNullWhen(true)] out EntityTypeIndex? entityTypeIndex) { if (beltId <= 0) { entityTypeIndex = null; return false; } CargoPath cargoPath = planet.cargoTraffic.GetCargoPath(planet.cargoTraffic.beltPool[beltId].segPathId); if (cargoPath == null) { entityTypeIndex = null; return false; } entityTypeIndex = new EntityTypeIndex(EntityType.Belt, cargoPath.id); return true; } } internal static class GraphStatistics { public static void Enable(Harmony harmony) { harmony.PatchAll(typeof(GraphStatistics)); } [HarmonyPostfix] [HarmonyPatch(typeof(GameSave), "LoadCurrentGame")] private static void LoadCurrentGame_Postfix() { WeaverFixes.Logger.LogInfo((object)"Initializing GraphStatistics"); List list = new List(); Dictionary dictionary = new Dictionary(); for (int i = 0; i < GameMain.data.factoryCount; i++) { PlanetFactory val = GameMain.data.factories[i]; FactorySystem factorySystem = val.factorySystem; if (factorySystem == null) { continue; } List list2 = Graphifier.ToGraphs(val); list.AddRange(list2); WeaverFixes.Logger.LogInfo((object)("Name: " + val.planet.displayName)); WeaverFixes.Logger.LogInfo((object)$"\tDistinct Graphs: {list2.Count}"); WeaverFixes.Logger.LogInfo((object)"\tGraph Sizes: Size, Count"); foreach (IGrouping item in from x in list2 group x by x.NodeCount) { WeaverFixes.Logger.LogInfo((object)$"\t\t{item.Key:N0}: {item.Count():N0}"); } for (int j = 1; j < factorySystem.inserterCursor; j++) { ref InserterComponent reference = ref factorySystem.inserterPool[j]; if (reference.id == j) { if (dictionary.TryGetValue(reference.grade, out var _)) { dictionary[reference.grade]++; } else { dictionary.Add(reference.grade, 1); } } } PrintGraphStats(list2, new Dictionary()); } WeaverFixes.Logger.LogInfo((object)"Entity type counts"); foreach (EntityType entityType in Enum.GetValues(typeof(EntityType))) { int num = (from x in list.SelectMany((Graph x) => x.GetAllNodes()) where x.EntityTypeIndex.EntityType == entityType select x).Count(); if (entityType == EntityType.Inserter) { WeaverFixes.Logger.LogInfo((object)$"\t{entityType}: {num:N0}"); foreach (KeyValuePair item2 in dictionary.OrderBy((KeyValuePair x) => x.Key)) { WeaverFixes.Logger.LogInfo((object)$"\t\t{item2.Key}: {item2.Value:N0}"); } } else { WeaverFixes.Logger.LogInfo((object)$"\t{entityType}: {num:N0}"); } } } private static void PrintGraphStats(List graphs, Dictionary gradeToCount) { WeaverFixes.Logger.LogInfo((object)"Entity type counts"); foreach (EntityType entityType in Enum.GetValues(typeof(EntityType))) { int num = (from x in graphs.SelectMany((Graph x) => x.GetAllNodes()) where x.EntityTypeIndex.EntityType == entityType select x).Count(); if (entityType == EntityType.Inserter) { WeaverFixes.Logger.LogInfo((object)$"\t{entityType}: {num:N0}"); foreach (KeyValuePair item in gradeToCount.OrderBy((KeyValuePair x) => x.Key)) { WeaverFixes.Logger.LogInfo((object)$"\t\t{item.Key}: {item.Value:N0}"); } } else { WeaverFixes.Logger.LogInfo((object)$"\t{entityType}: {num:N0}"); } } } } internal static class GraphValidation { public static void Enable(Harmony harmony) { harmony.PatchAll(typeof(GraphValidation)); } [HarmonyPostfix] [HarmonyPatch(typeof(GameSave), "LoadCurrentGame")] private static void LoadCurrentGame_Postfix() { WeaverFixes.Logger.LogInfo((object)"Initializing GraphValidation"); for (int i = 0; i < GameMain.data.factoryCount; i++) { PlanetFactory val = GameMain.data.factories[i]; FactorySystem factorySystem = val.factorySystem; CargoTraffic cargoTraffic = val.cargoTraffic; if (factorySystem != null && cargoTraffic != null) { Graphifier.ToGraphs(val); } } } } internal sealed class Node { public HashSet ReceivingFrom = new HashSet(); public HashSet SendingTo = new HashSet(); public EntityTypeIndex EntityTypeIndex; public IEnumerable Nodes => ReceivingFrom.Concat(SendingTo); public Node(EntityTypeIndex entityTypeIndex) { EntityTypeIndex = entityTypeIndex; } } } namespace Weaver.Extensions { internal static class ArrayExtensions { [CompilerGenerated] private sealed class d__1 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator where T : notnull { private int <>1__state; private T <>2__current; private int <>l__initialThreadId; private IEnumerator <>7__wrap1; T IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__1(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>7__wrap1 = null; <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>7__wrap1 = Enum.GetValues(typeof(T)).GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; } if (<>7__wrap1.MoveNext()) { T val = (T)<>7__wrap1.Current; <>2__current = val; <>1__state = 1; return true; } <>m__Finally1(); <>7__wrap1 = null; return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>7__wrap1 is IDisposable disposable) { disposable.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__1(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } public static int Sum(this int[] array) { int num = 0; for (int i = 0; i < array.Length; i++) { num += array[i]; } return num; } [IteratorStateMachine(typeof(d__1<>))] public static IEnumerable GetEnumValuesEnumerable() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__1(-2); } public static void Fill(this T[] array, T value) { for (int i = 0; i < array.Length; i++) { array[i] = value; } } } internal static class ConverterUtilities { public static short ThrowIfNotWithinPositiveShortRange(int value, string name) { if (value < 0 || value > 32767) { throw new ArgumentOutOfRangeException(name, $"{name} was not within the bounds of a short. Value: {value}"); } return (short)value; } internal static short[] ConvertToShortArrayOrThrow(int[] values, string name) { short[] array = new short[values.Length]; for (int i = 0; i < values.Length; i++) { ThrowIfNotWithinPositiveShortRange(values[i], name); array[i] = (short)values[i]; } return array; } } internal static class LinqExtenstions { [CompilerGenerated] private sealed class d__0 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator where T : notnull { private int <>1__state; private T[] <>2__current; private int <>l__initialThreadId; private IEnumerable enumerable; public IEnumerable <>3__enumerable; private int chunkSize; public int <>3__chunkSize; private List 5__2; private IEnumerator 5__3; T[] IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__0(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { 5__2 = null; 5__3 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__2 = new List(); 5__3 = enumerable.GetEnumerator(); goto IL_0095; case 1: <>1__state = -1; 5__2.Clear(); goto IL_0095; case 2: { <>1__state = -1; break; } IL_0095: while (5__3.MoveNext()) { 5__2.Add(5__3.Current); if (5__2.Count == chunkSize) { <>2__current = 5__2.ToArray(); <>1__state = 1; return true; } } if (5__2.Count != 0) { <>2__current = 5__2.ToArray(); <>1__state = 2; return true; } break; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__0 d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__0(0); } d__.enumerable = <>3__enumerable; d__.chunkSize = <>3__chunkSize; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__1 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator where T : notnull { private int <>1__state; private T <>2__current; private int <>l__initialThreadId; private IEnumerator <>7__wrap1; T IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__1(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>7__wrap1 = null; <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>7__wrap1 = Enum.GetValues(typeof(T)).GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; } if (<>7__wrap1.MoveNext()) { T val = (T)<>7__wrap1.Current; <>2__current = val; <>1__state = 1; return true; } <>m__Finally1(); <>7__wrap1 = null; return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>7__wrap1 is IDisposable disposable) { disposable.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new d__1(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [IteratorStateMachine(typeof(d__0<>))] public static IEnumerable Chunk(this IEnumerable enumerable, int chunkSize) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__0(-2) { <>3__enumerable = enumerable, <>3__chunkSize = chunkSize }; } [IteratorStateMachine(typeof(d__1<>))] public static IEnumerable GetEnumValuesEnumerable() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__1(-2); } public static T MinBy(this IEnumerable enumerable, Func comparatorSelector) { T result = default(T); int? num = null; foreach (T item in enumerable) { int num2 = comparatorSelector(item); if (!num.HasValue || num2 < num.Value) { result = item; num = num2; } } if (!num.HasValue) { throw new InvalidOperationException("No data to enumerate."); } return result; } } } namespace Weaver.Benchmarking { internal sealed class TimeIndexedCollectionStatistic { private struct SampleAverage { private Queue _samples; private float _averageSample; public readonly float Average => _averageSample / (float)Math.Max(1, _samples.Count); public readonly bool IsInitialized => _samples != null; public readonly bool IsFilledWithData(int length) { if (!IsInitialized) { return false; } return _samples.Count == length; } public void EnsureInitialized() { if (!IsInitialized) { _samples = new Queue(); _averageSample = 0f; } } public void AddSample(int maxSampleCount, float sample) { if (_samples.Count == maxSampleCount) { _averageSample -= _samples.Dequeue(); } _samples.Enqueue(sample); _averageSample += sample; } public void Clear() { _samples?.Clear(); _averageSample = 0f; } } internal record struct IndexTime(int Index, float TimeInMilliseconds); [CompilerGenerated] private sealed class d__5 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private IndexTime <>2__current; private int <>l__initialThreadId; public TimeIndexedCollectionStatistic <>4__this; private int 5__2; IndexTime IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__5(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; TimeIndexedCollectionStatistic timeIndexedCollectionStatistic = <>4__this; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; goto IL_0076; } <>1__state = -1; 5__2 = 0; goto IL_0086; IL_0076: 5__2++; goto IL_0086; IL_0086: if (5__2 < timeIndexedCollectionStatistic._itemSampleAverages.Length) { if (timeIndexedCollectionStatistic._itemSampleAverages[5__2].IsInitialized) { <>2__current = new IndexTime(5__2, timeIndexedCollectionStatistic._itemSampleAverages[5__2].Average); <>1__state = 1; return true; } goto IL_0076; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__5 result; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; result = this; } else { result = new d__5(0) { <>4__this = <>4__this }; } return result; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } private Stopwatch[] _timers = Array.Empty(); private SampleAverage[] _itemSampleAverages = Array.Empty(); private readonly int _maxSampleCount; public TimeIndexedCollectionStatistic(int maxSampleCount) { _maxSampleCount = maxSampleCount; } public float GetAverageTimeInMilliseconds(int index) { if (index >= _itemSampleAverages.Length) { throw new IndexOutOfRangeException(string.Format("{0} is out of range. Value: {1}", "index", index)); } return _itemSampleAverages[index].Average; } [IteratorStateMachine(typeof(d__5))] public IEnumerable GetIndexTimes() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__5(-2) { <>4__this = this }; } public void StartSampling(int index) { _timers[index].Restart(); } public void EndSampling(int index) { if (index >= _itemSampleAverages.Length) { throw new IndexOutOfRangeException(string.Format("{0} is out of range. Value: {1}", "index", index)); } float sample = (float)_timers[index].Elapsed.TotalMilliseconds; ref SampleAverage reference = ref _itemSampleAverages[index]; reference.EnsureInitialized(); reference.AddSample(_maxSampleCount, sample); } public void EnsureCapacity(int size) { if (_itemSampleAverages.Length >= size) { return; } Array.Resize(ref _itemSampleAverages, size); Array.Resize(ref _timers, size); for (int i = 0; i < _timers.Length; i++) { Stopwatch[] timers = _timers; int num = i; if (timers[num] == null) { timers[num] = new Stopwatch(); } } } public bool IsFilledWithData(int length) { if (_itemSampleAverages.Length > length) { throw new ArgumentOutOfRangeException("length", string.Format("{0} is out of range. Value: {1}", "length", length)); } for (int i = 0; i < length; i++) { if (!_itemSampleAverages[i].IsFilledWithData(_maxSampleCount)) { return false; } } return true; } public void Clear() { for (int i = 0; i < _itemSampleAverages.Length; i++) { _itemSampleAverages[i].Clear(); } } } }