1
0
mirror of https://github.com/soarqin/DSP_Mods.git synced 2025-12-09 02:53:29 +08:00

UXAssist: Work in progress

This commit is contained in:
2023-10-10 02:38:24 +08:00
parent 41f2103c11
commit 6caa183cfa
26 changed files with 1477 additions and 1800 deletions

View File

@@ -1,10 +1,4 @@
using System.Collections.Generic;
using System.Reflection.Emit;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;
using UnityEngine.UI;
using BepInEx;
using UXAssist.Common;
namespace CheatEnabler;
@@ -16,11 +10,8 @@ public class CheatEnabler : BaseUnityPlugin
public new static readonly BepInEx.Logging.ManualLogSource Logger =
BepInEx.Logging.Logger.CreateLogSource(PluginInfo.PLUGIN_NAME);
public static ConfigEntry<KeyboardShortcut> Hotkey;
private void Awake()
{
Hotkey = Config.Bind("General", "Shortcut", KeyboardShortcut.Deserialize("BackQuote + LeftAlt"), "Shortcut to open config window");
DevShortcuts.Enabled = Config.Bind("General", "DevShortcuts", false, "Enable DevMode shortcuts");
AbnormalDisabler.Enabled = Config.Bind("General", "DisableAbnormalChecks", false,
"disable all abnormal checks");
@@ -30,10 +21,6 @@ public class CheatEnabler : BaseUnityPlugin
"Build immediately");
FactoryPatch.ArchitectModeEnabled = Config.Bind("Build", "Architect", false,
"Architect Mode");
FactoryPatch.UnlimitInteractiveEnabled = Config.Bind("Build", "UnlimitInteractive", false,
"Unlimit interactive range");
FactoryPatch.RemoveSomeConditionEnabled = Config.Bind("Build", "RemoveSomeBuildConditionCheck", false,
"Remove part of build condition checks that does not affect game logic");
FactoryPatch.NoConditionEnabled = Config.Bind("Build", "BuildWithoutCondition", false,
"Build without condition");
FactoryPatch.NoCollisionEnabled = Config.Bind("Build", "NoCollision", false,
@@ -44,8 +31,6 @@ public class CheatEnabler : BaseUnityPlugin
"Belt signal number format alternative format (AAAA=generation speed in minutes, B=proliferate points, C=stack count):\n AAAABC by default\n BCAAAA as alternative");
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,
@@ -56,20 +41,14 @@ public class CheatEnabler : BaseUnityPlugin
"Boost fuel power");
FactoryPatch.BoostGeothermalPowerEnabled = Config.Bind("Build", "BoostGeothermalPower", false,
"Boost geothermal power");
PlanetFunctions.PlayerActionsInGlobeViewEnabled = Config.Bind("Planet", "PlayerActionsInGlobeView", false,
"Enable player actions in globe view");
ResourcePatch.InfiniteResourceEnabled = Config.Bind("Planet", "AlwaysInfiniteResource", false,
"always infinite natural resource");
ResourcePatch.FastMiningEnabled = Config.Bind("Planet", "FastMining", false,
"super-fast mining speed");
WaterPumperPatch.Enabled = Config.Bind("Planet", "WaterPumpAnywhere", false,
PlanetPatch.WaterPumpAnywhereEnabled = Config.Bind("Planet", "WaterPumpAnywhere", false,
"Can pump water anywhere (while water type is not None)");
TerraformPatch.Enabled = Config.Bind("Planet", "TerraformAnyway", false,
PlanetPatch.TerraformAnywayEnabled = Config.Bind("Planet", "TerraformAnyway", false,
"Can do terraform without enough sands");
DysonSpherePatch.StopEjectOnNodeCompleteEnabled = Config.Bind("DysonSphere", "StopEjectOnNodeComplete", false,
"Stop ejectors when available nodes are all filled up");
DysonSpherePatch.OnlyConstructNodesEnabled = Config.Bind("DysonSphere", "OnlyConstructNodes", false,
"Construct only nodes but frames");
DysonSpherePatch.SkipBulletEnabled = Config.Bind("DysonSphere", "SkipBullet", false,
"Skip bullet");
DysonSpherePatch.SkipAbsorbEnabled = Config.Bind("DysonSphere", "SkipAbsorb", false,
@@ -113,10 +92,8 @@ public class CheatEnabler : BaseUnityPlugin
AbnormalDisabler.Init();
TechPatch.Init();
FactoryPatch.Init();
PlanetFunctions.Init();
ResourcePatch.Init();
WaterPumperPatch.Init();
TerraformPatch.Init();
PlanetPatch.Init();
DysonSpherePatch.Init();
BirthPlanetPatch.Init();
}
@@ -125,18 +102,11 @@ public class CheatEnabler : BaseUnityPlugin
{
BirthPlanetPatch.Uninit();
DysonSpherePatch.Uninit();
TerraformPatch.Uninit();
WaterPumperPatch.Uninit();
PlanetPatch.Uninit();
ResourcePatch.Uninit();
PlanetFunctions.Uninit();
FactoryPatch.Uninit();
TechPatch.Uninit();
AbnormalDisabler.Uninit();
DevShortcuts.Uninit();
}
private void LateUpdate()
{
FactoryPatch.NightLight.LateUpdate();
}
}

View File

@@ -5,7 +5,7 @@
<TargetFramework>net472</TargetFramework>
<BepInExPluginGuid>org.soardev.cheatenabler</BepInExPluginGuid>
<Description>DSP MOD - CheatEnabler</Description>
<Version>2.2.7</Version>
<Version>2.3.0</Version>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>latest</LangVersion>
<PackageId>CheatEnabler</PackageId>

View File

@@ -8,30 +8,22 @@ namespace CheatEnabler;
public static class DysonSpherePatch
{
public static ConfigEntry<bool> StopEjectOnNodeCompleteEnabled;
public static ConfigEntry<bool> OnlyConstructNodesEnabled;
public static ConfigEntry<bool> SkipBulletEnabled;
public static ConfigEntry<bool> SkipAbsorbEnabled;
public static ConfigEntry<bool> QuickAbsorbEnabled;
public static ConfigEntry<bool> EjectAnywayEnabled;
public static ConfigEntry<bool> OverclockEjectorEnabled;
public static ConfigEntry<bool> OverclockSiloEnabled;
private static Harmony _dysonSpherePatch;
private static bool _instantAbsorb;
public static void Init()
{
_dysonSpherePatch ??= Harmony.CreateAndPatchAll(typeof(DysonSpherePatch));
StopEjectOnNodeCompleteEnabled.SettingChanged += (_, _) => StopEjectOnNodeComplete.Enable(StopEjectOnNodeCompleteEnabled.Value);
OnlyConstructNodesEnabled.SettingChanged += (_, _) => OnlyConstructNodes.Enable(OnlyConstructNodesEnabled.Value);
SkipBulletEnabled.SettingChanged += (_, _) => SkipBulletPatch.Enable(SkipBulletEnabled.Value);
SkipAbsorbEnabled.SettingChanged += (_, _) => SkipAbsorbPatch.Enable(SkipBulletEnabled.Value);
QuickAbsorbEnabled.SettingChanged += (_, _) => QuickAbsorbPatch.Enable(QuickAbsorbEnabled.Value);
EjectAnywayEnabled.SettingChanged += (_, _) => EjectAnywayPatch.Enable(EjectAnywayEnabled.Value);
OverclockEjectorEnabled.SettingChanged += (_, _) => OverclockEjector.Enable(OverclockEjectorEnabled.Value);
OverclockSiloEnabled.SettingChanged += (_, _) => OverclockSilo.Enable(OverclockSiloEnabled.Value);
StopEjectOnNodeComplete.Enable(StopEjectOnNodeCompleteEnabled.Value);
OnlyConstructNodes.Enable(OnlyConstructNodesEnabled.Value);
SkipBulletPatch.Enable(SkipBulletEnabled.Value);
SkipAbsorbPatch.Enable(SkipBulletEnabled.Value);
QuickAbsorbPatch.Enable(QuickAbsorbEnabled.Value);
@@ -42,298 +34,12 @@ public static class DysonSpherePatch
public static void Uninit()
{
StopEjectOnNodeComplete.Enable(false);
OnlyConstructNodes.Enable(false);
SkipBulletPatch.Enable(false);
SkipAbsorbPatch.Enable(false);
QuickAbsorbPatch.Enable(false);
EjectAnywayPatch.Enable(false);
OverclockEjector.Enable(false);
OverclockSilo.Enable(false);
_dysonSpherePatch?.UnpatchSelf();
_dysonSpherePatch = null;
}
public static void InitCurrentDysonSphere(int index)
{
var star = GameMain.localStar;
if (star == null) return;
var dysonSpheres = GameMain.data?.dysonSpheres;
if (dysonSpheres == null) return;
if (index < 0)
{
if (dysonSpheres[star.index] == null) return;
var dysonSphere = new DysonSphere();
dysonSpheres[star.index] = dysonSphere;
dysonSphere.Init(GameMain.data, star);
dysonSphere.ResetNew();
return;
}
var ds = dysonSpheres[star.index];
if (ds?.layersIdBased[index] == null) return;
var pool = ds.rocketPool;
for (var id = ds.rocketCursor - 1; id > 0; id--)
{
if (pool[id].id != id) continue;
if (pool[id].nodeLayerId != index) continue;
ds.RemoveDysonRocket(id);
}
ds.RemoveLayer(index);
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(DysonNode), nameof(DysonNode.ConstructCp))]
private static IEnumerable<CodeInstruction> DysonSpherePatch_DysonNode_ConstructCp_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var matcher = new CodeMatcher(instructions, generator);
matcher.MatchBack(false,
new CodeMatch(OpCodes.Ldc_I4_0),
new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(DysonShell), nameof(DysonShell.Construct)))
).Advance(3).InsertAndAdvance(
// node._cpReq = node._cpReq - 1;
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(DysonNode), nameof(DysonNode._cpReq))),
new CodeInstruction(OpCodes.Ldc_I4_1),
new CodeInstruction(OpCodes.Sub),
new CodeInstruction(OpCodes.Stfld, AccessTools.Field(typeof(DysonNode), nameof(DysonNode._cpReq)))
);
// Remove use of RecalcCpReq()
matcher.MatchForward(false,
new CodeMatch(OpCodes.Ldarg_0),
new CodeMatch(OpCodes.Call, AccessTools.Method(typeof(DysonNode), nameof(DysonNode.RecalcCpReq)))
);
var labels = matcher.Labels;
matcher.Labels = new List<Label>();
matcher.RemoveInstructions(2).Labels.AddRange(labels);
return matcher.InstructionEnumeration();
}
private static class StopEjectOnNodeComplete
{
private static Harmony _patch;
private static HashSet<int>[] _nodeForAbsorb;
private static bool _initialized;
public static void Enable(bool on)
{
if (on)
{
InitNodeForAbsorb();
_patch ??= Harmony.CreateAndPatchAll(typeof(StopEjectOnNodeComplete));
}
else
{
_initialized = false;
_patch?.UnpatchSelf();
_patch = null;
_nodeForAbsorb = null;
}
}
private static void InitNodeForAbsorb()
{
_initialized = false;
_nodeForAbsorb = null;
var data = GameMain.data;
var galaxy = data?.galaxy;
if (galaxy == null) return;
_nodeForAbsorb = new HashSet<int>[galaxy.starCount];
var spheres = data.dysonSpheres;
if (spheres == null) return;
foreach (var sphere in spheres)
{
if (sphere?.layersSorted == null) continue;
var starIndex = sphere.starData.index;
foreach (var layer in sphere.layersSorted)
{
if (layer == null) continue;
for (var i = layer.nodeCursor - 1; i > 0; i--)
{
var node = layer.nodePool[i];
if (node == null || node.id != i || node.sp < node.spMax || node.cpReqOrder == 0) continue;
SetNodeForAbsorb(starIndex, layer.id, node.id, true);
}
}
}
_initialized = true;
}
private static void SetNodeForAbsorb(int index, int layerId, int nodeId, bool canAbsorb)
{
ref var comp = ref _nodeForAbsorb[index];
comp ??= new HashSet<int>();
var idx = nodeId * 10 + layerId;
if (canAbsorb)
comp.Add(idx);
else
comp.Remove(idx);
}
private static void UpdateNodeForAbsorbOnSpChange(DysonNode node)
{
if (!_initialized) return;
if (node.sp < node.spMax || node.cpReqOrder <= 0) return;
var shells = node.shells;
if (shells.Count == 0) return;
SetNodeForAbsorb(shells[0].dysonSphere.starData.index, node.layerId, node.id, true);
}
private static void UpdateNodeForAbsorbOnCpChange(DysonNode node)
{
if (!_initialized) return;
if (node.sp < node.spMax || node.cpReqOrder > 0) return;
var shells = node.shells;
if (shells.Count == 0) return;
SetNodeForAbsorb(shells[0].dysonSphere.starData.index, node.layerId, node.id, false);
}
private static bool AnyNodeForAbsorb(int starIndex)
{
var comp = _nodeForAbsorb[starIndex];
return comp != null && comp.Count > 0;
}
[HarmonyPostfix]
[HarmonyPatch(typeof(GameMain), nameof(GameMain.Begin))]
private static void GameMain_Begin_Postfix()
{
InitNodeForAbsorb();
}
[HarmonyPostfix]
[HarmonyPatch(typeof(DysonNode), nameof(DysonNode.RecalcCpReq))]
private static void DysonNode_RecalcCpReq_Postfix(DysonNode __instance)
{
UpdateNodeForAbsorbOnCpChange(__instance);
}
[HarmonyPrefix]
[HarmonyPatch(typeof(DysonSphereLayer), nameof(DysonSphereLayer.RemoveDysonNode))]
private static void DysonSphereLayer_RemoveDysonNode_Prefix(DysonSphereLayer __instance, int nodeId)
{
if (_initialized)
SetNodeForAbsorb(__instance.starData.index, __instance.id, nodeId, false);
}
[HarmonyPrefix]
[HarmonyPatch(typeof(DysonSphere), nameof(DysonSphere.ResetNew))]
private static void DysonSphere_ResetNew_Prefix(DysonSphere __instance)
{
var starIndex = __instance.starData.index;
if (_nodeForAbsorb[starIndex] == null) return;
_nodeForAbsorb[starIndex].Clear();
_nodeForAbsorb[starIndex] = null;
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(EjectorComponent), nameof(EjectorComponent.InternalUpdate))]
private static IEnumerable<CodeInstruction> EjectorComponent_InternalUpdate_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var matcher = new CodeMatcher(instructions, generator);
matcher.MatchForward(false,
// if (this.orbitId == 0
new CodeMatch(OpCodes.Ldarg_0),
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(EjectorComponent), nameof(EjectorComponent.orbitId))),
new CodeMatch(OpCodes.Brtrue)
).Advance(2).Insert(
// || !StopEjectOnNodeComplete.AnyNodeForAbsorb(this.starData.index))
new CodeInstruction(OpCodes.Ldarg_2),
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(DysonSwarm), nameof(DysonSwarm.starData))),
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(StarData), nameof(StarData.index))),
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(StopEjectOnNodeComplete), nameof(StopEjectOnNodeComplete.AnyNodeForAbsorb))),
new CodeInstruction(OpCodes.And)
);
return matcher.InstructionEnumeration();
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(DysonNode), nameof(DysonNode.ConstructSp))]
private static IEnumerable<CodeInstruction> DysonNode_ConstructSp_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var matcher = new CodeMatcher(instructions, generator);
matcher.Start().MatchForward(false,
new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(DysonNode), nameof(DysonNode.sp)))
).Advance(1);
var labels = matcher.Labels;
matcher.Labels = new List<Label>();
matcher.Insert(
new CodeInstruction(OpCodes.Ldarg_0).WithLabels(labels),
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(StopEjectOnNodeComplete), nameof(StopEjectOnNodeComplete.UpdateNodeForAbsorbOnSpChange)))
);
return matcher.InstructionEnumeration();
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(DysonNode), nameof(DysonNode.ConstructCp))]
private static IEnumerable<CodeInstruction> DysonNode_ConstructCp_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var matcher = new CodeMatcher(instructions, generator);
matcher.MatchBack(false,
// Search for previous patch:
// node._cpReq = node._cpReq - 1;
new CodeMatch(OpCodes.Ldarg_0),
new CodeMatch(OpCodes.Ldarg_0),
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(DysonNode), nameof(DysonNode._cpReq))),
new CodeMatch(OpCodes.Ldc_I4_1),
new CodeMatch(OpCodes.Sub),
new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(DysonNode), nameof(DysonNode._cpReq)))
).Advance(6).Insert(
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(StopEjectOnNodeComplete), nameof(StopEjectOnNodeComplete.UpdateNodeForAbsorbOnCpChange)))
);
return matcher.InstructionEnumeration();
}
}
private static class OnlyConstructNodes
{
private static Harmony _patch;
public static void Enable(bool on)
{
if (on)
{
_patch ??= Harmony.CreateAndPatchAll(typeof(OnlyConstructNodes));
}
else
{
_patch?.UnpatchSelf();
_patch = null;
}
var spheres = GameMain.data?.dysonSpheres;
if (spheres == null) return;
foreach (var sphere in spheres)
{
if (sphere == null) continue;
sphere.CheckAutoNodes();
if (sphere.autoNodeCount > 0) continue;
sphere.PickAutoNode();
sphere.PickAutoNode();
sphere.PickAutoNode();
sphere.PickAutoNode();
}
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(DysonNode), nameof(DysonNode.spReqOrder), MethodType.Getter)]
private static IEnumerable<CodeInstruction> DysonNode_spReqOrder_Getter_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var matcher = new CodeMatcher(instructions, generator);
matcher.MatchForward(false,
new CodeMatch(OpCodes.Ldarg_0),
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(DysonNode), nameof(DysonNode._spReq)))
).Advance(1).SetInstructionAndAdvance(
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(DysonNode), nameof(DysonNode.spMax)))
).Insert(
new CodeInstruction(OpCodes.Ldarg_0),
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(DysonNode), nameof(DysonNode.sp))),
new CodeInstruction(OpCodes.Sub)
);
return matcher.InstructionEnumeration();
}
}
private static class SkipBulletPatch

