diff --git a/DSP_Mods.sln b/DSP_Mods.sln index ed98e40..ab0cd03 100644 --- a/DSP_Mods.sln +++ b/DSP_Mods.sln @@ -4,7 +4,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UXAssist", "UXAssist\UXAssi EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CheatEnabler", "CheatEnabler\CheatEnabler.csproj", "{F9F16B62-D1D3-466B-BE22-E64B9EA957C2}" 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 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HideTips", "HideTips\HideTips.csproj", "{4EABD71D-477F-448B-801B-48F8745A3FA7}" EndProject diff --git a/LogisticHub/LogisticHub.cs b/LogisticHub/LogisticHub.cs new file mode 100644 index 0000000..6a17b9b --- /dev/null +++ b/LogisticHub/LogisticHub.cs @@ -0,0 +1,55 @@ +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 0.5W)"); + Module.Miner.OilEnergyConsume = Config.Bind("Miner", "EnergyConsumptionForOil", 3600000L, + "Energy consumption for each oil seep(in 0.5W)"); + Module.Miner.WaterEnergyConsume = Config.Bind("Miner", "EnergyConsumptionForWater", 20000000L, + "Energy consumption for water slot(in kW)"); + Module.Miner.WaterSpeed = Config.Bind("Miner", "WaterMiningSpeed", 100, + "Water mining speed (count per second)"); + Module.Miner.MiningScale = Config.Bind("Miner", "MiningScale", 0, + """ + 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. + """); + Module.Miner.FuelIlsSlot = Config.Bind("Miner", "ILSFuelSlot", 4, + new ConfigDescription("Fuel slot for ILS, set 0 to disable.", new AcceptableValueRange(0, 5))); + Module.Miner.FuelPlsSlot = Config.Bind("Miner", "PLSFuelSlot", 4, + new ConfigDescription("Fuel slot for PLS, set 0 to disable.", new AcceptableValueRange(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)); + } +} \ No newline at end of file diff --git a/LogisticMiner/LogisticMiner.csproj b/LogisticHub/LogisticHub.csproj similarity index 68% rename from LogisticMiner/LogisticMiner.csproj rename to LogisticHub/LogisticHub.csproj index 2397e84..293e30e 100644 --- a/LogisticMiner/LogisticMiner.csproj +++ b/LogisticHub/LogisticHub.csproj @@ -3,13 +3,14 @@ net472 - LogisticMiner - org.soardev.logisticminer - DSP MOD - LogisticMiner - 0.2.0 + org.soardev.logistichub + DSP MOD - LogisticHub + 0.1.0 true latest https://nuget.bepinex.dev/v3/index.json + LogisticHub + LogisticHub @@ -20,12 +21,7 @@ - - ..\AssemblyFromGame\Assembly-CSharp.dll - - - ..\AssemblyFromGame\UnityEngine.UI.dll - + diff --git a/LogisticHub/Module/AuxData.cs b/LogisticHub/Module/AuxData.cs new file mode 100644 index 0000000..25e4e24 --- /dev/null +++ b/LogisticHub/Module/AuxData.cs @@ -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; + } +} diff --git a/LogisticHub/Module/Ejector.cs b/LogisticHub/Module/Ejector.cs new file mode 100644 index 0000000..e69de29 diff --git a/LogisticHub/Module/Miner.cs b/LogisticHub/Module/Miner.cs new file mode 100644 index 0000000..9f8d554 --- /dev/null +++ b/LogisticHub/Module/Miner.cs @@ -0,0 +1,338 @@ +using System; +using BepInEx.Configuration; +using HarmonyLib; +using UnityEngine; +using UXAssist.Common; +using Random = UnityEngine.Random; + +namespace LogisticHub.Module; + +public class Miner : PatchImpl +{ + public static ConfigEntry Enabled; + public static ConfigEntry OreEnergyConsume; + public static ConfigEntry OilEnergyConsume; + public static ConfigEntry WaterEnergyConsume; + public static ConfigEntry WaterSpeed; + public static ConfigEntry MiningScale; + public static ConfigEntry FuelIlsSlot; + public static ConfigEntry FuelPlsSlot; + + 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 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() + { + GameLogic.OnGameBegin += OnGameBegin; + } + + protected override void OnDisable() + { + GameLogic.OnGameBegin -= OnGameBegin; + } + + private static void OnGameBegin() + { + VeinManager.Clear(); + _frame = 0f; + 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() + { + _miningSpeedScaleByTech = GameMain.history.miningSpeedScale; + _miningSpeedScaleLong = (long)(_miningSpeedScaleByTech * 100); + _miningFrames = _miningSpeedScaleByTech * 600000f; + } + + [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(GameData), "GameTick")] + private static void GameData_GameTick_Prefix() + { + var main = GameMain.instance; + if (main.isMenuDemo) return; + if (_miningSpeedScaleLong <= 0) return; + + PerformanceMonitor.BeginSample(ECpuWorkEntry.Miner); + if (main.timei % 60 != 0) return; + _frame += _miningFrames; + var frameCounter = Mathf.FloorToInt(_frame / 1200000f); + if (frameCounter <= 0) return; + _frame -= frameCounter * 1200000f; + // LogisticHub.Logger.LogDebug($"FrameCounter: {frameCounter}"); + + var data = GameMain.data; + for (var factoryIndex = data.factoryCount - 1; factoryIndex >= 0; factoryIndex--) + { + var factory = data.factories[factoryIndex]; + var veins = VeinManager.GetVeins(factoryIndex); + if (veins == null) return; + var stations = StationManager.GetStations(factoryIndex); + var planetTransport = factory.transport; + var factoryProductionStat = GameMain.statistics.production.factoryStatPool[factoryIndex]; + var productRegister = factoryProductionStat?.productRegister; + var demands = stations.StorageIndices[1]; + if (_mineIndex == null || factoryIndex >= _mineIndex.Length) + Array.Resize(ref _mineIndex, factoryIndex + 1); + foreach (var (itemIndex, itemId) in VeinList) + { + foreach (var storageIndex in demands[itemIndex]) + { + var station = planetTransport.stationPool[storageIndex / 100]; + if (station == null) + continue; + ref var storage = ref station.storage[storageIndex % 100]; + 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, 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 (factoryProductionStat != null) + productRegister[itemId] += amount; + station.energy -= energyConsume; + } + } + + for (var i = planetTransport.stationCursor - 1; i > 0; i--) + { + var stationComponent = planetTransport.stationPool[i]; + if (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; + } + } + } + + PerformanceMonitor.EndSample(ECpuWorkEntry.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); + } +} \ No newline at end of file diff --git a/LogisticHub/Module/StationManager.cs b/LogisticHub/Module/StationManager.cs new file mode 100644 index 0000000..21194ac --- /dev/null +++ b/LogisticHub/Module/StationManager.cs @@ -0,0 +1,321 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using HarmonyLib; +using UXAssist.Common; + +namespace LogisticHub.Module; + +public class PlanetStations +{ + public readonly List[][] StorageIndices = [null, null]; + + public void AddStationStorage(bool demand, int id, int stationId, int 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 +{ + private static PlanetStations[] _stations; + + public static void Init() + { + GameLogic.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); + } + } + }; + Enable(true); + } + + public static void Uninit() + { + Enable(false); + } + + 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(); + } +} \ No newline at end of file diff --git a/LogisticHub/Module/VeinManager.cs b/LogisticHub/Module/VeinManager.cs new file mode 100644 index 0000000..17f0b87 --- /dev/null +++ b/LogisticHub/Module/VeinManager.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections.Generic; +using HarmonyLib; +using UXAssist.Common; + +namespace LogisticHub.Module; + +public class ProductVeinData +{ + public readonly List VeinIndices = []; + public readonly HashSet GroupIndices = []; + public int GroupCount = 0; +} + +public class VeinManager : PatchImpl +{ + private static ProductVeinData[][] _veins; + + public static void Init() + { + Enable(true); + } + + public static void Uninit() + { + Enable(false); + } + + public static void Clear() + { + _veins = null; + } + + 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(); + } +} \ No newline at end of file diff --git a/LogisticHub/README.md b/LogisticHub/README.md new file mode 100644 index 0000000..a3d9a65 --- /dev/null +++ b/LogisticHub/README.md @@ -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则关闭燃料补充能量功能。 diff --git a/LogisticHub/package/manifest.json b/LogisticHub/package/manifest.json new file mode 100644 index 0000000..2611639 --- /dev/null +++ b/LogisticHub/package/manifest.json @@ -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" + ] +} diff --git a/LogisticMiner/LogisticMiner.cs b/LogisticMiner/LogisticMiner.cs deleted file mode 100644 index 5aa5fed..0000000 --- a/LogisticMiner/LogisticMiner.cs +++ /dev/null @@ -1,484 +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 = 2000000; - private static int _waterSpeed = 10; - private static int _miningScale; - private static int _fuelIlsSlot = 3; - private static int _fuelPlsSlot = 3; - - 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 PlanetVeinCacheData = []; - private static readonly Dictionary Fuels = []; - - 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(0, 5), [])) - .Value - 1; - _fuelPlsSlot = Config.Bind("General", "PLSFuelSlot", _fuelPlsSlot + 1, - new ConfigDescription("Fuel slot for PLS, set to 0 to disable", - new AcceptableValueRange(0, 4), [])) - .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), nameof(DSPGame.StartGame), typeof(GameDesc))] - [HarmonyPatch(typeof(DSPGame), nameof(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), nameof(GameMain.Start))] - private static void OnGameLoaded() - { - _frame = 0f; - - UpdateMiningCostRate(); - UpdateSpeedScale(); - CheckRecipes(); - } - - [HarmonyPostfix] - [HarmonyPatch(typeof(GameHistoryData), nameof(GameHistoryData.UnlockTechFunction))] - private static void OnUnlockTech(int func) - { - switch (func) - { - case 20: - UpdateMiningCostRate(); - break; - case 21: - UpdateSpeedScale(); - break; - } - } - - [HarmonyPostfix] - [HarmonyPatch(typeof(GameLogic), nameof(GameLogic.OnFactoryFrameBegin))] - 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), nameof(GameHistoryData.UnlockRecipe))] - private static void OnUnlockRecipe(int recipeId) - { - if (recipeId == 119) - { - CheckRecipes(); - } - } - - [HarmonyPostfix] - [HarmonyPatch(typeof(PlanetFactory), nameof(PlanetFactory.Init))] - [HarmonyPatch(typeof(PlanetFactory), nameof(PlanetFactory.RecalculateVeinGroup))] - [HarmonyPatch(typeof(PlanetFactory), nameof(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(PlanetFactory), nameof(PlanetFactory.BeforeGameTick))] - private static void FactorySystemLogisticMiner(PlanetFactory __instance) - { - if (_miningSpeedScaleLong <= 0) - return; - var planetId = __instance.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.transport; - var factoryProductionStat = - GameMain.statistics.production.factoryStatPool[__instance.index]; - var productRegister = factoryProductionStat?.productRegister; - DeepProfiler.BeginSample(DPEntry.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(__instance, 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); - - DeepProfiler.EndSample(DPEntry.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> _veins = new(); - private int _mineIndex = -1; - - public bool HasVein(int productId) - { - return _veins.ContainsKey(productId); - } - - public void GenVeins(PlanetFactory factory) - { - _veins = []; - var veinPool = factory.veinPool; - Dictionary> vg = []; - 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); - } - } -} \ No newline at end of file diff --git a/LogisticMiner/README.md b/LogisticMiner/README.md deleted file mode 100644 index 8e60f1c..0000000 --- a/LogisticMiner/README.md +++ /dev/null @@ -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, 4th 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格,行星内物流塔第4格。设为0则关闭燃料补充能量功能。 diff --git a/LogisticMiner/package/manifest.json b/LogisticMiner/package/manifest.json deleted file mode 100644 index b5e8fdf..0000000 --- a/LogisticMiner/package/manifest.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "LogisticMiner", - "version_number": "0.2.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" - ] -} diff --git a/README.md b/README.md index 775d90a..9bbf23c 100644 --- a/README.md +++ b/README.md @@ -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) -## [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)