mirror of
https://github.com/soarqin/DSP_Mods.git
synced 2025-12-09 05:33:37 +08:00
Finished all scheduled functions for LogisticMiner
This commit is contained in:
@@ -14,7 +14,6 @@ public class DevShortcuts : BaseUnityPlugin
|
||||
{
|
||||
_cfgEnabled = Config.Bind("General", "Enabled", _cfgEnabled, "enable/disable this plugin").Value;
|
||||
if (!_cfgEnabled) return;
|
||||
Logger.LogInfo($"Plugin {PluginInfo.PLUGIN_GUID} is loaded!");
|
||||
Harmony.CreateAndPatchAll(typeof(DevShortcuts));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BepInEx;
|
||||
using HarmonyLib;
|
||||
using Random = UnityEngine.Random;
|
||||
@@ -10,36 +9,45 @@ namespace LogisticMiner;
|
||||
[BepInPlugin(PluginInfo.PLUGIN_GUID, PluginInfo.PLUGIN_NAME, PluginInfo.PLUGIN_VERSION)]
|
||||
public class LogisticMiner : BaseUnityPlugin
|
||||
{
|
||||
private new static readonly BepInEx.Logging.ManualLogSource Logger = BepInEx.Logging.Logger.CreateLogSource(PluginInfo.PLUGIN_NAME);
|
||||
private new static readonly BepInEx.Logging.ManualLogSource Logger =
|
||||
BepInEx.Logging.Logger.CreateLogSource(PluginInfo.PLUGIN_NAME);
|
||||
|
||||
private static int _veinEnergyRatio = 200000;
|
||||
private static int _waterEnergyRatio = 50000;
|
||||
private static long _oreEnergyConsume = 2000000;
|
||||
private static long _oilEnergyConsume = 3600000;
|
||||
private static long _waterEnergyConsume = 20000000;
|
||||
private static int _waterSpeed = 100;
|
||||
private static int _miningScale = 100;
|
||||
|
||||
private static float _frame;
|
||||
private static float _miningCostRate;
|
||||
private static uint _miningCostBarrier;
|
||||
private static uint _miningCostBarrierOil;
|
||||
|
||||
private static uint _seed = (uint)Random.Range(int.MinValue, int.MaxValue);
|
||||
private static readonly Dictionary<int, List<int>> Veins = new();
|
||||
private static readonly Dictionary<int, float> FrameNext = new();
|
||||
private static readonly Dictionary<int, VeinCacheData> PlanetVeinCacheData = new();
|
||||
|
||||
private bool _cfgEnabled = true;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_cfgEnabled = Config.Bind("General", "Enabled", _cfgEnabled, "enable/disable this plugin").Value;
|
||||
_veinEnergyRatio = Config.Bind("General", "EnergyConsumptionEachVein", _veinEnergyRatio / 1000, "200 for default. Energy consumption for each vein(in kJ)").Value * 1000;
|
||||
_waterEnergyRatio = Config.Bind("General", "EnergyConsumptionEachWater", _waterEnergyRatio / 1000, "50 for default. Energy consumption for each water(in kJ)").Value * 1000;
|
||||
_waterSpeed = Config.Bind("General", "WaterMiningSpeed", _waterSpeed, "100 for default. Water mining speed (count per second)").Value;
|
||||
_miningScale = Config.Bind("General", "MiningScale", _miningScale, "100 for default. Must not be less than 100. Mining scale(in percents) for slots nearly empty (mining scale will slowly reduce to 1 till reach half of slot limits)").Value;
|
||||
_oreEnergyConsume = Config.Bind("General", "EnergyConsumptionForOre", _oreEnergyConsume / 2000,
|
||||
"Energy consumption for each ore vein group(in kW)").Value * 2000;
|
||||
_oilEnergyConsume = Config.Bind("General", "EnergyConsumptionForOil", _oilEnergyConsume / 2000,
|
||||
"Energy consumption for each oil seep(in kW)").Value * 2000;
|
||||
_waterEnergyConsume = Config.Bind("General", "EnergyConsumptionForWater", _waterEnergyConsume / 2000,
|
||||
"Energy consumption for water slot(in kW)").Value * 2000;
|
||||
_waterSpeed = Config.Bind("General", "WaterMiningSpeed", _waterSpeed,
|
||||
"Water mining speed (count per second)").Value;
|
||||
_miningScale = Config.Bind("General", "MiningScale", _miningScale,
|
||||
"Must not be less than 100. Mining scale(in percents) for slots nearly empty, and the scale reduces to 1 smoothly till reach half of slot limits. Please note that the power consumption increases by the square of the scale which is the same as Advanced Mining Machine")
|
||||
.Value;
|
||||
if (_miningScale < 100)
|
||||
{
|
||||
_miningScale = 100;
|
||||
}
|
||||
|
||||
if (!_cfgEnabled) return;
|
||||
Logger.LogInfo($"Plugin {PluginInfo.PLUGIN_GUID} is loaded!");
|
||||
Harmony.CreateAndPatchAll(typeof(LogisticMiner));
|
||||
}
|
||||
|
||||
@@ -49,9 +57,12 @@ public class LogisticMiner : BaseUnityPlugin
|
||||
private static void OnGameStart()
|
||||
{
|
||||
Logger.LogInfo("Game Start");
|
||||
FrameNext.Clear();
|
||||
PlanetVeinCacheData.Clear();
|
||||
_frame = 0f;
|
||||
Veins.Clear();
|
||||
/* codes reserved for future use: storage max may affect mining scale
|
||||
_localStationMax = LDB.items.Select(2103).prefabDesc.stationMaxItemCount;
|
||||
_remoteStationMax = LDB.items.Select(2104).prefabDesc.stationMaxItemCount;
|
||||
*/
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
@@ -63,13 +74,14 @@ public class LogisticMiner : BaseUnityPlugin
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_frame++;
|
||||
if (_frame <= 1000000f) return;
|
||||
/* keep precision of floats by limiting them <= 1000000f */
|
||||
_frame -= 1000000f;
|
||||
foreach(var key in FrameNext.Keys.ToList())
|
||||
foreach (var pair in PlanetVeinCacheData)
|
||||
{
|
||||
FrameNext[key] -= 1000000f;
|
||||
pair.Value.FrameNext -= 1000000f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,18 +96,18 @@ public class LogisticMiner : BaseUnityPlugin
|
||||
|
||||
private static void RecalcVeins(PlanetFactory factory)
|
||||
{
|
||||
VeinData[] veinPool = factory.veinPool;
|
||||
var planetId = factory.planetId;
|
||||
/* remove planet veins from dict */
|
||||
Veins.Keys.Where(key => (key >> 16) == planetId).ToList().ForEach(key => Veins.Remove(key));
|
||||
/* re-add all veins to dict */
|
||||
for (var i = 0; i < veinPool.Length; i++)
|
||||
if (PlanetVeinCacheData.TryGetValue(planetId, out var vcd))
|
||||
{
|
||||
var veinData = veinPool[i];
|
||||
if (veinData.amount > 0 && veinData.type > EVeinType.None)
|
||||
{
|
||||
AddVeinData(planetId, veinData.productId, i);
|
||||
}
|
||||
vcd.GenVeins(factory);
|
||||
}
|
||||
else
|
||||
{
|
||||
vcd = new VeinCacheData();
|
||||
vcd.GenVeins(factory);
|
||||
vcd.FrameNext = _frame + 120f / GameMain.history.miningSpeedScale;
|
||||
PlanetVeinCacheData.Add(planetId, vcd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,31 +116,37 @@ public class LogisticMiner : BaseUnityPlugin
|
||||
private static void Miner(FactorySystem __instance)
|
||||
{
|
||||
var history = GameMain.history;
|
||||
var miningSpeedScale = history.miningSpeedScale;
|
||||
if (miningSpeedScale <= 0f)
|
||||
var miningSpeedScalef = history.miningSpeedScale;
|
||||
var miningSpeedScale = (long)(miningSpeedScalef * 100);
|
||||
if (miningSpeedScale <= 0)
|
||||
return;
|
||||
var factory = __instance.factory;
|
||||
var planetId = factory.planetId;
|
||||
if (FrameNext.TryGetValue(planetId, out var frameNext))
|
||||
if (PlanetVeinCacheData.TryGetValue(planetId, out var vcd))
|
||||
{
|
||||
if (frameNext > _frame)
|
||||
if (vcd.FrameNext > _frame)
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
FrameNext[planetId] = _frame + 60f / miningSpeedScale;
|
||||
PlanetVeinCacheData[planetId] = new VeinCacheData
|
||||
{
|
||||
FrameNext = _frame + 120f / miningSpeedScalef
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
var miningFrames = 60f / miningSpeedScale;
|
||||
var miningFrames = 120f / miningSpeedScalef;
|
||||
var miningCostRate = history.miningCostRate;
|
||||
if (!miningCostRate.Equals(_miningCostRate))
|
||||
{
|
||||
_miningCostRate = miningCostRate;
|
||||
_miningCostBarrier = (uint)(int)Math.Ceiling(2147483646.0 * miningCostRate);
|
||||
_miningCostBarrierOil =
|
||||
(uint)(int)Math.Ceiling(2147483646.0 * miningCostRate * 0.401116669f /
|
||||
factory.gameData.gameDesc.resourceMultiplier);
|
||||
}
|
||||
var key0 = planetId << 16;
|
||||
var veinPool = factory.veinPool;
|
||||
|
||||
var planetTransport = __instance.planet.factory.transport;
|
||||
var factoryProductionStat =
|
||||
GameMain.statistics.production.factoryStatPool[__instance.factory.index];
|
||||
@@ -152,127 +170,214 @@ public class LogisticMiner : BaseUnityPlugin
|
||||
stationStore.max <= stationStore.count)
|
||||
continue;
|
||||
|
||||
var isVein = Veins.TryGetValue(key0 | stationStore.itemId, out var val);
|
||||
var isVein = vcd.HasVein(stationStore.itemId);
|
||||
var isVeinOrWater = isVein || stationStore.itemId == __instance.planet.waterItemId;
|
||||
if (!isVeinOrWater) continue;
|
||||
int amount;
|
||||
int energyRatio;
|
||||
long energyConsume;
|
||||
isCollecting = true;
|
||||
var miningScale = _miningScale;
|
||||
if (miningScale > 100)
|
||||
{
|
||||
if (stationStore.count * 2 < stationStore.max)
|
||||
miningScale = 100 +
|
||||
((miningScale - 100) * (stationStore.max - stationStore.count * 2) +
|
||||
stationStore.max - 1) / stationStore.max;
|
||||
else
|
||||
miningScale = 100;
|
||||
}
|
||||
|
||||
if (isVein)
|
||||
{
|
||||
if (stationComponent.energy < _veinEnergyRatio)
|
||||
(amount, energyConsume) = vcd.Mine(factory, stationStore.itemId, miningScale, miningSpeedScale,
|
||||
stationComponent.energy);
|
||||
if (amount < 0)
|
||||
{
|
||||
isCollecting = true;
|
||||
k = int.MaxValue - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (veinPool[val.First()].type == EVeinType.Oil)
|
||||
amount = (int)val
|
||||
.Where(item => item < veinPool.Length && veinPool[item].type > EVeinType.None)
|
||||
.Sum(item => veinPool[item].amount * VeinData.oilSpeedMultiplier * 2f);
|
||||
else
|
||||
amount = val.Sum(
|
||||
item => GetMine(veinPool, item, __instance.planet.factory) ? 1 : 0);
|
||||
energyRatio = _veinEnergyRatio;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (stationComponent.energy < _waterEnergyRatio)
|
||||
energyConsume = (_waterEnergyConsume * miningScale * miningScale + 9999L) / 100L /
|
||||
miningSpeedScale;
|
||||
if (stationComponent.energy < energyConsume)
|
||||
{
|
||||
isCollecting = true;
|
||||
k = int.MaxValue - 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
amount = _waterSpeed;
|
||||
energyRatio = _waterEnergyRatio;
|
||||
}
|
||||
|
||||
if (amount == 0) continue;
|
||||
isCollecting = true;
|
||||
var energyConsume = (int)Math.Ceiling(energyRatio * amount / miningSpeedScale);
|
||||
if (energyConsume > stationComponent.energy)
|
||||
{
|
||||
amount = (int)(stationComponent.energy * miningSpeedScale / energyRatio);
|
||||
energyConsume = (int)Math.Ceiling(energyRatio * amount / miningSpeedScale);
|
||||
amount = _waterSpeed * miningScale / 100;
|
||||
}
|
||||
|
||||
if (amount <= 0) continue;
|
||||
stationStore.count += amount;
|
||||
if (factoryProductionStat != null)
|
||||
productRegister[stationStore.itemId] += amount;
|
||||
stationComponent.energy -= energyConsume;
|
||||
}
|
||||
|
||||
if (isCollecting && stationComponent.energyMax > stationComponent.energy * 2)
|
||||
{
|
||||
var index = storage.Length - 2;
|
||||
var fuelCount = storage[index].count;
|
||||
if (fuelCount > 0)
|
||||
{
|
||||
var heatValue = LDB.items.Select(storage[index].itemId).HeatValue;
|
||||
if (heatValue > 0)
|
||||
{
|
||||
var count = (int)((stationComponent.energyMax - stationComponent.energy) /
|
||||
heatValue);
|
||||
if (count > fuelCount)
|
||||
count = fuelCount;
|
||||
storage[index].count -= count;
|
||||
stationComponent.energy += count * heatValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isCollecting || stationComponent.energy * 2 >= stationComponent.energyMax) continue;
|
||||
var index = stationComponent.isStellar ? storage.Length - 2 : storage.Length - 1;
|
||||
var fuelCount = storage[index].count;
|
||||
if (fuelCount == 0) continue;
|
||||
var heatValue = LDB.items.Select(storage[index].itemId).HeatValue;
|
||||
if (heatValue <= 0) continue;
|
||||
var count = (int)((stationComponent.energyMax - stationComponent.energy) /
|
||||
heatValue);
|
||||
if (count > fuelCount)
|
||||
count = fuelCount;
|
||||
storage[index].count -= count;
|
||||
stationComponent.energy += count * heatValue;
|
||||
}
|
||||
|
||||
frameNext += miningFrames;
|
||||
} while (frameNext <= _frame);
|
||||
vcd.FrameNext += miningFrames;
|
||||
} while (vcd.FrameNext <= _frame);
|
||||
|
||||
PerformanceMonitor.EndSample(ECpuWorkEntry.Miner);
|
||||
FrameNext[planetId] = frameNext;
|
||||
}
|
||||
|
||||
private static void AddVeinData(int planetId, int productId, int index)
|
||||
private class VeinCacheData
|
||||
{
|
||||
var key = (planetId << 16) + productId;
|
||||
if (Veins.TryGetValue(key, out var val))
|
||||
val.Add(index);
|
||||
else
|
||||
Veins.Add(key, new List<int> { index });
|
||||
}
|
||||
public float FrameNext;
|
||||
/* stores list of indices to veinData, with an extra INT which indicates cout of veinGroups at last */
|
||||
private Dictionary<int, List<int>> _veins = new();
|
||||
private int _mineIndex = -1;
|
||||
|
||||
private static bool GetMine(VeinData[] veinDatas, int index, PlanetFactory factory)
|
||||
{
|
||||
if (veinDatas.Length == 0 || veinDatas[index].type == EVeinType.None)
|
||||
return false;
|
||||
|
||||
short groupIndex;
|
||||
if (veinDatas[index].amount > 0)
|
||||
public bool HasVein(int productId)
|
||||
{
|
||||
bool flag = true;
|
||||
if (_miningCostBarrier < 2147483646u)
|
||||
{
|
||||
_seed = (uint)((int)((ulong)((_seed % 2147483646u + 1) * 48271L) % 2147483647uL) - 1);
|
||||
flag = _seed < _miningCostBarrier;
|
||||
}
|
||||
|
||||
if (flag)
|
||||
{
|
||||
veinDatas[index].amount--;
|
||||
factory.veinGroups[veinDatas[index].groupIndex].amount--;
|
||||
if (veinDatas[index].amount <= 0)
|
||||
{
|
||||
groupIndex = veinDatas[index].groupIndex;
|
||||
factory.veinGroups[groupIndex].count--;
|
||||
factory.RemoveVeinWithComponents(index);
|
||||
factory.RecalculateVeinGroup(groupIndex);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return _veins.ContainsKey(productId);
|
||||
}
|
||||
|
||||
groupIndex = veinDatas[index].groupIndex;
|
||||
factory.veinGroups[groupIndex].count--;
|
||||
factory.RemoveVeinWithComponents(index);
|
||||
factory.RecalculateVeinGroup(groupIndex);
|
||||
return false;
|
||||
public void GenVeins(PlanetFactory factory)
|
||||
{
|
||||
_veins = new Dictionary<int, List<int>>();
|
||||
var veinPool = factory.veinPool;
|
||||
var vg = new Dictionary<int, HashSet<int>>();
|
||||
for (var i = 0; i < veinPool.Length; i++)
|
||||
{
|
||||
if (veinPool[i].amount <= 0 || veinPool[i].type == EVeinType.None) continue;
|
||||
var productId = veinPool[i].productId;
|
||||
if (_veins.TryGetValue(productId, out var l))
|
||||
{
|
||||
l.Add(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
_veins.Add(productId, new List<int> { i });
|
||||
}
|
||||
|
||||
if (vg.TryGetValue(productId, out var hs))
|
||||
{
|
||||
hs.Add(veinPool[i].groupIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
vg.Add(productId, new HashSet<int> { veinPool[i].groupIndex });
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var pair in vg)
|
||||
{
|
||||
_veins[pair.Key].Add(pair.Value.Count);
|
||||
}
|
||||
}
|
||||
|
||||
public (int, long) Mine(PlanetFactory factory, int productId, int percent, long miningSpeedScale,
|
||||
long energyMax)
|
||||
{
|
||||
if (!_veins.TryGetValue(productId, out var veins))
|
||||
{
|
||||
return (-1, -1L);
|
||||
}
|
||||
|
||||
uint barrier;
|
||||
int limit;
|
||||
int count;
|
||||
long energy;
|
||||
var length = veins.Count - 1;
|
||||
/* if is Oil */
|
||||
if (productId == 1007)
|
||||
{
|
||||
energy = (_oilEnergyConsume * length * percent * percent + 9999L) / 100L / miningSpeedScale;
|
||||
if (energy > energyMax)
|
||||
return (-1, -1L);
|
||||
float countf = 0f;
|
||||
var veinsPool = factory.veinPool;
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
ref var vd = ref veinsPool[veins[i]];
|
||||
countf += vd.amount * 4 * VeinData.oilSpeedMultiplier;
|
||||
}
|
||||
|
||||
count = ((int)countf * percent + 99) / 100;
|
||||
if (count == 0)
|
||||
return (-1, -1L);
|
||||
barrier = _miningCostBarrierOil;
|
||||
limit = 2500;
|
||||
}
|
||||
else
|
||||
{
|
||||
count = (length * percent + 99) / 100;
|
||||
if (count == 0)
|
||||
return (-1, -1L);
|
||||
energy = (_oreEnergyConsume * veins[length] * percent * percent + 9999L) / 100L / miningSpeedScale;
|
||||
if (energy > energyMax)
|
||||
return (-1, -1L);
|
||||
barrier = _miningCostBarrier;
|
||||
limit = 0;
|
||||
}
|
||||
|
||||
var veinsData = factory.veinPool;
|
||||
var total = 0;
|
||||
for (; count > 0; count--)
|
||||
{
|
||||
_mineIndex = (_mineIndex + 1) % length;
|
||||
var index = veins[_mineIndex];
|
||||
ref var vd = ref veinsData[index];
|
||||
int groupIndex;
|
||||
if (vd.amount > 0)
|
||||
{
|
||||
total++;
|
||||
if (vd.amount > limit)
|
||||
{
|
||||
var consume = true;
|
||||
if (barrier < 2147483646u)
|
||||
{
|
||||
_seed = (uint)((int)((ulong)((_seed % 2147483646u + 1) * 48271L) % 2147483647uL) - 1);
|
||||
consume = _seed < barrier;
|
||||
}
|
||||
|
||||
if (consume)
|
||||
{
|
||||
vd.amount--;
|
||||
groupIndex = vd.groupIndex;
|
||||
factory.veinGroups[groupIndex].amount--;
|
||||
if (vd.amount <= 0)
|
||||
{
|
||||
factory.veinGroups[groupIndex].count--;
|
||||
factory.RemoveVeinWithComponents(index);
|
||||
factory.RecalculateVeinGroup(groupIndex);
|
||||
if (!_veins.TryGetValue(productId, out veins))
|
||||
break;
|
||||
length = veins.Count - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
groupIndex = vd.groupIndex;
|
||||
factory.veinGroups[groupIndex].count--;
|
||||
factory.RemoveVeinWithComponents(index);
|
||||
factory.RecalculateVeinGroup(groupIndex);
|
||||
if (!_veins.TryGetValue(productId, out veins))
|
||||
break;
|
||||
length = veins.Count - 1;
|
||||
}
|
||||
|
||||
return (total, energy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,3 @@
|
||||
* The same speed as normal Mining Machine for normal ores and 100/s for water.
|
||||
* Energy costs: 200kJ for each vein or oil, 50kJ for each water. `Veins Utilization` upgrades does not increase power consumption.
|
||||
* `Veins Utilization` upgrades affects mining speed and ore consume as normal.
|
||||
### TODO
|
||||
* Make Oil mining logic the same as normal (reduce speed periodically)
|
||||
* Support mining scale in config
|
||||
Reference in New Issue
Block a user