mirror of
https://github.com/soarqin/DSP_Mods.git
synced 2025-12-09 05:33:37 +08:00
626 lines
22 KiB
C#
626 lines
22 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
|
|
namespace LabOpt;
|
|
|
|
public static class LabOptPatchFunctions
|
|
{
|
|
public static void SetRootId(ref LabComponent lab, int rootId)
|
|
{
|
|
lab.pcId = rootId;
|
|
}
|
|
|
|
public static void SetRootLabIdForStacking(FactorySystem factorySystem, int labId, int nextEntityId)
|
|
{
|
|
var labPool = factorySystem.labPool;
|
|
var factory = factorySystem.factory;
|
|
var rootId = labPool[labId].pcId;
|
|
if (rootId <= 0)
|
|
{
|
|
var radiusBear = factory.planet.radius + 2.0f;
|
|
if (factory.entityPool[labPool[labId].entityId].pos.sqrMagnitude > radiusBear * radiusBear)
|
|
return;
|
|
rootId = labId;
|
|
}
|
|
ref var rootLab = ref labPool[rootId];
|
|
var needSetFunction = rootLab.researchMode || rootLab.recipeId > 0;
|
|
var entitySignPool = needSetFunction ? factorySystem.factory.entitySignPool : null;
|
|
var targetLabId = factory.entityPool[nextEntityId].labId;
|
|
do
|
|
{
|
|
ref var targetLab = ref labPool[targetLabId];
|
|
targetLab.pcId = rootId;
|
|
// LabOptPatch.Logger.LogDebug($"Set rootLabId of lab {targetLabId} to {rootId}, {needSetFunction}");
|
|
if (needSetFunction)
|
|
{
|
|
SetFunctionInternal(ref targetLab, rootLab.researchMode, rootLab.recipeId, rootLab.techId, entitySignPool, labPool);
|
|
}
|
|
} while ((targetLabId = labPool[targetLabId].nextLabId) > 0);
|
|
}
|
|
|
|
public static void SetRootLabIdOnLoading(FactorySystem factorySystem)
|
|
{
|
|
var labCursor = factorySystem.labCursor;
|
|
var labPool = factorySystem.labPool;
|
|
var parentDict = new Dictionary<int, int>();
|
|
for (var id = 1; id < labCursor; id++)
|
|
{
|
|
if (labPool[id].id != id) continue;
|
|
ref var lab = ref labPool[id];
|
|
if (lab.researchMode)
|
|
{
|
|
var len = lab.matrixIncServed.Length;
|
|
for (var i = 0; i < len; i++)
|
|
{
|
|
if (lab.matrixIncServed[i] < 0)
|
|
{
|
|
lab.matrixIncServed[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
else if (lab.recipeId > 0)
|
|
{
|
|
var len = lab.incServed.Length;
|
|
for (var i = 0; i < len; i++)
|
|
{
|
|
if (lab.incServed[i] < 0)
|
|
{
|
|
lab.incServed[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
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;
|
|
ref var targetLab = ref labPool[pair.Key];
|
|
targetLab.pcId = rootId;
|
|
// LabOptPatch.Logger.LogDebug($"Set rootLabId of lab {pair.Key} to {rootId}");
|
|
AssignRootLabValues(ref labPool[rootId], ref targetLab);
|
|
}
|
|
}
|
|
|
|
private 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++)
|
|
{
|
|
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)
|
|
{
|
|
productRegister[lab.products[0]] += lab.productCounts[0];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (var i = 0; i < len; i++)
|
|
{
|
|
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 (var 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
|
|
{
|
|
incLevel = 0;
|
|
}
|
|
|
|
if (lab.productive && !lab.forceAccMode)
|
|
{
|
|
lab.extraSpeed = (int)(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)(lab.speed * (1.0 + Cargo.accTableMilli[incLevel]) + 0.1);
|
|
lab.extraPowerRatio = Cargo.powerTable[incLevel];
|
|
}
|
|
|
|
lab.replicating = true;
|
|
}
|
|
|
|
switch (lab.replicating)
|
|
{
|
|
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 void SetFunctionManually(ref LabComponent lab, bool researchMode, int recpId, int techId, SignData[] signPool, LabComponent[] labPool)
|
|
{
|
|
var rootLabId = lab.pcId;
|
|
if (rootLabId > 0)
|
|
{
|
|
ref var rootLab = ref labPool[rootLabId];
|
|
if (researchMode != rootLab.researchMode)
|
|
{
|
|
SetFunctionManually(ref rootLab, researchMode, recpId, techId, signPool, labPool);
|
|
}
|
|
else if (researchMode)
|
|
{
|
|
if (techId != rootLab.techId)
|
|
{
|
|
SetFunctionManually(ref rootLab, true, recpId, techId, signPool, labPool);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (recpId != rootLab.recipeId)
|
|
{
|
|
SetFunctionManually(ref rootLab, false, recpId, techId, signPool, labPool);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetFunctionInternal(ref lab, researchMode, recpId, techId, signPool, labPool);
|
|
var thisId = lab.id;
|
|
var needs = lab.needs;
|
|
var nextLabId = lab.nextLabId;
|
|
while (nextLabId > 0)
|
|
{
|
|
ref var nextLab = ref labPool[nextLabId];
|
|
if (nextLab.pcId != thisId) break;
|
|
if (needs != nextLab.needs)
|
|
SetFunctionInternal(ref nextLab, researchMode, recpId, techId, signPool, labPool);
|
|
nextLabId = nextLab.nextLabId;
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void SetFunctionInternal(ref LabComponent lab, bool researchMode, int recpId, int techId, SignData[] signPool, LabComponent[] labPool)
|
|
{
|
|
// LabOptPatch.Logger.LogDebug($"SetFunctionInternal: id={lab.id} root={(int)RootLabIdField.GetValue(lab)} research={researchMode} recp={recpId} tech={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 = lab.pcId;
|
|
if (rootLabId > 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.needs = new int[LabComponent.matrixIds.Length];
|
|
}
|
|
|
|
Array.Copy(LabComponent.matrixIds, lab.needs, LabComponent.matrixIds.Length);
|
|
if (lab.matrixPoints == null)
|
|
{
|
|
lab.matrixPoints = new int[LabComponent.matrixIds.Length];
|
|
}
|
|
else
|
|
{
|
|
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 = lab.pcId;
|
|
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
|
|
{
|
|
if (lab.needs == null || lab.needs.Length != 6)
|
|
lab.needs = new int[6];
|
|
else
|
|
Array.Clear(lab.needs, 0, 6);
|
|
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);
|
|
if (lab.served == null)
|
|
lab.served = new int[lab.requireCounts.Length];
|
|
else
|
|
Array.Clear(lab.served, 0, lab.served.Length);
|
|
if (lab.incServed == null)
|
|
lab.incServed = new int[lab.requireCounts.Length];
|
|
else
|
|
Array.Clear(lab.incServed, 0, lab.incServed.Length);
|
|
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);
|
|
if (lab.produced == null)
|
|
lab.produced = new int[lab.productCounts.Length];
|
|
else
|
|
Array.Clear(lab.produced, 0, lab.produced.Length);
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
|
|
public static int InsertIntoLab(PlanetFactory factory, int labId, int itemId, byte itemCount, byte itemInc, ref byte remainInc, int[] needs)
|
|
{
|
|
var factorySystem = factory.factorySystem;
|
|
var served = factorySystem.labPool[labId].served;
|
|
var incServed = factorySystem.labPool[labId].incServed;
|
|
var matrixServed = factorySystem.labPool[labId].matrixServed;
|
|
var matrixIncServed = factorySystem.labPool[labId].matrixIncServed;
|
|
var len = needs.Length;
|
|
for (var i = 0; i < len; i++)
|
|
{
|
|
if (needs[i] != itemId) continue;
|
|
if (served != null)
|
|
{
|
|
lock (served)
|
|
{
|
|
served[i] += itemCount;
|
|
incServed[i] += itemInc;
|
|
}
|
|
remainInc = 0;
|
|
return itemCount;
|
|
}
|
|
if (matrixServed != null)
|
|
{
|
|
lock (matrixServed)
|
|
{
|
|
matrixServed[i] += 3600 * itemCount;
|
|
matrixIncServed[i] += 3600 * itemInc;
|
|
}
|
|
remainInc = 0;
|
|
return itemCount;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
public static int PickFromLab(PlanetFactory factory, int labId, int filter, int[] needs)
|
|
{
|
|
var factorySystem = factory.factorySystem;
|
|
var products = factorySystem.labPool[labId].products;
|
|
if (products == null) return 0;
|
|
var produced = factorySystem.labPool[labId].produced;
|
|
if (produced == null) return 0;
|
|
lock (produced)
|
|
{
|
|
for (var j = 0; j < products.Length; j++)
|
|
{
|
|
if (produced[j] <= 0 || products[j] <= 0 ||
|
|
(filter != 0 && filter != products[j]) ||
|
|
(needs != null && needs[0] != products[j] && needs[1] != products[j] &&
|
|
needs[2] != products[j] && needs[3] != products[j] &&
|
|
needs[4] != products[j] && needs[5] != products[j])) continue;
|
|
produced[j]--;
|
|
return products[j];
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
}
|