mirror of
https://github.com/soarqin/DSP_Mods.git
synced 2025-12-08 20:13:29 +08:00
338 lines
12 KiB
C#
338 lines
12 KiB
C#
using System;
|
|
using BepInEx.Configuration;
|
|
using HarmonyLib;
|
|
using UXAssist.Common;
|
|
using Random = UnityEngine.Random;
|
|
using GameLogicProc = UXAssist.Common.GameLogic;
|
|
|
|
namespace LogisticHub.Module;
|
|
|
|
public class Miner : PatchImpl<Miner>
|
|
{
|
|
public static ConfigEntry<bool> Enabled;
|
|
public static ConfigEntry<long> OreEnergyConsume;
|
|
public static ConfigEntry<long> OilEnergyConsume;
|
|
public static ConfigEntry<long> WaterEnergyConsume;
|
|
public static ConfigEntry<int> WaterSpeed;
|
|
public static ConfigEntry<int> MiningScale;
|
|
public static ConfigEntry<int> FuelIlsSlot;
|
|
public static ConfigEntry<int> FuelPlsSlot;
|
|
|
|
private static long _frame;
|
|
private static float _miningCostRateByTech;
|
|
private static long _miningFrames;
|
|
private static long _miningSpeedScaleLong;
|
|
private static bool _advancedMiningMachineUnlocked;
|
|
private static uint _miningCostBarrier;
|
|
private static uint _miningCostBarrierOil;
|
|
private static int[] _mineIndex;
|
|
|
|
private static uint _miningSeed = (uint)Random.Range(0, int.MaxValue);
|
|
|
|
private static readonly (int, int)[] VeinList =
|
|
[
|
|
(0, 1000),
|
|
(1, 1001),
|
|
(2, 1002),
|
|
(3, 1003),
|
|
(4, 1004),
|
|
(5, 1005),
|
|
(6, 1006),
|
|
(7, 1007),
|
|
(11, 1011),
|
|
(12, 1012),
|
|
(13, 1013),
|
|
(14, 1014),
|
|
(15, 1015),
|
|
(16, 1016)
|
|
];
|
|
|
|
public static void Init()
|
|
{
|
|
Enabled.SettingChanged += (_, _) => { Enable(Enabled.Value); };
|
|
|
|
Enable(Enabled.Value);
|
|
}
|
|
|
|
public static void Uninit()
|
|
{
|
|
Enable(false);
|
|
}
|
|
|
|
protected override void OnEnable()
|
|
{
|
|
GameLogicProc.OnGameBegin += OnGameBegin;
|
|
}
|
|
|
|
protected override void OnDisable()
|
|
{
|
|
GameLogicProc.OnGameBegin -= OnGameBegin;
|
|
}
|
|
|
|
private static void OnGameBegin()
|
|
{
|
|
_frame = 0L;
|
|
UpdateMiningCostRate();
|
|
UpdateSpeedScale();
|
|
CheckRecipes();
|
|
}
|
|
|
|
private static int SplitIncLevel(ref int n, ref int m, int p)
|
|
{
|
|
var level = m / n;
|
|
var left = m - level * n;
|
|
n -= p;
|
|
left -= n;
|
|
m -= left > 0 ? level * p + left : level * p;
|
|
return level;
|
|
}
|
|
|
|
private static void CheckRecipes()
|
|
{
|
|
_advancedMiningMachineUnlocked = GameMain.history.recipeUnlocked.Contains(119);
|
|
}
|
|
|
|
private static void UpdateMiningCostRate()
|
|
{
|
|
_miningCostRateByTech = GameMain.history.miningCostRate;
|
|
_miningCostBarrier = (uint)(int)Math.Ceiling(2147483646.0 * _miningCostRateByTech);
|
|
_miningCostBarrierOil = (uint)(int)Math.Ceiling(2147483646.0 * _miningCostRateByTech * 0.401116669f / Math.Max(DSPGame.GameDesc.resourceMultiplier, 0.416666657f));
|
|
}
|
|
|
|
private static void UpdateSpeedScale()
|
|
{
|
|
_miningSpeedScaleLong = (long)Math.Round(GameMain.history.miningSpeedScale * 100f);
|
|
_miningFrames = _miningSpeedScaleLong * 6000L;
|
|
}
|
|
|
|
[HarmonyPostfix]
|
|
[HarmonyPatch(typeof(GameHistoryData), nameof(GameHistoryData.UnlockTechFunction))]
|
|
private static void OnUnlockTech(int func)
|
|
{
|
|
switch (func)
|
|
{
|
|
case 20:
|
|
UpdateMiningCostRate();
|
|
break;
|
|
case 21:
|
|
UpdateSpeedScale();
|
|
break;
|
|
}
|
|
}
|
|
|
|
[HarmonyPrefix]
|
|
[HarmonyPatch(typeof(GameLogic), nameof(GameLogic.OnFactoryFrameBegin))]
|
|
private static void GameLogic_OnFactoryFrameBegin_Prefix()
|
|
{
|
|
var main = GameMain.instance;
|
|
if (main.isMenuDemo) return;
|
|
if (_miningSpeedScaleLong <= 0L) return;
|
|
|
|
if (main.timei % 60 != 0) return;
|
|
_frame += _miningFrames;
|
|
var frameCounter = _frame / 1200000L;
|
|
if (frameCounter <= 0) return;
|
|
_frame -= frameCounter * 1200000L;
|
|
|
|
DeepProfiler.BeginSample(DPEntry.Miner);
|
|
var data = GameMain.data;
|
|
if (_mineIndex == null || data.factoryCount > _mineIndex.Length)
|
|
Array.Resize(ref _mineIndex, data.factoryCount);
|
|
var factoryStatPool = GameMain.statistics.production.factoryStatPool;
|
|
for (var factoryIndex = data.factoryCount - 1; factoryIndex >= 0; factoryIndex--)
|
|
{
|
|
var factory = data.factories[factoryIndex];
|
|
var veins = VeinManager.GetVeins(factoryIndex);
|
|
if (veins == null) continue;
|
|
var stations = StationManager.GetStations(factoryIndex);
|
|
var planetTransport = factory.transport;
|
|
var productRegister = factoryStatPool[factoryIndex]?.productRegister;
|
|
var demands = stations.StorageIndices[1];
|
|
if (demands == null) continue;
|
|
foreach (var (itemIndex, itemId) in VeinList)
|
|
{
|
|
if (itemIndex >= demands.Length) continue;
|
|
var demandList = demands[itemIndex];
|
|
if (demandList == null) continue;
|
|
foreach (var storageIndex in demandList)
|
|
{
|
|
var station = planetTransport.stationPool[storageIndex / 100];
|
|
if (station == null)
|
|
continue;
|
|
ref var storage = ref station.storage[storageIndex % 100];
|
|
if (storage.count >= storage.max) continue;
|
|
int amount;
|
|
long energyConsume;
|
|
var miningScale = MiningScale.Value;
|
|
if (miningScale == 0)
|
|
{
|
|
miningScale = _advancedMiningMachineUnlocked ? 300 : 100;
|
|
}
|
|
if (miningScale > 100 && storage.count * 2 > storage.max)
|
|
{
|
|
miningScale = 100 + ((miningScale - 100) * (storage.max - storage.count) * 2 + storage.max - 1) / storage.max;
|
|
}
|
|
|
|
if (itemIndex > 0)
|
|
{
|
|
(amount, energyConsume) = Mine(factory, veins, itemId, miningScale, (int)frameCounter, station.energy);
|
|
if (amount < 0) continue;
|
|
}
|
|
else
|
|
{
|
|
energyConsume = (WaterEnergyConsume.Value * frameCounter * miningScale * miningScale + 9999L) / 10000L;
|
|
if (station.energy < energyConsume) continue;
|
|
amount = WaterSpeed.Value * miningScale / 100;
|
|
}
|
|
|
|
if (amount <= 0) continue;
|
|
storage.count += amount;
|
|
if (productRegister != null)
|
|
productRegister[itemId] += amount;
|
|
station.energy -= energyConsume;
|
|
}
|
|
}
|
|
|
|
for (var i = planetTransport.stationCursor - 1; i > 0; i--)
|
|
{
|
|
var stationComponent = planetTransport.stationPool[i];
|
|
if (stationComponent == null || stationComponent.isCollector || stationComponent.isVeinCollector || stationComponent.energy * 2 >= stationComponent.energyMax) continue;
|
|
var index = (stationComponent.isStellar ? FuelIlsSlot.Value : FuelPlsSlot.Value) - 1;
|
|
var storage = stationComponent.storage;
|
|
if (index < 0 || index >= storage.Length)
|
|
continue;
|
|
var fuelCount = storage[index].count;
|
|
if (fuelCount == 0) continue;
|
|
var (heat, prod) = AuxData.Fuels[storage[index].itemId];
|
|
if (heat <= 0)
|
|
continue;
|
|
/* Sprayed fuels */
|
|
int pretendIncLevel;
|
|
if (prod && (pretendIncLevel = storage[index].inc / storage[index].count) > 0)
|
|
{
|
|
var count = (int)((stationComponent.energyMax - stationComponent.energy) * 1000L / Cargo.incTable[pretendIncLevel] / 7L);
|
|
if (count > fuelCount)
|
|
count = fuelCount;
|
|
var incLevel = SplitIncLevel(ref storage[index].count, ref storage[index].inc, count);
|
|
if (incLevel > 10)
|
|
incLevel = 10;
|
|
stationComponent.energy += heat * count * (1000L + Cargo.incTable[incLevel]) / 1000L;
|
|
}
|
|
else
|
|
{
|
|
var count = (int)((stationComponent.energyMax - stationComponent.energy) / heat);
|
|
if (count > fuelCount)
|
|
count = fuelCount;
|
|
SplitIncLevel(ref storage[index].count, ref storage[index].inc, count);
|
|
stationComponent.energy += heat * count;
|
|
}
|
|
}
|
|
}
|
|
|
|
DeepProfiler.EndSample(DPEntry.Miner);
|
|
}
|
|
|
|
[HarmonyPostfix]
|
|
[HarmonyPatch(typeof(GameHistoryData), nameof(GameHistoryData.UnlockRecipe))]
|
|
private static void OnUnlockRecipe(int recipeId)
|
|
{
|
|
if (recipeId == 119)
|
|
{
|
|
CheckRecipes();
|
|
}
|
|
}
|
|
|
|
private static (int, long) Mine(PlanetFactory factory, ProductVeinData[] allVeins, int productId, int percent, int counter, long energyMax)
|
|
{
|
|
var veins = allVeins[productId - 1000];
|
|
if (veins == null)
|
|
return (-1, -1L);
|
|
|
|
var veinIndices = veins.VeinIndices;
|
|
uint barrier;
|
|
int limit;
|
|
int count;
|
|
long energy;
|
|
var length = veinIndices.Count - 1;
|
|
/* if is Oil */
|
|
if (productId == 1007)
|
|
{
|
|
energy = (OilEnergyConsume.Value * length * percent * percent + 9999L) / 10000L;
|
|
if (energy > energyMax)
|
|
return (-1, -1L);
|
|
var countf = 0f;
|
|
var veinsPool = factory.veinPool;
|
|
for (var i = length; i > 0; i--)
|
|
{
|
|
countf += veinsPool[veinIndices[i]].amount * 4 * VeinData.oilSpeedMultiplier;
|
|
}
|
|
|
|
count = ((int)countf * counter * percent + 99) / 100;
|
|
if (count == 0)
|
|
return (-1, -1L);
|
|
barrier = _miningCostBarrierOil;
|
|
limit = 2500;
|
|
}
|
|
else
|
|
{
|
|
count = (length * counter * percent + 99) / 100;
|
|
if (count == 0)
|
|
return (-1, -1L);
|
|
energy = (OreEnergyConsume.Value * veins.GroupCount * percent * percent + 9999L) / 10000L;
|
|
if (energy > energyMax)
|
|
return (-1, -1L);
|
|
barrier = _miningCostBarrier;
|
|
limit = 0;
|
|
}
|
|
|
|
var veinsData = factory.veinPool;
|
|
var total = 0;
|
|
var factoryIndex = factory.index;
|
|
var mineIndex = _mineIndex[factoryIndex];
|
|
for (; count > 0; count--)
|
|
{
|
|
mineIndex = mineIndex % length + 1;
|
|
var index = veinIndices[mineIndex];
|
|
ref var vd = ref veinsData[index];
|
|
int groupIndex;
|
|
|
|
if (vd.amount <= 0)
|
|
{
|
|
groupIndex = vd.groupIndex;
|
|
factory.veinGroups[groupIndex].count--;
|
|
factory.RemoveVeinWithComponents(index);
|
|
factory.RecalculateVeinGroup(groupIndex);
|
|
length = veinIndices.Count - 1;
|
|
if (length <= 0) break;
|
|
continue;
|
|
}
|
|
|
|
total++;
|
|
|
|
if (vd.amount <= limit) continue;
|
|
var consume = true;
|
|
if (barrier < 2147483646u)
|
|
{
|
|
_miningSeed = (uint)((int)((ulong)((_miningSeed % 2147483646u + 1) * 48271L) % 2147483647uL) - 1);
|
|
consume = _miningSeed < barrier;
|
|
}
|
|
|
|
if (!consume) continue;
|
|
|
|
vd.amount--;
|
|
groupIndex = vd.groupIndex;
|
|
factory.veinGroups[groupIndex].amount--;
|
|
|
|
if (vd.amount > 0) continue;
|
|
factory.veinGroups[groupIndex].count--;
|
|
factory.RemoveVeinWithComponents(index);
|
|
factory.RecalculateVeinGroup(groupIndex);
|
|
length = veinIndices.Count - 1;
|
|
if (length <= 0) break;
|
|
}
|
|
|
|
_mineIndex[factoryIndex] = mineIndex;
|
|
|
|
return (total, energy);
|
|
}
|
|
} |