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

Work in progress

This commit is contained in:
2023-07-29 17:13:19 +08:00
parent d3951e986b
commit f79a3f1201
4 changed files with 586 additions and 695 deletions

View File

@@ -1,23 +1,26 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using HarmonyLib;
namespace LabOpt;
public class LabOptPatchFunctions
public static class LabOptPatchFunctions
{
private static readonly FieldInfo RootLabIdField = AccessTools.Field(typeof(LabComponent), "rootLabId");
private const int RequireCountForAssemble = 15;
private const int RequireCountForResearch = 54000;
public static void SetRootLabIdForStacking(FactorySystem factorySystem, int labId, int nextEntityId)
{
var rootId = (int)RootLabIdField.GetValue(factorySystem.labPool[labId]);
var labPool = factorySystem.labPool;
var rootId = (int)RootLabIdField.GetValue(labPool[labId]);
var targetLabId = factorySystem.factory.entityPool[nextEntityId].labId;
if (rootId <= 0) rootId = labId;
RootLabIdField.SetValueDirect(__makeref(factorySystem.labPool[targetLabId]), rootId);
LabOptPatch.Logger.LogDebug($"Set rootLabId of lab {targetLabId} to {rootId}");
do
{
RootLabIdField.SetValueDirect(__makeref(labPool[targetLabId]), rootId);
LabOptPatch.Logger.LogDebug($"Set rootLabId of lab {targetLabId} to {rootId}");
} while ((targetLabId = labPool[targetLabId].nextLabId) > 0);
}
public static void SetRootLabIdOnLoading(FactorySystem factorySystem)
@@ -40,7 +43,7 @@ public class LabOptPatchFunctions
}
}
}
else
else if (lab.recipeId > 0)
{
var len = lab.incServed.Length;
for (var i = 0; i < len; i++)
@@ -53,329 +56,451 @@ public class LabOptPatchFunctions
}
if (lab.nextLabId != 0) parentDict[lab.nextLabId] = id;
}
foreach (var pair in parentDict)
{
var rootId = pair.Value;
while (parentDict.TryGetValue(rootId, out var parentId)) rootId = parentId;
RootLabIdField.SetValueDirect(__makeref(labPool[pair.Key]), rootId);
LabOptPatch.Logger.LogDebug($"Set rootLabId of lab {pair.Key} to {rootId}");
AssignRootLabValues(ref labPool[rootId], ref labPool[pair.Key]);
}
}
ref var rootLab = ref labPool[rootId];
ref var thisLab = ref labPool[pair.Key];
int len;
if (rootLab.researchMode)
public static void AssignRootLabValues(ref LabComponent rootLab, ref LabComponent thisLab)
{
int len;
if (rootLab.researchMode)
{
len = Math.Min(rootLab.matrixServed.Length, thisLab.matrixServed.Length);
for (var i = 0; i < len; i++)
{
len = Math.Min(rootLab.matrixServed.Length, thisLab.matrixServed.Length);
for (var i = 0; i < len; i++)
if (thisLab.matrixServed[i] > 0)
{
if (thisLab.matrixServed[i] != 0)
rootLab.matrixServed[i] += thisLab.matrixServed[i];
thisLab.matrixServed[i] = 0;
}
if (thisLab.matrixIncServed[i] > 0)
{
rootLab.matrixIncServed[i] += thisLab.matrixIncServed[i];
thisLab.matrixIncServed[i] = 0;
}
}
}
else if (rootLab.recipeId > 0)
{
len = Math.Min(rootLab.produced.Length, thisLab.produced.Length);
for (var i = 0; i < len; i++)
{
if (thisLab.produced[i] <= 0) continue;
rootLab.produced[i] += thisLab.produced[i];
thisLab.produced[i] = 0;
}
len = Math.Min(rootLab.served.Length, thisLab.served.Length);
for (var i = 0; i < len; i++)
{
if (thisLab.served[i] > 0)
{
rootLab.served[i] += thisLab.served[i];
thisLab.served[i] = 0;
}
if (thisLab.incServed[i] > 0)
{
rootLab.incServed[i] += thisLab.incServed[i];
thisLab.incServed[i] = 0;
}
}
}
thisLab.needs = rootLab.needs;
thisLab.requires = rootLab.requires;
thisLab.requireCounts = rootLab.requireCounts;
thisLab.products = rootLab.products;
thisLab.productCounts = rootLab.productCounts;
thisLab.produced = rootLab.produced;
thisLab.served = rootLab.served;
thisLab.incServed = rootLab.incServed;
thisLab.matrixPoints = rootLab.matrixPoints;
thisLab.matrixServed = rootLab.matrixServed;
thisLab.matrixIncServed = rootLab.matrixIncServed;
thisLab.techId = rootLab.techId;
}
public static void LabExportZero(ref LabComponent lab, BinaryWriter w)
{
if (lab.matrixMode)
{
w.Write(lab.timeSpend);
w.Write(lab.extraTimeSpend);
w.Write(lab.requires.Length);
foreach (var n in lab.requires)
{
w.Write(n);
}
w.Write(lab.requireCounts.Length);
foreach (var n in lab.requireCounts)
{
w.Write(n);
}
w.Write(lab.served.Length);
for (var i = 0; i < lab.served.Length; i++)
{
w.Write(0);
}
w.Write(lab.incServed.Length);
for (var i = 0; i < lab.incServed.Length; i++)
{
w.Write(0);
}
w.Write(lab.needs.Length);
for (var i = 0; i < lab.needs.Length; i++)
{
w.Write(0);
}
w.Write(lab.products.Length);
foreach (var n in lab.products)
{
w.Write(n);
}
w.Write(lab.productCounts.Length);
foreach (var n in lab.productCounts)
{
w.Write(n);
}
w.Write(lab.produced.Length);
for (var i = 0; i < lab.produced.Length; i++)
{
w.Write(0);
}
}
if (lab.researchMode)
{
w.Write(lab.matrixPoints.Length);
foreach (var n in lab.matrixPoints)
{
w.Write(n);
}
w.Write(lab.matrixServed.Length);
for (var i = 0; i < lab.matrixServed.Length; i++)
{
w.Write(0);
}
w.Write(lab.needs.Length);
for (var i = 0; i < lab.needs.Length; i++)
{
w.Write(0);
}
w.Write(lab.matrixIncServed.Length);
for (var i = 0; i < lab.matrixIncServed.Length; i++)
{
w.Write(0);
}
}
}
public static uint InternalUpdateAssembleNew(ref LabComponent lab, float power, int[] productRegister, int[] consumeRegister)
{
if (power < 0.1f)
{
return 0U;
}
if (lab.extraTime >= lab.extraTimeSpend)
{
var len = lab.products.Length;
lock (lab.produced)
{
if (len == 1)
{
lab.produced[0] += lab.productCounts[0];
lock (productRegister)
{
rootLab.matrixServed[i] += thisLab.matrixServed[i];
thisLab.matrixServed[i] = 0;
productRegister[lab.products[0]] += lab.productCounts[0];
}
if (thisLab.matrixIncServed[i] != 0)
}
else
{
for (var i = 0; i < len; i++)
{
rootLab.matrixIncServed[i] += thisLab.matrixIncServed[i];
thisLab.matrixIncServed[i] = 0;
lab.produced[i] += lab.productCounts[i];
lock (productRegister)
{
productRegister[lab.products[i]] += lab.productCounts[i];
}
}
}
}
lab.extraTime -= lab.extraTimeSpend;
}
if (lab.time >= lab.timeSpend)
{
lab.replicating = false;
var len = lab.products.Length;
lock (lab.produced)
{
if (len == 1)
{
if (lab.produced[0] + lab.productCounts[0] > 30)
{
return 0U;
}
lab.produced[0] += lab.productCounts[0];
lock (productRegister)
{
productRegister[lab.products[0]] += lab.productCounts[0];
}
}
else
{
for (var j = 0; j < len; j++)
{
if (lab.produced[j] + lab.productCounts[j] > 30)
{
return 0U;
}
}
for (var k = 0; k < len; k++)
{
lab.produced[k] += lab.productCounts[k];
lock (productRegister)
{
productRegister[lab.products[k]] += lab.productCounts[k];
}
}
}
}
lab.extraSpeed = 0;
lab.speedOverride = lab.speed;
lab.extraPowerRatio = 0;
lab.time -= lab.timeSpend;
}
if (!lab.replicating)
{
var len = lab.requireCounts.Length;
int incLevel;
if (len > 0)
{
var served = lab.served;
lock (served)
{
for (int l = 0; l < len; l++)
{
if (served[l] >= lab.requireCounts[l] && served[l] != 0) continue;
lab.time = 0;
return 0U;
}
incLevel = 10;
for (var m = 0; m < len; m++)
{
var splittedIncLevel = lab.split_inc_level(ref served[m], ref lab.incServed[m], lab.requireCounts[m]);
if (splittedIncLevel < incLevel) incLevel = splittedIncLevel;
if (served[m] == 0)
{
lab.incServed[m] = 0;
}
lock (consumeRegister)
{
consumeRegister[lab.requires[m]] += lab.requireCounts[m];
}
}
if (incLevel < 0)
{
incLevel = 0;
}
}
}
else
{
len = Math.Min(rootLab.produced.Length, thisLab.produced.Length);
for (var i = 0; i < len; i++)
{
if (thisLab.produced[i] == 0) continue;
rootLab.produced[i] += thisLab.produced[i];
thisLab.produced[i] = 0;
}
len = Math.Min(rootLab.served.Length, thisLab.served.Length);
for (var i = 0; i < len; i++)
{
if (thisLab.served[i] != 0)
{
rootLab.served[i] += thisLab.served[i];
thisLab.served[i] = 0;
}
if (thisLab.incServed[i] != 0)
{
rootLab.incServed[i] += thisLab.incServed[i];
thisLab.incServed[i] = 0;
}
}
incLevel = 0;
}
LabOptPatch.Logger.LogDebug($"Set rootLabId of lab {pair.Key} to {rootId}");
}
}
public static uint InternalUpdateAssembleNew(ref LabComponent lab, float power, int[] productRegister, int[] consumeRegister, LabComponent[] labPool)
{
if (power < 0.1f)
{
return 0U;
}
var extraPassed = lab.extraTime >= lab.extraTimeSpend;
var timePassed = lab.time >= lab.timeSpend;
if (extraPassed || timePassed || !lab.replicating)
{
var rootLabId = (int)RootLabIdField.GetValue(lab);
ref var rootLab = ref rootLabId > 0 ? ref labPool[rootLabId] : ref lab;
if (extraPassed)
if (lab.productive && !lab.forceAccMode)
{
int len = lab.products.Length;
lock (rootLab.produced)
{
if (len == 1)
{
rootLab.produced[0] += lab.productCounts[0];
lock (productRegister)
{
productRegister[lab.products[0]] += lab.productCounts[0];
}
}
else
{
for (int i = 0; i < len; i++)
{
rootLab.produced[i] += lab.productCounts[i];
lock (productRegister)
{
productRegister[lab.products[i]] += lab.productCounts[i];
}
}
}
}
lab.extraTime -= lab.extraTimeSpend;
}
if (timePassed)
{
lab.replicating = false;
int len = lab.products.Length;
lock (rootLab.produced)
{
if (len == 1)
{
if (rootLab.produced[0] + lab.productCounts[0] > 30)
{
return 0U;
}
rootLab.produced[0] += lab.productCounts[0];
lock (productRegister)
{
productRegister[lab.products[0]] += lab.productCounts[0];
}
}
else
{
for (int j = 0; j < len; j++)
{
if (rootLab.produced[j] + lab.productCounts[j] > 30)
{
return 0U;
}
}
for (int k = 0; k < len; k++)
{
rootLab.produced[k] += lab.productCounts[k];
lock (productRegister)
{
productRegister[lab.products[k]] += lab.productCounts[k];
}
}
}
}
lab.extraSpeed = 0;
lab.extraSpeed = (int)(lab.speed * Cargo.incTableMilli[incLevel] * 10.0 + 0.1);
lab.speedOverride = lab.speed;
lab.extraPowerRatio = 0;
lab.time -= lab.timeSpend;
lab.extraPowerRatio = Cargo.powerTable[incLevel];
}
if (!lab.replicating)
else
{
int len = lab.requireCounts.Length;
int incLevel;
if (len > 0)
{
var served = rootLab.served;
lock (served)
{
for (int l = 0; l < len; l++)
{
if (served[l] < lab.requireCounts[l] || served[l] == 0)
{
lab.time = 0;
return 0U;
}
}
incLevel = 10;
for (int m = 0; m < len; m++)
{
int splittedIncLevel = lab.split_inc_level(ref served[m], ref rootLab.incServed[m], lab.requireCounts[m]);
if (splittedIncLevel < incLevel) incLevel = splittedIncLevel;
if (served[m] == 0)
{
rootLab.incServed[m] = 0;
}
rootLab.needs[m] = served[m] < RequireCountForAssemble ? rootLab.requires[0] : 0;
lock (consumeRegister)
{
consumeRegister[lab.requires[m]] += lab.requireCounts[m];
}
}
if (incLevel < 0)
{
incLevel = 0;
}
}
}
else
{
incLevel = 0;
}
if (lab.productive && !lab.forceAccMode)
{
lab.extraSpeed = (int)((double)lab.speed * Cargo.incTableMilli[incLevel] * 10.0 + 0.1);
lab.speedOverride = lab.speed;
lab.extraPowerRatio = Cargo.powerTable[incLevel];
}
else
{
lab.extraSpeed = 0;
lab.speedOverride = (int)((double)lab.speed * (1.0 + Cargo.accTableMilli[incLevel]) + 0.1);
lab.extraPowerRatio = Cargo.powerTable[incLevel];
}
lab.replicating = true;
lab.extraSpeed = 0;
lab.speedOverride = (int)(lab.speed * (1.0 + Cargo.accTableMilli[incLevel]) + 0.1);
lab.extraPowerRatio = Cargo.powerTable[incLevel];
}
lab.replicating = true;
}
if (lab.replicating && lab.time < lab.timeSpend && lab.extraTime < lab.extraTimeSpend)
switch (lab.replicating)
{
lab.time += (int)(power * (float)lab.speedOverride);
lab.extraTime += (int)(power * (float)lab.extraSpeed);
}
if (!lab.replicating)
{
return 0U;
case true when lab.time < lab.timeSpend && lab.extraTime < lab.extraTimeSpend:
lab.time += (int)(power * lab.speedOverride);
lab.extraTime += (int)(power * lab.extraSpeed);
break;
case false:
return 0U;
}
return (uint)(lab.products[0] - LabComponent.matrixIds[0] + 1);
}
public static uint InternalUpdateResearchNew(ref LabComponent lab, float power, float speed, int[] consumeRegister, ref TechState ts, ref int techHashedThisFrame, ref long uMatrixPoint, ref long hashRegister, LabComponent[] labPool)
public static void SetFunctionNew(ref LabComponent lab, bool researchMode, int recpId, int techId, SignData[] signPool, LabComponent[] labPool)
{
if (power < 0.1f)
{
return 0U;
}
var rootLabId = (int)RootLabIdField.GetValue(lab);
ref var rootLab = ref rootLabId > 0 ? ref labPool[rootLabId] : ref lab;
int multiplier = (int)(speed + 2f);
var matrixServed = rootLab.matrixServed;
for (var i = 0; i < 6; i++)
{
if (lab.matrixPoints[i] <= 0) continue;
int mult = matrixServed[i] / lab.matrixPoints[i];
if (mult < multiplier)
LabOptPatch.Logger.LogDebug($"SetFunctionNew: {lab.id} {(int)RootLabIdField.GetValue(lab)} {researchMode} {recpId} {techId}");
lab.replicating = false;
lab.time = 0;
lab.hashBytes = 0;
lab.extraHashBytes = 0;
lab.extraTime = 0;
lab.extraSpeed = 0;
lab.extraPowerRatio = 0;
lab.productive = false;
if (researchMode)
{
lab.forceAccMode = false;
lab.researchMode = true;
lab.recipeId = 0;
lab.techId = 0;
lab.timeSpend = 0;
lab.extraTimeSpend = 0;
lab.requires = null;
lab.requireCounts = null;
lab.served = null;
lab.incServed = null;
lab.products = null;
lab.productCounts = null;
lab.produced = null;
lab.productive = true;
var rootLabId = (int)RootLabIdField.GetValue(lab);
if (rootLabId > 0)
{
multiplier = mult;
if (multiplier == 0)
ref var rootLab = ref labPool[rootLabId];
lab.needs = rootLab.needs;
lab.matrixPoints = rootLab.matrixPoints;
lab.matrixServed = rootLab.matrixServed;
lab.matrixIncServed = rootLab.matrixIncServed;
lab.techId = rootLab.techId;
}
else
{
if (lab.needs == null || lab.needs.Length != LabComponent.matrixIds.Length)
{
lab.replicating = false;
return 0U;
lab.needs = new int[LabComponent.matrixIds.Length];
}
}
}
lab.replicating = true;
if (multiplier < speed) speed = multiplier;
int hashBytes = (int)(power * 10000f * speed + 0.5f);
lab.hashBytes += hashBytes;
long count = lab.hashBytes / 10000;
lab.hashBytes -= (int)count * 10000;
long maxNeeded = ts.hashNeeded - ts.hashUploaded;
if (maxNeeded < count) count = maxNeeded;
if (multiplier < count) count = multiplier;
int icount = (int)count;
if (icount > 0)
{
int len = matrixServed.Length;
int incLevel = ((len == 0) ? 0 : 10);
for (int i = 0; i < len; i++)
{
if (lab.matrixPoints[i] <= 0) continue;
int matrixBefore = matrixServed[i] / 3600;
int splittedIncLevel = lab.split_inc_level(ref matrixServed[i], ref rootLab.matrixIncServed[i], lab.matrixPoints[i] * icount);
incLevel = incLevel < splittedIncLevel ? incLevel : splittedIncLevel;
if (matrixServed[i] <= 0)
Array.Copy(LabComponent.matrixIds, lab.needs, LabComponent.matrixIds.Length);
if (lab.matrixPoints == null)
{
rootLab.matrixIncServed[i] = 0;
}
rootLab.needs[i] = matrixServed[i] < RequireCountForResearch ? LabComponent.matrixIds[i] : 0;
consumeRegister[LabComponent.matrixIds[i]] += matrixBefore - matrixServed[i] / 3600;
}
if (incLevel < 0)
{
incLevel = 0;
}
lab.extraSpeed = (int)(10000.0 * Cargo.incTableMilli[incLevel] * 10.0 + 0.1);
lab.extraPowerRatio = Cargo.powerTable[incLevel];
lab.extraHashBytes += (int)(power * lab.extraSpeed * speed + 0.5f);
long extraCount = lab.extraHashBytes / 100000;
lab.extraHashBytes -= (int)extraCount * 100000;
if (extraCount < 0L) extraCount = 0L;
int iextraCount = (int)extraCount;
ts.hashUploaded += count + extraCount;
hashRegister += count + extraCount;
uMatrixPoint += ts.uPointPerHash * count;
techHashedThisFrame += icount + iextraCount;
if (ts.hashUploaded >= ts.hashNeeded)
{
TechProto techProto = LDB.techs.Select(lab.techId);
if (ts.curLevel >= ts.maxLevel)
{
ts.curLevel = ts.maxLevel;
ts.hashUploaded = ts.hashNeeded;
ts.unlocked = true;
lab.matrixPoints = new int[LabComponent.matrixIds.Length];
}
else
{
ts.curLevel++;
ts.hashUploaded = 0L;
ts.hashNeeded = techProto.GetHashNeeded(ts.curLevel);
Array.Clear(lab.matrixPoints, 0, lab.matrixPoints.Length);
}
lab.matrixServed ??= new int[LabComponent.matrixIds.Length];
lab.matrixIncServed ??= new int[LabComponent.matrixIds.Length];
TechProto techProto = LDB.techs.Select(techId);
if (techProto != null && techProto.IsLabTech)
{
lab.techId = techId;
for (var i = 0; i < techProto.Items.Length; i++)
{
var index = techProto.Items[i] - LabComponent.matrixIds[0];
if (index >= 0 && index < lab.matrixPoints.Length)
{
lab.matrixPoints[index] = techProto.ItemPoints[i];
}
}
}
}
signPool[lab.entityId].iconId0 = (uint)lab.techId;
signPool[lab.entityId].iconType = lab.techId == 0 ? 0U : 3U;
return;
}
lab.researchMode = false;
lab.recipeId = 0;
lab.techId = 0;
lab.matrixPoints = null;
lab.matrixServed = null;
lab.matrixIncServed = null;
RecipeProto recipeProto = null;
if (recpId > 0)
{
recipeProto = LDB.recipes.Select(recpId);
}
if (recipeProto != null && recipeProto.Type == ERecipeType.Research)
{
lab.recipeId = recipeProto.ID;
lab.speed = 10000;
lab.speedOverride = lab.speed;
lab.timeSpend = recipeProto.TimeSpend * 10000;
lab.extraTimeSpend = recipeProto.TimeSpend * 100000;
lab.productive = recipeProto.productive;
lab.forceAccMode &= lab.productive;
var rootLabId = (int)RootLabIdField.GetValue(lab);
if (rootLabId > 0)
{
ref var rootLab = ref labPool[rootLabId];
lab.needs = rootLab.needs;
lab.requires = rootLab.requires;
lab.requireCounts = rootLab.requireCounts;
lab.products = rootLab.products;
lab.productCounts = rootLab.productCounts;
lab.produced = rootLab.produced;
lab.served = rootLab.served;
lab.incServed = rootLab.incServed;
}
else
{
lab.requires = new int[recipeProto.Items.Length];
Array.Copy(recipeProto.Items, lab.requires, lab.requires.Length);
lab.requireCounts = new int[recipeProto.ItemCounts.Length];
Array.Copy(recipeProto.ItemCounts, lab.requireCounts, lab.requireCounts.Length);
lab.served = new int[lab.requireCounts.Length];
lab.incServed = new int[lab.requireCounts.Length];
Assert.True(lab.requires.Length == lab.requireCounts.Length);
if (lab.needs == null || lab.needs.Length != 6)
{
lab.needs = new int[6];
}
else
{
Array.Clear(lab.needs, 0, 6);
}
lab.products = new int[recipeProto.Results.Length];
Array.Copy(recipeProto.Results, lab.products, lab.products.Length);
lab.productCounts = new int[recipeProto.ResultCounts.Length];
Array.Copy(recipeProto.ResultCounts, lab.productCounts, lab.productCounts.Length);
Assert.True(lab.products.Length == lab.productCounts.Length);
lab.produced = new int[lab.productCounts.Length];
}
}
else
{
lab.extraSpeed = 0;
lab.extraPowerRatio = 0;
}
return 1U;
}
public static void UpdateNeedsAssembleSingle(ref LabComponent lab, int m)
{
lab.needs[m] = lab.served[m] < RequireCountForAssemble ? lab.requires[m] : 0;
}
public static void UpdateNeedsResearchSingle(ref LabComponent lab, int m)
{
lab.needs[m] = lab.matrixServed[m] < RequireCountForResearch ? LabComponent.matrixIds[m] : 0;
}
else
{
lab.forceAccMode = false;
lab.recipeId = 0;
lab.speed = 0;
lab.speedOverride = 0;
lab.timeSpend = 0;
lab.extraTimeSpend = 0;
lab.requires = null;
lab.requireCounts = null;
lab.served = null;
lab.incServed = null;
lab.needs = null;
lab.products = null;
lab.productCounts = null;
lab.produced = null;
}
signPool[lab.entityId].iconId0 = (uint)lab.recipeId;
signPool[lab.entityId].iconType = lab.recipeId == 0 ? 0U : 2U;
}
}

View File

@@ -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();
}
}

View File

@@ -5,7 +5,7 @@
<AssemblyName>LabOpt</AssemblyName>
<BepInExPluginGuid>org.soardev.labopt</BepInExPluginGuid>
<Description>DSP MOD - LabOpt</Description>
<Version>0.2.1</Version>
<Version>0.3.0</Version>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>latest</LangVersion>
</PropertyGroup>

View File

@@ -1,6 +1,6 @@
{
"name": "LabOpt",
"version_number": "0.2.1",
"version_number": "0.3.0",
"website_url": "https://github.com/soarqin/DSP_Mods/tree/master/LabOpt",
"description": "Optimize Lab performance / 优化研究站性能",
"dependencies": [