1
0
mirror of https://github.com/soarqin/DSP_Mods.git synced 2025-12-09 04:13:32 +08:00
Files
DSP_Mods/CheatEnabler/BuildPatch.cs
2023-09-10 15:23:35 +08:00

269 lines
9.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Reflection.Emit;
using BepInEx.Configuration;
using HarmonyLib;
namespace CheatEnabler;
public static class BuildPatch
{
public static ConfigEntry<bool> ImmediateEnabled;
public static ConfigEntry<bool> NoCostEnabled;
public static ConfigEntry<bool> NoConditionEnabled;
public static ConfigEntry<bool> NoCollisionEnabled;
private static Harmony _patch;
private static Harmony _noConditionPatch;
public static void Init()
{
ImmediateEnabled.SettingChanged += (_, _) => ImmediateValueChanged();
NoCostEnabled.SettingChanged += (_, _) => NoCostValueChanged();
NoConditionEnabled.SettingChanged += (_, _) => NoConditionValueChanged();
NoCollisionEnabled.SettingChanged += (_, _) => NoCollisionValueChanged();
ImmediateValueChanged();
NoCostValueChanged();
NoConditionValueChanged();
NoCollisionValueChanged();
_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);
NoCostBuild.Enable(false);
}
private static void ImmediateValueChanged()
{
ImmediateBuild.Enable(ImmediateEnabled.Value);
}
private static void NoCostValueChanged()
{
NoCostBuild.Enable(NoCostEnabled.Value);
}
private static void NoConditionValueChanged()
{
if (NoConditionEnabled.Value)
{
if (_noConditionPatch != null)
{
_noConditionPatch.UnpatchSelf();
_noConditionPatch = null;
}
_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);
}
public static void ArrivePlanet(PlanetFactory factory)
{
var imm = ImmediateEnabled.Value;
var noCost = NoCostEnabled.Value;
if (!imm && !noCost) 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 (!noCost) 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);
}
private static class ImmediateBuild
{
private static Harmony _immediatePatch;
public static void Enable(bool enable)
{
if (enable)
{
if (_immediatePatch != null)
{
_immediatePatch.UnpatchSelf();
_immediatePatch = null;
}
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<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> 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(BuildPatch.ArrivePlanet)))
);
return matcher.InstructionEnumeration();
}
}
private static class NoCostBuild
{
private static Harmony _noCostPatch;
private static bool[] _canBuildItems;
public static void Enable(bool enable)
{
if (enable)
{
if (_noCostPatch != null)
{
_noCostPatch.UnpatchSelf();
_noCostPatch = null;
}
var factory = GameMain.mainPlayer?.factory;
if (factory != null)
{
ArrivePlanet(factory);
}
_noCostPatch = Harmony.CreateAndPatchAll(typeof(NoCostBuild));
}
else if (_noCostPatch != null)
{
_noCostPatch.UnpatchSelf();
_noCostPatch = 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 >= 10000 || !_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 < 10000 && _canBuildItems[itemId]) __result = 100;
}
private static void DoInit()
{
_canBuildItems = new bool[10000];
foreach (var ip in LDB.items.dataArray)
{
if (ip.CanBuild && ip.ID < 10000) _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<CodeInstruction> BuildTool_CheckBuildConditions_Transpiler(IEnumerable<CodeInstruction> 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<CodeInstruction> BuildTool_Click_CheckBuildConditions_Transpiler(IEnumerable<CodeInstruction> instructions)
{
yield return new CodeInstruction(OpCodes.Ldarg_0);
yield return new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(NoConditionBuild), nameof(NoConditionBuild.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;
}
}
}