From 1cb9cb8e96779148767f0efeb5c34d0c39474797 Mon Sep 17 00:00:00 2001 From: Soar Qin Date: Tue, 19 Sep 2023 23:12:45 +0800 Subject: [PATCH] CheatEnabler v2.2.0 --- CheatEnabler/BuildPatch.cs | 790 ----------------- CheatEnabler/CheatEnabler.cs | 35 +- CheatEnabler/CheatEnabler.csproj | 2 +- CheatEnabler/FactoryPatch.cs | 1276 ++++++++++++++++++++++++++++ CheatEnabler/I18N.cs | 4 +- CheatEnabler/PlanetFunctions.cs | 171 +--- CheatEnabler/README.md | 25 +- CheatEnabler/UIConfigWindow.cs | 59 +- CheatEnabler/package/manifest.json | 2 +- 9 files changed, 1386 insertions(+), 978 deletions(-) delete mode 100644 CheatEnabler/BuildPatch.cs create mode 100644 CheatEnabler/FactoryPatch.cs diff --git a/CheatEnabler/BuildPatch.cs b/CheatEnabler/BuildPatch.cs deleted file mode 100644 index 10a7696..0000000 --- a/CheatEnabler/BuildPatch.cs +++ /dev/null @@ -1,790 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Reflection.Emit; -using BepInEx.Configuration; -using HarmonyLib; -using UnityEngine; - -namespace CheatEnabler; - -public static class BuildPatch -{ - public static ConfigEntry ImmediateEnabled; - public static ConfigEntry ArchitectModeEnabled; - public static ConfigEntry NoConditionEnabled; - public static ConfigEntry NoCollisionEnabled; - public static ConfigEntry BeltSignalGeneratorEnabled; - - private static Harmony _patch; - private static Harmony _noConditionPatch; - - public static void Init() - { - if (_patch != null) return; - ImmediateEnabled.SettingChanged += (_, _) => ImmediateValueChanged(); - ArchitectModeEnabled.SettingChanged += (_, _) => ArchitectModeValueChanged(); - NoConditionEnabled.SettingChanged += (_, _) => NoConditionValueChanged(); - NoCollisionEnabled.SettingChanged += (_, _) => NoCollisionValueChanged(); - BeltSignalGeneratorEnabled.SettingChanged += (_, _) => BeltSignalGeneratorValueChanged(); - ImmediateValueChanged(); - ArchitectModeValueChanged(); - NoConditionValueChanged(); - NoCollisionValueChanged(); - BeltSignalGeneratorValueChanged(); - _patch = Harmony.CreateAndPatchAll(typeof(BuildPatch)); - } - - public static void Uninit() - { - if (_patch != null) - { - _patch.UnpatchSelf(); - _patch = null; - } - - if (_noConditionPatch != null) - { - _noConditionPatch.UnpatchSelf(); - _noConditionPatch = null; - } - - ImmediateBuild.Enable(false); - ArchitectMode.Enable(false); - BeltSignalGenerator.Enable(false); - NightLightEnd(); - } - - private static void ImmediateValueChanged() - { - ImmediateBuild.Enable(ImmediateEnabled.Value); - } - - private static void ArchitectModeValueChanged() - { - ArchitectMode.Enable(ArchitectModeEnabled.Value); - NightLightUpdateState(); - } - - private static void NoConditionValueChanged() - { - if (NoConditionEnabled.Value) - { - if (_noConditionPatch != null) - { - return; - } - - _noConditionPatch = Harmony.CreateAndPatchAll(typeof(NoConditionBuild)); - } - else if (_noConditionPatch != null) - { - _noConditionPatch.UnpatchSelf(); - _noConditionPatch = null; - } - } - - private static void NoCollisionValueChanged() - { - var coll = ColliderPool.instance; - if (coll == null) return; - var obj = coll.gameObject; - if (obj == null) return; - obj.gameObject.SetActive(!NoCollisionEnabled.Value); - } - - private static void BeltSignalGeneratorValueChanged() - { - BeltSignalGenerator.Enable(BeltSignalGeneratorEnabled.Value); - } - - public static void ArrivePlanet(PlanetFactory factory) - { - var imm = ImmediateEnabled.Value; - var architect = ArchitectModeEnabled.Value; - if (!imm && !architect) return; - var prebuilds = factory.prebuildPool; - if (imm) factory.BeginFlattenTerrain(); - for (var i = factory.prebuildCursor - 1; i > 0; i--) - { - if (prebuilds[i].id != i) continue; - if (prebuilds[i].itemRequired > 0) - { - if (!architect) continue; - prebuilds[i].itemRequired = 0; - if (imm) - factory.BuildFinally(GameMain.mainPlayer, i, false); - else - factory.AlterPrebuildModelState(i); - } - else - { - if (imm) - factory.BuildFinally(GameMain.mainPlayer, i, false); - } - } - - if (imm) factory.EndFlattenTerrain(); - } - - [HarmonyPostfix] - [HarmonyPatch(typeof(PlanetData), nameof(PlanetData.NotifyFactoryLoaded))] - private static void PlanetData_NotifyFactoryLoaded_Postfix(PlanetData __instance) - { - ArrivePlanet(__instance.factory); - } - - /* Night Light Begin */ - private const float NightLightAngleX = -8; - private const float NightLightAngleY = -2; - public static bool NightlightEnabled; - private static bool _nightlightInitialized; - private static bool _mechaOnEarth; - private static AnimationState _sail; - private static Light _sunlight; - - private static void NightLightUpdateState() - { - if (ArchitectModeEnabled.Value) - { - NightlightEnabled = _mechaOnEarth; - return; - } - - NightlightEnabled = false; - if (_sunlight == null) return; - _sunlight.transform.localEulerAngles = new Vector3(0f, 180f); - } - - public static void NightLightLateUpdate() - { - switch (_nightlightInitialized) - { - case false: - NightLightReady(); - break; - case true: - NightLightGo(); - break; - } - } - - private static void NightLightReady() - { - if (!GameMain.isRunning || !GameMain.mainPlayer.controller.model.gameObject.activeInHierarchy) return; - if (_sail == null) - { - _sail = GameMain.mainPlayer.animator.sails[GameMain.mainPlayer.animator.sailAnimIndex]; - } - - _nightlightInitialized = true; - } - - private static void NightLightGo() - { - if (!GameMain.isRunning) - { - NightLightEnd(); - return; - } - - if (_sail.enabled) - { - _mechaOnEarth = false; - NightlightEnabled = false; - if (_sunlight == null) return; - _sunlight.transform.localEulerAngles = new Vector3(0f, 180f); - _sunlight = null; - return; - } - - if (!_mechaOnEarth) - { - if (_sunlight == null) - { - _sunlight = GameMain.universeSimulator.LocalStarSimulator().sunLight; - if (_sunlight == null) return; - } - - _mechaOnEarth = true; - NightlightEnabled = ArchitectModeEnabled.Value; - } - - if (NightlightEnabled) - { - _sunlight.transform.rotation = - Quaternion.LookRotation(-GameMain.mainPlayer.transform.up + GameMain.mainPlayer.transform.forward * NightLightAngleX / 10f + - GameMain.mainPlayer.transform.right * NightLightAngleY / 10f); - } - } - - private static void NightLightEnd() - { - _mechaOnEarth = false; - NightlightEnabled = false; - if (_sunlight != null) - { - _sunlight.transform.localEulerAngles = new Vector3(0f, 180f); - _sunlight = null; - } - - _sail = null; - _nightlightInitialized = false; - } - - [HarmonyTranspiler] - [HarmonyPatch(typeof(StarSimulator), "LateUpdate")] - private static IEnumerable StarSimulator_LateUpdate_Transpiler(IEnumerable instructions, ILGenerator generator) - { - // var vec = NightlightEnabled ? GameMain.mainPlayer.transform.up : __instance.transform.forward; - var matcher = new CodeMatcher(instructions, generator); - var label1 = generator.DefineLabel(); - var label2 = generator.DefineLabel(); - matcher.MatchForward(false, - new CodeMatch(OpCodes.Ldarg_0), - new CodeMatch(OpCodes.Call, AccessTools.PropertyGetter(typeof(Component), nameof(Component.transform))) - ).InsertAndAdvance( - new CodeInstruction(OpCodes.Ldsfld, AccessTools.Field(typeof(BuildPatch), nameof(BuildPatch.NightlightEnabled))), - new CodeInstruction(OpCodes.Brfalse_S, label1), - new CodeInstruction(OpCodes.Call, AccessTools.PropertyGetter(typeof(GameMain), nameof(GameMain.mainPlayer))), - new CodeInstruction(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(Player), nameof(Player.transform))), - new CodeInstruction(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(Transform), nameof(Transform.up))), - new CodeInstruction(OpCodes.Stloc_0), - new CodeInstruction(OpCodes.Br_S, label2) - ); - matcher.Labels.Add(label1); - matcher.MatchForward(false, - new CodeMatch(OpCodes.Stloc_0) - ).Advance(1).Labels.Add(label2); - return matcher.InstructionEnumeration(); - } - - [HarmonyTranspiler] - [HarmonyPatch(typeof(PlanetSimulator), "LateUpdate")] - private static IEnumerable PlanetSimulator_LateUpdate_Transpiler(IEnumerable instructions, ILGenerator generator) - { - // var vec = (NightlightEnabled ? GameMain.mainPlayer.transform.up : (Quaternion.Inverse(localPlanet.runtimeRotation) * (__instance.planetData.star.uPosition - __instance.planetData.uPosition).normalized)); - var matcher = new CodeMatcher(instructions, generator); - var label1 = generator.DefineLabel(); - var label2 = generator.DefineLabel(); - matcher.MatchForward(false, - new CodeMatch(OpCodes.Pop) - ).Advance(1).InsertAndAdvance( - new CodeInstruction(OpCodes.Ldsfld, AccessTools.Field(typeof(BuildPatch), nameof(BuildPatch.NightlightEnabled))), - new CodeInstruction(OpCodes.Brfalse_S, label1), - new CodeInstruction(OpCodes.Call, AccessTools.PropertyGetter(typeof(GameMain), nameof(GameMain.mainPlayer))), - new CodeInstruction(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(Player), nameof(Player.transform))), - new CodeInstruction(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(Transform), nameof(Transform.up))), - new CodeInstruction(OpCodes.Stloc_1), - new CodeInstruction(OpCodes.Br_S, label2) - ); - matcher.Labels.Add(label1); - matcher.MatchForward(false, - new CodeMatch(OpCodes.Ldsfld, AccessTools.Field(typeof(FactoryModel), nameof(FactoryModel.whiteMode0))) - ).Labels.Add(label2); - return matcher.InstructionEnumeration(); - } - /* Night Light End */ - - private static class ImmediateBuild - { - private static Harmony _immediatePatch; - - public static void Enable(bool enable) - { - if (enable) - { - if (_immediatePatch != null) - { - return; - } - - var factory = GameMain.mainPlayer?.factory; - if (factory != null) - { - ArrivePlanet(factory); - } - - _immediatePatch = Harmony.CreateAndPatchAll(typeof(ImmediateBuild)); - } - else if (_immediatePatch != null) - { - _immediatePatch.UnpatchSelf(); - _immediatePatch = null; - } - } - - [HarmonyTranspiler] - [HarmonyPatch(typeof(BuildTool_Addon), nameof(BuildTool_Addon.CreatePrebuilds))] - [HarmonyPatch(typeof(BuildTool_BlueprintPaste), nameof(BuildTool_BlueprintPaste.CreatePrebuilds))] - [HarmonyPatch(typeof(BuildTool_Click), nameof(BuildTool_Click.CreatePrebuilds))] - [HarmonyPatch(typeof(BuildTool_Inserter), nameof(BuildTool_Inserter.CreatePrebuilds))] - [HarmonyPatch(typeof(BuildTool_Path), nameof(BuildTool_Path.CreatePrebuilds))] - private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) - { - var matcher = new CodeMatcher(instructions, generator); - matcher.MatchForward(false, - new CodeMatch(OpCodes.Call, AccessTools.Method(typeof(GC), nameof(GC.Collect))) - ).Insert( - new CodeInstruction(OpCodes.Ldarg_0), - new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(BuildTool), nameof(BuildTool.factory))), - new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(BuildPatch), nameof(ArrivePlanet))) - ); - return matcher.InstructionEnumeration(); - } - } - - private static class ArchitectMode - { - private static Harmony _architectPatch; - private static bool[] _canBuildItems; - - public static void Enable(bool enable) - { - if (enable) - { - if (_architectPatch != null) - { - return; - } - - var factory = GameMain.mainPlayer?.factory; - if (factory != null) - { - ArrivePlanet(factory); - } - - _architectPatch = Harmony.CreateAndPatchAll(typeof(ArchitectMode)); - } - else if (_architectPatch != null) - { - _architectPatch.UnpatchSelf(); - _architectPatch = null; - } - } - - [HarmonyPrefix] - [HarmonyPatch(typeof(StorageComponent), nameof(StorageComponent.TakeTailItems), new[] { typeof(int), typeof(int), typeof(int), typeof(bool) }, - new[] { ArgumentType.Ref, ArgumentType.Ref, ArgumentType.Out, ArgumentType.Normal })] - [HarmonyPatch(typeof(StorageComponent), nameof(StorageComponent.TakeTailItems), new[] { typeof(int), typeof(int), typeof(int[]), typeof(int), typeof(bool) }, - new[] { ArgumentType.Ref, ArgumentType.Ref, ArgumentType.Normal, ArgumentType.Out, ArgumentType.Normal })] - public static bool TakeTailItemsPatch(StorageComponent __instance, int itemId) - { - if (__instance == null || __instance.id != GameMain.mainPlayer.package.id) return true; - if (itemId <= 0) return true; - if (_canBuildItems == null) - { - DoInit(); - } - - return itemId >= 12000 || !_canBuildItems[itemId]; - } - - [HarmonyPostfix] - [HarmonyPatch(typeof(StorageComponent), "GetItemCount", new Type[] { typeof(int) })] - public static void GetItemCountPatch(StorageComponent __instance, int itemId, ref int __result) - { - if (__result > 99) return; - if (__instance == null || __instance.id != GameMain.mainPlayer.package.id) return; - if (itemId <= 0) return; - if (_canBuildItems == null) - { - DoInit(); - } - - if (itemId < 12000 && _canBuildItems[itemId]) __result = 100; - } - - [HarmonyTranspiler] - [HarmonyPatch(typeof(PlayerAction_Inspect), nameof(PlayerAction_Inspect.GetObjectSelectDistance))] - private static IEnumerable PlayerAction_Inspect_GetObjectSelectDistance_Transpiler(IEnumerable instructions) - { - yield return new CodeInstruction(OpCodes.Ldc_R4, 10000f); - yield return new CodeInstruction(OpCodes.Ret); - } - - private static void DoInit() - { - _canBuildItems = new bool[12000]; - foreach (var ip in LDB.items.dataArray) - { - if (ip.CanBuild && ip.ID < 12000) _canBuildItems[ip.ID] = true; - } - } - } - - private static class NoConditionBuild - { - [HarmonyTranspiler] - [HarmonyPatch(typeof(BuildTool_Addon), nameof(BuildTool_Addon.CheckBuildConditions))] - // [HarmonyPatch(typeof(BuildTool_Click), nameof(BuildTool_Click.CheckBuildConditions))] - [HarmonyPatch(typeof(BuildTool_Inserter), nameof(BuildTool_Inserter.CheckBuildConditions))] - [HarmonyPatch(typeof(BuildTool_Path), nameof(BuildTool_Path.CheckBuildConditions))] - private static IEnumerable BuildTool_CheckBuildConditions_Transpiler(IEnumerable instructions) - { - yield return new CodeInstruction(OpCodes.Ldc_I4_1); - yield return new CodeInstruction(OpCodes.Ret); - } - - [HarmonyTranspiler] - [HarmonyPatch(typeof(BuildTool_Click), nameof(BuildTool_Click.CheckBuildConditions))] - private static IEnumerable BuildTool_Click_CheckBuildConditions_Transpiler(IEnumerable instructions) - { - yield return new CodeInstruction(OpCodes.Ldarg_0); - yield return new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(NoConditionBuild), nameof(CheckForMiner))); - yield return new CodeInstruction(OpCodes.Ret); - } - - public static bool CheckForMiner(BuildTool tool) - { - var previews = tool.buildPreviews; - foreach (var preview in previews) - { - var desc = preview?.item?.prefabDesc; - if (desc == null) continue; - if (desc.veinMiner || desc.oilMiner) return false; - } - - return true; - } - } - - private static class BeltSignalGenerator - { - private static Harmony _beltSignalPatch; - private static Dictionary[] _signalBelts; - private static Dictionary _portalFrom; - private static Dictionary> _portalTo; - private static int _signalBeltsCapacity; - private static bool _initialized; - - private class BeltSignal - { - public int SignalId; - public int SpeedLimit; - public byte Stack; - public byte Inc; - public int Progress; - } - - public static void Enable(bool on) - { - if (on) - { - InitSignalBelts(); - _beltSignalPatch ??= Harmony.CreateAndPatchAll(typeof(BeltSignalGenerator)); - } - else - { - _beltSignalPatch?.UnpatchSelf(); - _initialized = false; - _signalBelts = null; - _signalBeltsCapacity = 0; - } - } - - private static void InitSignalBelts() - { - if (!GameMain.isRunning) return; - _signalBelts = new Dictionary[64]; - _signalBeltsCapacity = 64; - _portalFrom = new Dictionary(); - _portalTo = new Dictionary>(); - - foreach (var factory in GameMain.data.factories) - { - var entitySignPool = factory?.entitySignPool; - if (entitySignPool == null) continue; - var cargoTraffic = factory.cargoTraffic; - var beltPool = cargoTraffic.beltPool; - for (var i = cargoTraffic.beltCursor - 1; i > 0; i--) - { - if (beltPool[i].id != i) continue; - ref var signal = ref entitySignPool[beltPool[i].entityId]; - var signalId = signal.iconId0; - if (signalId == 0U) continue; - var number = Mathf.RoundToInt(signal.count0); - switch (signalId) - { - case 404: - SetSignalBelt(factory.index, i, (int)signalId, 0); - continue; - case >= 1000 and < 20000: - if (number > 0) - SetSignalBelt(factory.index, i, (int)signalId, number); - continue; - case 600: - if (number > 0) - SetSignalBelt(factory.index, i, (int)signalId, number); - continue; - case >= 601 and <= 609: - if (number > 0) - SetSignalBeltPortalTo(factory.index, i, (int)signalId, number); - continue; - } - } - } - - _initialized = true; - } - - private static Dictionary GetOrCreateSignalBelts(int index) - { - Dictionary obj; - if (index < 0) return null; - if (index >= _signalBeltsCapacity) - { - var newCapacity = _signalBeltsCapacity * 2; - var newSignalBelts = new Dictionary[newCapacity]; - Array.Copy(_signalBelts, newSignalBelts, _signalBeltsCapacity); - _signalBelts = newSignalBelts; - _signalBeltsCapacity = newCapacity; - } - else - { - obj = _signalBelts[index]; - if (obj != null) return obj; - } - - obj = new Dictionary(); - _signalBelts[index] = obj; - return obj; - } - - private static Dictionary GetSignalBelts(int index) - { - return index >= 0 && index < _signalBeltsCapacity ? _signalBelts[index] : null; - } - - private static void SetSignalBelt(int factory, int beltId, int signalId, int number) - { - int stack; - int inc; - int speedLimit; - if (signalId >= 1000) - { - stack = Mathf.Clamp(number % 10, 1, 4); - inc = number / 10 % 10 * stack; - speedLimit = number / 100 % 4000; - } - else - { - stack = 0; - inc = 0; - speedLimit = number; - } - GetOrCreateSignalBelts(factory)[beltId] = new BeltSignal { SignalId = signalId, SpeedLimit = speedLimit, Stack = (byte)stack, Inc = (byte)inc, Progress = 0 }; - } - - private static void SetSignalBeltPortalTo(int factory, int beltId, int signalId, int number) - { - var v = ((long)factory << 32) | (long)beltId; - _portalFrom[v] = number; - if (!_portalTo.TryGetValue(number, out var set)) - { - set = new HashSet(); - _portalTo[number] = set; - } - set.Add(v); - } - - private static void RemoveSignalBelt(int factory, int beltId) - { - GetSignalBelts(factory)?.Remove(beltId); - } - - private static void RemoveSignalBeltPortalEnd(int factory, int beltId) - { - var v = ((long)factory << 32) | (long)beltId; - if (!_portalFrom.TryGetValue(v, out var number)) return; - _portalFrom.Remove(beltId); - if (!_portalTo.TryGetValue(number, out var set)) return; - set.Remove(v); - } - - [HarmonyPostfix] - [HarmonyPatch(typeof(GameMain), nameof(GameMain.Begin))] - private static void GameMain_Begin_Postfix() - { - InitSignalBelts(); - } - - [HarmonyPrefix] - [HarmonyPatch(typeof(CargoTraffic), nameof(CargoTraffic.RemoveBeltComponent))] - public static void CargoTraffic_RemoveBeltComponent_Prefix(int id) - { - if (!_initialized) return; - var planet = GameMain.localPlanet; - if (planet == null) return; - RemoveSignalBeltPortalEnd(planet.factoryIndex, id); - RemoveSignalBelt(planet.factoryIndex, id); - } - - [HarmonyPostfix] - [HarmonyPatch(typeof(CargoTraffic), nameof(CargoTraffic.SetBeltSignalIcon))] - public static void CargoTraffic_SetBeltSignalIcon_Postfix(CargoTraffic __instance, int signalId, int entityId) - { - if (!_initialized) return; - var planet = GameMain.localPlanet; - if (planet == null) return; - var factory = __instance.factory; - int number; - var needAdd = false; - switch (signalId) - { - case 404: - number = 0; - needAdd = true; - break; - case >= 1000 and < 20000: - number = Mathf.RoundToInt(factory.entitySignPool[entityId].count0); - if (number > 0) - needAdd = true; - break; - case 600: - number = Mathf.RoundToInt(factory.entitySignPool[entityId].count0); - if (number > 0) - needAdd = true; - break; - case >= 601 and <= 609: - number = Mathf.RoundToInt(factory.entitySignPool[entityId].count0); - var factoryIndex = planet.factoryIndex; - var beltId = factory.entityPool[entityId].beltId; - if (number > 0) - SetSignalBeltPortalTo(factoryIndex, beltId, signalId, number); - RemoveSignalBelt(factoryIndex, beltId); - return; - default: - number = 0; - break; - } - { - var factoryIndex = planet.factoryIndex; - var beltId = factory.entityPool[entityId].beltId; - if (needAdd) - { - SetSignalBelt(factoryIndex, beltId, signalId, number); - } - else - { - RemoveSignalBelt(factoryIndex, beltId); - } - RemoveSignalBeltPortalEnd(factoryIndex, beltId); - } - } - - [HarmonyPostfix] - [HarmonyPatch(typeof(CargoTraffic), nameof(CargoTraffic.SetBeltSignalNumber))] - public static void CargoTraffic_SetBeltSignalNumber_Postfix(CargoTraffic __instance, float number, int entityId) - { - if (!_initialized) return; - var planet = GameMain.localPlanet; - if (planet == null) return; - var factory = __instance.factory; - var entitySignPool = factory.entitySignPool; - uint signalId; - if (entitySignPool[entityId].iconType == 0U || (signalId = entitySignPool[entityId].iconId0) == 0U) return; - switch (signalId) - { - case 404: - return; - case 600: - case >= 1000 and < 20000: - break; - case >= 601 and <= 609: - var factoryIndex = planet.factoryIndex; - var beltId = factory.entityPool[entityId].beltId; - RemoveSignalBeltPortalEnd(factoryIndex, beltId); - SetSignalBeltPortalTo(factoryIndex, beltId, (int)signalId, Mathf.RoundToInt(number)); - return; - default: - return; - } - { - var factoryIndex = planet.factoryIndex; - var beltId = factory.entityPool[entityId].beltId; - var n = Mathf.RoundToInt(number); - if (n == 0) - { - RemoveSignalBelt(factoryIndex, beltId); - } - else - { - SetSignalBelt(factoryIndex, beltId, (int)signalId, n); - } - } - } - - [HarmonyPrefix] - [HarmonyPatch(typeof(GameData), "GameTick")] - public static void GameData_GameTick_Prefix() - { - if (!_initialized) return; - var factories = GameMain.data?.factories; - if (factories == null) return; - foreach (var factory in factories) - { - if (factory == null) continue; - var belts = GetSignalBelts(factory.index); - if (belts == null) continue; - foreach (var pair in belts) - { - var beltSignal = pair.Value; - var signalId = beltSignal.SignalId; - switch (signalId) - { - case 404: - { - var beltId = pair.Key; - var cargoTraffic = factory.cargoTraffic; - var belt = cargoTraffic.beltPool[beltId]; - var cargoPath = cargoTraffic.GetCargoPath(belt.segPathId); - cargoPath.TryPickItem(belt.segIndex + belt.segPivotOffset - 5, 12, out _, out _); - continue; - } - case 600: - { - if (!_portalTo.TryGetValue(beltSignal.SpeedLimit, out var set)) continue; - var cargoTraffic = factory.cargoTraffic; - var beltId = pair.Key; - ref var belt = ref cargoTraffic.beltPool[beltId]; - var cargoPath = cargoTraffic.GetCargoPath(belt.segPathId); - var segIndex = belt.segIndex + belt.segPivotOffset; - if (!cargoPath.GetCargoAtIndex(segIndex, out var cargo, out var cargoId, out var offset)) break; - var itemId = cargo.item; - var cargoPool = cargoPath.cargoContainer.cargoPool; - var inc = cargoPool[cargoId].inc; - var stack = cargoPool[cargoId].stack; - foreach (var n in set) - { - var cargoTraffic1 = factories[(int)(n >> 32)].cargoTraffic; - ref var belt1 = ref cargoTraffic1.beltPool[(int)(n & 0x7FFFFFFF)]; - if (!cargoTraffic1.GetCargoPath(belt1.segPathId).TryInsertItem(belt1.segIndex + belt1.segPivotOffset, itemId, stack, inc)) continue; - cargoPath.TryPickItem(segIndex - 5, 12, out var stack1, out var inc1); - if (inc1 != inc || stack1 != stack) - cargoPath.TryPickItem(segIndex - 5, 12, out _, out _); - break; - } - continue; - } - case >= 1000 and < 20000: - { - if (beltSignal.SpeedLimit > 0) - { - beltSignal.Progress += beltSignal.SpeedLimit; - if (beltSignal.Progress < 3600) continue; - beltSignal.Progress -= 3600; - } - var beltId = pair.Key; - var cargoTraffic = factory.cargoTraffic; - ref var belt = ref cargoTraffic.beltPool[beltId]; - var stack = beltSignal.Stack; - var inc = beltSignal.Inc; - cargoTraffic.GetCargoPath(belt.segPathId).TryInsertItem(belt.segIndex + belt.segPivotOffset, signalId, stack, inc); - continue; - } - } - } - } - } - } -} diff --git a/CheatEnabler/CheatEnabler.cs b/CheatEnabler/CheatEnabler.cs index f2d6fc6..57c5b78 100644 --- a/CheatEnabler/CheatEnabler.cs +++ b/CheatEnabler/CheatEnabler.cs @@ -32,16 +32,32 @@ public class CheatEnabler : BaseUnityPlugin "disable all abnormal checks"); TechPatch.Enabled = Config.Bind("General", "UnlockTech", false, "Unlock clicked tech by holding key-modifilers(Shift/Alt/Ctrl)"); - BuildPatch.ImmediateEnabled = Config.Bind("Build", "ImmediateBuild", false, + FactoryPatch.ImmediateEnabled = Config.Bind("Build", "ImmediateBuild", false, "Build immediately"); - BuildPatch.ArchitectModeEnabled = Config.Bind("Build", "Architect", false, + FactoryPatch.ArchitectModeEnabled = Config.Bind("Build", "Architect", false, "Architect Mode"); - BuildPatch.NoConditionEnabled = Config.Bind("Build", "BuildWithoutCondition", false, + FactoryPatch.UnlimitInteractiveEnabled = Config.Bind("Build", "UnlimitInteractive", false, + "Unlimit interactive range"); + FactoryPatch.NoConditionEnabled = Config.Bind("Build", "BuildWithoutCondition", false, "Build without condition"); - BuildPatch.NoCollisionEnabled = Config.Bind("Build", "NoCollision", false, + FactoryPatch.NoCollisionEnabled = Config.Bind("Build", "NoCollision", false, "No collision"); - BuildPatch.BeltSignalGeneratorEnabled = Config.Bind("Build", "BeltSignalGenerator", false, + FactoryPatch.BeltSignalGeneratorEnabled = Config.Bind("Build", "BeltSignalGenerator", false, "Belt signal generator"); + FactoryPatch.BeltSignalCountRecipeEnabled = Config.Bind("Build", "BeltSignalCountRecipe", false, + "Belt signal count all raws and intermediates in statistics"); + FactoryPatch.NightLightEnabled = Config.Bind("Build", "NightLight", false, + "Night light"); + FactoryPatch.RemovePowerSpaceLimitEnabled = Config.Bind("Build", "RemovePowerDistanceLimit", false, + "Remove distance limit for wind turbines and geothermals"); + FactoryPatch.BoostWindPowerEnabled = Config.Bind("Build", "BoostWindPower", false, + "Boost wind power"); + FactoryPatch.BoostSolarPowerEnabled = Config.Bind("Build", "BoostSolarPower", false, + "Boost solar power"); + FactoryPatch.BoostFuelPowerEnabled = Config.Bind("Build", "BoostFuelPower", false, + "Boost fuel power"); + FactoryPatch.BoostGeothermalPowerEnabled = Config.Bind("Build", "BoostGeothermalPower", false, + "Boost geothermal power"); ResourcePatch.InfiniteEnabled = Config.Bind("Planet", "AlwaysInfiniteResource", false, "always infinite natural resource"); ResourcePatch.FastEnabled = Config.Bind("Planet", "FastMining", false, @@ -94,8 +110,7 @@ public class CheatEnabler : BaseUnityPlugin DevShortcuts.Init(); AbnormalDisabler.Init(); TechPatch.Init(); - BuildPatch.Init(); - PlanetFunctions.Init(); + FactoryPatch.Init(); ResourcePatch.Init(); WaterPumperPatch.Init(); TerraformPatch.Init(); @@ -110,8 +125,7 @@ public class CheatEnabler : BaseUnityPlugin TerraformPatch.Uninit(); WaterPumperPatch.Uninit(); ResourcePatch.Uninit(); - PlanetFunctions.Uninit(); - BuildPatch.Uninit(); + FactoryPatch.Uninit(); TechPatch.Uninit(); AbnormalDisabler.Uninit(); DevShortcuts.Uninit(); @@ -134,7 +148,7 @@ public class CheatEnabler : BaseUnityPlugin private void LateUpdate() { - BuildPatch.NightLightLateUpdate(); + FactoryPatch.NightLight.LateUpdate(); } [HarmonyPostfix, HarmonyPatch(typeof(UIRoot), nameof(UIRoot.OpenMainMenuUI))] @@ -240,6 +254,7 @@ public class CheatEnabler : BaseUnityPlugin { if (!_configWinInitialized) { + if (!I18N.Initialized()) return; _configWinInitialized = true; _configWin = UIConfigWindow.CreateInstance(); } diff --git a/CheatEnabler/CheatEnabler.csproj b/CheatEnabler/CheatEnabler.csproj index 86f8e81..88612a8 100644 --- a/CheatEnabler/CheatEnabler.csproj +++ b/CheatEnabler/CheatEnabler.csproj @@ -5,7 +5,7 @@ net472 org.soardev.cheatenabler DSP MOD - CheatEnabler - 2.1.0 + 2.2.0 true latest CheatEnabler diff --git a/CheatEnabler/FactoryPatch.cs b/CheatEnabler/FactoryPatch.cs new file mode 100644 index 0000000..9e99ccc --- /dev/null +++ b/CheatEnabler/FactoryPatch.cs @@ -0,0 +1,1276 @@ +using System; +using System.Collections.Generic; +using System.Reflection.Emit; +using BepInEx.Configuration; +using HarmonyLib; +using UnityEngine; + +namespace CheatEnabler; + +public static class FactoryPatch +{ + public static ConfigEntry ImmediateEnabled; + public static ConfigEntry ArchitectModeEnabled; + public static ConfigEntry UnlimitInteractiveEnabled; + public static ConfigEntry NoConditionEnabled; + public static ConfigEntry NoCollisionEnabled; + public static ConfigEntry BeltSignalGeneratorEnabled; + public static ConfigEntry BeltSignalCountRecipeEnabled; + public static ConfigEntry NightLightEnabled; + public static ConfigEntry RemovePowerSpaceLimitEnabled; + public static ConfigEntry BoostWindPowerEnabled; + public static ConfigEntry BoostSolarPowerEnabled; + public static ConfigEntry BoostFuelPowerEnabled; + public static ConfigEntry BoostGeothermalPowerEnabled; + + private static Harmony _factoryPatch; + private static Harmony _noConditionPatch; + + public static void Init() + { + if (_factoryPatch != null) return; + ImmediateEnabled.SettingChanged += (_, _) => ImmediateValueChanged(); + ArchitectModeEnabled.SettingChanged += (_, _) => ArchitectModeValueChanged(); + UnlimitInteractiveEnabled.SettingChanged += (_, _) => UnlimitInteractiveValueChanged(); + NoConditionEnabled.SettingChanged += (_, _) => NoConditionValueChanged(); + NoCollisionEnabled.SettingChanged += (_, _) => NoCollisionValueChanged(); + BeltSignalGeneratorEnabled.SettingChanged += (_, _) => BeltSignalGeneratorValueChanged(); + NightLightEnabled.SettingChanged += (_, _) => NightLightValueChanged(); + RemovePowerSpaceLimitEnabled.SettingChanged += (_, _) => RemovePowerSpaceLimitValueChanged(); + BoostWindPowerEnabled.SettingChanged += (_, _) => BoostWindPowerValueChanged(); + BoostSolarPowerEnabled.SettingChanged += (_, _) => BoostSolarPowerValueChanged(); + BoostFuelPowerEnabled.SettingChanged += (_, _) => BoostFuelPowerValueChanged(); + BoostGeothermalPowerEnabled.SettingChanged += (_, _) => BoostGeothermalPowerValueChanged(); + ImmediateValueChanged(); + ArchitectModeValueChanged(); + UnlimitInteractiveValueChanged(); + NoConditionValueChanged(); + NoCollisionValueChanged(); + BeltSignalGeneratorValueChanged(); + NightLightValueChanged(); + RemovePowerSpaceLimitValueChanged(); + BoostWindPowerValueChanged(); + BoostSolarPowerValueChanged(); + BoostFuelPowerValueChanged(); + BoostGeothermalPowerValueChanged(); + _factoryPatch = Harmony.CreateAndPatchAll(typeof(FactoryPatch)); + } + + public static void Uninit() + { + _factoryPatch?.UnpatchSelf(); + _factoryPatch = null; + _noConditionPatch?.UnpatchSelf(); + _noConditionPatch = null; + ImmediateBuild.Enable(false); + ArchitectMode.Enable(false); + UnlimitInteractive.Enable(false); + BeltSignalGenerator.Enable(false); + NightLight.Enable(false); + RemovePowerSpaceLimit.Enable(false); + BoostWindPower.Enable(false); + BoostSolarPower.Enable(false); + BoostFuelPower.Enable(false); + BoostGeothermalPower.Enable(false); + } + + private static void ImmediateValueChanged() + { + ImmediateBuild.Enable(ImmediateEnabled.Value); + } + + private static void ArchitectModeValueChanged() + { + ArchitectMode.Enable(ArchitectModeEnabled.Value); + } + + private static void UnlimitInteractiveValueChanged() + { + UnlimitInteractive.Enable(UnlimitInteractiveEnabled.Value); + } + + private static void NoConditionValueChanged() + { + if (NoConditionEnabled.Value) + { + _noConditionPatch ??= Harmony.CreateAndPatchAll(typeof(NoConditionBuild)); + return; + } + _noConditionPatch?.UnpatchSelf(); + _noConditionPatch = null; + } + + private static void NoCollisionValueChanged() + { + var coll = ColliderPool.instance; + if (coll == null) return; + var obj = coll.gameObject; + if (obj == null) return; + obj.gameObject.SetActive(!NoCollisionEnabled.Value); + } + + private static void BeltSignalGeneratorValueChanged() + { + BeltSignalGenerator.Enable(BeltSignalGeneratorEnabled.Value); + } + + private static void NightLightValueChanged() + { + NightLight.Enable(NightLightEnabled.Value); + } + + private static void RemovePowerSpaceLimitValueChanged() + { + RemovePowerSpaceLimit.Enable(RemovePowerSpaceLimitEnabled.Value); + } + + private static void BoostWindPowerValueChanged() + { + BoostWindPower.Enable(BoostWindPowerEnabled.Value); + } + + private static void BoostSolarPowerValueChanged() + { + BoostSolarPower.Enable(BoostSolarPowerEnabled.Value); + } + + private static void BoostFuelPowerValueChanged() + { + BoostFuelPower.Enable(BoostFuelPowerEnabled.Value); + } + + private static void BoostGeothermalPowerValueChanged() + { + BoostGeothermalPower.Enable(BoostGeothermalPowerEnabled.Value); + } + + public static void ArrivePlanet(PlanetFactory factory) + { + var imm = ImmediateEnabled.Value; + var architect = ArchitectModeEnabled.Value; + if (!imm && !architect) return; + var prebuilds = factory.prebuildPool; + if (imm) factory.BeginFlattenTerrain(); + for (var i = factory.prebuildCursor - 1; i > 0; i--) + { + if (prebuilds[i].id != i) continue; + if (prebuilds[i].itemRequired > 0) + { + if (!architect) continue; + prebuilds[i].itemRequired = 0; + if (imm) + factory.BuildFinally(GameMain.mainPlayer, i, false); + else + factory.AlterPrebuildModelState(i); + } + else + { + if (imm) + factory.BuildFinally(GameMain.mainPlayer, i, false); + } + } + + if (imm) factory.EndFlattenTerrain(); + } + + [HarmonyPostfix] + [HarmonyPatch(typeof(PlanetData), nameof(PlanetData.NotifyFactoryLoaded))] + private static void PlanetData_NotifyFactoryLoaded_Postfix(PlanetData __instance) + { + ArrivePlanet(__instance.factory); + } + + public static class NightLight + { + private static Harmony _patch; + private const float NightLightAngleX = -8; + private const float NightLightAngleY = -2; + public static bool Enabled; + private static bool _nightlightInitialized; + private static bool _mechaOnEarth; + private static AnimationState _sail; + private static Light _sunlight; + + public static void Enable(bool on) + { + if (on) + { + Enabled = _mechaOnEarth; + _patch ??= Harmony.CreateAndPatchAll(typeof(NightLight)); + return; + } + + Enabled = false; + _patch?.UnpatchSelf(); + _patch = null; + if (_sunlight == null) return; + _sunlight.transform.localEulerAngles = new Vector3(0f, 180f); + } + + public static void LateUpdate() + { + switch (_nightlightInitialized) + { + case false: + Ready(); + break; + case true: + Go(); + break; + } + } + + private static void Ready() + { + if (!GameMain.isRunning || !GameMain.mainPlayer.controller.model.gameObject.activeInHierarchy) return; + if (_sail == null) + { + _sail = GameMain.mainPlayer.animator.sails[GameMain.mainPlayer.animator.sailAnimIndex]; + } + + _nightlightInitialized = true; + } + + private static void Go() + { + if (!GameMain.isRunning) + { + End(); + return; + } + + if (_sail.enabled) + { + _mechaOnEarth = false; + Enabled = false; + if (_sunlight == null) return; + _sunlight.transform.localEulerAngles = new Vector3(0f, 180f); + _sunlight = null; + return; + } + + if (!_mechaOnEarth) + { + if (_sunlight == null) + { + _sunlight = GameMain.universeSimulator.LocalStarSimulator().sunLight; + if (_sunlight == null) return; + } + + _mechaOnEarth = true; + Enabled = NightLightEnabled.Value; + } + + if (Enabled) + { + _sunlight.transform.rotation = + Quaternion.LookRotation(-GameMain.mainPlayer.transform.up + GameMain.mainPlayer.transform.forward * NightLightAngleX / 10f + + GameMain.mainPlayer.transform.right * NightLightAngleY / 10f); + } + } + + private static void End() + { + _mechaOnEarth = false; + Enabled = false; + if (_sunlight != null) + { + _sunlight.transform.localEulerAngles = new Vector3(0f, 180f); + _sunlight = null; + } + + _sail = null; + _nightlightInitialized = false; + } + + [HarmonyTranspiler] + [HarmonyPatch(typeof(StarSimulator), "LateUpdate")] + private static IEnumerable StarSimulator_LateUpdate_Transpiler(IEnumerable instructions, ILGenerator generator) + { + // var vec = NightlightEnabled ? GameMain.mainPlayer.transform.up : __instance.transform.forward; + var matcher = new CodeMatcher(instructions, generator); + var label1 = generator.DefineLabel(); + var label2 = generator.DefineLabel(); + matcher.MatchForward(false, + new CodeMatch(OpCodes.Ldarg_0), + new CodeMatch(OpCodes.Call, AccessTools.PropertyGetter(typeof(Component), nameof(Component.transform))) + ).InsertAndAdvance( + new CodeInstruction(OpCodes.Ldsfld, AccessTools.Field(typeof(NightLight), nameof(NightLight.Enabled))), + new CodeInstruction(OpCodes.Brfalse_S, label1), + new CodeInstruction(OpCodes.Call, AccessTools.PropertyGetter(typeof(GameMain), nameof(GameMain.mainPlayer))), + new CodeInstruction(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(Player), nameof(Player.transform))), + new CodeInstruction(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(Transform), nameof(Transform.up))), + new CodeInstruction(OpCodes.Stloc_0), + new CodeInstruction(OpCodes.Br_S, label2) + ); + matcher.Labels.Add(label1); + matcher.MatchForward(false, + new CodeMatch(OpCodes.Stloc_0) + ).Advance(1).Labels.Add(label2); + return matcher.InstructionEnumeration(); + } + + [HarmonyTranspiler] + [HarmonyPatch(typeof(PlanetSimulator), "LateUpdate")] + private static IEnumerable PlanetSimulator_LateUpdate_Transpiler(IEnumerable instructions, ILGenerator generator) + { + // var vec = (NightlightEnabled ? GameMain.mainPlayer.transform.up : (Quaternion.Inverse(localPlanet.runtimeRotation) * (__instance.planetData.star.uPosition - __instance.planetData.uPosition).normalized)); + var matcher = new CodeMatcher(instructions, generator); + var label1 = generator.DefineLabel(); + var label2 = generator.DefineLabel(); + matcher.MatchForward(false, + new CodeMatch(OpCodes.Pop) + ).Advance(1).InsertAndAdvance( + new CodeInstruction(OpCodes.Ldsfld, AccessTools.Field(typeof(NightLight), nameof(NightLight.Enabled))), + new CodeInstruction(OpCodes.Brfalse_S, label1), + new CodeInstruction(OpCodes.Call, AccessTools.PropertyGetter(typeof(GameMain), nameof(GameMain.mainPlayer))), + new CodeInstruction(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(Player), nameof(Player.transform))), + new CodeInstruction(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(Transform), nameof(Transform.up))), + new CodeInstruction(OpCodes.Stloc_1), + new CodeInstruction(OpCodes.Br_S, label2) + ); + matcher.Labels.Add(label1); + matcher.MatchForward(false, + new CodeMatch(OpCodes.Ldsfld, AccessTools.Field(typeof(FactoryModel), nameof(FactoryModel.whiteMode0))) + ).Labels.Add(label2); + return matcher.InstructionEnumeration(); + } + } + + private static class ImmediateBuild + { + private static Harmony _immediatePatch; + + public static void Enable(bool enable) + { + if (enable) + { + if (_immediatePatch != null) return; + var factory = GameMain.mainPlayer?.factory; + if (factory != null) + { + ArrivePlanet(factory); + } + _immediatePatch = Harmony.CreateAndPatchAll(typeof(ImmediateBuild)); + return; + } + _immediatePatch?.UnpatchSelf(); + _immediatePatch = null; + } + + [HarmonyTranspiler] + [HarmonyPatch(typeof(BuildTool_Addon), nameof(BuildTool_Addon.CreatePrebuilds))] + [HarmonyPatch(typeof(BuildTool_BlueprintPaste), nameof(BuildTool_BlueprintPaste.CreatePrebuilds))] + [HarmonyPatch(typeof(BuildTool_Click), nameof(BuildTool_Click.CreatePrebuilds))] + [HarmonyPatch(typeof(BuildTool_Inserter), nameof(BuildTool_Inserter.CreatePrebuilds))] + [HarmonyPatch(typeof(BuildTool_Path), nameof(BuildTool_Path.CreatePrebuilds))] + private static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + var matcher = new CodeMatcher(instructions, generator); + matcher.MatchForward(false, + new CodeMatch(OpCodes.Call, AccessTools.Method(typeof(GC), nameof(GC.Collect))) + ).Insert( + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(BuildTool), nameof(BuildTool.factory))), + new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(FactoryPatch), nameof(ArrivePlanet))) + ); + return matcher.InstructionEnumeration(); + } + } + + private static class ArchitectMode + { + private static Harmony _patch; + private static bool[] _canBuildItems; + + public static void Enable(bool enable) + { + if (enable) + { + if (_patch != null) return; + var factory = GameMain.mainPlayer?.factory; + if (factory != null) + { + ArrivePlanet(factory); + } + _patch = Harmony.CreateAndPatchAll(typeof(ArchitectMode)); + return; + } + _patch?.UnpatchSelf(); + _patch = null; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(StorageComponent), nameof(StorageComponent.TakeTailItems), new[] { typeof(int), typeof(int), typeof(int), typeof(bool) }, + new[] { ArgumentType.Ref, ArgumentType.Ref, ArgumentType.Out, ArgumentType.Normal })] + [HarmonyPatch(typeof(StorageComponent), nameof(StorageComponent.TakeTailItems), new[] { typeof(int), typeof(int), typeof(int[]), typeof(int), typeof(bool) }, + new[] { ArgumentType.Ref, ArgumentType.Ref, ArgumentType.Normal, ArgumentType.Out, ArgumentType.Normal })] + public static bool TakeTailItemsPatch(StorageComponent __instance, int itemId) + { + if (__instance == null || __instance.id != GameMain.mainPlayer.package.id) return true; + if (itemId <= 0) return true; + if (_canBuildItems == null) + { + DoInit(); + } + + return itemId >= 12000 || !_canBuildItems[itemId]; + } + + [HarmonyPostfix] + [HarmonyPatch(typeof(StorageComponent), "GetItemCount", new Type[] { typeof(int) })] + public static void GetItemCountPatch(StorageComponent __instance, int itemId, ref int __result) + { + if (__result > 99) return; + if (__instance == null || __instance.id != GameMain.mainPlayer.package.id) return; + if (itemId <= 0) return; + if (_canBuildItems == null) + { + DoInit(); + } + + if (itemId < 12000 && _canBuildItems[itemId]) __result = 100; + } + + private static void DoInit() + { + _canBuildItems = new bool[12000]; + foreach (var ip in LDB.items.dataArray) + { + if (ip.CanBuild && ip.ID < 12000) _canBuildItems[ip.ID] = true; + } + } + } + + private static class UnlimitInteractive + { + private static Harmony _patch; + + public static void Enable(bool enable) + { + if (enable) + { + _patch ??= Harmony.CreateAndPatchAll(typeof(UnlimitInteractive)); + return; + } + _patch?.UnpatchSelf(); + _patch = null; + } + + [HarmonyTranspiler] + [HarmonyPatch(typeof(PlayerAction_Inspect), nameof(PlayerAction_Inspect.GetObjectSelectDistance))] + private static IEnumerable PlayerAction_Inspect_GetObjectSelectDistance_Transpiler(IEnumerable instructions) + { + yield return new CodeInstruction(OpCodes.Ldc_R4, 10000f); + yield return new CodeInstruction(OpCodes.Ret); + } + } + + private static class NoConditionBuild + { + [HarmonyTranspiler] + [HarmonyPatch(typeof(BuildTool_Addon), nameof(BuildTool_Addon.CheckBuildConditions))] + // [HarmonyPatch(typeof(BuildTool_Click), nameof(BuildTool_Click.CheckBuildConditions))] + [HarmonyPatch(typeof(BuildTool_Inserter), nameof(BuildTool_Inserter.CheckBuildConditions))] + [HarmonyPatch(typeof(BuildTool_Path), nameof(BuildTool_Path.CheckBuildConditions))] + private static IEnumerable BuildTool_CheckBuildConditions_Transpiler(IEnumerable instructions) + { + yield return new CodeInstruction(OpCodes.Ldc_I4_1); + yield return new CodeInstruction(OpCodes.Ret); + } + + [HarmonyTranspiler] + [HarmonyPatch(typeof(BuildTool_Click), nameof(BuildTool_Click.CheckBuildConditions))] + private static IEnumerable BuildTool_Click_CheckBuildConditions_Transpiler(IEnumerable instructions) + { + yield return new CodeInstruction(OpCodes.Ldarg_0); + yield return new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(NoConditionBuild), nameof(CheckForMiner))); + yield return new CodeInstruction(OpCodes.Ret); + } + + public static bool CheckForMiner(BuildTool tool) + { + var previews = tool.buildPreviews; + foreach (var preview in previews) + { + var desc = preview?.item?.prefabDesc; + if (desc == null) continue; + if (desc.veinMiner || desc.oilMiner) return false; + } + + return true; + } + } + + private static class BeltSignalGenerator + { + private static Harmony _beltSignalPatch; + private static Dictionary[] _signalBelts; + private static Dictionary _portalFrom; + private static Dictionary> _portalTo; + private static int _signalBeltsCapacity; + private static bool _initialized; + + private class BeltSignal + { + public int SignalId; + public int SpeedLimit; + public byte Stack; + public byte Inc; + public int Progress; + public Tuple[] Sources; + public float[] SourceProgress; + } + + public static void Enable(bool on) + { + if (on) + { + InitSignalBelts(); + _beltSignalPatch ??= Harmony.CreateAndPatchAll(typeof(BeltSignalGenerator)); + return; + } + _beltSignalPatch?.UnpatchSelf(); + _initialized = false; + _signalBelts = null; + _signalBeltsCapacity = 0; + } + + private static void InitSignalBelts() + { + if (!GameMain.isRunning) return; + _signalBelts = new Dictionary[64]; + _signalBeltsCapacity = 64; + _portalFrom = new Dictionary(); + _portalTo = new Dictionary>(); + + foreach (var factory in GameMain.data.factories) + { + var entitySignPool = factory?.entitySignPool; + if (entitySignPool == null) continue; + var cargoTraffic = factory.cargoTraffic; + var beltPool = cargoTraffic.beltPool; + for (var i = cargoTraffic.beltCursor - 1; i > 0; i--) + { + if (beltPool[i].id != i) continue; + ref var signal = ref entitySignPool[beltPool[i].entityId]; + var signalId = signal.iconId0; + if (signalId == 0U) continue; + var number = Mathf.RoundToInt(signal.count0); + switch (signalId) + { + case 404: + SetSignalBelt(factory.index, i, (int)signalId, 0); + continue; + case 600: + case >= 1000 and < 20000: + if (number > 0) + SetSignalBelt(factory.index, i, (int)signalId, number); + continue; + case >= 601 and <= 609: + if (number > 0) + SetSignalBeltPortalTo(factory.index, i, (int)signalId, number); + continue; + } + } + } + + _initialized = true; + } + + private static Dictionary GetOrCreateSignalBelts(int index) + { + Dictionary obj; + if (index < 0) return null; + if (index >= _signalBeltsCapacity) + { + var newCapacity = _signalBeltsCapacity * 2; + var newSignalBelts = new Dictionary[newCapacity]; + Array.Copy(_signalBelts, newSignalBelts, _signalBeltsCapacity); + _signalBelts = newSignalBelts; + _signalBeltsCapacity = newCapacity; + } + else + { + obj = _signalBelts[index]; + if (obj != null) return obj; + } + + obj = new Dictionary(); + _signalBelts[index] = obj; + return obj; + } + + private static Dictionary GetSignalBelts(int index) + { + return index >= 0 && index < _signalBeltsCapacity ? _signalBelts[index] : null; + } + + private static void SetSignalBelt(int factory, int beltId, int signalId, int number) + { + int stack; + int inc; + int speedLimit; + if (signalId >= 1000) + { + stack = Mathf.Clamp(number % 10, 1, 4); + inc = number / 10 % 10 * stack; + speedLimit = number / 100 % 4000; + } + else + { + stack = 0; + inc = 0; + speedLimit = number; + } + + var signalBelts = GetOrCreateSignalBelts(factory); + if (signalBelts.TryGetValue(beltId, out var oldBeltSignal)) + { + oldBeltSignal.SpeedLimit = speedLimit; + oldBeltSignal.Stack = (byte)stack; + oldBeltSignal.Inc = (byte)inc; + oldBeltSignal.Progress = 0; + if (oldBeltSignal.SignalId == signalId) return; + oldBeltSignal.SignalId = signalId; + AddSourcesToBeltSignal(oldBeltSignal, signalId); + return; + } + + var beltSignal = new BeltSignal + { + SignalId = signalId, + SpeedLimit = speedLimit, + Stack = (byte)stack, + Inc = (byte)inc + }; + if (signalId >= 1000) + { + AddSourcesToBeltSignal(beltSignal, signalId); + } + + signalBelts[beltId] = beltSignal; + } + + private static void AddSourcesToBeltSignal(BeltSignal beltSignal, int itemId) + { + var result = new Dictionary(); + var extra = new Dictionary(); + CalculateAllProductions(result, extra, itemId); + foreach (var p in extra) + { + if (result.TryGetValue(itemId, out var v) && v >= p.Value) continue; + result[itemId] = p.Value; + } + + result.Remove(itemId); + var cnt = result.Count; + if (cnt == 0) + { + beltSignal.Sources = null; + beltSignal.SourceProgress = null; + return; + } + + var items = new Tuple[cnt]; + var progress = new float[cnt]; + foreach (var p in result) + { + items[--cnt] = Tuple.Create(p.Key, p.Value); + } + + beltSignal.Sources = items; + beltSignal.SourceProgress = progress; + } + + private static void SetSignalBeltPortalTo(int factory, int beltId, int signalId, int number) + { + var v = ((long)factory << 32) | (uint)beltId; + _portalFrom[v] = number; + if (!_portalTo.TryGetValue(number, out var set)) + { + set = new HashSet(); + _portalTo[number] = set; + } + + set.Add(v); + } + + private static void RemoveSignalBelt(int factory, int beltId) + { + GetSignalBelts(factory)?.Remove(beltId); + } + + private static void RemoveSignalBeltPortalEnd(int factory, int beltId) + { + var v = ((long)factory << 32) | (uint)beltId; + if (!_portalFrom.TryGetValue(v, out var number)) return; + _portalFrom.Remove(beltId); + if (!_portalTo.TryGetValue(number, out var set)) return; + set.Remove(v); + } + + [HarmonyPostfix] + [HarmonyPatch(typeof(GameMain), nameof(GameMain.Begin))] + private static void GameMain_Begin_Postfix() + { + if (BeltSignalGeneratorEnabled.Value) InitSignalBelts(); + InitItemSources(); + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(CargoTraffic), nameof(CargoTraffic.RemoveBeltComponent))] + public static void CargoTraffic_RemoveBeltComponent_Prefix(int id) + { + if (!_initialized) return; + var planet = GameMain.localPlanet; + if (planet == null) return; + RemoveSignalBeltPortalEnd(planet.factoryIndex, id); + RemoveSignalBelt(planet.factoryIndex, id); + } + + [HarmonyPostfix] + [HarmonyPatch(typeof(CargoTraffic), nameof(CargoTraffic.SetBeltSignalIcon))] + public static void CargoTraffic_SetBeltSignalIcon_Postfix(CargoTraffic __instance, int signalId, int entityId) + { + if (!_initialized) return; + var planet = GameMain.localPlanet; + if (planet == null) return; + var factory = __instance.factory; + int number; + var needAdd = false; + switch (signalId) + { + case 404: + number = 0; + needAdd = true; + break; + case 600: + case >= 1000 and < 20000: + number = Mathf.RoundToInt(factory.entitySignPool[entityId].count0); + if (number > 0) + needAdd = true; + break; + case >= 601 and <= 609: + number = Mathf.RoundToInt(factory.entitySignPool[entityId].count0); + var factoryIndex = planet.factoryIndex; + var beltId = factory.entityPool[entityId].beltId; + if (number > 0) + SetSignalBeltPortalTo(factoryIndex, beltId, signalId, number); + RemoveSignalBelt(factoryIndex, beltId); + return; + default: + number = 0; + break; + } + + { + var factoryIndex = planet.factoryIndex; + var beltId = factory.entityPool[entityId].beltId; + if (needAdd) + { + SetSignalBelt(factoryIndex, beltId, signalId, number); + } + else + { + RemoveSignalBelt(factoryIndex, beltId); + } + + RemoveSignalBeltPortalEnd(factoryIndex, beltId); + } + } + + [HarmonyPostfix] + [HarmonyPatch(typeof(CargoTraffic), nameof(CargoTraffic.SetBeltSignalNumber))] + public static void CargoTraffic_SetBeltSignalNumber_Postfix(CargoTraffic __instance, float number, int entityId) + { + if (!_initialized) return; + var planet = GameMain.localPlanet; + if (planet == null) return; + var factory = __instance.factory; + var entitySignPool = factory.entitySignPool; + uint signalId; + if (entitySignPool[entityId].iconType == 0U || (signalId = entitySignPool[entityId].iconId0) == 0U) return; + switch (signalId) + { + case 404: + return; + case 600: + case >= 1000 and < 20000: + break; + case >= 601 and <= 609: + var factoryIndex = planet.factoryIndex; + var beltId = factory.entityPool[entityId].beltId; + RemoveSignalBeltPortalEnd(factoryIndex, beltId); + SetSignalBeltPortalTo(factoryIndex, beltId, (int)signalId, Mathf.RoundToInt(number)); + return; + default: + return; + } + + { + var factoryIndex = planet.factoryIndex; + var beltId = factory.entityPool[entityId].beltId; + var n = Mathf.RoundToInt(number); + if (n == 0) + { + RemoveSignalBelt(factoryIndex, beltId); + } + else + { + SetSignalBelt(factoryIndex, beltId, (int)signalId, n); + } + } + } + + public static void ProcessBeltSignals() + { + if (!_initialized) return; + var factories = GameMain.data?.factories; + if (factories == null) return; + PerformanceMonitor.BeginSample(ECpuWorkEntry.Belt); + foreach (var factory in factories) + { + if (factory == null) continue; + var belts = GetSignalBelts(factory.index); + if (belts == null || belts.Count == 0) continue; + var factoryProductionStat = GameMain.statistics.production.factoryStatPool[factory.index]; + var productRegister = factoryProductionStat.productRegister; + var consumeRegister = factoryProductionStat.consumeRegister; + var countRecipe = BeltSignalCountRecipeEnabled.Value; + foreach (var pair in belts) + { + var beltSignal = pair.Value; + var signalId = beltSignal.SignalId; + switch (signalId) + { + case 404: + { + var beltId = pair.Key; + var cargoTraffic = factory.cargoTraffic; + var belt = cargoTraffic.beltPool[beltId]; + var cargoPath = cargoTraffic.GetCargoPath(belt.segPathId); + int itemId; + if ((itemId = cargoPath.TryPickItem(belt.segIndex + belt.segPivotOffset - 5, 12, out var stack, out _)) > 0) + { + consumeRegister[itemId] += stack; + } + + continue; + } + case 600: + { + if (!_portalTo.TryGetValue(beltSignal.SpeedLimit, out var set)) continue; + var cargoTraffic = factory.cargoTraffic; + var beltId = pair.Key; + ref var belt = ref cargoTraffic.beltPool[beltId]; + var cargoPath = cargoTraffic.GetCargoPath(belt.segPathId); + var segIndex = belt.segIndex + belt.segPivotOffset; + if (!cargoPath.GetCargoAtIndex(segIndex, out var cargo, out var cargoId, out var _)) break; + var itemId = cargo.item; + var cargoPool = cargoPath.cargoContainer.cargoPool; + var inc = cargoPool[cargoId].inc; + var stack = cargoPool[cargoId].stack; + foreach (var n in set) + { + var cargoTraffic1 = factories[(int)(n >> 32)].cargoTraffic; + ref var belt1 = ref cargoTraffic1.beltPool[(int)(n & 0x7FFFFFFF)]; + if (!cargoTraffic1.GetCargoPath(belt1.segPathId).TryInsertItem(belt1.segIndex + belt1.segPivotOffset, itemId, stack, inc)) continue; + cargoPath.TryPickItem(segIndex - 5, 12, out var stack1, out var inc1); + if (inc1 != inc || stack1 != stack) + cargoPath.TryPickItem(segIndex - 5, 12, out _, out _); + break; + } + + continue; + } + case >= 1000 and < 20000: + { + if (beltSignal.SpeedLimit > 0) + { + beltSignal.Progress += beltSignal.SpeedLimit; + if (beltSignal.Progress < 3600) continue; + beltSignal.Progress -= 3600; + } + + var beltId = pair.Key; + var cargoTraffic = factory.cargoTraffic; + ref var belt = ref cargoTraffic.beltPool[beltId]; + var stack = beltSignal.Stack; + var inc = beltSignal.Inc; + if (!cargoTraffic.GetCargoPath(belt.segPathId).TryInsertItem(belt.segIndex + belt.segPivotOffset, signalId, stack, inc)) continue; + productRegister[signalId] += stack; + if (!countRecipe) continue; + var sources = beltSignal.Sources; + if (sources == null) continue; + var progress = beltSignal.SourceProgress; + var stackf = (float)stack; + for (var i = sources.Length - 1; i >= 0; i--) + { + var newCnt = progress[i] + sources[i].Item2 * stackf; + if (newCnt > 0) + { + var itemId = sources[i].Item1; + var cnt = Mathf.CeilToInt(newCnt); + productRegister[itemId] += cnt; + consumeRegister[itemId] += cnt; + progress[i] = newCnt - cnt; + } + else + { + progress[i] = newCnt; + } + } + + continue; + } + } + } + } + + PerformanceMonitor.EndSample(ECpuWorkEntry.Belt); + } + + [HarmonyTranspiler] + [HarmonyPatch(typeof(GameData), "GameTick")] + public static IEnumerable GameData_GameTick_Transpiler(IEnumerable instructions) + { + var matcher = new CodeMatcher(instructions); + matcher.MatchForward(false, + new CodeMatch(OpCodes.Call, AccessTools.Method(typeof(PerformanceMonitor), nameof(PerformanceMonitor.EndSample))) + ).Advance(1).Insert( + new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(BeltSignalGenerator), nameof(ProcessBeltSignals))) + ); + return matcher.InstructionEnumeration(); + } + + + /* BEGIN: Item sources calculation */ + private static readonly Dictionary ItemSources = new(); + private static bool _itemSourcesInitialized; + + private class ItemSource + { + public float Count; + public Dictionary From; + public Dictionary Extra; + } + + private static void InitItemSources() + { + if (_itemSourcesInitialized) return; + foreach (var vein in LDB.veins.dataArray) + { + ItemSources[vein.MiningItem] = new ItemSource { Count = 1 }; + } + + foreach (var ip in LDB.items.dataArray) + { + if (!string.IsNullOrEmpty(ip.MiningFrom)) + { + ItemSources[ip.ID] = new ItemSource { Count = 1 }; + } + } + + ItemSources[1208] = new ItemSource { Count = 1 }; + var recipes = LDB.recipes.dataArray; + foreach (var recipe in recipes) + { + if (!recipe.Explicit || recipe.ID == 58 || recipe.ID == 121) continue; + var res = recipe.Results; + var rescnt = recipe.ResultCounts; + var len = res.Length; + for (var i = 0; i < len; i++) + { + if (ItemSources.ContainsKey(res[i])) continue; + var rs = new ItemSource { Count = rescnt[i], From = new Dictionary() }; + var it = recipe.Items; + var itcnt = recipe.ItemCounts; + var len2 = it.Length; + for (var j = 0; j < len2; j++) + { + rs.From[it[j]] = itcnt[j]; + } + + if (len > 1) + { + rs.Extra = new Dictionary(); + for (var k = 0; k < len; k++) + { + if (i != k) + { + rs.Extra[res[k]] = rescnt[k]; + } + } + } + + ItemSources[res[i]] = rs; + } + } + + foreach (var recipe in recipes) + { + if (recipe.Explicit) continue; + var res = recipe.Results; + var rescnt = recipe.ResultCounts; + var len = res.Length; + for (var i = 0; i < len; i++) + { + if (ItemSources.ContainsKey(res[i])) continue; + var rs = new ItemSource { Count = rescnt[i], From = new Dictionary() }; + var it = recipe.Items; + var itcnt = recipe.ItemCounts; + var len2 = it.Length; + for (var j = 0; j < len2; j++) + { + rs.From[it[j]] = itcnt[j]; + } + + if (len > 1) + { + rs.Extra = new Dictionary(); + for (var k = 0; k < len; k++) + { + if (i != k) + { + rs.Extra[res[k]] = rescnt[k]; + } + } + } + + ItemSources[res[i]] = rs; + } + } + + _itemSourcesInitialized = true; + } + + private static void CalculateAllProductions(IDictionary result, IDictionary extra, int itemId, float count = 1f) + { + if (!ItemSources.TryGetValue(itemId, out var itemSource)) + { + return; + } + + var times = 1f; + if (Math.Abs(count - itemSource.Count) > 0.000001f) + { + times = count / itemSource.Count; + } + + { + result.TryGetValue(itemId, out var oldCount); + result[itemId] = oldCount + count; + } + if (itemSource.Extra != null) + { + foreach (var p in itemSource.Extra) + { + extra.TryGetValue(p.Key, out var oldCount); + extra[p.Key] = oldCount + times * p.Value; + } + } + + if (itemSource.From == null) return; + foreach (var p in itemSource.From) + { + CalculateAllProductions(result, extra, p.Key, times * p.Value); + } + } + /* END: Item sources calculation */ + } + + private static class RemovePowerSpaceLimit + { + private static Harmony _patch; + public static void Enable(bool enable) + { + if (enable) + { + _patch ??= Harmony.CreateAndPatchAll(typeof(RemovePowerSpaceLimit)); + return; + } + _patch?.UnpatchSelf(); + _patch = null; + } + + [HarmonyTranspiler] + [HarmonyPatch(typeof(BuildTool_Click), nameof(BuildTool_Click.CheckBuildConditions))] + [HarmonyPatch(typeof(BuildTool_BlueprintPaste), nameof(BuildTool_BlueprintPaste.CheckBuildConditions))] + private static IEnumerable BuildTool_CheckBuildConditions_Transpiler(IEnumerable instructions) + { + var matcher = new CodeMatcher(instructions); + matcher.Start().MatchForward(false, + new CodeMatch(OpCodes.Ldc_R4, 110.25f) + ).Repeat(codeMatcher => codeMatcher.SetAndAdvance( + OpCodes.Ldc_R4, 1f + )); + matcher.Start().MatchForward(false, + new CodeMatch(OpCodes.Ldc_R4, 144f) + ).Repeat(codeMatcher => codeMatcher.SetAndAdvance( + OpCodes.Ldc_R4, 1f + )); + return matcher.InstructionEnumeration(); + } + } + + private static class BoostWindPower + { + private static Harmony _patch; + public static void Enable(bool enable) + { + if (enable) + { + _patch ??= Harmony.CreateAndPatchAll(typeof(BoostWindPower)); + return; + } + _patch?.UnpatchSelf(); + _patch = null; + } + [HarmonyTranspiler] + [HarmonyPatch(typeof(PowerGeneratorComponent), nameof(PowerGeneratorComponent.EnergyCap_Wind))] + private static IEnumerable PowerGeneratorComponent_EnergyCap_Wind_Transpiler(IEnumerable instructions, ILGenerator generator) + { + var matcher = new CodeMatcher(instructions, generator); + matcher.Start().RemoveInstructions(matcher.Length); + matcher.Insert( + // this.currentStrength = windStrength + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldarg_1), + new CodeInstruction(OpCodes.Stfld, AccessTools.Field(typeof(PowerGeneratorComponent), nameof(PowerGeneratorComponent.currentStrength))), + // this.capacityCurrentTick = 500000000L + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldc_I8, 500000000L), + new CodeInstruction(OpCodes.Stfld, AccessTools.Field(typeof(PowerGeneratorComponent), nameof(PowerGeneratorComponent.capacityCurrentTick))), + // return 500000000L + new CodeInstruction(OpCodes.Ldc_I8, 500000000L), + new CodeInstruction(OpCodes.Ret) + ); + return matcher.InstructionEnumeration(); + } + } + + private static class BoostSolarPower + { + private static Harmony _patch; + public static void Enable(bool enable) + { + if (enable) + { + _patch ??= Harmony.CreateAndPatchAll(typeof(BoostSolarPower)); + return; + } + _patch?.UnpatchSelf(); + _patch = null; + } + [HarmonyTranspiler] + [HarmonyPatch(typeof(PowerGeneratorComponent), nameof(PowerGeneratorComponent.EnergyCap_PV))] + private static IEnumerable PowerGeneratorComponent_EnergyCap_PV_Transpiler(IEnumerable instructions, ILGenerator generator) + { + var matcher = new CodeMatcher(instructions, generator); + matcher.Start().RemoveInstructions(matcher.Length).Insert( + // this.currentStrength = lumino + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldarg_S, 4), + new CodeInstruction(OpCodes.Stfld, AccessTools.Field(typeof(PowerGeneratorComponent), nameof(PowerGeneratorComponent.currentStrength))), + // this.capacityCurrentTick = 600000000L + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldc_I8, 600000000L), + new CodeInstruction(OpCodes.Stfld, AccessTools.Field(typeof(PowerGeneratorComponent), nameof(PowerGeneratorComponent.capacityCurrentTick))), + // return 600000000L + new CodeInstruction(OpCodes.Ldc_I8, 600000000L), + new CodeInstruction(OpCodes.Ret) + ); + return matcher.InstructionEnumeration(); + } + } + + private static class BoostFuelPower + { + private static Harmony _patch; + public static void Enable(bool enable) + { + if (enable) + { + _patch ??= Harmony.CreateAndPatchAll(typeof(BoostFuelPower)); + return; + } + _patch?.UnpatchSelf(); + _patch = null; + } + [HarmonyTranspiler] + [HarmonyPatch(typeof(PowerGeneratorComponent), nameof(PowerGeneratorComponent.EnergyCap_Fuel))] + private static IEnumerable PowerGeneratorComponent_EnergyCap_Fuel_Transpiler(IEnumerable instructions, ILGenerator generator) + { + var matcher = new CodeMatcher(instructions, generator); + var label1 = generator.DefineLabel(); + var label2 = generator.DefineLabel(); + var label3 = generator.DefineLabel(); + matcher.Start().MatchForward(false, + new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(PowerGeneratorComponent), nameof(PowerGeneratorComponent.capacityCurrentTick))) + ); + var labels = matcher.Labels; + matcher.Labels = null; + matcher.Insert( + // if (this.fuelMask == 4) + new CodeInstruction(OpCodes.Ldarg_0).WithLabels(labels), + new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(PowerGeneratorComponent), nameof(PowerGeneratorComponent.fuelMask))), + new CodeInstruction(OpCodes.Ldc_I4_4), + new CodeInstruction(OpCodes.Bne_Un_S, label1), + // multiplier = 10000L + new CodeInstruction(OpCodes.Ldc_I8, 10000L), + new CodeInstruction(OpCodes.Br_S, label3), + // else if (this.fuelMask == 2) + new CodeInstruction(OpCodes.Ldarg_0).WithLabels(label1), + new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(PowerGeneratorComponent), nameof(PowerGeneratorComponent.fuelMask))), + new CodeInstruction(OpCodes.Ldc_I4_2), + new CodeInstruction(OpCodes.Bne_Un_S, label2), + // multiplier = 20000L + new CodeInstruction(OpCodes.Ldc_I8, 20000L), + new CodeInstruction(OpCodes.Br_S, label3), + // else multiplier = 50000L + new CodeInstruction(OpCodes.Ldc_I8, 50000L).WithLabels(label2), + // do multiplier before store to this.capacityCurrentTick + new CodeInstruction(OpCodes.Mul).WithLabels(label3) + ); + return matcher.InstructionEnumeration(); + } + } + + private static class BoostGeothermalPower + { + private static Harmony _patch; + public static void Enable(bool enable) + { + if (enable) + { + _patch ??= Harmony.CreateAndPatchAll(typeof(BoostGeothermalPower)); + return; + } + _patch?.UnpatchSelf(); + _patch = null; + } + [HarmonyTranspiler] + [HarmonyPatch(typeof(PowerGeneratorComponent), nameof(PowerGeneratorComponent.EnergyCap_GTH))] + private static IEnumerable PowerGeneratorComponent_EnergyCap_GTH_Transpiler(IEnumerable instructions, ILGenerator generator) + { + var matcher = new CodeMatcher(instructions, generator); + matcher.Start().RemoveInstructions(matcher.Length).Insert( + // this.currentStrength = this.gthStrength + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(PowerGeneratorComponent), nameof(PowerGeneratorComponent.gthStrength))), + new CodeInstruction(OpCodes.Stfld, AccessTools.Field(typeof(PowerGeneratorComponent), nameof(PowerGeneratorComponent.currentStrength))), + // this.capacityCurrentTick = 2000000000L + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldc_I8, 2000000000L), + new CodeInstruction(OpCodes.Stfld, AccessTools.Field(typeof(PowerGeneratorComponent), nameof(PowerGeneratorComponent.capacityCurrentTick))), + // return 2000000000L + new CodeInstruction(OpCodes.Ldc_I8, 2000000000L), + new CodeInstruction(OpCodes.Ret) + ); + return matcher.InstructionEnumeration(); + } + } + +} \ No newline at end of file diff --git a/CheatEnabler/I18N.cs b/CheatEnabler/I18N.cs index 07b78aa..bcab0b1 100644 --- a/CheatEnabler/I18N.cs +++ b/CheatEnabler/I18N.cs @@ -5,7 +5,7 @@ using HarmonyLib; namespace CheatEnabler; -public class I18N +public static class I18N { private static bool _initialized; @@ -15,6 +15,8 @@ public class I18N { Harmony.CreateAndPatchAll(typeof(I18N)); } + + public static bool Initialized() => _initialized; private static int _nextID = 1; private static readonly List StringsToAdd = new(); public static void Add(string key, string enus, string zhcn = null, string frfr = null) diff --git a/CheatEnabler/PlanetFunctions.cs b/CheatEnabler/PlanetFunctions.cs index b91f34b..ca58dff 100644 --- a/CheatEnabler/PlanetFunctions.cs +++ b/CheatEnabler/PlanetFunctions.cs @@ -8,8 +8,8 @@ using Random = UnityEngine.Random; namespace CheatEnabler; public static class PlanetFunctions { + /* private static Harmony _patch; - private static readonly Dictionary ItemSources = new(); private static PumpSource[] _pumpItemSources = new PumpSource[16]; private static int _pumpItemSourcesLength = 16; @@ -44,6 +44,16 @@ public static class PlanetFunctions } } + [HarmonyPostfix] + [HarmonyPatch(typeof(PlanetFactory), nameof(PlanetFactory.Init))] + private static void PlanetFactory_Init_Postfix(PlanetFactory __instance) + { + const int waterItemId = 6006; + __instance.planet.waterItemId = waterItemId; + CheatEnabler.Logger.LogDebug($"Init PlanetFactory with waterItemId {waterItemId}"); + UpdatePumpItemSources(__instance); + } + private static void UpdatePumpItemSources(PlanetFactory factory) { var index = factory.index; @@ -96,164 +106,7 @@ public static class PlanetFunctions pump.Items = items; pump.Progress = progress; } - - /* Pump item calculation */ - private class ItemSource - { - public float Count; - public Dictionary From; - public Dictionary Extra; - } - - private static void InitItemSources() - { - ItemSources.Clear(); - foreach (var vein in LDB.veins.dataArray) - { - ItemSources[vein.MiningItem] = new ItemSource { Count = 1 }; - } - - foreach (var ip in LDB.items.dataArray) - { - if (!string.IsNullOrEmpty(ip.MiningFrom)) - { - ItemSources[ip.ID] = new ItemSource { Count = 1 }; - } - } - - ItemSources[1208] = new ItemSource { Count = 1 }; - var recipes = LDB.recipes.dataArray; - foreach (var recipe in recipes) - { - if (!recipe.Explicit || recipe.ID == 58 || recipe.ID == 121) continue; - var res = recipe.Results; - var rescnt = recipe.ResultCounts; - var len = res.Length; - for (var i = 0; i < len; i++) - { - if (ItemSources.ContainsKey(res[i])) continue; - var rs = new ItemSource { Count = rescnt[i], From = new Dictionary() }; - var it = recipe.Items; - var itcnt = recipe.ItemCounts; - var len2 = it.Length; - for (var j = 0; j < len2; j++) - { - rs.From[it[j]] = itcnt[j]; - } - if (len > 1) - { - rs.Extra = new Dictionary(); - for (var k = 0; k < len; k++) - { - if (i != k) - { - rs.Extra[res[k]] = rescnt[k]; - } - } - } - - ItemSources[res[i]] = rs; - } - } - foreach (var recipe in recipes) - { - if (recipe.Explicit) continue; - var res = recipe.Results; - var rescnt = recipe.ResultCounts; - var len = res.Length; - for (var i = 0; i < len; i++) - { - if (ItemSources.ContainsKey(res[i])) continue; - var rs = new ItemSource { Count = rescnt[i], From = new Dictionary() }; - var it = recipe.Items; - var itcnt = recipe.ItemCounts; - var len2 = it.Length; - for (var j = 0; j < len2; j++) - { - rs.From[it[j]] = itcnt[j]; - } - if (len > 1) - { - rs.Extra = new Dictionary(); - for (var k = 0; k < len; k++) - { - if (i != k) - { - rs.Extra[res[k]] = rescnt[k]; - } - } - } - - ItemSources[res[i]] = rs; - } - } - } - - public static void CalculateAllProductions(Dictionary result, Dictionary extra, int itemId, float count = 0f) - { - if (!ItemSources.TryGetValue(itemId, out var itemSource)) - { - if (count <= 0) return; - result.TryGetValue(itemId, out var oldCount); - result[itemId] = oldCount + count; - return; - } - - var times = 1f; - if (count == 0f) - { - count = itemSource.Count; - } - else if (Math.Abs(count - itemSource.Count) > 0.000001f) - { - times = count / itemSource.Count; - } - - { - result.TryGetValue(itemId, out var oldCount); - result[itemId] = oldCount + count; - } - if (itemSource.Extra != null) - { - foreach (var p in itemSource.Extra) - { - extra.TryGetValue(p.Key, out var oldCount); - extra[p.Key] = oldCount + times * p.Value; - } - } - - if (itemSource.From == null) return; - foreach (var p in itemSource.From) - { - CalculateAllProductions(result, extra, p.Key, times * p.Value); - } - } - - public static void CalculateAllProductions(Dictionary result, int itemId, float count = 0f) - { - var extra = new Dictionary(); - CalculateAllProductions(result, extra, itemId, count); - foreach (var k in extra.Keys.ToArray()) - { - if (!result.TryGetValue(k, out var cnt)) continue; - var cnt2 = extra[k]; - if (Math.Abs(cnt - cnt2) < 0.000001f) - { - result.Remove(k); - extra.Remove(k); - continue; - } - if (cnt > cnt2) - { - result[k] = cnt - cnt2; - extra.Remove(k); - continue; - } - result.Remove(k); - extra[k] = cnt2 - cnt; - } - } - /* Pump item calculation */ + */ public static void DismantleAll(bool toBag) { diff --git a/CheatEnabler/README.md b/CheatEnabler/README.md index 007e2b6..9851252 100644 --- a/CheatEnabler/README.md +++ b/CheatEnabler/README.md @@ -4,6 +4,10 @@ #### 添加一些作弊功能,同时屏蔽异常检测 ## Changlog +* 2.2.0 + + Add some power related functions + + Add a subfunction to belt signal item generation, which simulates production process of raws and intermediates on statistics + + Split some functions from Architect mode * 2.1.0 + Belt signal item generation + Fix window display priority which may cause tips to be covered by main window @@ -24,12 +28,17 @@ + Enable Dev Shortcuts (check config panel for usage) + Disable Abnormal Checks + Unlock techs with key-modifiers (Ctrl/Alt/Shift) - + Build: + + Factory: + Finish build immediately - + Architect mode (Infinite buildings + Interactive without distance limit + Sunlight at night) + + Architect mode (Infinite buildings) + + Unlimited interactive range + Build without condition + No collision + Belt signal item generation + + Count all raws and intermediates in statistics + + Sunlight at night + + Remove space limit between wind turbines and solar panels + + Boost power generations for kinds of power generators + Planet: + Infinite Natural Resources + Fast Mining @@ -56,6 +65,10 @@ * [LSTM](https://github.com/hetima/DSP_LSTM) & [PlanetFinder](https://github.com/hetima/DSP_PlanetFinder): UI implementations ## 更新日志 +* 2.2.0 + + 添加了一些发电相关功能 + + 为传送带信号物品生成添加了一个子功能,在统计面板模拟了原材料和中间产物的生产过程 + + 从建筑师模式中分离了一些功能 * 2.1.0 + 传送带信号物品生成 + 修复窗口显示优先级可能导致提示信息被主窗口遮挡的问题 @@ -76,12 +89,16 @@ + 启用开发模式快捷键(使用说明见设置面板) + 屏蔽异常检测 + 使用组合键解锁科技(Ctrl/Alt/Shift) - + 建造: + + 工厂: + 建造秒完成 - + 建筑师模式(无限建筑+无视距离操作+夜间日光灯) + + 建筑师模式(无限建筑) + + 无限交互距离 + 无条件建造 + 无碰撞 + 传送带信号物品生成 + + 夜间日光灯 + + 风力发电机和太阳能板无间距限制 + + 提升各种发电设备发电量 + 行星: + 自然资源采集不消耗 + 高速采集 diff --git a/CheatEnabler/UIConfigWindow.cs b/CheatEnabler/UIConfigWindow.cs index 51a47fa..5d1002b 100644 --- a/CheatEnabler/UIConfigWindow.cs +++ b/CheatEnabler/UIConfigWindow.cs @@ -22,12 +22,21 @@ public class UIConfigWindow : UI.MyWindowWithTabs I18N.Add("Unlock Tech with Key-Modifiers Tips", "Click tech on tree while holding:\n Shift: Tech level + 1\n Ctrl: Tech level + 10\n Ctrl + Shift: Tech level + 100\n Alt: Tech level to MAX\n\nNote: all direct prerequisites will be unlocked as well.", "按住以下组合键点击科技树:\n Shift:科技等级+1\n Ctrl:科技等级+10\n Ctrl+Shift:科技等级+100\n Alt:科技等级升到最大\n\n注意:所有直接前置科技也会被解锁"); - I18N.Add("Build", "Build", "建造"); + I18N.Add("Factory", "Factory", "工厂"); I18N.Add("Finish build immediately", "Finish build immediately", "建造秒完成"); I18N.Add("Architect mode", "Architect mode", "建筑师模式"); + I18N.Add("Unlimited interactive range", "Unlimited interactive range", "无限交互距离"); I18N.Add("Build without condition", "Build without condition check", "无条件建造"); I18N.Add("No collision", "No collision", "无碰撞"); I18N.Add("Belt signal generator", "Belt signal generator", "传送带信号物品生成"); + I18N.Add("Count all raws and intermediates in statistics","Count all raw materials in statistics", "统计信息里计算所有原料和中间产物"); + I18N.Add("Night Light", "Sunlight at night", "夜间日光灯"); + I18N.Add("Remove power space limit", "Remove space limit for winds and geothermals", "移除风力发电和地热发电的间距限制"); + I18N.Add("Boost wind power", "Boost wind power(x100,000)", "提升风力发电(x100,000)"); + I18N.Add("Boost solar power", "Boost solar power(x100,000)", "提升太阳能发电(x100,000)"); + I18N.Add("Boost fuel power", "Boost fuel power(x50,000)", "提升燃料发电(x50,000)"); + I18N.Add("Boost fuel power 2", "(x20,000 for deuteron, x10,000 for antimatter)", "(氘核燃料棒x20,000,反物质燃料棒x10,000)"); + I18N.Add("Boost geothermal power", "Boost geothermal power(x50,000)", "提升地热发电(x50,000)"); I18N.Add("Planet", "Planet", "行星"); I18N.Add("Infinite Natural Resources", "Infinite Natural Resources", "自然资源采集不消耗"); I18N.Add("Fast Mining", "Fast Mining", "高速采集"); @@ -66,7 +75,7 @@ public class UIConfigWindow : UI.MyWindowWithTabs public override void _OnCreate() { _windowTrans = GetComponent(); - _windowTrans.sizeDelta = new Vector2(580f, 331f); + _windowTrans.sizeDelta = new Vector2(580f, 400f); CreateUI(); } @@ -82,7 +91,7 @@ public class UIConfigWindow : UI.MyWindowWithTabs UI.MyCheckBox.CreateCheckBox(x, y, tab1, AbnormalDisabler.Enabled, "Disable Abnormal Checks"); y += 36f; UI.MyCheckBox.CreateCheckBox(x, y, tab1, TechPatch.Enabled, "Unlock Tech with Key-Modifiers"); - y += 50f; + y += 118f; UI.MyKeyBinder.CreateKeyBinder(x, y, tab1, CheatEnabler.Hotkey, "Hotkey"); x = 156f; y = 16f; @@ -91,18 +100,44 @@ public class UIConfigWindow : UI.MyWindowWithTabs y += 72f; AddTipsButton(x, y, tab1, "Unlock Tech with Key-Modifiers", "Unlock Tech with Key-Modifiers Tips", "unlock-tech-tips"); - var tab2 = AddTab(136f, 1, _windowTrans, "Build"); + var tab2 = AddTab(136f, 1, _windowTrans, "Factory"); x = 0f; y = 10f; - UI.MyCheckBox.CreateCheckBox(x, y, tab2, BuildPatch.ImmediateEnabled, "Finish build immediately"); + UI.MyCheckBox.CreateCheckBox(x, y, tab2, FactoryPatch.ImmediateEnabled, "Finish build immediately"); y += 36f; - UI.MyCheckBox.CreateCheckBox(x, y, tab2, BuildPatch.ArchitectModeEnabled, "Architect mode"); + UI.MyCheckBox.CreateCheckBox(x, y, tab2, FactoryPatch.ArchitectModeEnabled, "Architect mode"); y += 36f; - UI.MyCheckBox.CreateCheckBox(x, y, tab2, BuildPatch.NoConditionEnabled, "Build without condition"); + UI.MyCheckBox.CreateCheckBox(x, y, tab2, FactoryPatch.UnlimitInteractiveEnabled, "Unlimited interactive range"); y += 36f; - UI.MyCheckBox.CreateCheckBox(x, y, tab2, BuildPatch.NoCollisionEnabled, "No collision"); + UI.MyCheckBox.CreateCheckBox(x, y, tab2, FactoryPatch.NoConditionEnabled, "Build without condition"); y += 36f; - UI.MyCheckBox.CreateCheckBox(x, y, tab2, BuildPatch.BeltSignalGeneratorEnabled, "Belt signal generator"); + UI.MyCheckBox.CreateCheckBox(x, y, tab2, FactoryPatch.NoCollisionEnabled, "No collision"); + y += 36f; + UI.MyCheckBox.CreateCheckBox(x, y, tab2, FactoryPatch.NightLightEnabled, "Night Light"); + y += 36f; + UI.MyCheckBox.CreateCheckBox(x, y, tab2, FactoryPatch.BeltSignalGeneratorEnabled, "Belt signal generator"); + y += 26f; + x += 26f; + var cb = UI.MyCheckBox.CreateCheckBox(x, y, tab2, FactoryPatch.BeltSignalCountRecipeEnabled, "Count all raws and intermediates in statistics", 13); + cb.gameObject.SetActive(FactoryPatch.BeltSignalGeneratorEnabled.Value); + FactoryPatch.BeltSignalGeneratorEnabled.SettingChanged += (_, _) => + { + cb.gameObject.SetActive(FactoryPatch.BeltSignalGeneratorEnabled.Value); + }; + x = 240f; + y = 10f; + UI.MyCheckBox.CreateCheckBox(x, y, tab2, FactoryPatch.RemovePowerSpaceLimitEnabled, "Remove power space limit"); + y += 36f; + UI.MyCheckBox.CreateCheckBox(x, y, tab2, FactoryPatch.BoostWindPowerEnabled, "Boost wind power"); + y += 36f; + UI.MyCheckBox.CreateCheckBox(x, y, tab2, FactoryPatch.BoostSolarPowerEnabled, "Boost solar power"); + y += 36f; + UI.MyCheckBox.CreateCheckBox(x, y, tab2, FactoryPatch.BoostGeothermalPowerEnabled, "Boost geothermal power"); + y += 36f; + UI.MyCheckBox.CreateCheckBox(x, y, tab2, FactoryPatch.BoostFuelPowerEnabled, "Boost fuel power"); + x += 32f; + y += 26f; + AddText(x, y, tab2, "Boost fuel power 2", 13); // Planet Tab var tab3 = AddTab(236f, 2, _windowTrans, "Planet"); @@ -191,14 +226,14 @@ public class UIConfigWindow : UI.MyWindowWithTabs UI.MyCheckBox.CreateCheckBox(x, y, tab5, BirthPlanetPatch.FractalOnBirthPlanet, "Fractal silicon on birth planet"); y += 36f; UI.MyCheckBox.CreateCheckBox(x, y, tab5, BirthPlanetPatch.OrganicOnBirthPlanet, "Organic crystal on birth planet"); - x = 200f; - y = 10f; + y += 36f; UI.MyCheckBox.CreateCheckBox(x, y, tab5, BirthPlanetPatch.OpticalOnBirthPlanet, "Optical grating crystal on birth planet"); y += 36f; UI.MyCheckBox.CreateCheckBox(x, y, tab5, BirthPlanetPatch.SpiniformOnBirthPlanet, "Spiniform stalagmite crystal on birth planet"); y += 36f; UI.MyCheckBox.CreateCheckBox(x, y, tab5, BirthPlanetPatch.UnipolarOnBirthPlanet, "Unipolar magnet on birth planet"); - y += 36f; + x = 200f; + y = 10f; UI.MyCheckBox.CreateCheckBox(x, y, tab5, BirthPlanetPatch.FlatBirthPlanet, "Birth planet is solid flat (no water at all)"); y += 36f; UI.MyCheckBox.CreateCheckBox(x, y, tab5, BirthPlanetPatch.HighLuminosityBirthStar, "Birth star has high luminosity"); diff --git a/CheatEnabler/package/manifest.json b/CheatEnabler/package/manifest.json index f236270..17f0ded 100644 --- a/CheatEnabler/package/manifest.json +++ b/CheatEnabler/package/manifest.json @@ -1,6 +1,6 @@ { "name": "CheatEnabler", - "version_number": "2.1.0", + "version_number": "2.2.0", "website_url": "https://github.com/soarqin/DSP_Mods/tree/master/CheatEnabler", "description": "Add various cheat functions while disabling abnormal determinants / 添加一些作弊功能,同时屏蔽异常检测", "dependencies": [