View File

@@ -11,14 +11,11 @@ public static class FactoryPatch
{
public static ConfigEntry<bool> ImmediateEnabled;
public static ConfigEntry<bool> ArchitectModeEnabled;
public static ConfigEntry<bool> UnlimitInteractiveEnabled;
public static ConfigEntry<bool> RemoveSomeConditionEnabled;
public static ConfigEntry<bool> NoConditionEnabled;
public static ConfigEntry<bool> NoCollisionEnabled;
public static ConfigEntry<bool> BeltSignalGeneratorEnabled;
public static ConfigEntry<bool> BeltSignalNumberAltFormat;
public static ConfigEntry<bool> BeltSignalCountRecipeEnabled;
public static ConfigEntry<bool> NightLightEnabled;
public static ConfigEntry<bool> RemovePowerSpaceLimitEnabled;
public static ConfigEntry<bool> BoostWindPowerEnabled;
public static ConfigEntry<bool> BoostSolarPowerEnabled;
@@ -32,13 +29,10 @@ public static class FactoryPatch
if (_factoryPatch != null) return;
ImmediateEnabled.SettingChanged += (_, _) => ImmediateBuild.Enable(ImmediateEnabled.Value);
ArchitectModeEnabled.SettingChanged += (_, _) => ArchitectMode.Enable(ArchitectModeEnabled.Value);
UnlimitInteractiveEnabled.SettingChanged += (_, _) => UnlimitInteractive.Enable(UnlimitInteractiveEnabled.Value);
RemoveSomeConditionEnabled.SettingChanged += (_, _) => RemoveSomeConditionBuild.Enable(RemoveSomeConditionEnabled.Value);
NoConditionEnabled.SettingChanged += (_, _) => NoConditionBuild.Enable(NoConditionEnabled.Value);
NoCollisionEnabled.SettingChanged += (_, _) => NoCollisionValueChanged();
BeltSignalGeneratorEnabled.SettingChanged += (_, _) => BeltSignalGenerator.Enable(BeltSignalGeneratorEnabled.Value);
BeltSignalNumberAltFormat.SettingChanged += (_, _) => BeltSignalGenerator.OnAltFormatChanged();
NightLightEnabled.SettingChanged += (_, _) => NightLight.Enable(NightLightEnabled.Value);
RemovePowerSpaceLimitEnabled.SettingChanged += (_, _) => RemovePowerSpaceLimit.Enable(RemovePowerSpaceLimitEnabled.Value);
BoostWindPowerEnabled.SettingChanged += (_, _) => BoostWindPower.Enable(BoostWindPowerEnabled.Value);
BoostSolarPowerEnabled.SettingChanged += (_, _) => BoostSolarPower.Enable(BoostSolarPowerEnabled.Value);
@@ -46,12 +40,9 @@ public static class FactoryPatch
BoostGeothermalPowerEnabled.SettingChanged += (_, _) => BoostGeothermalPower.Enable(BoostGeothermalPowerEnabled.Value);
ImmediateBuild.Enable(ImmediateEnabled.Value);
ArchitectMode.Enable(ArchitectModeEnabled.Value);
UnlimitInteractive.Enable(UnlimitInteractiveEnabled.Value);
RemoveSomeConditionBuild.Enable(RemoveSomeConditionEnabled.Value);
NoConditionBuild.Enable(NoConditionEnabled.Value);
NoCollisionValueChanged();
BeltSignalGenerator.Enable(BeltSignalGeneratorEnabled.Value);
NightLight.Enable(NightLightEnabled.Value);
RemovePowerSpaceLimit.Enable(RemovePowerSpaceLimitEnabled.Value);
BoostWindPower.Enable(BoostWindPowerEnabled.Value);
BoostSolarPower.Enable(BoostSolarPowerEnabled.Value);
@@ -66,11 +57,8 @@ public static class FactoryPatch
_factoryPatch = null;
ImmediateBuild.Enable(false);
ArchitectMode.Enable(false);
RemoveSomeConditionBuild.Enable(false);
NoConditionBuild.Enable(false);
UnlimitInteractive.Enable(false);
BeltSignalGenerator.Enable(false);
NightLight.Enable(false);
RemovePowerSpaceLimit.Enable(false);
BoostWindPower.Enable(false);
BoostSolarPower.Enable(false);
@@ -123,165 +111,6 @@ public static class FactoryPatch
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)
{
var simu = GameMain.universeSimulator;
if (simu)
_sunlight = simu.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<CodeInstruction> StarSimulator_LateUpdate_Transpiler(IEnumerable<CodeInstruction> 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<CodeInstruction> PlanetSimulator_LateUpdate_Transpiler(IEnumerable<CodeInstruction> 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;
@@ -398,136 +227,6 @@ public static class FactoryPatch
}
}
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<CodeInstruction> PlayerAction_Inspect_GetObjectSelectDistance_Transpiler(IEnumerable<CodeInstruction> instructions)
{
yield return new CodeInstruction(OpCodes.Ldc_R4, 10000f);
yield return new CodeInstruction(OpCodes.Ret);
}
}
private static class RemoveSomeConditionBuild
{
private static Harmony _patch;
public static void Enable(bool on)
{
if (on)
{
_patch ??= Harmony.CreateAndPatchAll(typeof(RemoveSomeConditionBuild));
return;
}
_patch?.UnpatchSelf();
_patch = null;
}
[HarmonyTranspiler, HarmonyPriority(Priority.First)]
[HarmonyPatch(typeof(BuildTool_BlueprintPaste), nameof(BuildTool_BlueprintPaste.CheckBuildConditions))]
[HarmonyPatch(typeof(BuildTool_Click), nameof(BuildTool_Click.CheckBuildConditions))]
private static IEnumerable<CodeInstruction> BuildTool_Click_CheckBuildConditions_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var matcher = new CodeMatcher(instructions, generator);
/* search for:
* ldloc.s V_8 (8)
* ldfld class PrefabDesc BuildPreview::desc
* ldfld bool PrefabDesc::isInserter
* brtrue 2358 (1C12) ldloc.s V_8 (8)
* ldloca.s V_10 (10)
* call instance float32 [UnityEngine.CoreModule]UnityEngine.Vector3::get_magnitude()
*/
matcher.MatchForward(false,
new CodeMatch(OpCodes.Ldloc_S),
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(BuildPreview), nameof(BuildPreview.desc))),
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(PrefabDesc), nameof(PrefabDesc.isInserter))),
new CodeMatch(instr => instr.opcode == OpCodes.Brtrue || instr.opcode == OpCodes.Brtrue_S),
new CodeMatch(OpCodes.Ldloca_S),
new CodeMatch(OpCodes.Call, AccessTools.PropertyGetter(typeof(Vector3), nameof(Vector3.magnitude)))
);
var jumpPos = matcher.InstructionAt(3).operand;
var labels = matcher.Labels;
matcher.Labels = new List<Label>();
/* Insert: br 2358 (1C12) ldloc.s V_8 (8)
*/
matcher.Insert(new CodeInstruction(OpCodes.Br, jumpPos).WithLabels(labels));
return matcher.InstructionEnumeration();
}
[HarmonyTranspiler, HarmonyPriority(Priority.First)]
[HarmonyPatch(typeof(BuildTool_Path), nameof(BuildTool_Path.CheckBuildConditions))]
private static IEnumerable<CodeInstruction> BuildTool_Path_CheckBuildConditions_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var matcher = new CodeMatcher(instructions, generator);
/* search for:
* ldloc.s V_88 (88)
* ldloc.s V_120 (120)
* brtrue.s 2054 (173A) ldc.i4.s 17
* ldc.i4.s 18
* br.s 2055 (173C) stfld valuetype EBuildCondition BuildPreview::condition
* ldc.i4.s 17
* stfld valuetype EBuildCondition BuildPreview::condition
*/
matcher.MatchForward(false,
new CodeMatch(OpCodes.Ldloc_S),
new CodeMatch(OpCodes.Ldloc_S),
new CodeMatch(instr => instr.opcode == OpCodes.Brtrue_S || instr.opcode == OpCodes.Brtrue),
new CodeMatch(instr => instr.opcode == OpCodes.Ldc_I4_S && instr.OperandIs(18)),
new CodeMatch(instr => instr.opcode == OpCodes.Br_S || instr.opcode == OpCodes.Br),
new CodeMatch(instr => instr.opcode == OpCodes.Ldc_I4_S && instr.OperandIs(17)),
new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(BuildPreview), nameof(BuildPreview.condition)))
);
if (matcher.IsValid)
{
// Remove 7 instructions, if the following instruction is br/br.s, remove it as well
var labels = matcher.Labels;
matcher.Labels = new List<Label>();
matcher.RemoveInstructions(7);
var opcode = matcher.Opcode;
if (opcode == OpCodes.Br || opcode == OpCodes.Br_S)
matcher.RemoveInstruction();
matcher.Labels.AddRange(labels);
}
/* search for:
* ldloc.s V_88 (88)
* ldc.i4.s 15-19
* stfld valuetype EBuildCondition BuildPreview::condition
*/
matcher.Start().MatchForward(false,
new CodeMatch(instr => instr.opcode == OpCodes.Ldloc_S || instr.opcode == OpCodes.Ldloc),
new CodeMatch(instr => (instr.opcode == OpCodes.Ldc_I4_S || instr.opcode == OpCodes.Ldc_I4) && Convert.ToInt64(instr.operand) is >= 15 and <= 19),
new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(BuildPreview), nameof(BuildPreview.condition)))
);
if (matcher.IsValid)
{
// Remove 3 instructions, if the following instruction is br/br.s, remove it as well
matcher.Repeat(codeMatcher =>
{
var labels = codeMatcher.Labels;
codeMatcher.Labels = new List<Label>();
codeMatcher.RemoveInstructions(3);
var opcode = codeMatcher.Opcode;
if (opcode == OpCodes.Br || opcode == OpCodes.Br_S)
codeMatcher.RemoveInstruction();
codeMatcher.Labels.AddRange(labels);
});
}
return matcher.InstructionEnumeration();
}
}
private static class NoConditionBuild
{
private static Harmony _noConditionPatch;
@@ -840,6 +539,20 @@ public static class FactoryPatch
set.Remove(v);
}
[HarmonyPostfix]
[HarmonyPatch(typeof(UXAssist.PlanetFunctions), nameof(UXAssist.PlanetFunctions.RecreatePlanet))]
private static void UXAssist_PlanetFunctions_RecreatePlanet_Postfix()
{
var player = GameMain.mainPlayer;
if (player == null) return;
var factory = GameMain.localPlanet?.factory;
if (factory == null) return;
if (BeltSignalGeneratorEnabled.Value)
{
RemovePlanetSignalBelts(factory.index);
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(GameMain), nameof(GameMain.Begin))]
private static void GameMain_Begin_Postfix()

