mirror of
https://github.com/soarqin/DSP_Mods.git
synced 2025-12-09 03:33:29 +08:00
Compare commits
11 Commits
77f5803a24
...
logistic_h
| Author | SHA1 | Date | |
|---|---|---|---|
| 09cdaf3a12 | |||
| 8d5bb140e1 | |||
| c99c59a117 | |||
| 61811f9a8c | |||
| cf3117e0da | |||
| dfd34601cf | |||
| 6934607fca | |||
| be9de43492 | |||
| 2dbf017a5e | |||
| 3c7744047c | |||
| a9959a2f07 |
Binary file not shown.
Binary file not shown.
@@ -4,7 +4,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UXAssist", "UXAssist\UXAssi
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CheatEnabler", "CheatEnabler\CheatEnabler.csproj", "{F9F16B62-D1D3-466B-BE22-E64B9EA957C2}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CheatEnabler", "CheatEnabler\CheatEnabler.csproj", "{F9F16B62-D1D3-466B-BE22-E64B9EA957C2}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LogisticMiner", "LogisticMiner\LogisticMiner.csproj", "{7149D717-C913-4153-9425-38CB9D087F83}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LogisticHub", "LogisticHub\LogisticHub.csproj", "{7149D717-C913-4153-9425-38CB9D087F83}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HideTips", "HideTips\HideTips.csproj", "{4EABD71D-477F-448B-801B-48F8745A3FA7}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HideTips", "HideTips\HideTips.csproj", "{4EABD71D-477F-448B-801B-48F8745A3FA7}"
|
||||||
EndProject
|
EndProject
|
||||||
|
|||||||
57
LogisticHub/LogisticHub.cs
Normal file
57
LogisticHub/LogisticHub.cs
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using BepInEx;
|
||||||
|
using BepInEx.Configuration;
|
||||||
|
using HarmonyLib;
|
||||||
|
using UXAssist.Common;
|
||||||
|
|
||||||
|
namespace LogisticHub;
|
||||||
|
|
||||||
|
[BepInPlugin(PluginInfo.PLUGIN_GUID, PluginInfo.PLUGIN_NAME, PluginInfo.PLUGIN_VERSION)]
|
||||||
|
public class LogisticHub : BaseUnityPlugin
|
||||||
|
{
|
||||||
|
public new static readonly BepInEx.Logging.ManualLogSource Logger =
|
||||||
|
BepInEx.Logging.Logger.CreateLogSource(PluginInfo.PLUGIN_NAME);
|
||||||
|
|
||||||
|
private Type[] _modules;
|
||||||
|
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
Module.Miner.Enabled = Config.Bind("Miner", "Enabled", true, "enable/disable this plugin");
|
||||||
|
Module.Miner.OreEnergyConsume = Config.Bind("Miner", "EnergyConsumptionForOre", 2000000L,
|
||||||
|
"Energy consumption for each ore vein group(in W)");
|
||||||
|
Module.Miner.OreMiningMultiplier = Config.Bind("Miner", "OreMiningMultiplier", 3,
|
||||||
|
new ConfigDescription("Mining multiplier for ore veins, multiplies to the number of veins in the group", new AcceptableValueRange<int>(1, 100)));
|
||||||
|
Module.Miner.OreMiningScale = Config.Bind("Miner", "OreMiningScale", 100,
|
||||||
|
"""
|
||||||
|
0 for Auto(which means having researched advanced mining machine makes mining scale 300, otherwise 100).
|
||||||
|
Mining scale(in percents) for slots below half of slot limits, and the scale reduces to 100% smoothly till reach full.
|
||||||
|
Please note that the power consumption increases by the square of the scale which is the same as Advanced Mining Machine.
|
||||||
|
""");
|
||||||
|
Module.Miner.OilEnergyConsume = Config.Bind("Miner", "EnergyConsumptionForOil", 1800000L,
|
||||||
|
"Energy consumption for each oil seep(in W)");
|
||||||
|
Module.Miner.WaterEnergyConsume = Config.Bind("Miner", "EnergyConsumptionForWater", 2000000L,
|
||||||
|
"Energy consumption for water slot(in W)");
|
||||||
|
Module.Miner.WaterSpeed = Config.Bind("Miner", "WaterMiningSpeed", 10,
|
||||||
|
"Water mining speed (count per second)");
|
||||||
|
Module.Miner.FuelIlsSlot = Config.Bind("Miner", "ILSFuelSlot", 4,
|
||||||
|
new ConfigDescription("Fuel slot for ILS, set 0 to disable.", new AcceptableValueRange<int>(0, 5)));
|
||||||
|
Module.Miner.FuelPlsSlot = Config.Bind("Miner", "PLSFuelSlot", 4,
|
||||||
|
new ConfigDescription("Fuel slot for PLS, set 0 to disable.", new AcceptableValueRange<int>(0, 4)));
|
||||||
|
|
||||||
|
_modules = Util.GetTypesFiltered(Assembly.GetExecutingAssembly(),
|
||||||
|
t => string.Equals(t.Namespace, "LogisticHub.Module", StringComparison.Ordinal));
|
||||||
|
_modules?.Do(type => type.GetMethod("Init")?.Invoke(null, null));
|
||||||
|
Harmony.CreateAndPatchAll(typeof(LogisticHub));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Start()
|
||||||
|
{
|
||||||
|
_modules?.Do(type => type.GetMethod("Start")?.Invoke(null, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDestroy()
|
||||||
|
{
|
||||||
|
_modules?.Do(type => type.GetMethod("Uninit")?.Invoke(null, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
39
LogisticHub/LogisticHub.csproj
Normal file
39
LogisticHub/LogisticHub.csproj
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net472</TargetFramework>
|
||||||
|
<BepInExPluginGuid>org.soardev.logistichub</BepInExPluginGuid>
|
||||||
|
<Description>DSP MOD - LogisticHub</Description>
|
||||||
|
<Version>0.1.0</Version>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
<RestoreAdditionalProjectSources>https://nuget.bepinex.dev/v3/index.json</RestoreAdditionalProjectSources>
|
||||||
|
<PackageId>LogisticHub</PackageId>
|
||||||
|
<RootNamespace>LogisticHub</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="BepInEx.Core" Version="5.*" />
|
||||||
|
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" />
|
||||||
|
<PackageReference Include="UnityEngine.Modules" Version="2022.3.53" IncludeAssets="compile" />
|
||||||
|
<!-- <PackageReference Include="DysonSphereProgram.GameLibs" Version="0.10.32.*-r.*" /> -->
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Assembly-CSharp">
|
||||||
|
<HintPath>..\AssemblyFromGame\Assembly-CSharp.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="UnityEngine.UI">
|
||||||
|
<HintPath>..\AssemblyFromGame\UnityEngine.UI.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\UXAssist\UXAssist.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'">
|
||||||
|
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
33
LogisticHub/Module/AuxData.cs
Normal file
33
LogisticHub/Module/AuxData.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace LogisticHub.Module;
|
||||||
|
|
||||||
|
using UXAssist.Common;
|
||||||
|
|
||||||
|
public static class AuxData
|
||||||
|
{
|
||||||
|
public static (long, bool)[] Fuels;
|
||||||
|
|
||||||
|
public static void Init()
|
||||||
|
{
|
||||||
|
GameLogic.OnDataLoaded += () =>
|
||||||
|
{
|
||||||
|
var maxId = LDB.items.dataArray.Select(data => data.ID).Prepend(0).Max();
|
||||||
|
Fuels = new (long, bool)[maxId + 1];
|
||||||
|
foreach (var data in LDB.items.dataArray)
|
||||||
|
Fuels[data.ID] = (data.HeatValue, data.Productive);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int AlignUpToPowerOf2(int n)
|
||||||
|
{
|
||||||
|
if (n < 16) return 16;
|
||||||
|
n--;
|
||||||
|
n |= n >> 1;
|
||||||
|
n |= n >> 2;
|
||||||
|
n |= n >> 4;
|
||||||
|
n |= n >> 8;
|
||||||
|
n |= n >> 16;
|
||||||
|
return n + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
0
LogisticHub/Module/Ejector.cs
Normal file
0
LogisticHub/Module/Ejector.cs
Normal file
345
LogisticHub/Module/Miner.cs
Normal file
345
LogisticHub/Module/Miner.cs
Normal file
@@ -0,0 +1,345 @@
|
|||||||
|
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<int> OreMiningScale;
|
||||||
|
public static ConfigEntry<int> OreMiningMultiplier;
|
||||||
|
public static ConfigEntry<long> OilEnergyConsume;
|
||||||
|
public static ConfigEntry<long> WaterEnergyConsume;
|
||||||
|
public static ConfigEntry<int> WaterSpeed;
|
||||||
|
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 int _miningMultiplier = 3;
|
||||||
|
private static int _miningScale = 100;
|
||||||
|
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);
|
||||||
|
_miningMultiplier = OreMiningMultiplier.Value;
|
||||||
|
if (OreMiningScale.Value == 0)
|
||||||
|
{
|
||||||
|
_miningScale = _advancedMiningMachineUnlocked ? 300 : 100;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_miningScale = OreMiningScale.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
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, _miningMultiplier, 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, int multiplier, 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;
|
||||||
|
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) / 100f);
|
||||||
|
if (count == 0)
|
||||||
|
return (-1, -1L);
|
||||||
|
barrier = _miningCostBarrierOil;
|
||||||
|
limit = 2500;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
count = (length * multiplier * 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
325
LogisticHub/Module/StationManager.cs
Normal file
325
LogisticHub/Module/StationManager.cs
Normal file
@@ -0,0 +1,325 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using HarmonyLib;
|
||||||
|
using UXAssist.Common;
|
||||||
|
using GameLogicProc = UXAssist.Common.GameLogic;
|
||||||
|
|
||||||
|
namespace LogisticHub.Module;
|
||||||
|
|
||||||
|
public class PlanetStations
|
||||||
|
{
|
||||||
|
public readonly List<int>[][] StorageIndices = [null, null];
|
||||||
|
|
||||||
|
public void AddStationStorage(bool demand, int id, int stationId, int storageIdx)
|
||||||
|
{
|
||||||
|
LogisticHub.Logger.LogDebug($"AddStationStorage: demand={demand}, id={id}, stationId={stationId}, storageIdx={storageIdx}");
|
||||||
|
var stations = StorageIndices[demand ? 1 : 0];
|
||||||
|
if (stations == null || id >= stations.Length)
|
||||||
|
{
|
||||||
|
Array.Resize(ref stations, AuxData.AlignUpToPowerOf2(id + 1));
|
||||||
|
StorageIndices[demand ? 1 : 0] = stations;
|
||||||
|
}
|
||||||
|
|
||||||
|
var list = stations[id];
|
||||||
|
if (list == null)
|
||||||
|
{
|
||||||
|
list = [];
|
||||||
|
stations[id] = list;
|
||||||
|
}
|
||||||
|
|
||||||
|
var value = stationId * 100 + storageIdx;
|
||||||
|
var index = list.BinarySearch(value);
|
||||||
|
if (index < 0)
|
||||||
|
list.Insert(~index, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveStationStorage(bool demand, int id, int stationId, int storageIdx)
|
||||||
|
{
|
||||||
|
var stations = StorageIndices[demand ? 1 : 0];
|
||||||
|
if (stations == null || id >= stations.Length)
|
||||||
|
return;
|
||||||
|
var list = stations[id];
|
||||||
|
if (list == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var value = stationId * 100 + storageIdx;
|
||||||
|
var index = list.BinarySearch(value);
|
||||||
|
if (index >= 0)
|
||||||
|
list.RemoveAt(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class StationManager : PatchImpl<StationManager>
|
||||||
|
{
|
||||||
|
private static PlanetStations[] _stations;
|
||||||
|
|
||||||
|
public static void Init()
|
||||||
|
{
|
||||||
|
GameLogicProc.OnGameBegin += OnGameBegin;
|
||||||
|
Enable(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Uninit()
|
||||||
|
{
|
||||||
|
GameLogicProc.OnGameBegin -= OnGameBegin;
|
||||||
|
Enable(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnGameBegin()
|
||||||
|
{
|
||||||
|
_stations = null;
|
||||||
|
var data = GameMain.data;
|
||||||
|
for (var index = data.factoryCount - 1; index >= 0; index--)
|
||||||
|
{
|
||||||
|
var factory = data.factories[index];
|
||||||
|
if (factory == null || factory.index != index) continue;
|
||||||
|
var planetIndex = factory.index;
|
||||||
|
var stations = StationsByPlanet(planetIndex);
|
||||||
|
var transport = factory.transport;
|
||||||
|
var pool = transport.stationPool;
|
||||||
|
for (var i = transport.stationCursor - 1; i > 0; i--)
|
||||||
|
{
|
||||||
|
var station = pool[i];
|
||||||
|
if (station == null || station.id != i || station.isCollector || station.isVeinCollector) continue;
|
||||||
|
UpdateStationInfo(stations, station);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int ItemIdToIndex(int itemId)
|
||||||
|
{
|
||||||
|
return itemId switch
|
||||||
|
{
|
||||||
|
>= 1000 and < 2000 => itemId - 1000,
|
||||||
|
>= 5000 and < 5050 => itemId - 5000 + 900,
|
||||||
|
>= 6000 and < 6050 => itemId - 6000 + 950,
|
||||||
|
_ => -1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int IndexToItemId(int index)
|
||||||
|
{
|
||||||
|
return index switch
|
||||||
|
{
|
||||||
|
< 900 => index + 1000,
|
||||||
|
< 950 => index - 900 + 5000,
|
||||||
|
< 1000 => index - 950 + 6000,
|
||||||
|
_ => -1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PlanetStations GetStations(int planetIndex)
|
||||||
|
{
|
||||||
|
return _stations != null && planetIndex < _stations.Length ? _stations[planetIndex] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PlanetStations StationsByPlanet(int planetIndex)
|
||||||
|
{
|
||||||
|
if (_stations == null || _stations.Length <= planetIndex)
|
||||||
|
Array.Resize(ref _stations, AuxData.AlignUpToPowerOf2(planetIndex + 1));
|
||||||
|
var stations = _stations[planetIndex];
|
||||||
|
if (stations != null) return stations;
|
||||||
|
stations = new PlanetStations();
|
||||||
|
_stations[planetIndex] = stations;
|
||||||
|
return stations;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DebugLog()
|
||||||
|
{
|
||||||
|
for (var idx = 0; idx < _stations.Length; idx++)
|
||||||
|
{
|
||||||
|
var stations = _stations[idx];
|
||||||
|
if (stations == null) continue;
|
||||||
|
LogisticHub.Logger.LogDebug($"Planet {idx}:");
|
||||||
|
for (var i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
var storage = stations.StorageIndices[i];
|
||||||
|
if (storage == null) continue;
|
||||||
|
LogisticHub.Logger.LogDebug(i == 1 ? " Demand:" : " Supply:");
|
||||||
|
for (var j = 0; j < storage.Length; j++)
|
||||||
|
{
|
||||||
|
var list = storage[j];
|
||||||
|
if (list == null) continue;
|
||||||
|
var count = list.Count;
|
||||||
|
if (count <= 0) continue;
|
||||||
|
var itemId = IndexToItemId(j);
|
||||||
|
LogisticHub.Logger.LogDebug($" {itemId}: {string.Join(", ", list)}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void UpdateStationInfo(PlanetStations stations, StationComponent station, int storageIdx = -1)
|
||||||
|
{
|
||||||
|
var storage = station.storage;
|
||||||
|
var stationId = station.id;
|
||||||
|
if (storageIdx >= 0)
|
||||||
|
{
|
||||||
|
if (storageIdx >= storage.Length) return;
|
||||||
|
var itemId = ItemIdToIndex(storage[storageIdx].itemId);
|
||||||
|
if (itemId <= 0) return;
|
||||||
|
var logic = storage[storageIdx].localLogic;
|
||||||
|
switch (logic)
|
||||||
|
{
|
||||||
|
case ELogisticStorage.Demand:
|
||||||
|
stations.AddStationStorage(true, itemId, stationId, storageIdx);
|
||||||
|
break;
|
||||||
|
case ELogisticStorage.Supply:
|
||||||
|
stations.AddStationStorage(false, itemId, stationId, storageIdx);
|
||||||
|
break;
|
||||||
|
case ELogisticStorage.None:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = storage.Length - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
var itemId = ItemIdToIndex(storage[i].itemId);
|
||||||
|
if (itemId <= 0) continue;
|
||||||
|
var logic = storage[i].localLogic;
|
||||||
|
switch (logic)
|
||||||
|
{
|
||||||
|
case ELogisticStorage.Demand:
|
||||||
|
stations.AddStationStorage(true, itemId, stationId, i);
|
||||||
|
break;
|
||||||
|
case ELogisticStorage.Supply:
|
||||||
|
stations.AddStationStorage(false, itemId, stationId, i);
|
||||||
|
break;
|
||||||
|
case ELogisticStorage.None:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RemoveStationInfo(PlanetStations stations, StationComponent station, int storageIdx = -1)
|
||||||
|
{
|
||||||
|
var storage = station.storage;
|
||||||
|
var stationId = station.id;
|
||||||
|
if (storageIdx >= 0)
|
||||||
|
{
|
||||||
|
var itemId = ItemIdToIndex(storage[storageIdx].itemId);
|
||||||
|
if (itemId <= 0) return;
|
||||||
|
var logic = storage[storageIdx].localLogic;
|
||||||
|
switch (logic)
|
||||||
|
{
|
||||||
|
case ELogisticStorage.Demand:
|
||||||
|
stations.RemoveStationStorage(true, itemId, stationId, storageIdx);
|
||||||
|
break;
|
||||||
|
case ELogisticStorage.Supply:
|
||||||
|
stations.RemoveStationStorage(false, itemId, stationId, storageIdx);
|
||||||
|
break;
|
||||||
|
case ELogisticStorage.None:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = storage.Length - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
var itemId = ItemIdToIndex(storage[i].itemId);
|
||||||
|
if (itemId <= 0) continue;
|
||||||
|
var logic = storage[i].localLogic;
|
||||||
|
switch (logic)
|
||||||
|
{
|
||||||
|
case ELogisticStorage.Demand:
|
||||||
|
stations.RemoveStationStorage(true, itemId, stationId, i);
|
||||||
|
break;
|
||||||
|
case ELogisticStorage.Supply:
|
||||||
|
stations.RemoveStationStorage(false, itemId, stationId, i);
|
||||||
|
break;
|
||||||
|
case ELogisticStorage.None:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(typeof(PlanetTransport), nameof(PlanetTransport.Init))]
|
||||||
|
private static void PlanetTransport_Init_Postfix(PlanetTransport __instance)
|
||||||
|
{
|
||||||
|
var factory = __instance.factory;
|
||||||
|
var planetIndex = factory.index;
|
||||||
|
|
||||||
|
if (_stations == null || _stations.Length <= planetIndex)
|
||||||
|
Array.Resize(ref _stations, AuxData.AlignUpToPowerOf2(planetIndex + 1));
|
||||||
|
var stations = new PlanetStations();
|
||||||
|
_stations[planetIndex] = stations;
|
||||||
|
|
||||||
|
var pool = __instance.stationPool;
|
||||||
|
for (var i = __instance.stationCursor - 1; i > 0; i--)
|
||||||
|
{
|
||||||
|
var station = pool[i];
|
||||||
|
if (station == null || station.id != i || station.isCollector || station.isVeinCollector) continue;
|
||||||
|
UpdateStationInfo(stations, station);
|
||||||
|
}
|
||||||
|
// DebugLog();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(typeof(BuildingParameters), nameof(BuildingParameters.ApplyPrebuildParametersToEntity))]
|
||||||
|
private static void BuildingParameters_ApplyPrebuildParametersToEntity_Postfix(int entityId, PlanetFactory factory)
|
||||||
|
{
|
||||||
|
if (entityId <= 0) return;
|
||||||
|
ref var entity = ref factory.entityPool[entityId];
|
||||||
|
var stationId = entity.stationId;
|
||||||
|
if (stationId <= 0) return;
|
||||||
|
var station = factory.transport.stationPool[stationId];
|
||||||
|
if (station == null || station.id != stationId || station.isCollector || station.isVeinCollector) return;
|
||||||
|
UpdateStationInfo(StationsByPlanet(factory.index), station);
|
||||||
|
// DebugLog();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPrefix]
|
||||||
|
[HarmonyPatch(typeof(PlanetTransport), nameof(PlanetTransport.RemoveStationComponent))]
|
||||||
|
private static void PlanetTransport_RemoveStationComponent_Prefix(PlanetTransport __instance, int id)
|
||||||
|
{
|
||||||
|
if (id <= 0) return;
|
||||||
|
var station = __instance.stationPool[id];
|
||||||
|
if (station == null || station.id != id || station.isCollector || station.isVeinCollector) return;
|
||||||
|
RemoveStationInfo(StationsByPlanet(__instance.factory.index), station);
|
||||||
|
// DebugLog();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPrefix]
|
||||||
|
[HarmonyPatch(typeof(PlanetTransport), nameof(PlanetTransport.SetStationStorage))]
|
||||||
|
private static void PlanetTransport_SetStationStorage_Prefix(PlanetTransport __instance, int stationId, int storageIdx, int itemId, ELogisticStorage localLogic, out bool __state)
|
||||||
|
{
|
||||||
|
var station = __instance.stationPool[stationId];
|
||||||
|
if (station == null || station.id != stationId || station.isCollector || station.isVeinCollector || storageIdx < 0 || storageIdx >= station.storage.Length)
|
||||||
|
{
|
||||||
|
__state = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ref var storage = ref station.storage[storageIdx];
|
||||||
|
var oldItemId = storage.itemId;
|
||||||
|
var oldLocalLogic = storage.localLogic;
|
||||||
|
if (localLogic == oldLocalLogic && itemId == oldItemId)
|
||||||
|
{
|
||||||
|
__state = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldItemId > 0 && oldLocalLogic != ELogisticStorage.None)
|
||||||
|
RemoveStationInfo(StationsByPlanet(__instance.factory.index), station, storageIdx);
|
||||||
|
__state = localLogic != ELogisticStorage.None;
|
||||||
|
// if (!__state) DebugLog();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(typeof(PlanetTransport), nameof(PlanetTransport.SetStationStorage))]
|
||||||
|
private static void PlanetTransport_SetStationStorage_Postfix(PlanetTransport __instance, int stationId, int storageIdx, bool __state)
|
||||||
|
{
|
||||||
|
if (!__state) return;
|
||||||
|
var station = __instance.stationPool[stationId];
|
||||||
|
UpdateStationInfo(StationsByPlanet(__instance.factory.index), station, storageIdx);
|
||||||
|
// DebugLog();
|
||||||
|
}
|
||||||
|
}
|
||||||
123
LogisticHub/Module/VeinManager.cs
Normal file
123
LogisticHub/Module/VeinManager.cs
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using HarmonyLib;
|
||||||
|
using UXAssist.Common;
|
||||||
|
using GameLogicProc = UXAssist.Common.GameLogic;
|
||||||
|
|
||||||
|
namespace LogisticHub.Module;
|
||||||
|
|
||||||
|
public class ProductVeinData
|
||||||
|
{
|
||||||
|
public readonly List<int> VeinIndices = [];
|
||||||
|
public readonly HashSet<int> GroupIndices = [];
|
||||||
|
public int GroupCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class VeinManager : PatchImpl<VeinManager>
|
||||||
|
{
|
||||||
|
private static ProductVeinData[][] _veins;
|
||||||
|
|
||||||
|
public static void Init()
|
||||||
|
{
|
||||||
|
Enable(true);
|
||||||
|
GameLogicProc.OnGameBegin += OnGameBegin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Uninit()
|
||||||
|
{
|
||||||
|
GameLogicProc.OnGameBegin -= OnGameBegin;
|
||||||
|
Enable(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnGameBegin()
|
||||||
|
{
|
||||||
|
_veins = null;
|
||||||
|
var data = GameMain.data;
|
||||||
|
for (var index = data.factoryCount - 1; index >= 0; index--)
|
||||||
|
{
|
||||||
|
var factory = data.factories[index];
|
||||||
|
if (factory == null || factory.index != index) continue;
|
||||||
|
RecalcVeins(factory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProductVeinData[] GetVeins(int planetIndex)
|
||||||
|
{
|
||||||
|
if (_veins == null || _veins.Length <= planetIndex)
|
||||||
|
return null;
|
||||||
|
return _veins[planetIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ProductVeinData[] GetOrCreateVeins(int planetIndex)
|
||||||
|
{
|
||||||
|
if (_veins == null || _veins.Length <= planetIndex)
|
||||||
|
Array.Resize(ref _veins, AuxData.AlignUpToPowerOf2(planetIndex + 1));
|
||||||
|
var veins = _veins[planetIndex];
|
||||||
|
if (veins != null) return veins;
|
||||||
|
veins = new ProductVeinData[20];
|
||||||
|
_veins[planetIndex] = veins;
|
||||||
|
return veins;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPostfix]
|
||||||
|
[HarmonyPatch(typeof(PlanetFactory), nameof(PlanetFactory.Init))]
|
||||||
|
[HarmonyPatch(typeof(PlanetFactory), nameof(PlanetFactory.RecalculateVeinGroup))]
|
||||||
|
[HarmonyPatch(typeof(PlanetFactory), nameof(PlanetFactory.RecalculateAllVeinGroups))]
|
||||||
|
private static void PlanetFactory_RecalculateAllVeinGroups_Postfix(PlanetFactory __instance)
|
||||||
|
{
|
||||||
|
RecalcVeins(__instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DebugLog()
|
||||||
|
{
|
||||||
|
foreach (var veins in _veins)
|
||||||
|
{
|
||||||
|
if (veins == null) continue;
|
||||||
|
for (var i = 0; i < veins.Length; i++)
|
||||||
|
{
|
||||||
|
var pvd = veins[i];
|
||||||
|
if (pvd == null) continue;
|
||||||
|
LogisticHub.Logger.LogInfo($"Product {i} VeinTypeCount={pvd.VeinIndices.Count} GroupCount={pvd.GroupCount}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RecalcVeins(PlanetFactory factory)
|
||||||
|
{
|
||||||
|
var planetIndex = factory.index;
|
||||||
|
var veins = GetOrCreateVeins(planetIndex);
|
||||||
|
var veinPool = factory.veinPool;
|
||||||
|
|
||||||
|
foreach (var pvd in veins)
|
||||||
|
{
|
||||||
|
if (pvd == null) continue;
|
||||||
|
pvd.VeinIndices.Clear();
|
||||||
|
pvd.GroupIndices.Clear();
|
||||||
|
pvd.GroupCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = factory.veinCursor - 1; i > 0; i--)
|
||||||
|
{
|
||||||
|
if (veinPool[i].id != i || veinPool[i].amount <= 0 || veinPool[i].type == EVeinType.None) continue;
|
||||||
|
var productId = veinPool[i].productId - 1000;
|
||||||
|
if (productId is < 0 or >= 20) continue;
|
||||||
|
var pvd = veins[productId];
|
||||||
|
if (pvd == null)
|
||||||
|
{
|
||||||
|
pvd = new ProductVeinData();
|
||||||
|
veins[productId] = pvd;
|
||||||
|
}
|
||||||
|
|
||||||
|
pvd.VeinIndices.Add(i);
|
||||||
|
pvd.GroupIndices.Add(veinPool[i].groupIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var pvd in veins)
|
||||||
|
{
|
||||||
|
if (pvd == null) continue;
|
||||||
|
pvd.GroupCount = pvd.GroupIndices.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DebugLog();
|
||||||
|
}
|
||||||
|
}
|
||||||
47
LogisticHub/README.md
Normal file
47
LogisticHub/README.md
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# LogisticHub
|
||||||
|
|
||||||
|
#### Cheat functions for Logistic Storages, make them mine resources on the planet and exchange items from certain buildings
|
||||||
|
#### 物流塔作弊功能,使其可以在星球上采矿并与特定建筑物交换物品
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
* Miner(and fuel burning) functions
|
||||||
|
+ Inspired by [PlanetMiner](https://dsp.thunderstore.io/package/blacksnipebiu/PlanetMiner)([github](https://github.com/blacksnipebiu/PlanetMiner))
|
||||||
|
But it is heavily optimized to resolve performance, accuracy and other issues in PlanetMiner.
|
||||||
|
+ (Optimization to PlanetMiner) Only recalculate count of veins when vein chunks are changed (added/removed by foundations/Sandbox-Mode, or exhausted), so this removes Dictionary allocation on each planet for every frame.
|
||||||
|
+ (Optimization to PlanetMiner) More accurate frame counting by use float number.
|
||||||
|
+ (Optimization to PlanetMiner) Does not increase power consumptions on `Veins Utilization` upgrades.
|
||||||
|
+ (Optimization to PlanetMiner) Separate power consumptions for veins, oil seeps and water.
|
||||||
|
+ (Optimization to PlanetMiner) Power consumptions are counted by groups of veins and count of oil seeps, which is more sensible.
|
||||||
|
+ Can burn fuels in certain slot when energy below half of max.
|
||||||
|
- (Optimization to PlanetMiner) Sprayed fuels generates extra energy as normal.
|
||||||
|
+ (Optimization to PlanetMiner) All used parameters are configurable:
|
||||||
|
- LogisticHub has the same speed as normal Mining Machine for normal ores by default.
|
||||||
|
But you can set mining scale in configuration, which makes LogisticHub working like Advance Mining Machines:
|
||||||
|
power consumption increases by the square of the scale, and gradually decrease mining speed over half of the maximum count.
|
||||||
|
This applies to all of veins, oils and water.
|
||||||
|
Mining scale can be set to 0(by default), which means it is automatically set by tech unlocks, set to 300 when you reaches Advanced Mining Machine, otherwise 100.
|
||||||
|
- 100/s for water by default.
|
||||||
|
- Energy costs: 1MW/vein-group & 10MW/water-slot & 1.8MW/oil-seep(configurable)
|
||||||
|
- Fuels burning slot. Default: 4th for ILS and PLS. Set to 0 to disable it.
|
||||||
|
|
||||||
|
## 使用说明
|
||||||
|
|
||||||
|
* 采矿(和燃料燃烧)功能
|
||||||
|
+ 创意来自 [PlanetMiner](https://dsp.thunderstore.io/package/blacksnipebiu/PlanetMiner)([github](https://github.com/blacksnipebiu/PlanetMiner))
|
||||||
|
对性能重度优化,并解决了PlanetMiner的精度等问题。
|
||||||
|
+ (对PlanetMiner的优化) 仅当矿堆发生变化(填埋/恢复/采完)时重新计算矿堆数据,解决每行星每计算帧要重建字典的性能问题。
|
||||||
|
+ (对PlanetMiner的优化) 用浮点数保证更精确的帧计算。
|
||||||
|
+ (对PlanetMiner的优化) 升级`矿物利用`不会提升能耗。
|
||||||
|
+ (对PlanetMiner的优化) 分开矿物,油井和水的采集能耗。
|
||||||
|
+ (对PlanetMiner的优化) 采集能耗以矿物组,油井为单位,相对更加合理。
|
||||||
|
+ 剩余电量少于一半时可以燃烧指定格子的燃料补充。
|
||||||
|
- (对PlanetMiner的优化) 喷涂了增产剂的燃料按照正常的计算方式提供更多的能量(除了原本就不增加能量输出的反物质燃料棒)。
|
||||||
|
+ (对PlanetMiner的优化) 所有参数都可以在设置文件内配置:
|
||||||
|
- 物流塔枢纽和普通矿机采矿速度一样(等同于同时采集所有对应矿物)。
|
||||||
|
你可以设置采矿倍率改变物流塔枢纽采矿速度,和高级采矿机相同地,能耗和倍率的平方成正比,并且在存储矿物量多于一半时逐渐降低采矿倍率。
|
||||||
|
此倍率对各种矿物,油井和水的采集都生效。
|
||||||
|
倍率可以设置为0(默认),此时倍率会随科技解锁而变化,默认是100%,解锁高级采矿机后变为300%。
|
||||||
|
- 水的采集速度默认为100/s。
|
||||||
|
- 能耗:每矿物组 1MW,单格水 10MW,每油井 1.8MW。
|
||||||
|
- 燃料格位置。默认:星际物流塔和行星内物流塔第4格。设为0则关闭燃料补充能量功能。
|
||||||
10
LogisticHub/package/manifest.json
Normal file
10
LogisticHub/package/manifest.json
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "LogisticHub",
|
||||||
|
"version_number": "0.1.0",
|
||||||
|
"website_url": "https://github.com/soarqin/DSP_Mods/tree/master/LogisticHub",
|
||||||
|
"description": "Cheat functions to Logistic Storages which make them miner and items hub / 物流塔作弊功能,使其成为矿机和物品枢纽",
|
||||||
|
"dependencies": [
|
||||||
|
"xiaoye97-BepInEx-5.4.17",
|
||||||
|
"soarqin-UXAssist-1.2.0"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,485 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using BepInEx;
|
|
||||||
using BepInEx.Configuration;
|
|
||||||
using HarmonyLib;
|
|
||||||
using Random = UnityEngine.Random;
|
|
||||||
|
|
||||||
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 static long _oreEnergyConsume = 2000000;
|
|
||||||
private static long _oilEnergyConsume = 3600000;
|
|
||||||
private static long _waterEnergyConsume = 20000000;
|
|
||||||
private static int _waterSpeed = 100;
|
|
||||||
private static int _miningScale;
|
|
||||||
private static int _fuelIlsSlot = 3;
|
|
||||||
private static int _fuelPlsSlot = 2;
|
|
||||||
|
|
||||||
private static float _frame;
|
|
||||||
private static float _miningCostRateByTech;
|
|
||||||
private static float _miningSpeedScaleByTech;
|
|
||||||
private static float _miningFrames;
|
|
||||||
private static long _miningSpeedScaleLong;
|
|
||||||
private static bool _advancedMiningMachineUnlocked;
|
|
||||||
private static uint _miningCostBarrier;
|
|
||||||
private static uint _miningCostBarrierOil;
|
|
||||||
|
|
||||||
private static uint _seed = (uint)Random.Range(int.MinValue, int.MaxValue);
|
|
||||||
private static readonly Dictionary<int, VeinCacheData> PlanetVeinCacheData = new();
|
|
||||||
private static readonly Dictionary<int, (long, bool)> Fuels = new();
|
|
||||||
|
|
||||||
private bool _cfgEnabled = true;
|
|
||||||
|
|
||||||
private void Awake()
|
|
||||||
{
|
|
||||||
_cfgEnabled = Config.Bind("General", "Enabled", _cfgEnabled, "enable/disable this plugin").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,
|
|
||||||
"0 for Auto(which means having researched makes mining scale 300, otherwise 100). Mining scale(in percents) for slots below half of slot limits, and the scale reduces to 100% smoothly till reach full. Please note that the power consumption increases by the square of the scale which is the same as Advanced Mining Machine")
|
|
||||||
.Value;
|
|
||||||
_fuelIlsSlot = Config.Bind("General", "ILSFuelSlot", _fuelIlsSlot + 1,
|
|
||||||
new ConfigDescription("Fuel slot for ILS, set to 0 to disable",
|
|
||||||
new AcceptableValueRange<int>(0, 5), Array.Empty<object>()))
|
|
||||||
.Value - 1;
|
|
||||||
_fuelPlsSlot = Config.Bind("General", "PLSFuelSlot", _fuelPlsSlot + 1,
|
|
||||||
new ConfigDescription("Fuel slot for PLS, set to 0 to disable",
|
|
||||||
new AcceptableValueRange<int>(0, 4), Array.Empty<object>()))
|
|
||||||
.Value - 1;
|
|
||||||
if (!_cfgEnabled) return;
|
|
||||||
|
|
||||||
Harmony.CreateAndPatchAll(typeof(LogisticMiner));
|
|
||||||
}
|
|
||||||
|
|
||||||
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 /
|
|
||||||
DSPGame.GameDesc.resourceMultiplier);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void UpdateSpeedScale()
|
|
||||||
{
|
|
||||||
_miningSpeedScaleByTech = GameMain.history.miningSpeedScale;
|
|
||||||
_miningSpeedScaleLong = (long)(_miningSpeedScaleByTech * 100);
|
|
||||||
lock (PlanetVeinCacheData)
|
|
||||||
{
|
|
||||||
_miningFrames = 120f / _miningSpeedScaleByTech;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPostfix]
|
|
||||||
[HarmonyPatch(typeof(DSPGame), "StartGame", typeof(GameDesc))]
|
|
||||||
[HarmonyPatch(typeof(DSPGame), "StartGame", typeof(string))]
|
|
||||||
private static void OnGameStart()
|
|
||||||
{
|
|
||||||
Logger.LogInfo("Game Start");
|
|
||||||
PlanetVeinCacheData.Clear();
|
|
||||||
Fuels.Clear();
|
|
||||||
foreach (var data in LDB.items.dataArray)
|
|
||||||
{
|
|
||||||
if (data.HeatValue > 0)
|
|
||||||
{
|
|
||||||
Fuels.Add(data.ID, (data.HeatValue, data.Productive));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Thinking: storage max may affect mining scale?
|
|
||||||
_localStationMax = LDB.items.Select(2103).prefabDesc.stationMaxItemCount;
|
|
||||||
_remoteStationMax = LDB.items.Select(2104).prefabDesc.stationMaxItemCount;
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPostfix]
|
|
||||||
[HarmonyPatch(typeof(GameMain), "Start")]
|
|
||||||
private static void OnGameLoaded()
|
|
||||||
{
|
|
||||||
_frame = 0f;
|
|
||||||
|
|
||||||
UpdateMiningCostRate();
|
|
||||||
UpdateSpeedScale();
|
|
||||||
CheckRecipes();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPostfix]
|
|
||||||
[HarmonyPatch(typeof(GameHistoryData), "UnlockTechFunction")]
|
|
||||||
private static void OnUnlockTech(int func)
|
|
||||||
{
|
|
||||||
switch (func)
|
|
||||||
{
|
|
||||||
case 20:
|
|
||||||
UpdateMiningCostRate();
|
|
||||||
break;
|
|
||||||
case 21:
|
|
||||||
UpdateSpeedScale();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPostfix]
|
|
||||||
[HarmonyPatch(typeof(GameData), "GameTick")]
|
|
||||||
private static void FrameTick()
|
|
||||||
{
|
|
||||||
var main = GameMain.instance;
|
|
||||||
if (main.isMenuDemo)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_frame++;
|
|
||||||
if (_frame <= 1000000f) return;
|
|
||||||
/* keep precision of floats by limiting them <= 1000000f */
|
|
||||||
_frame -= 1000000f;
|
|
||||||
foreach (var pair in PlanetVeinCacheData)
|
|
||||||
{
|
|
||||||
pair.Value.FrameNext -= 1000000f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPostfix]
|
|
||||||
[HarmonyPatch(typeof(GameHistoryData), "UnlockRecipe")]
|
|
||||||
private static void OnUnlockRecipe(int recipeId)
|
|
||||||
{
|
|
||||||
if (recipeId == 119)
|
|
||||||
{
|
|
||||||
CheckRecipes();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPostfix]
|
|
||||||
[HarmonyPatch(typeof(PlanetFactory), "Init")]
|
|
||||||
[HarmonyPatch(typeof(PlanetFactory), "RecalculateVeinGroup")]
|
|
||||||
[HarmonyPatch(typeof(PlanetFactory), "RecalculateAllVeinGroups")]
|
|
||||||
private static void NeedRecalcVeins(PlanetFactory __instance)
|
|
||||||
{
|
|
||||||
RecalcVeins(__instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void RecalcVeins(PlanetFactory factory)
|
|
||||||
{
|
|
||||||
var planetId = factory.planetId;
|
|
||||||
lock (PlanetVeinCacheData)
|
|
||||||
{
|
|
||||||
/* remove planet veins from dict */
|
|
||||||
if (PlanetVeinCacheData.TryGetValue(planetId, out var vcd))
|
|
||||||
{
|
|
||||||
vcd.GenVeins(factory);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
vcd = new VeinCacheData();
|
|
||||||
vcd.GenVeins(factory);
|
|
||||||
vcd.FrameNext = _frame + _miningFrames;
|
|
||||||
PlanetVeinCacheData.Add(planetId, vcd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPostfix]
|
|
||||||
[HarmonyPatch(typeof(FactorySystem), "CheckBeforeGameTick")]
|
|
||||||
private static void FactorySystemLogisticMiner(FactorySystem __instance)
|
|
||||||
{
|
|
||||||
if (_miningSpeedScaleLong <= 0)
|
|
||||||
return;
|
|
||||||
var factory = __instance.factory;
|
|
||||||
var planetId = factory.planetId;
|
|
||||||
lock (PlanetVeinCacheData)
|
|
||||||
{
|
|
||||||
if (PlanetVeinCacheData.TryGetValue(planetId, out var vcd))
|
|
||||||
{
|
|
||||||
if (vcd.FrameNext > _frame)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PlanetVeinCacheData[planetId] = new VeinCacheData
|
|
||||||
{
|
|
||||||
FrameNext = _frame + _miningFrames
|
|
||||||
};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var planetTransport = __instance.planet.factory.transport;
|
|
||||||
var factoryProductionStat =
|
|
||||||
GameMain.statistics.production.factoryStatPool[__instance.factory.index];
|
|
||||||
var productRegister = factoryProductionStat?.productRegister;
|
|
||||||
PerformanceMonitor.BeginSample(ECpuWorkEntry.Miner);
|
|
||||||
do
|
|
||||||
{
|
|
||||||
for (var j = 1; j < planetTransport.stationCursor; j++)
|
|
||||||
{
|
|
||||||
var stationComponent = planetTransport.stationPool[j];
|
|
||||||
if (stationComponent == null) continue;
|
|
||||||
/* skip Orbital Collectors and Advanced Mining Machines */
|
|
||||||
if (stationComponent.isCollector || stationComponent.isVeinCollector) continue;
|
|
||||||
var storage = stationComponent.storage;
|
|
||||||
if (storage == null) continue;
|
|
||||||
var isCollecting = false;
|
|
||||||
for (var k = 0; k < stationComponent.storage.Length; k++)
|
|
||||||
{
|
|
||||||
ref var stationStore = ref storage[k];
|
|
||||||
if (stationStore.localLogic != ELogisticStorage.Demand ||
|
|
||||||
stationStore.max <= stationStore.count)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var isVein = vcd.HasVein(stationStore.itemId);
|
|
||||||
var isVeinOrWater = isVein || stationStore.itemId == __instance.planet.waterItemId;
|
|
||||||
if (!isVeinOrWater) continue;
|
|
||||||
int amount;
|
|
||||||
long energyConsume;
|
|
||||||
isCollecting = true;
|
|
||||||
var miningScale = _miningScale;
|
|
||||||
if (miningScale == 0)
|
|
||||||
{
|
|
||||||
miningScale = _advancedMiningMachineUnlocked ? 300 : 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (miningScale > 100 && stationStore.count * 2 > stationStore.max)
|
|
||||||
{
|
|
||||||
miningScale = 100 +
|
|
||||||
((miningScale - 100) * (stationStore.max - stationStore.count) * 2 +
|
|
||||||
stationStore.max - 1) / stationStore.max;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isVein)
|
|
||||||
{
|
|
||||||
(amount, energyConsume) = vcd.Mine(factory, stationStore.itemId, miningScale,
|
|
||||||
_miningSpeedScaleLong,
|
|
||||||
stationComponent.energy);
|
|
||||||
if (amount < 0)
|
|
||||||
{
|
|
||||||
k = int.MaxValue - 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
energyConsume = (_waterEnergyConsume * miningScale * miningScale + 9999L) / 100L /
|
|
||||||
_miningSpeedScaleLong;
|
|
||||||
if (stationComponent.energy < energyConsume)
|
|
||||||
{
|
|
||||||
k = int.MaxValue - 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
amount = _waterSpeed * miningScale / 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (amount <= 0) continue;
|
|
||||||
stationStore.count += amount;
|
|
||||||
if (factoryProductionStat != null)
|
|
||||||
productRegister[stationStore.itemId] += amount;
|
|
||||||
stationComponent.energy -= energyConsume;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isCollecting || stationComponent.energy * 2 >= stationComponent.energyMax) continue;
|
|
||||||
var index = stationComponent.isStellar ? _fuelIlsSlot : _fuelPlsSlot;
|
|
||||||
if (index < 0 || index >= storage.Length)
|
|
||||||
continue;
|
|
||||||
var fuelCount = storage[index].count;
|
|
||||||
if (fuelCount == 0) continue;
|
|
||||||
if (!Fuels.TryGetValue(storage[index].itemId, out var val) || val.Item1 <= 0)
|
|
||||||
continue;
|
|
||||||
/* Sprayed fuels */
|
|
||||||
int pretendIncLevel;
|
|
||||||
if (val.Item2 && (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 += val.Item1 * count * (1000L + Cargo.incTable[incLevel]) / 1000L;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var count = (int)((stationComponent.energyMax - stationComponent.energy) / val.Item1);
|
|
||||||
if (count > fuelCount)
|
|
||||||
count = fuelCount;
|
|
||||||
SplitIncLevel(ref storage[index].count, ref storage[index].inc, count);
|
|
||||||
stationComponent.energy += val.Item1 * count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vcd.FrameNext += _miningFrames;
|
|
||||||
} while (vcd.FrameNext <= _frame);
|
|
||||||
|
|
||||||
PerformanceMonitor.EndSample(ECpuWorkEntry.Miner);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class VeinCacheData
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
|
|
||||||
public bool HasVein(int productId)
|
|
||||||
{
|
|
||||||
return _veins.ContainsKey(productId);
|
|
||||||
}
|
|
||||||
|
|
||||||
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, [i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vg.TryGetValue(productId, out var hs))
|
|
||||||
{
|
|
||||||
hs.Add(veinPool[i].groupIndex);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
vg.Add(productId, [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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net472</TargetFramework>
|
|
||||||
<AssemblyName>LogisticMiner</AssemblyName>
|
|
||||||
<BepInExPluginGuid>org.soardev.logisticminer</BepInExPluginGuid>
|
|
||||||
<Description>DSP MOD - LogisticMiner</Description>
|
|
||||||
<Version>0.1.0</Version>
|
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
|
||||||
<LangVersion>latest</LangVersion>
|
|
||||||
<RestoreAdditionalProjectSources>https://nuget.bepinex.dev/v3/index.json</RestoreAdditionalProjectSources>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="BepInEx.Core" Version="5.*" />
|
|
||||||
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" />
|
|
||||||
<PackageReference Include="DysonSphereProgram.GameLibs" Version="0.10.32.*-r.*" />
|
|
||||||
<PackageReference Include="UnityEngine.Modules" Version="2018.4.12" IncludeAssets="compile" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'">
|
|
||||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" PrivateAssets="all" />
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
# LogisticMiner
|
|
||||||
|
|
||||||
#### Logistic Storages can mine all ores/water on current planet
|
|
||||||
#### 物流塔可以采集当前星球的全部矿产(以及水)
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
* Inspired
|
|
||||||
by [PlanetMiner](https://dsp.thunderstore.io/package/blacksnipebiu/PlanetMiner)([github](https://github.com/blacksnipebiu/PlanetMiner))
|
|
||||||
But it is heavily optimized to resolve performance, accuracy and other issues in PlanetMiner.
|
|
||||||
* (Optimization to PlanetMiner) Only recalculate count of veins when vein chunks are changed (added/removed by foundations/Sandbox-Mode, or
|
|
||||||
exhausted), so this removes Dictionary allocation on each planet for every frame.
|
|
||||||
* (Optimization to PlanetMiner) More accurate frame counting by use float number.
|
|
||||||
* (Optimization to PlanetMiner) Does not increase power consumptions on `Veins Utilization` upgrades.
|
|
||||||
* (Optimization to PlanetMiner) Separate power consumptions for veins, oil seeps and water.
|
|
||||||
* (Optimization to PlanetMiner) Power consumptions are counted by groups of veins and count of oil seeps, which is more sensible.
|
|
||||||
* Can burn fuels in certain slot when energy below half of max.
|
|
||||||
* (Optimization to PlanetMiner) Sprayed fuels generates extra energy as normal.
|
|
||||||
* (Optimization to PlanetMiner) All used parameters are configurable:
|
|
||||||
* Logistic Miner has the same speed as normal Mining Machine for normal ores by default.
|
|
||||||
But you can set mining scale in configuration, which makes Logistic Miner working like Advance Mining Machines:
|
|
||||||
power
|
|
||||||
consumption increases by the square of the scale, and gradually decrease mining speed over half of the maximum
|
|
||||||
count.
|
|
||||||
This applies to all of veins, oils and water.
|
|
||||||
Mining scale can be set to 0(by default), which means it is automatically set by tech unlocks, set to 300 when you
|
|
||||||
reaches Advanced Mining Machine, otherwise 100.
|
|
||||||
* 100/s for water by default.
|
|
||||||
* Energy costs: 1MW/vein-group & 10MW/water-slot & 1.8MW/oil-seep(configurable)
|
|
||||||
* Fuels burning slot. Default: 4th for ILS, 3rd for PLS. Set to 0 to disable it.
|
|
||||||
|
|
||||||
## 使用说明
|
|
||||||
|
|
||||||
* 创意来自 [PlanetMiner](https://dsp.thunderstore.io/package/blacksnipebiu/PlanetMiner)([github](https://github.com/blacksnipebiu/PlanetMiner))
|
|
||||||
对性能重度优化,并解决了PlanetMiner的精度等问题。
|
|
||||||
* (对PlanetMiner的优化) 仅当矿堆发生变化(填埋/恢复/采完)时重新计算矿堆数据,解决每行星每计算帧要重建字典的性能问题。
|
|
||||||
* (对PlanetMiner的优化) 用浮点数保证更精确的帧计算。
|
|
||||||
* (对PlanetMiner的优化) 升级`矿物利用`不会提升能耗。
|
|
||||||
* (对PlanetMiner的优化) 分开矿物,油井和水的采集能耗。
|
|
||||||
* (对PlanetMiner的优化) 采集能耗以矿物组,油井为单位,相对更加合理。
|
|
||||||
* 剩余电量少于一半时可以燃烧指定格子的燃料补充。
|
|
||||||
* (对PlanetMiner的优化) 喷涂了增产剂的燃料按照正常的计算方式提供更多的能量(除了原本就不增加能量输出的反物质燃料棒)。
|
|
||||||
* (对PlanetMiner的优化) 所有参数都可以在设置文件内配置:
|
|
||||||
* 物流塔矿机和普通矿机采矿速度一样(等同于同时采集所有对应矿物)。
|
|
||||||
你可以设置采矿倍率改变物流塔矿机采矿速度,和高级采矿机相同地,能耗和倍率的平方成正比,并且在存储矿物量多于一半时逐渐降低采矿倍率。
|
|
||||||
此倍率对各种矿物,油井和水的采集都生效。
|
|
||||||
倍率可以设置为0(默认),此时倍率会随科技解锁而变化,默认是100%,解锁高级采矿机后变为300%。
|
|
||||||
* 水的采集速度默认为100/s。
|
|
||||||
* 能耗:每矿物组 1MW,单格水 10MW,每油井 1.8MW。
|
|
||||||
* 燃料格位置。默认:星际物流塔第4格,行星内物流塔第3格。设为0则关闭燃料补充能量功能。
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "LogisticMiner",
|
|
||||||
"version_number": "0.1.0",
|
|
||||||
"website_url": "https://github.com/soarqin/DSP_Mods/tree/master/LogisticMiner",
|
|
||||||
"description": "Logistic Storages can mine all ores/water on current planet / 物流塔可以采集当前星球的全部矿产(以及水)",
|
|
||||||
"dependencies": [
|
|
||||||
"xiaoye97-BepInEx-5.4.17"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -9,10 +9,10 @@ Add various cheat functions while disabling abnormal determinants
|
|||||||
|
|
||||||
Moved [to another repo](https://github.com/soarqin/DSP_Mods_TO/tree/master/CompressSave)
|
Moved [to another repo](https://github.com/soarqin/DSP_Mods_TO/tree/master/CompressSave)
|
||||||
|
|
||||||
## [LogisticMiner](LogisticMiner)
|
## [LogisticHub](LogisticHub)
|
||||||
|
|
||||||
Logistic Storages can mine all ores/water on current planet
|
Cheat functions for Logistic Storages, make them mine resources on the planet and exchange items from certain buildings
|
||||||
物流塔可以采集当前星球的全部矿产(以及水)
|
物流塔作弊功能,使其可以在星球上采矿并与特定建筑物交换物品
|
||||||
|
|
||||||
## [HideTips](HideTips)
|
## [HideTips](HideTips)
|
||||||
|
|
||||||
|
|||||||
@@ -1069,10 +1069,10 @@ public static class LogisticsPatch
|
|||||||
var localPlanet = GameMain.data?.localPlanet;
|
var localPlanet = GameMain.data?.localPlanet;
|
||||||
if (localPlanet == null || !localPlanet.factoryLoaded)
|
if (localPlanet == null || !localPlanet.factoryLoaded)
|
||||||
{
|
{
|
||||||
|
_stationTipsRoot.SetActive(false);
|
||||||
if (_lastPlanetId == 0) return;
|
if (_lastPlanetId == 0) return;
|
||||||
RecycleStationTips();
|
RecycleStationTips();
|
||||||
_lastPlanetId = 0;
|
_lastPlanetId = 0;
|
||||||
_stationTipsRoot.SetActive(false);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user