mirror of
https://github.com/soarqin/DSP_Mods.git
synced 2026-02-05 03:42:20 +08:00
Work in progress
This commit is contained in:
574
LabOpt/LabOpt.cs
574
LabOpt/LabOpt.cs
@@ -8,6 +8,9 @@ namespace LabOpt;
|
||||
[BepInPlugin(PluginInfo.PLUGIN_GUID, PluginInfo.PLUGIN_NAME, PluginInfo.PLUGIN_VERSION)]
|
||||
public class LabOptPatch : BaseUnityPlugin
|
||||
{
|
||||
private const int RequireCountForAssemble = 15;
|
||||
private const int RequireCountForResearch = 54000;
|
||||
|
||||
public new static readonly BepInEx.Logging.ManualLogSource Logger =
|
||||
BepInEx.Logging.Logger.CreateLogSource(PluginInfo.PLUGIN_NAME);
|
||||
|
||||
@@ -15,6 +18,83 @@ public class LabOptPatch : BaseUnityPlugin
|
||||
{
|
||||
Harmony.CreateAndPatchAll(typeof(LabOptPatch));
|
||||
}
|
||||
|
||||
// Patch LabComponent.Export() to save zero value if rootLabId > 0.
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(LabComponent), nameof(LabComponent.Export))]
|
||||
private static IEnumerable<CodeInstruction> LabComponent_Export_Transpiler(
|
||||
IEnumerable<CodeInstruction> instructions,
|
||||
ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
var label1 = generator.DefineLabel();
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Call, AccessTools.PropertyGetter(typeof(LabComponent), nameof(LabComponent.matrixMode)))
|
||||
).InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldarg_0),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(LabComponent), "rootLabId")),
|
||||
new CodeInstruction(OpCodes.Ldc_I4_0),
|
||||
new CodeInstruction(OpCodes.Ble, label1),
|
||||
new CodeInstruction(OpCodes.Ldarg_0),
|
||||
new CodeInstruction(OpCodes.Ldarg_1),
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(LabOptPatchFunctions), nameof(LabOptPatchFunctions.LabExportZero))),
|
||||
new CodeInstruction(OpCodes.Ret)
|
||||
);
|
||||
matcher.Instruction.labels.Add(label1);
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
// Patch UpdateNeedsAssemble() and UpdateNeedsResearch() to remove the execution if rootLabId > 0.
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(LabComponent), nameof(LabComponent.UpdateNeedsAssemble))]
|
||||
private static IEnumerable<CodeInstruction> LabComponent_UpdateNeedsAssemble_Transpiler(
|
||||
IEnumerable<CodeInstruction> instructions,
|
||||
ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
var label1 = generator.DefineLabel();
|
||||
matcher.Start().InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldarg_0),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(LabComponent), "rootLabId")),
|
||||
new CodeInstruction(OpCodes.Ldc_I4_0),
|
||||
new CodeInstruction(OpCodes.Ble, label1),
|
||||
new CodeInstruction(OpCodes.Ret)
|
||||
);
|
||||
matcher.Instruction.labels.Add(label1);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldelem_I4),
|
||||
new CodeMatch(OpCodes.Ldc_I4_4)
|
||||
);
|
||||
matcher.Repeat(codeMatcher =>
|
||||
codeMatcher.Advance(1).SetAndAdvance(OpCodes.Ldc_I4_S, RequireCountForAssemble)
|
||||
);
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(LabComponent), nameof(LabComponent.UpdateNeedsResearch))]
|
||||
private static IEnumerable<CodeInstruction> LabComponent_UpdateNeedsResearch_Transpiler(
|
||||
IEnumerable<CodeInstruction> instructions,
|
||||
ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
var label1 = generator.DefineLabel();
|
||||
matcher.Start().InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldarg_0),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(LabComponent), "rootLabId")),
|
||||
new CodeInstruction(OpCodes.Ldc_I4_0),
|
||||
new CodeInstruction(OpCodes.Ble, label1),
|
||||
new CodeInstruction(OpCodes.Ret)
|
||||
);
|
||||
matcher.Instruction.labels.Add(label1);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldc_I4, 0x8CA0)
|
||||
);
|
||||
matcher.Repeat(codeMatcher =>
|
||||
codeMatcher.SetAndAdvance(OpCodes.Ldc_I4, RequireCountForResearch)
|
||||
);
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
// Remove use of LabComponent.UpdateOutputToNext() for single-thread mode
|
||||
[HarmonyTranspiler]
|
||||
@@ -70,284 +150,7 @@ public class LabOptPatch : BaseUnityPlugin
|
||||
LabOptPatchFunctions.SetRootLabIdOnLoading(__instance);
|
||||
}
|
||||
|
||||
// Insert to root lab
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(PlanetFactory), nameof(PlanetFactory.InsertInto))]
|
||||
private static IEnumerable<CodeInstruction> PlanetFactory_InsertInto_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
var label1 = generator.DefineLabel();
|
||||
var local1 = generator.DeclareLocal(typeof(LabComponent).MakeArrayType());
|
||||
matcher.MatchForward(false, new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(EntityData), nameof(EntityData.labId))))
|
||||
.MatchForward(false, new CodeMatch(OpCodes.Ret))
|
||||
.Advance(1);
|
||||
var labels = matcher.Instruction.labels;
|
||||
matcher.InsertAndAdvance(
|
||||
// labPool = this.factorySystem.labPool;
|
||||
new CodeInstruction(OpCodes.Ldarg_0).WithLabels(labels),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(PlanetFactory), nameof(PlanetFactory.factorySystem))),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(FactorySystem), nameof(FactorySystem.labPool))),
|
||||
new CodeInstruction(OpCodes.Stloc_S, local1),
|
||||
// rootLabId = labPool[labId].rootLabId;
|
||||
new CodeInstruction(OpCodes.Ldloc_S, local1),
|
||||
new CodeInstruction(OpCodes.Ldloc_S, 5),
|
||||
new CodeInstruction(OpCodes.Ldelema, typeof(LabComponent)),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(LabComponent), "rootLabId")),
|
||||
new CodeInstruction(OpCodes.Stloc_S, 6),
|
||||
// if (rootLabId <= 0) goto label1;
|
||||
new CodeInstruction(OpCodes.Ldloc_S, 6),
|
||||
new CodeInstruction(OpCodes.Ldc_I4_0),
|
||||
new CodeInstruction(OpCodes.Ble, label1),
|
||||
// labId = rootLabId;
|
||||
new CodeInstruction(OpCodes.Ldloc_S, 6),
|
||||
new CodeInstruction(OpCodes.Stloc_S, 5),
|
||||
// entityId = labPool[labId].entityId;
|
||||
new CodeInstruction(OpCodes.Ldloc_S, local1),
|
||||
new CodeInstruction(OpCodes.Ldloc_S, 5),
|
||||
new CodeInstruction(OpCodes.Ldelema, typeof(LabComponent)),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(LabComponent), nameof(LabComponent.entityId))),
|
||||
new CodeInstruction(OpCodes.Starg_S, 1),
|
||||
new CodeInstruction(OpCodes.Ldarg_S, 1),
|
||||
// array = this.entityNeeds[entityId];
|
||||
new CodeInstruction(OpCodes.Ldarg_0),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(PlanetFactory), nameof(PlanetFactory.entityNeeds))),
|
||||
new CodeInstruction(OpCodes.Ldarg_1),
|
||||
new CodeInstruction(OpCodes.Ldelem_Ref),
|
||||
new CodeInstruction(OpCodes.Stloc_1)
|
||||
// lable1:
|
||||
);
|
||||
matcher.Instruction.labels = new List<Label> { label1 };
|
||||
|
||||
for (;;)
|
||||
{
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(PlanetFactory), nameof(PlanetFactory.factorySystem))),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(FactorySystem), nameof(FactorySystem.labPool)))
|
||||
);
|
||||
if (matcher.IsInvalid) break;
|
||||
var labels2 = matcher.Instruction.labels;
|
||||
var instr = new CodeInstruction(OpCodes.Ldloc_S, local1).WithLabels(labels2);
|
||||
matcher.RemoveInstructions(3).InsertAndAdvance(instr);
|
||||
}
|
||||
|
||||
// UpdateNeedsXXXXSingle() after item count changed
|
||||
matcher.Start().MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldloc_S),
|
||||
new CodeMatch(OpCodes.Ldelema, typeof(int)),
|
||||
new CodeMatch(OpCodes.Dup),
|
||||
new CodeMatch(OpCodes.Ldind_I4),
|
||||
new CodeMatch(OpCodes.Ldarg_S, (byte)5),
|
||||
new CodeMatch(OpCodes.Add),
|
||||
new CodeMatch(OpCodes.Stind_I4)
|
||||
);
|
||||
var v19 = matcher.Operand;
|
||||
matcher.Advance(7).InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldloc_S, local1),
|
||||
new CodeInstruction(OpCodes.Ldloc_S, 5),
|
||||
new CodeInstruction(OpCodes.Ldelema, typeof(LabComponent)),
|
||||
new CodeInstruction(OpCodes.Ldloc_S, 19),
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof (LabOptPatchFunctions), nameof(LabOptPatchFunctions.UpdateNeedsAssembleSingle)))
|
||||
);
|
||||
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldloc_S, v19),
|
||||
new CodeMatch(OpCodes.Ldelema, typeof(int)),
|
||||
new CodeMatch(OpCodes.Dup),
|
||||
new CodeMatch(OpCodes.Ldind_I4),
|
||||
new CodeMatch(OpCodes.Ldc_I4, 0xE10),
|
||||
new CodeMatch(OpCodes.Ldarg_S, (byte)5),
|
||||
new CodeMatch(OpCodes.Mul),
|
||||
new CodeMatch(OpCodes.Add),
|
||||
new CodeMatch(OpCodes.Stind_I4)
|
||||
).Advance(9).InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldloc_S, local1),
|
||||
new CodeInstruction(OpCodes.Ldloc_S, 5),
|
||||
new CodeInstruction(OpCodes.Ldelema, typeof(LabComponent)),
|
||||
new CodeInstruction(OpCodes.Ldloc_S, 19),
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof (LabOptPatchFunctions), nameof(LabOptPatchFunctions.UpdateNeedsResearchSingle)))
|
||||
);
|
||||
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
// Fill into root lab
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(PlanetFactory), nameof(PlanetFactory.EntityFastFillIn))]
|
||||
private static IEnumerable<CodeInstruction> PlanetFactory_EntityFastFillIn_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
var label1 = generator.DefineLabel();
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(FactorySystem), nameof(FactorySystem.labPool)))
|
||||
)
|
||||
.Advance(2)
|
||||
.InsertAndAdvance(
|
||||
// rootLabId = labPool[labId].rootLabId;
|
||||
new CodeInstruction(OpCodes.Ldloc_S, 69),
|
||||
new CodeInstruction(OpCodes.Ldloc_S, 68),
|
||||
new CodeInstruction(OpCodes.Ldelema, typeof(LabComponent)),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(LabComponent), "rootLabId")),
|
||||
new CodeInstruction(OpCodes.Stloc_S, 73),
|
||||
// if (rootLabId <= 0) goto label1;
|
||||
new CodeInstruction(OpCodes.Ldloc_S, 73),
|
||||
new CodeInstruction(OpCodes.Ldc_I4_0),
|
||||
new CodeInstruction(OpCodes.Ble, label1),
|
||||
// labId = rootLabId;
|
||||
new CodeInstruction(OpCodes.Ldloc_S, 73),
|
||||
new CodeInstruction(OpCodes.Stloc_S, 68)
|
||||
// lable1:
|
||||
);
|
||||
matcher.Instruction.labels.Add(label1);
|
||||
|
||||
// Add UpdateNeedsXXXXSingle() after item count changed
|
||||
// -- Find V_76
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Sub),
|
||||
new CodeMatch(OpCodes.Stloc_S),
|
||||
new CodeMatch(OpCodes.Ldc_I4_0),
|
||||
new CodeMatch(OpCodes.Stloc_S))
|
||||
.Advance(3);
|
||||
var v76 = matcher.Operand;
|
||||
// -- Patch
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldloc_S, v76),
|
||||
new CodeMatch(OpCodes.Add),
|
||||
new CodeMatch(OpCodes.Stind_I4)
|
||||
).Advance(3).InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldloc_S, 69),
|
||||
new CodeInstruction(OpCodes.Ldloc_S, 68),
|
||||
new CodeInstruction(OpCodes.Ldelema, typeof(LabComponent)),
|
||||
new CodeInstruction(OpCodes.Ldloc_S, 73),
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(LabOptPatchFunctions), nameof(LabOptPatchFunctions.UpdateNeedsAssembleSingle)))
|
||||
);
|
||||
// -- Find V_83
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldc_I4, 0xE10),
|
||||
new CodeMatch(OpCodes.Div),
|
||||
new CodeMatch(OpCodes.Sub),
|
||||
new CodeMatch(OpCodes.Stloc_S),
|
||||
new CodeMatch(OpCodes.Ldc_I4_0),
|
||||
new CodeMatch(OpCodes.Stloc_S))
|
||||
.Advance(5);
|
||||
var v83 = matcher.Operand;
|
||||
// -- Patch
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldloc_S, v83),
|
||||
new CodeMatch(OpCodes.Ldc_I4, 0xE10),
|
||||
new CodeMatch(OpCodes.Mul),
|
||||
new CodeMatch(OpCodes.Add),
|
||||
new CodeMatch(OpCodes.Stind_I4)
|
||||
).Advance(5).InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldloc_S, 69),
|
||||
new CodeInstruction(OpCodes.Ldloc_S, 68),
|
||||
new CodeInstruction(OpCodes.Ldelema, typeof(LabComponent)),
|
||||
new CodeInstruction(OpCodes.Ldloc_S, 73),
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof (LabOptPatchFunctions), nameof(LabOptPatchFunctions.UpdateNeedsResearchSingle)))
|
||||
);
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
// Fill into root lab
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(UILabWindow), nameof(UILabWindow.OnItemButtonClick))]
|
||||
private static IEnumerable<CodeInstruction> UILabWindow_OnItemButtonClick_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
var local1 = generator.DeclareLocal(typeof(int));
|
||||
var label1 = generator.DefineLabel();
|
||||
matcher
|
||||
.MatchForward(false, new CodeMatch(OpCodes.Ret))
|
||||
.Advance(1)
|
||||
.MatchForward(false, new CodeMatch(OpCodes.Ret))
|
||||
.Advance(1);
|
||||
var labels = matcher.Instruction.labels;
|
||||
matcher.InsertAndAdvance(
|
||||
// labId = this.labId;
|
||||
new CodeInstruction(OpCodes.Ldarg_0).WithLabels(labels),
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.PropertyGetter(typeof(UILabWindow), nameof(UILabWindow.labId))),
|
||||
new CodeInstruction(OpCodes.Stloc_S, local1),
|
||||
// rootLabId = this.factorySystem.labPool[labId].rootLabId;
|
||||
new CodeInstruction(OpCodes.Ldarg_0),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(UILabWindow), nameof(UILabWindow.factorySystem))),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(FactorySystem), nameof(FactorySystem.labPool))),
|
||||
new CodeInstruction(OpCodes.Ldloc_S, local1),
|
||||
new CodeInstruction(OpCodes.Ldelema, typeof(LabComponent)),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(LabComponent), "rootLabId")),
|
||||
new CodeInstruction(OpCodes.Stloc_S, 27),
|
||||
// if (rootLabId <= 0) goto label1;
|
||||
new CodeInstruction(OpCodes.Ldloc_S, 27),
|
||||
new CodeInstruction(OpCodes.Ldc_I4_0),
|
||||
new CodeInstruction(OpCodes.Ble, label1),
|
||||
// labId = rootLabId;
|
||||
new CodeInstruction(OpCodes.Ldloc_S, 27),
|
||||
new CodeInstruction(OpCodes.Stloc_S, local1)
|
||||
// lable1:
|
||||
);
|
||||
matcher.Instruction.labels = new List<Label> { label1 };
|
||||
for (;;)
|
||||
{
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Call, AccessTools.PropertyGetter(typeof(UILabWindow), nameof(UILabWindow.labId))));
|
||||
if (matcher.IsInvalid) break;
|
||||
matcher.RemoveInstructions(2).InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, local1));
|
||||
}
|
||||
|
||||
matcher.Start().MatchForward(false,
|
||||
new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(Player), nameof(Player.AddHandItemCount_Unsafe)))
|
||||
).MatchBack(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0)
|
||||
).InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldarg_0),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(UILabWindow), nameof(UILabWindow.factorySystem))),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(FactorySystem), nameof(FactorySystem.labPool))),
|
||||
new CodeInstruction(OpCodes.Ldloc_S, local1),
|
||||
new CodeInstruction(OpCodes.Ldelema, typeof(LabComponent)),
|
||||
new CodeInstruction(OpCodes.Ldarg_1),
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof (LabOptPatchFunctions), nameof(LabOptPatchFunctions.UpdateNeedsResearchSingle)))
|
||||
).Advance(10).MatchForward(false,
|
||||
new CodeMatch(OpCodes.Callvirt, AccessTools.Method(typeof(Player), nameof(Player.AddHandItemCount_Unsafe)))
|
||||
).MatchBack(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0)
|
||||
).Insert(
|
||||
new CodeInstruction(OpCodes.Ldarg_0),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(UILabWindow), nameof(UILabWindow.factorySystem))),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(FactorySystem), nameof(FactorySystem.labPool))),
|
||||
new CodeInstruction(OpCodes.Ldloc_S, local1),
|
||||
new CodeInstruction(OpCodes.Ldelema, typeof(LabComponent)),
|
||||
new CodeInstruction(OpCodes.Ldarg_1),
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof (LabOptPatchFunctions), nameof(LabOptPatchFunctions.UpdateNeedsAssembleSingle)))
|
||||
);
|
||||
matcher.Start().MatchForward(false,
|
||||
new CodeMatch(OpCodes.Stelem_I4),
|
||||
new CodeMatch(OpCodes.Ret)
|
||||
).Advance(1).InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldarg_0),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(UILabWindow), nameof(UILabWindow.factorySystem))),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(FactorySystem), nameof(FactorySystem.labPool))),
|
||||
new CodeInstruction(OpCodes.Ldloc_S, local1),
|
||||
new CodeInstruction(OpCodes.Ldelema, typeof(LabComponent)),
|
||||
new CodeInstruction(OpCodes.Ldarg_1),
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof (LabOptPatchFunctions), nameof(LabOptPatchFunctions.UpdateNeedsResearchSingle)))
|
||||
).Advance(1).MatchForward(false,
|
||||
new CodeMatch(OpCodes.Stelem_I4),
|
||||
new CodeMatch(OpCodes.Ret)
|
||||
).Advance(1).Insert(
|
||||
new CodeInstruction(OpCodes.Ldarg_0),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(UILabWindow), nameof(UILabWindow.factorySystem))),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(FactorySystem), nameof(FactorySystem.labPool))),
|
||||
new CodeInstruction(OpCodes.Ldloc_S, local1),
|
||||
new CodeInstruction(OpCodes.Ldelema, typeof(LabComponent)),
|
||||
new CodeInstruction(OpCodes.Ldarg_1),
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof (LabOptPatchFunctions), nameof(LabOptPatchFunctions.UpdateNeedsAssembleSingle)))
|
||||
);
|
||||
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
// Add a parameter on calling LabComponent.InternalUpdateAssemble()
|
||||
// Remove call to LabComponent.InternalUpdateAssemble()
|
||||
// Redirect call of LabComponent.InternalUpdateAssemble() to InternalUpdateAssembleNew()
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(FactorySystem), nameof(FactorySystem.GameTickLabProduceMode), typeof(long), typeof(bool))]
|
||||
[HarmonyPatch(typeof(FactorySystem), nameof(FactorySystem.GameTickLabProduceMode), typeof(long), typeof(bool), typeof(int), typeof(int), typeof(int))]
|
||||
@@ -356,150 +159,113 @@ public class LabOptPatch : BaseUnityPlugin
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Call, AccessTools.Method(typeof(LabComponent), nameof(LabComponent.InternalUpdateAssemble)))
|
||||
).RemoveInstructions(1).Insert(
|
||||
new CodeInstruction(OpCodes.Ldarg_0),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(FactorySystem), nameof(FactorySystem.labPool))),
|
||||
).SetInstruction(
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(LabOptPatchFunctions), nameof(LabOptPatchFunctions.InternalUpdateAssembleNew)))
|
||||
);
|
||||
matcher.Start().MatchForward(false,
|
||||
new CodeMatch(OpCodes.Call, AccessTools.Method(typeof(LabComponent), nameof(LabComponent.UpdateNeedsAssemble)))
|
||||
).Advance(-4).RemoveInstructions(5);
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
// Add a parameter on calling LabComponent.InternalUpdateResearch()
|
||||
// Remove call to LabComponent.InternalUpdateResearch()
|
||||
// Redirect call of LabComponent.SetFunction() to SetFunctionNew()
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(FactorySystem), nameof(FactorySystem.GameTickLabResearchMode), typeof(long), typeof(bool))]
|
||||
private static IEnumerable<CodeInstruction> FactorySystem_GameTickLabResearchMode_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
[HarmonyPatch(typeof(BuildingParameters), nameof(BuildingParameters.ApplyPrebuildParametersToEntity))]
|
||||
private static IEnumerable<CodeInstruction> BuildingParameters_ApplyPrebuildParametersToEntity_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Call, AccessTools.Method(typeof(LabComponent), nameof(LabComponent.InternalUpdateResearch)))
|
||||
).RemoveInstructions(1).Insert(
|
||||
new CodeInstruction(OpCodes.Ldarg_0),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(FactorySystem), nameof(FactorySystem.labPool))),
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(LabOptPatchFunctions), nameof(LabOptPatchFunctions.InternalUpdateResearchNew)))
|
||||
);
|
||||
matcher.Start().MatchForward(false,
|
||||
new CodeMatch(OpCodes.Call, AccessTools.Method(typeof(LabComponent), nameof(LabComponent.UpdateNeedsResearch)))
|
||||
).Advance(-4).RemoveInstructions(5);
|
||||
new CodeMatch(OpCodes.Call, AccessTools.Method(typeof(LabComponent), nameof(LabComponent.SetFunction)))
|
||||
).Repeat(codeMatcher =>
|
||||
{
|
||||
codeMatcher.InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldloc_2),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(FactorySystem), nameof(FactorySystem.labPool)))
|
||||
).SetInstructionAndAdvance(
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(LabOptPatchFunctions), nameof(LabOptPatchFunctions.SetFunctionNew)))
|
||||
);
|
||||
});
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(BuildingParameters), nameof(BuildingParameters.PasteToFactoryObject))]
|
||||
private static IEnumerable<CodeInstruction> BuildingParameters_PasteToFactoryObject_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Call, AccessTools.Method(typeof(LabComponent), nameof(LabComponent.SetFunction)))
|
||||
).Repeat(codeMatcher =>
|
||||
{
|
||||
codeMatcher.InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldarg_2),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(PlanetFactory), nameof(PlanetFactory.factorySystem))),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(FactorySystem), nameof(FactorySystem.labPool)))
|
||||
).SetInstructionAndAdvance(
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(LabOptPatchFunctions), nameof(LabOptPatchFunctions.SetFunctionNew)))
|
||||
);
|
||||
});
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(FactorySystem), nameof(FactorySystem.FindLabFunctionsForBuild))]
|
||||
[HarmonyPatch(typeof(FactorySystem), nameof(FactorySystem.GameTickLabResearchMode))]
|
||||
[HarmonyPatch(typeof(FactorySystem), nameof(FactorySystem.SyncLabFunctions))]
|
||||
// no need to patch this function, it just set everything to empty
|
||||
// [HarmonyPatch(typeof(FactorySystem), nameof(FactorySystem.TakeBackItems_Lab))]
|
||||
private static IEnumerable<CodeInstruction> FactorySystem_ReplaceLabSetFunction_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Call, AccessTools.Method(typeof(LabComponent), nameof(LabComponent.SetFunction)))
|
||||
).Repeat(codeMatcher =>
|
||||
{
|
||||
codeMatcher.InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldarg_0),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(FactorySystem), nameof(FactorySystem.labPool)))
|
||||
).SetInstructionAndAdvance(
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(LabOptPatchFunctions), nameof(LabOptPatchFunctions.SetFunctionNew)))
|
||||
);
|
||||
});
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(UILabWindow), nameof(UILabWindow.OnItemButtonClick))]
|
||||
[HarmonyPatch(typeof(UILabWindow), nameof(UILabWindow.OnProductButtonClick))]
|
||||
private static IEnumerable<CodeInstruction> UILabWindow_PasteToFactoryObject_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Call, AccessTools.Method(typeof(LabComponent), nameof(LabComponent.SetFunction)))
|
||||
).Repeat(codeMatcher =>
|
||||
{
|
||||
codeMatcher.InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldarg_0),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(UILabWindow), nameof(UILabWindow.factorySystem))),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(FactorySystem), nameof(FactorySystem.labPool)))
|
||||
).SetInstructionAndAdvance(
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(LabOptPatchFunctions), nameof(LabOptPatchFunctions.SetFunctionNew)))
|
||||
);
|
||||
});
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
// Display UI: use root lab's count
|
||||
// Do not take items back on dismantling labs
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(UILabWindow), nameof(UILabWindow._OnUpdate))]
|
||||
private static IEnumerable<CodeInstruction> UILabWindow__OnUpdate_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
[HarmonyPatch(typeof(FactorySystem), nameof(FactorySystem.TakeBackItems_Lab))]
|
||||
private static IEnumerable<CodeInstruction> FactorySystem_TakeBackItems_Lab_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var local1 = generator.DeclareLocal(typeof(LabComponent).MakeByRefType());
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
matcher.End().MatchBack(false,
|
||||
new CodeMatch(OpCodes.Call, AccessTools.PropertyGetter(typeof(LabComponent), nameof(LabComponent.matrixMode)))
|
||||
).Advance(-1);
|
||||
var labels = matcher.Instruction.labels;
|
||||
var label1 = generator.DefineLabel();
|
||||
var label2 = generator.DefineLabel();
|
||||
matcher.InsertAndAdvance(
|
||||
// rootLabId = labComponent.rootLabId;
|
||||
new CodeInstruction(OpCodes.Ldloca_S, 0).WithLabels(labels),
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Call, AccessTools.Method(typeof(LabComponent), nameof(LabComponent.SetFunction)))
|
||||
).Advance(-10);
|
||||
var label1 = matcher.Labels[0];
|
||||
matcher.Start().MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldloc_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(LabComponent), nameof(LabComponent.recipeId)))
|
||||
).Insert(
|
||||
new CodeInstruction(OpCodes.Ldloc_0),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(LabComponent), "rootLabId")),
|
||||
new CodeInstruction(OpCodes.Stloc_S, 46),
|
||||
// if (rootLabId <= 0) goto label1;
|
||||
new CodeInstruction(OpCodes.Ldloc_S, 46),
|
||||
new CodeInstruction(OpCodes.Ldc_I4_0),
|
||||
new CodeInstruction(OpCodes.Ble, label1),
|
||||
// labComponent2 = ref this.factorySystem.labPool[rootLabId];
|
||||
new CodeInstruction(OpCodes.Ldarg_0),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(UILabWindow), nameof(UILabWindow.factorySystem))),
|
||||
new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(FactorySystem), nameof(FactorySystem.labPool))),
|
||||
new CodeInstruction(OpCodes.Ldloc_S, 46),
|
||||
new CodeInstruction(OpCodes.Ldelema, typeof(LabComponent)),
|
||||
new CodeInstruction(OpCodes.Stloc_S, local1),
|
||||
new CodeInstruction(OpCodes.Br, label2),
|
||||
// lable1:
|
||||
// labComponent2 = ref labComponent;
|
||||
new CodeInstruction(OpCodes.Ldloca_S, 0).WithLabels(label1),
|
||||
new CodeInstruction(OpCodes.Stloc_S, local1)
|
||||
);
|
||||
matcher.Instruction.labels = new List<Label>{label2};
|
||||
matcher.Advance(2);
|
||||
var startPos = matcher.Pos;
|
||||
for (;;)
|
||||
{
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldloc_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(LabComponent), nameof(LabComponent.served)))
|
||||
);
|
||||
if (matcher.IsInvalid) break;
|
||||
matcher.Set(OpCodes.Ldloc_S, local1).Advance(2);
|
||||
}
|
||||
|
||||
matcher.Start().Advance(startPos);
|
||||
for (;;)
|
||||
{
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldloc_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(LabComponent), nameof(LabComponent.incServed)))
|
||||
);
|
||||
if (matcher.IsInvalid) break;
|
||||
matcher.Set(OpCodes.Ldloc_S, local1).Advance(2);
|
||||
}
|
||||
|
||||
matcher.Start().Advance(startPos);
|
||||
for (;;)
|
||||
{
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldloc_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(LabComponent), nameof(LabComponent.produced)))
|
||||
);
|
||||
if (matcher.IsInvalid) break;
|
||||
matcher.Set(OpCodes.Ldloc_S, local1).Advance(2);
|
||||
}
|
||||
|
||||
matcher.Start().Advance(startPos);
|
||||
for (;;)
|
||||
{
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldloc_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(LabComponent), nameof(LabComponent.matrixServed)))
|
||||
);
|
||||
if (matcher.IsInvalid) break;
|
||||
matcher.Set(OpCodes.Ldloc_S, local1).Advance(2);
|
||||
}
|
||||
|
||||
matcher.Start().Advance(startPos);
|
||||
for (;;)
|
||||
{
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldloc_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(LabComponent), nameof(LabComponent.matrixIncServed)))
|
||||
);
|
||||
if (matcher.IsInvalid) break;
|
||||
matcher.Set(OpCodes.Ldloc_S, local1).Advance(2);
|
||||
}
|
||||
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(LabComponent), nameof(LabComponent.SetFunction))]
|
||||
private static IEnumerable<CodeInstruction> LabComponent_SetFunction_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ret)
|
||||
).InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldarg_0),
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(LabComponent), nameof(LabComponent.UpdateNeedsResearch)))
|
||||
).Advance(1).MatchForward(false,
|
||||
new CodeMatch(OpCodes.Newarr, typeof(int)),
|
||||
new CodeMatch(OpCodes.Stfld, AccessTools.Field(typeof(LabComponent), nameof(LabComponent.produced)))
|
||||
).Advance(2).Insert(
|
||||
new CodeInstruction(OpCodes.Ldarg_0),
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(LabComponent), nameof(LabComponent.UpdateNeedsAssemble)))
|
||||
new CodeInstruction(OpCodes.Bgt, label1)
|
||||
);
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user