View File

@@ -1,147 +1,8 @@
using System.Collections.Generic;
using System.Reflection.Emit;
using System.Threading;
using BepInEx.Configuration;
using HarmonyLib;
using Random = UnityEngine.Random;
using Random = UnityEngine.Random;
namespace CheatEnabler;
public static class PlanetFunctions
{
public static ConfigEntry<bool> PlayerActionsInGlobeViewEnabled;
public static void Init()
{
PlayerActionsInGlobeViewEnabled.SettingChanged += (_, _) => PlayerActionsInGlobeView.Enable(PlayerActionsInGlobeViewEnabled.Value);
PlayerActionsInGlobeView.Enable(PlayerActionsInGlobeViewEnabled.Value);
}
public static void Uninit()
{
PlayerActionsInGlobeView.Enable(false);
}
public static class PlayerActionsInGlobeView
{
private static Harmony _patch;
public static void Enable(bool on)
{
if (on)
{
_patch ??= Harmony.CreateAndPatchAll(typeof(PlayerActionsInGlobeView));
return;
}
_patch?.UnpatchSelf();
_patch = null;
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(VFInput), nameof(VFInput.UpdateGameStates))]
private static IEnumerable<CodeInstruction> VFInput_UpdateGameStates_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var matcher = new CodeMatcher(instructions, generator);
/* remove UIGame.viewMode != EViewMode.Globe in two places:
* so search for:
* ldsfld bool VFInput::viewMode
* ldc.i4.3
*/
matcher.MatchForward(false,
new CodeMatch(OpCodes.Ldsfld, AccessTools.Field(typeof(UIGame), nameof(UIGame.viewMode))),
new CodeMatch(OpCodes.Ldc_I4_3)
);
matcher.Repeat(codeMatcher =>
{
var labels = codeMatcher.Labels;
codeMatcher.Labels = new List<Label>();
codeMatcher.RemoveInstructions(3).Labels.AddRange(labels);
});
return matcher.InstructionEnumeration();
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(PlayerController), nameof(PlayerController.GetInput))]
private static IEnumerable<CodeInstruction> PlayerController_GetInput_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var matcher = new CodeMatcher(instructions, generator);
// replace `UIGame.viewMode >= EViewMode.Globe` with `UIGame.viewMode >= EViewMode.Starmap`
matcher.MatchForward(false,
new CodeMatch(OpCodes.Ldsfld, AccessTools.Field(typeof(UIGame), nameof(UIGame.viewMode))),
new CodeMatch(OpCodes.Ldc_I4_3)
).Advance(1).Opcode = OpCodes.Ldc_I4_4;
return matcher.InstructionEnumeration();
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(PlayerAction_Rts), nameof(PlayerAction_Rts.GameTick))]
private static IEnumerable<CodeInstruction> PlayerAction_Rts_GameTick_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var matcher = new CodeMatcher(instructions, generator);
var local1 = generator.DeclareLocal(typeof(bool));
// var local1 = UIGame.viewMode == 3;
matcher.MatchForward(false,
new CodeMatch(OpCodes.Call, AccessTools.PropertyGetter(typeof(VFInput), nameof(VFInput.rtsMoveCameraConflict))),
new CodeMatch(OpCodes.Stloc_1)
);
var labels = matcher.Labels;
matcher.Labels = new List<Label>();
matcher.InsertAndAdvance(
new CodeInstruction(OpCodes.Ldsfld, AccessTools.Field(typeof(UIGame), nameof(UIGame.viewMode))).WithLabels(labels),
new CodeInstruction(OpCodes.Ldc_I4_3),
new CodeInstruction(OpCodes.Ceq),
new CodeInstruction(OpCodes.Stloc, local1)
);
// Add extra condition:
// VFInput.rtsMoveCameraConflict / VFInput.rtsMineCameraConflict `|| local1`
matcher.MatchForward(false,
new CodeMatch(instr => instr.opcode == OpCodes.Ldloc_1 || instr.opcode == OpCodes.Ldloc_2)
);
matcher.Repeat(codeMatcher =>
{
matcher.Advance(1);
matcher.InsertAndAdvance(
new CodeInstruction(OpCodes.Ldloc, local1),
new CodeInstruction(OpCodes.Or)
);
});
return matcher.InstructionEnumeration();
}
}
public static void DismantleAll(bool toBag)
{
var player = GameMain.mainPlayer;
if (player == null) return;
var planet = GameMain.localPlanet;
var factory = planet?.factory;
if (factory == null) return;
foreach (var etd in factory.entityPool)
{
var stationId = etd.stationId;
if (stationId > 0)
{
var sc = GameMain.localPlanet.factory.transport.stationPool[stationId];
if (toBag)
{
for (var i = 0; i < sc.storage.Length; i++)
{
var package = player.TryAddItemToPackage(sc.storage[i].itemId, sc.storage[i].count, 0, true, etd.id);
UIItemup.Up(sc.storage[i].itemId, package);
}
}
sc.storage = new StationStore[sc.storage.Length];
sc.needs = new int[sc.needs.Length];
}
if (toBag)
{
player.controller.actionBuild.DoDismantleObject(etd.id);
}
else
{
factory.RemoveEntityWithComponents(etd.id);
}
}
}
public static void BuryAllVeins(bool bury)
{
var planet = GameMain.localPlanet;
@@ -165,110 +26,4 @@ public static class PlanetFunctions
}
GameMain.gpuiManager.SyncAllGPUBuffer();
}
public static void RecreatePlanet(bool revertReform)
{
var player = GameMain.mainPlayer;
if (player == null) return;
var planet = GameMain.localPlanet;
var factory = planet?.factory;
if (factory == null) return;
//planet.data = new PlanetRawData(planet.precision);
//planet.data.CalcVerts();
for (var id = factory.entityCursor - 1; id > 0; id--)
{
var ed = factory.entityPool[id];
if (ed.id != id) continue;
if (ed.colliderId != 0)
{
planet.physics.RemoveLinkedColliderData(ed.colliderId);
planet.physics.NotifyObjectRemove(EObjectType.Entity, ed.id);
}
if (ed.modelId != 0)
{
GameMain.gpuiManager.RemoveModel(ed.modelIndex, ed.modelId);
}
if (ed.mmblockId != 0)
{
factory.blockContainer.RemoveMiniBlock(ed.mmblockId);
}
if (ed.audioId == 0) continue;
planet.audio?.RemoveAudioData(ed.audioId);
}
var stationPool = factory.transport?.stationPool;
if (stationPool != null)
{
foreach (var sc in stationPool)
{
if (sc == null || sc.id <= 0) continue;
sc.storage = new StationStore[sc.storage.Length];
sc.needs = new int[sc.needs.Length];
int protoId = factory.entityPool[sc.entityId].protoId;
factory.DismantleFinally(player, sc.entityId, ref protoId);
}
}
var gameScenario = GameMain.gameScenario;
if (gameScenario != null)
{
var genPool = factory.powerSystem?.genPool;
if (genPool != null)
{
foreach (var pgc in genPool)
{
if (pgc.id <= 0) continue;
int protoId = factory.entityPool[pgc.entityId].protoId;
gameScenario.achievementLogic.NotifyBeforeDismantleEntity(planet.id, protoId, pgc.entityId);
gameScenario.NotifyOnDismantleEntity(planet.id, protoId, pgc.entityId);
}
}
}
if (revertReform)
{
factory.PlanetReformRevert();
}
planet.UnloadFactory();
var index = factory.index;
var warningSystem = GameMain.data.warningSystem;
var warningPool = warningSystem.warningPool;
for (var i = warningSystem.warningCursor - 1; i > 0; i--)
{
if (warningPool[i].id == i && warningPool[i].factoryId == index)
warningSystem.RemoveWarningData(warningPool[i].id);
}
factory.entityCursor = 1;
factory.entityRecycleCursor = 0;
factory.entityCapacity = 0;
factory.SetEntityCapacity(1024);
factory.prebuildCursor = 1;
factory.prebuildRecycleCursor = 0;
factory.prebuildCapacity = 0;
factory.SetPrebuildCapacity(256);
factory.cargoContainer = new CargoContainer();
factory.cargoTraffic = new CargoTraffic(planet);
factory.blockContainer = new MiniBlockContainer();
factory.factoryStorage = new FactoryStorage(planet);
factory.powerSystem = new PowerSystem(planet);
factory.factorySystem = new FactorySystem(planet);
factory.transport = new PlanetTransport(GameMain.data, planet);
factory.transport.Init();
factory.digitalSystem = new DigitalSystem(planet);
if (FactoryPatch.BeltSignalGeneratorEnabled.Value)
{
FactoryPatch.BeltSignalGenerator.RemovePlanetSignalBelts(factory.index);
}
//GameMain.data.statistics.production.CreateFactoryStat(index);
planet.LoadFactory();
while (!planet.factoryLoaded)
{
PlanetModelingManager.Update();
Thread.Sleep(0);
}
}
}

View File

@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.Reflection.Emit;
using BepInEx.Configuration;
using HarmonyLib;
namespace CheatEnabler;
public static class PlanetPatch
{
public static ConfigEntry<bool> WaterPumpAnywhereEnabled;
public static ConfigEntry<bool> TerraformAnywayEnabled;
public static void Init()
{
WaterPumpAnywhereEnabled.SettingChanged += (_, _) => WaterPumperPatch.Enable(WaterPumpAnywhereEnabled.Value);
TerraformAnywayEnabled.SettingChanged += (_, _) => TerraformAnyway.Enable(TerraformAnywayEnabled.Value);
WaterPumperPatch.Enable(WaterPumpAnywhereEnabled.Value);
TerraformAnyway.Enable(TerraformAnywayEnabled.Value);
}
public static void Uninit()
{
WaterPumperPatch.Enable(false);
TerraformAnyway.Enable(false);
}
private static class WaterPumperPatch
{
private static Harmony _patch;
public static void Enable(bool on)
{
if (on)
{
_patch ??= Harmony.CreateAndPatchAll(typeof(WaterPumperPatch));
}
else
{
_patch?.UnpatchSelf();
_patch = null;
}
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(BuildTool_BlueprintPaste), "CheckBuildConditions")]
[HarmonyPatch(typeof(BuildTool_Click), "CheckBuildConditions")]
private static IEnumerable<CodeInstruction> BuildTool_CheckBuildConditions_Transpiler(
IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var matcher = new CodeMatcher(instructions, generator);
matcher.MatchForward(false,
new CodeMatch(instr => instr.opcode == OpCodes.Ldc_I4_S && instr.OperandIs(22))
).Advance(1).MatchForward(false,
new CodeMatch(instr => instr.opcode == OpCodes.Ldc_I4_S && instr.OperandIs(22))
);
matcher.Repeat(codeMatcher =>
{
codeMatcher.SetAndAdvance(OpCodes.Ldc_I4_S, 0);
});
return matcher.InstructionEnumeration();
}
}
private static class TerraformAnyway
{
private static Harmony _patch;
public static void Enable(bool on)
{
if (on)
{
_patch ??= Harmony.CreateAndPatchAll(typeof(TerraformAnyway));
}
else
{
_patch?.UnpatchSelf();
_patch = null;
}
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(BuildTool_Reform), nameof(BuildTool_Reform.ReformAction))]
private static IEnumerable<CodeInstruction> BuildTool_Reform_ReformAction_Patch(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var matcher = new CodeMatcher(instructions, generator);
matcher.MatchForward(false,
new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(Player), "get_sandCount"))
).Advance(3).InsertAndAdvance(
new CodeInstruction(OpCodes.Ldc_I4_0),
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Math), "Max", new[] { typeof(int), typeof(int) }))
).Advance(1).RemoveInstructions(3);
return matcher.InstructionEnumeration();
}
}
}

View File

@@ -4,6 +4,9 @@
#### 添加一些作弊功能,同时屏蔽异常检测
## Changlog
* 2.3.0
+ Move some functions to an individual mod: [UXAssist](https://dsp.thunderstore.io/package/soarqin/UXAssist)
+ Depends on [UXAssist](https://dsp.thunderstore.io/package/soarqin/UXAssist) now, so that config panel is unified with UXAssist.
* 2.2.7
+ New function: `Construct only nodes but frames`
+ Opening config panel does not close inventory panel now
@@ -46,10 +49,9 @@
## Usage
* Press `` LAlt+`(BackQuote) `` to call up the config panel. You can change the shortcut on the panel.
* Config panel is unified with UXAssist, tabs with text between star(*) are configurations for CheatEnabler.
* There are also buttons on title screen and planet minimap area to call up the config panel.
* Features:
+ Strict hotkey dectection for build menu, thus building hotkeys(0~9, F1~F10, X, U) are not triggered while holding Ctrl/Alt/Shift.
+ General:
+ Enable Dev Shortcuts (check config panel for usage)
+ Disable Abnormal Checks
@@ -58,33 +60,23 @@
+ Factory:
+ Finish build immediately
+ Architect mode (Infinite buildings)
+ Unlimited interactive range
+ Build without condition
+ Remove some build conditions
+ No collision
+ Sunlight at night
+ Belt signal item generation
+ Count all raws and intermediates in statistics
+ Belt signal alt format
+ Remove space limit between wind turbines and solar panels
+ Boost power generations for kinds of power generators
+ Planet:
+ Enable player actions in globe view
+ Infinite Natural Resources
+ Fast Mining
+ Pump Anywhere
+ Terraform without enought sands
+ Re-intialize planet (without reseting veins)
+ Quick dismantle all buildings (without drops)
+ Dyson Sphere:
+ Stop ejectors when available nodes are all filled up
+ Construct only nodes but frames
+ Skip bullet period
+ Skip absorption period
+ Quick absorb
+ Eject anyway
+ Re-initialize Dyson Spheres
+ Quick dismantle Dyson Shells
+ Birth star:
+ Rare resources on birth planet
+ Solid flat on birth planet
@@ -99,9 +91,11 @@
* [Dyson Sphere Program](https://store.steampowered.com/app/1366540): The great game
* [BepInEx](https://bepinex.dev/): Base modding framework
* [Multifunction_mod](https://github.com/blacksnipebiu/Multifunction_mod): Some cheat functions
* [LSTM](https://github.com/hetima/DSP_LSTM) & [PlanetFinder](https://github.com/hetima/DSP_PlanetFinder): UI implementations
## 更新日志
* 2.3.0
+ 将部分功能移动到单独的mod[UXAssist](https://dsp.thunderstore.io/package/soarqin/UXAssist)
+ 现在依赖[UXAssist](https://dsp.thunderstore.io/package/soarqin/UXAssist)因此配置面板与UXAssist合并
* 2.2.7
+ 新功能:`只建造节点不建造框架`
+ 打开设置面板时不再关闭背包面板
@@ -144,10 +138,9 @@
## 使用说明
* 按 `` 左Alt+`(反引号) `` 键呼出主面板,可以在面板上修改快捷键。
* 配置面板已经与UXAssist合并带有星号(*)的分页是CheatEnabler的配置
* 标题界面和行星小地图旁也有按钮呼出主面板。
* 功能:
+ 更严格的建造菜单热键检测因此在按住Ctrl/Alt/Shift时不再会触发建造热键(0~9, F1~F10, X, U)
+ 常规:
+ 启用开发模式快捷键(使用说明见设置面板)
+ 屏蔽异常检测
@@ -156,33 +149,23 @@
+ 工厂:
+ 建造秒完成
+ 建筑师模式(无限建筑)
+ ** 无限交互距离
+ 无条件建造
+ ** 移除部分不影响游戏逻辑的建造条件
+ 无碰撞
+ ** 夜间日光灯
+ 传送带信号物品生成
+ 统计面板中计算所有原材料和中间产物
+ 传送带信号替换格式
+ 风力发电机和太阳能板无间距限制
+ 提升各种发电设备发电量
+ 行星:
+ ** 在行星视图中允许玩家操作
+ 自然资源采集不消耗
+ 高速采集
+ 平地抽水
+ 沙土不够时依然可以整改地形
+ ** 初始化本行星(不重置矿脉)
+ ** 快速拆除所有建筑(不掉落)
+ 戴森球:
+ ** 可用节点全部造完时停止弹射
+ ** 只建造节点不建造框架
+ 跳过子弹阶段
+ 跳过吸收阶段
+ 快速吸收
+ 全球弹射
+ ** 初始化戴森球
+ ** 快速拆除戴森壳
+ 母星系:
+ 母星有稀有资源
+ 母星是纯平的
@@ -197,4 +180,3 @@
* [戴森球计划](https://store.steampowered.com/app/1366540): 伟大的游戏
* [BepInEx](https://bepinex.dev/): 基础模组框架
* [Multifunction_mod](https://github.com/blacksnipebiu/Multifunction_mod): 一些作弊功能
* [LSTM](https://github.com/hetima/DSP_LSTM) & [PlanetFinder](https://github.com/hetima/DSP_PlanetFinder): UI实现

View File

@@ -1,51 +0,0 @@
using System;
using System.Collections.Generic;
using System.Reflection.Emit;
using BepInEx.Configuration;
using HarmonyLib;
namespace CheatEnabler;
public static class TerraformPatch
{
public static ConfigEntry<bool> Enabled;
private static Harmony _patch;
public static void Init()
{
Enabled.SettingChanged += (_, _) => ValueChanged();
ValueChanged();
}
public static void Uninit()
{
_patch?.UnpatchSelf();
_patch = null;
}
private static void ValueChanged()
{
if (Enabled.Value)
{
_patch ??= Harmony.CreateAndPatchAll(typeof(TerraformPatch));
}
else
{
_patch?.UnpatchSelf();
_patch = null;
}
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(BuildTool_Reform), nameof(BuildTool_Reform.ReformAction))]
private static IEnumerable<CodeInstruction> BuildTool_Reform_ReformAction_Patch(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var matcher = new CodeMatcher(instructions, generator);
matcher.MatchForward(false,
new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(Player), "get_sandCount"))
).Advance(3).InsertAndAdvance(
new CodeInstruction(OpCodes.Ldc_I4_0),
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Math), "Max", new[] { typeof(int), typeof(int) }))
).Advance(1).RemoveInstructions(3);
return matcher.InstructionEnumeration();
}
}

View File

@@ -7,15 +7,12 @@ namespace CheatEnabler;
public static class UIConfigWindow
{
private static RectTransform _windowTrans;
private static MyConfigWindow _configWindow;
private static RectTransform _tab4;
private static UIButton _resignGameBtn;
private static readonly UIButton[] _dysonLayerBtn = new UIButton[10];
public static void Init()
{
I18N.Add("General", "General", "常规");
I18N.Add("General", "*General*", "*常规*");
I18N.Add("Enable Dev Shortcuts", "Enable Dev Shortcuts", "开发模式快捷键");
I18N.Add("Disable Abnormal Checks", "Disable Abnormal Checks", "关闭数据异常检查");
I18N.Add("Hotkey", "Hotkey", "快捷键");
@@ -28,11 +25,9 @@ public static class UIConfigWindow
"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("Assign game to current account", "Assign game to current account", "将游戏绑定给当前账号");
I18N.Add("Factory", "Factory", "工厂");
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("Remove some build conditions", "Remove some build conditions", "移除部分不影响游戏逻辑的建造条件");
I18N.Add("Build without condition", "Build without condition check", "无条件建造");
I18N.Add("No collision", "No collision", "无碰撞");
I18N.Add("Belt signal generator", "Belt signal generator", "传送带信号物品生成");
@@ -41,23 +36,17 @@ public static class UIConfigWindow
"Belt signal number format alternative format:\n AAAABC by default\n BCAAAA as alternative\nAAAA=generation speed in minutes, B=proliferate points, C=stack count",
"传送带信号物品生成数量格式:\n 默认为AAAABC\n 勾选替换为BCAAAA\nAAAA=生成速度B=增产点数C=堆叠数量");
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("Enable player actions in globe view", "Enable player actions in globe view", "在行星视图中允许玩家操作");
I18N.Add("Planet", "*Planet*", "*行星*");
I18N.Add("Infinite Natural Resources", "Infinite natural resources", "自然资源采集不消耗");
I18N.Add("Fast Mining", "Fast mining", "高速采集");
I18N.Add("Pump Anywhere", "Pump anywhere", "平地抽水");
I18N.Add("Initialize This Planet", "Initialize this planet", "初始化本行星");
I18N.Add("Dismantle All Buildings", "Dismantle all buildings", "拆除所有建筑");
I18N.Add("Dyson Sphere", "Dyson Sphere", "戴森球");
I18N.Add("Stop ejectors when available nodes are all filled up", "Stop ejectors when available nodes are all filled up", "可用节点全部造完时停止弹射");
I18N.Add("Construct only nodes but frames", "Construct only nodes but frames", "只造节点不造框架");
I18N.Add("Dyson Sphere", "*Dyson Sphere*", "*戴森球*");
I18N.Add("Skip bullet period", "Skip bullet period", "跳过子弹阶段");
I18N.Add("Skip absorption period", "Skip absorption period", "跳过吸收阶段");
I18N.Add("Quick absorb", "Quick absorb", "快速吸收");
@@ -65,9 +54,7 @@ public static class UIConfigWindow
I18N.Add("Overclock Ejectors", "Overclock Ejectors (10x)", "高速弹射器(10倍射速)");
I18N.Add("Overclock Silos", "Overclock Silos (10x)", "高速发射井(10倍射速)");
I18N.Add("Terraform without enough sands", "Terraform without enough sands", "沙土不够时依然可以整改地形");
I18N.Add("Initialize Dyson Sphere", "Initialize Dyson Sphere", "初始化戴森球");
I18N.Add("Click to dismantle selected layer", "Click to dismantle selected layer", "点击拆除对应的戴森壳");
I18N.Add("Birth", "Birth Sys", "母星系");
I18N.Add("Birth", "*Birth Sys*", "*母星系*");
I18N.Add("Silicon/Titanium on birth planet", "Silicon/Titanium on birth planet", "母星有硅和钛");
I18N.Add("Fire ice on birth planet", "Fire ice on birth planet", "母星有可燃冰");
I18N.Add("Kimberlite on birth planet", "Kimberlite on birth planet", "母星有金伯利矿");
@@ -85,7 +72,6 @@ public static class UIConfigWindow
private static void CreateUI(MyConfigWindow wnd, RectTransform trans)
{
_configWindow = wnd;
_windowTrans = trans;
// General tab
var x = 0f;
@@ -96,8 +82,6 @@ public static class UIConfigWindow
MyCheckBox.CreateCheckBox(x, y, tab1, AbnormalDisabler.Enabled, "Disable Abnormal Checks");
y += 36f;
MyCheckBox.CreateCheckBox(x, y, tab1, TechPatch.Enabled, "Unlock Tech with Key-Modifiers");
y += 118f;
MyKeyBinder.CreateKeyBinder(x, y, tab1, CheatEnabler.Hotkey, "Hotkey");
x = 156f;
y = 16f;
MyWindow.AddTipsButton(x, y, tab1, "Dev Shortcuts", "Dev Shortcuts Tips", "dev-shortcuts-tips");
@@ -117,14 +101,10 @@ public static class UIConfigWindow
y += 36f;
MyCheckBox.CreateCheckBox(x, y, tab2, FactoryPatch.ArchitectModeEnabled, "Architect mode");
y += 36f;
MyCheckBox.CreateCheckBox(x, y, tab2, FactoryPatch.UnlimitInteractiveEnabled, "Unlimited interactive range");
y += 36f;
MyCheckBox.CreateCheckBox(x, y, tab2, FactoryPatch.NoConditionEnabled, "Build without condition");
y += 36f;
MyCheckBox.CreateCheckBox(x, y, tab2, FactoryPatch.NoCollisionEnabled, "No collision");
y += 36f;
MyCheckBox.CreateCheckBox(x, y, tab2, FactoryPatch.NightLightEnabled, "Night Light");
y += 36f;
MyCheckBox.CreateCheckBox(x, y, tab2, FactoryPatch.BeltSignalGeneratorEnabled, "Belt signal generator");
y += 26f;
x += 26f;
@@ -140,10 +120,8 @@ public static class UIConfigWindow
OnBeltSignalChanged();
};
OnBeltSignalChanged();
x = 240f;
x = 350f;
y = 10f;
MyCheckBox.CreateCheckBox(x, y, tab2, FactoryPatch.RemoveSomeConditionEnabled, "Remove some build conditions");
y += 36f;
MyCheckBox.CreateCheckBox(x, y, tab2, FactoryPatch.RemovePowerSpaceLimitEnabled, "Remove power space limit");
y += 36f;
MyCheckBox.CreateCheckBox(x, y, tab2, FactoryPatch.BoostWindPowerEnabled, "Boost wind power");
@@ -161,16 +139,14 @@ public static class UIConfigWindow
var tab3 = wnd.AddTab(_windowTrans, "Planet");
x = 0f;
y = 10f;
MyCheckBox.CreateCheckBox(x, y, tab3, PlanetFunctions.PlayerActionsInGlobeViewEnabled, "Enable player actions in globe view");
y += 36f;
MyCheckBox.CreateCheckBox(x, y, tab3, ResourcePatch.InfiniteResourceEnabled, "Infinite Natural Resources");
y += 36f;
MyCheckBox.CreateCheckBox(x, y, tab3, ResourcePatch.FastMiningEnabled, "Fast Mining");
y += 36f;
MyCheckBox.CreateCheckBox(x, y, tab3, WaterPumperPatch.Enabled, "Pump Anywhere");
MyCheckBox.CreateCheckBox(x, y, tab3, PlanetPatch.WaterPumpAnywhereEnabled, "Pump Anywhere");
y += 36f;
MyCheckBox.CreateCheckBox(x, y, tab3, TerraformPatch.Enabled, "Terraform without enough sands");
x = 300f;
MyCheckBox.CreateCheckBox(x, y, tab3, PlanetPatch.TerraformAnywayEnabled, "Terraform without enough sands");
x = 400f;
y = 10f;
wnd.AddButton(x, y, tab3, "矿物掩埋标题", 16, "button-bury-all", () => { PlanetFunctions.BuryAllVeins(true); });
y += 36f;
@@ -192,18 +168,10 @@ public static class UIConfigWindow
if (factory == null) return;
GameMain.localPlanet.factory.PlanetReformRevert();
});
y += 36f;
wnd.AddButton(x, y, tab3, "Initialize This Planet", 16, "button-init-planet", () => { PlanetFunctions.RecreatePlanet(true); });
y += 36f;
wnd.AddButton(x, y, tab3, "Dismantle All Buildings", 16, "button-dismantle-all", () => { PlanetFunctions.DismantleAll(false); });
var tab4 = wnd.AddTab(_windowTrans, "Dyson Sphere");
x = 0f;
y = 10f;
MyCheckBox.CreateCheckBox(x, y, tab4, DysonSpherePatch.StopEjectOnNodeCompleteEnabled, "Stop ejectors when available nodes are all filled up");
y += 36f;
MyCheckBox.CreateCheckBox(x, y, tab4, DysonSpherePatch.OnlyConstructNodesEnabled, "Construct only nodes but frames");
y += 36f;
MyCheckBox.CreateCheckBox(x, y, tab4, DysonSpherePatch.SkipBulletEnabled, "Skip bullet period");
y += 36f;
MyCheckBox.CreateCheckBox(x, y, tab4, DysonSpherePatch.SkipAbsorbEnabled, "Skip absorption period");
@@ -215,28 +183,6 @@ public static class UIConfigWindow
MyCheckBox.CreateCheckBox(x, y, tab4, DysonSpherePatch.OverclockEjectorEnabled, "Overclock Ejectors");
y += 36f;
MyCheckBox.CreateCheckBox(x, y, tab4, DysonSpherePatch.OverclockSiloEnabled, "Overclock Silos");
x = 300f;
y = 10f;
wnd.AddButton(x, y, tab4, "Initialize Dyson Sphere", 16, "init-dyson-sphere", () => { DysonSpherePatch.InitCurrentDysonSphere(-1); });
y += 36f;
MyWindow.AddText(x, y, tab4, "Click to dismantle selected layer", 16, "text-dismantle-layer");
y += 26f;
for (var i = 0; i < 10; i++)
{
var id = i + 1;
var btn = wnd.AddFlatButton(x, y, tab4, id.ToString(), 12, "dismantle-layer-" + id, () => { DysonSpherePatch.InitCurrentDysonSphere(id); });
((RectTransform)btn.transform).sizeDelta = new Vector2(40f, 20f);
_dysonLayerBtn[i] = btn;
if (i == 4)
{
x -= 160f;
y += 20f;
}
else
{
x += 40f;
}
}
var tab5 = wnd.AddTab(_windowTrans, "Birth");
x = 0f;
@@ -256,13 +202,11 @@ public static class UIConfigWindow
MyCheckBox.CreateCheckBox(x, y, tab5, BirthPlanetPatch.SpiniformOnBirthPlanet, "Spiniform stalagmite crystal on birth planet");
y += 36f;
MyCheckBox.CreateCheckBox(x, y, tab5, BirthPlanetPatch.UnipolarOnBirthPlanet, "Unipolar magnet on birth planet");
x = 200f;
x = 300f;
y = 10f;
MyCheckBox.CreateCheckBox(x, y, tab5, BirthPlanetPatch.FlatBirthPlanet, "Birth planet is solid flat (no water at all)");
y += 36f;
MyCheckBox.CreateCheckBox(x, y, tab5, BirthPlanetPatch.HighLuminosityBirthStar, "Birth star has high luminosity");
_tab4 = tab4;
return;
void OnBeltSignalChanged()
@@ -277,7 +221,6 @@ public static class UIConfigWindow
private static void UpdateUI()
{
UpdateResignButton();
UpdateDysonShells();
}
private static void UpdateResignButton()
@@ -286,30 +229,4 @@ public static class UIConfigWindow
if (_resignGameBtn.gameObject.activeSelf == resignEnabled) return;
_resignGameBtn.gameObject.SetActive(resignEnabled);
}
private static void UpdateDysonShells()
{
if (!_tab4.gameObject.activeSelf) return;
var star = GameMain.localStar;
if (star != null)
{
var dysonSpheres = GameMain.data?.dysonSpheres;
if (dysonSpheres?[star.index] != null)
{
var ds = dysonSpheres[star.index];
for (var i = 1; i <= 10; i++)
{
var layer = ds.layersIdBased[i];
_dysonLayerBtn[i - 1].button.interactable = layer != null && layer.id == i;
}
return;
}
}
for (var i = 0; i < 10; i++)
{
_dysonLayerBtn[i].button.interactable = false;
}
}
}

View File

@@ -1,55 +0,0 @@
using System.Collections.Generic;
using System.Reflection.Emit;
using BepInEx.Configuration;
using HarmonyLib;
namespace CheatEnabler;
public static class WaterPumperPatch
{
public static ConfigEntry<bool> Enabled;
private static Harmony _patch;
public static void Init()
{
Enabled.SettingChanged += (_, _) => ValueChanged();
ValueChanged();
}
public static void Uninit()
{
_patch?.UnpatchSelf();
_patch = null;
}
private static void ValueChanged()
{
if (Enabled.Value)
{
_patch ??= Harmony.CreateAndPatchAll(typeof(WaterPumperPatch));
}
else
{
_patch?.UnpatchSelf();
_patch = null;
}
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(BuildTool_BlueprintPaste), "CheckBuildConditions")]
[HarmonyPatch(typeof(BuildTool_Click), "CheckBuildConditions")]
private static IEnumerable<CodeInstruction> BuildTool_CheckBuildConditions_Transpiler(
IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
var matcher = new CodeMatcher(instructions, generator);
matcher.MatchForward(false,
new CodeMatch(instr => instr.opcode == OpCodes.Ldc_I4_S && instr.OperandIs(22))
).Advance(1).MatchForward(false,
new CodeMatch(instr => instr.opcode == OpCodes.Ldc_I4_S && instr.OperandIs(22))
);
matcher.Repeat(codeMatcher =>
{
codeMatcher.SetAndAdvance(OpCodes.Ldc_I4_S, 0);
});
return matcher.InstructionEnumeration();
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "CheatEnabler",
"version_number": "2.2.7",
"version_number": "2.3.0",
"website_url": "https://github.com/soarqin/DSP_Mods/tree/master/CheatEnabler",
"description": "Add various cheat functions while disabling abnormal determinants / 添加一些作弊功能,同时屏蔽异常检测",
"dependencies": [