mirror of
https://github.com/soarqin/DSP_Mods.git
synced 2026-08-05 09:30:13 +08:00
refactor(UXAssist): split LogisticsPatch into focused classes
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection.Emit;
|
||||
using BepInEx.Configuration;
|
||||
using HarmonyLib;
|
||||
using UnityEngine;
|
||||
using UXAssist.Common;
|
||||
|
||||
namespace UXAssist.Patches.Logistics;
|
||||
|
||||
internal class AutoConfigLogistics : PatchImpl<AutoConfigLogistics>
|
||||
{
|
||||
protected override void OnEnable()
|
||||
{
|
||||
ToggleLimitAutoReplenishCount();
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
ToggleLimitAutoReplenishCount();
|
||||
}
|
||||
|
||||
internal static void ToggleLimitAutoReplenishCount()
|
||||
{
|
||||
LimitAutoReplenishCount.Enable(LogisticsPatch.AutoConfigLogisticsEnabled.Value && LogisticsPatch.AutoConfigLimitAutoReplenishCount.Value);
|
||||
}
|
||||
|
||||
private class LimitAutoReplenishCount : PatchImpl<LimitAutoReplenishCount>
|
||||
{
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(PlanetFactory), nameof(PlanetFactory.EntityAutoReplenishIfNeeded))]
|
||||
[HarmonyPatch(typeof(PlanetFactory), nameof(PlanetFactory.StationAutoReplenishIfNeeded))]
|
||||
private static IEnumerable<CodeInstruction> PlanetFactory_StationAutoReplenishIfNeeded_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
// Patch dispenser courier count
|
||||
matcher.Start().MatchForward(false,
|
||||
new CodeMatch(ci => ci.IsLdloc()),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(DispenserComponent), nameof(DispenserComponent.workCourierDatas))),
|
||||
new CodeMatch(OpCodes.Ldlen),
|
||||
new CodeMatch(OpCodes.Conv_I4)
|
||||
);
|
||||
matcher.Repeat(m => m.Advance(4).InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldsfld, AccessTools.Field(typeof(LogisticsPatch), nameof(LogisticsPatch.AutoConfigDispenserCourierCount))),
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.PropertyGetter(typeof(ConfigEntry<int>), nameof(ConfigEntry<int>.Value))),
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Math), nameof(Math.Min), [typeof(int), typeof(int)]))
|
||||
));
|
||||
|
||||
// Patch PLS/ILS drone count
|
||||
matcher.Start().MatchForward(false,
|
||||
new CodeMatch(ci => ci.IsLdloc()),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(StationComponent), nameof(StationComponent.workDroneDatas))),
|
||||
new CodeMatch(OpCodes.Ldlen),
|
||||
new CodeMatch(OpCodes.Conv_I4)
|
||||
);
|
||||
matcher.Repeat(m =>
|
||||
{
|
||||
var instr = m.Instruction;
|
||||
m.Advance(4).InsertAndAdvance(
|
||||
instr,
|
||||
Transpilers.EmitDelegate((int x, StationComponent station)
|
||||
=> Math.Min(x, station.isStellar ? LogisticsPatch.AutoConfigILSDroneCount.Value : LogisticsPatch.AutoConfigPLSDroneCount.Value))
|
||||
);
|
||||
});
|
||||
|
||||
// Patch ILS ship count
|
||||
matcher.Start().MatchForward(false,
|
||||
new CodeMatch(ci => ci.IsLdloc()),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(StationComponent), nameof(StationComponent.workShipDatas))),
|
||||
new CodeMatch(OpCodes.Ldlen),
|
||||
new CodeMatch(OpCodes.Conv_I4)
|
||||
);
|
||||
matcher.Repeat(m => m.Advance(4).InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldsfld, AccessTools.Field(typeof(LogisticsPatch), nameof(LogisticsPatch.AutoConfigILSShipCount))),
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.PropertyGetter(typeof(ConfigEntry<int>), nameof(ConfigEntry<int>.Value))),
|
||||
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Math), nameof(Math.Min), [typeof(int), typeof(int)]))
|
||||
));
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(BuildTool_Addon), nameof(BuildTool_Addon.SetDefaultParams))]
|
||||
private static void BuildTool_Addon_SetDefaultParams_Postfix(BuildTool_Addon __instance, int bpIndex)
|
||||
{
|
||||
if (__instance.handPrefabDesc.isDispenser)
|
||||
{
|
||||
__instance.handBpParams[bpIndex][2] = (int)(long)(5000.0 * LogisticsPatch.AutoConfigDispenserChargePower.Value + 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(PlanetTransport), nameof(PlanetTransport.NewStationComponent))]
|
||||
private static void PlanetTransport_NewStationComponent_Postfix(PlanetTransport __instance, StationComponent __result)
|
||||
{
|
||||
LogisticsPatch.DoConfigStation(__instance.factory, __result);
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(DefenseSystem), nameof(DefenseSystem.NewBattleBaseComponent))]
|
||||
private static void DefenseSystem_NewBattleBaseComponent_Postfix(DefenseSystem __instance, int __result)
|
||||
{
|
||||
if (__result <= 0) return;
|
||||
LogisticsPatch.BattleBaseSetChargePower(__instance.factory, __instance.battleBases[__result]);
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(PlanetTransport), nameof(PlanetTransport.NewDispenserComponent))]
|
||||
private static void PlanetTransport_NewDispenserComponent_Postfix(PlanetTransport __instance, int __result)
|
||||
{
|
||||
if (__result <= 0) return;
|
||||
LogisticsPatch.DispenserFillCouriers(__instance.factory, __instance.dispenserPool[__result]);
|
||||
}
|
||||
}
|
||||
|
||||
internal class AutoConfigLogisticsSetDefaultRemoteLogicToStorage : PatchImpl<AutoConfigLogisticsSetDefaultRemoteLogicToStorage>
|
||||
{
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(UIControlPanelStationStorage), nameof(UIControlPanelStationStorage.OnItemPickerReturn))]
|
||||
[HarmonyPatch(typeof(UIStationStorage), nameof(UIStationStorage.OnItemPickerReturn))]
|
||||
private static IEnumerable<CodeInstruction> UIStationStorage_OnItemPickerReturn_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Ldfld),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(StationComponent), nameof(StationComponent.isStellar))),
|
||||
new CodeMatch(ci => ci.opcode == OpCodes.Brtrue_S || ci.opcode == OpCodes.Brtrue),
|
||||
new CodeMatch(OpCodes.Ldc_I4_0),
|
||||
new CodeMatch(ci => ci.opcode == OpCodes.Br_S || ci.opcode == OpCodes.Br),
|
||||
new CodeMatch(OpCodes.Ldc_I4_1),
|
||||
new CodeMatch(OpCodes.Call, AccessTools.PropertyGetter(typeof(GameMain), nameof(GameMain.mainPlayer)))
|
||||
);
|
||||
if (matcher.IsValid)
|
||||
{
|
||||
matcher.RemoveInstructions(7).InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldc_I4_0)
|
||||
);
|
||||
}
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,419 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection.Emit;
|
||||
using HarmonyLib;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
using UXAssist.Common;
|
||||
|
||||
namespace UXAssist.Patches.Logistics;
|
||||
|
||||
internal class LogisticsCapacityTweaks : PatchImpl<LogisticsCapacityTweaks>
|
||||
{
|
||||
private static KeyCode _lastKey = KeyCode.None;
|
||||
private static long _nextKeyTick;
|
||||
private static bool _skipNextUIStationStorageEvent;
|
||||
private static bool _skipNextUIControlPanelStationStorageEvent;
|
||||
private static bool _refreshingUIStationStorage;
|
||||
private static bool _refreshingUIControlPanelStationStorage;
|
||||
|
||||
private static bool UpdateKeyPressed(KeyCode code)
|
||||
{
|
||||
if (!Input.GetKey(code))
|
||||
return false;
|
||||
var main = GameMain.instance;
|
||||
if (main == null)
|
||||
return false;
|
||||
if (code != _lastKey)
|
||||
{
|
||||
_lastKey = code;
|
||||
_nextKeyTick = main.timei + 30;
|
||||
return true;
|
||||
}
|
||||
|
||||
var currTick = main.timei;
|
||||
if (_nextKeyTick > currTick) return false;
|
||||
_nextKeyTick = currTick + 4;
|
||||
return true;
|
||||
}
|
||||
|
||||
internal static void UpdateInput()
|
||||
{
|
||||
if (_lastKey != KeyCode.None && Input.GetKeyUp(_lastKey))
|
||||
{
|
||||
_lastKey = KeyCode.None;
|
||||
}
|
||||
|
||||
if (VFInput.shift) return;
|
||||
var ctrl = VFInput.control;
|
||||
var alt = VFInput.alt;
|
||||
if (ctrl && alt) return;
|
||||
int delta;
|
||||
if (UpdateKeyPressed(KeyCode.LeftArrow))
|
||||
{
|
||||
if (ctrl)
|
||||
delta = -100000;
|
||||
else if (alt)
|
||||
delta = -1000;
|
||||
else
|
||||
delta = -10;
|
||||
}
|
||||
else if (UpdateKeyPressed(KeyCode.RightArrow))
|
||||
{
|
||||
if (ctrl)
|
||||
delta = 100000;
|
||||
else if (alt)
|
||||
delta = 1000;
|
||||
else
|
||||
delta = 10;
|
||||
}
|
||||
else if (UpdateKeyPressed(KeyCode.DownArrow))
|
||||
{
|
||||
if (ctrl)
|
||||
delta = -1000000;
|
||||
else if (alt)
|
||||
delta = -10000;
|
||||
else
|
||||
delta = -100;
|
||||
}
|
||||
else if (UpdateKeyPressed(KeyCode.UpArrow))
|
||||
{
|
||||
if (ctrl)
|
||||
delta = 1000000;
|
||||
else if (alt)
|
||||
delta = 10000;
|
||||
else
|
||||
delta = 100;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var targets = new List<RaycastResult>();
|
||||
EventSystem.current.RaycastAll(new PointerEventData(EventSystem.current) { position = Input.mousePosition }, targets);
|
||||
foreach (var target in targets)
|
||||
{
|
||||
StationComponent station = null;
|
||||
int index = -1;
|
||||
PlanetFactory planetFactory = null;
|
||||
var stationStorage = target.gameObject.GetComponentInParent<UIStationStorage>();
|
||||
bool isControlPanelStationStorage = false;
|
||||
if (stationStorage != null)
|
||||
{
|
||||
station = stationStorage.station;
|
||||
index = stationStorage.index;
|
||||
planetFactory = stationStorage.stationWindow?.factory;
|
||||
}
|
||||
else
|
||||
{
|
||||
var controlPanelStationStorage = target.gameObject.GetComponentInParent<UIControlPanelStationStorage>();
|
||||
if (controlPanelStationStorage == null) continue;
|
||||
station = controlPanelStationStorage.station;
|
||||
index = controlPanelStationStorage.index;
|
||||
planetFactory = controlPanelStationStorage.factory;
|
||||
isControlPanelStationStorage = true;
|
||||
}
|
||||
if (station?.storage is null) continue;
|
||||
ref var storage = ref station.storage[index];
|
||||
var oldMax = storage.max;
|
||||
var newMax = oldMax + delta;
|
||||
if (newMax < 0)
|
||||
{
|
||||
newMax = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int itemCountMax;
|
||||
if (LogisticsPatch.AllowOverflowInLogisticsEnabled.Value)
|
||||
{
|
||||
itemCountMax = 90000000;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (planetFactory == null || station.entityId <= 0 || station.entityId >= planetFactory.entityCursor) continue;
|
||||
var modelProto = LDB.models.Select(planetFactory.entityPool[station.entityId].modelIndex);
|
||||
itemCountMax = modelProto == null ? 0 : modelProto.prefabDesc.stationMaxItemCount;
|
||||
itemCountMax += station.isStellar && !station.isCollector ? GameMain.history.remoteStationExtraStorage : GameMain.history.localStationExtraStorage;
|
||||
}
|
||||
|
||||
if (newMax > itemCountMax)
|
||||
{
|
||||
newMax = itemCountMax;
|
||||
}
|
||||
}
|
||||
|
||||
storage.max = newMax;
|
||||
if (isControlPanelStationStorage)
|
||||
{
|
||||
_skipNextUIControlPanelStationStorageEvent = oldMax / 100 != newMax / 100;
|
||||
}
|
||||
else
|
||||
{
|
||||
_skipNextUIStationStorageEvent = oldMax / 100 != newMax / 100;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(UIStationStorage), "RefreshValues")]
|
||||
private static void UIStationStorage_RefreshValues_Prefix()
|
||||
{
|
||||
_refreshingUIStationStorage = true;
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(UIStationStorage), "RefreshValues")]
|
||||
private static void UIStationStorage_RefreshValues_Postfix()
|
||||
{
|
||||
_refreshingUIStationStorage = false;
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(UIControlPanelStationStorage), "RefreshValues")]
|
||||
private static void UIControlPanelStationStorage_RefreshValues_Prefix()
|
||||
{
|
||||
_refreshingUIControlPanelStationStorage = true;
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(UIControlPanelStationStorage), "RefreshValues")]
|
||||
private static void UIControlPanelStationStorage_RefreshValues_Postfix()
|
||||
{
|
||||
_refreshingUIControlPanelStationStorage = false;
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(UIStationStorage), nameof(UIStationStorage.OnMaxSliderValueChange))]
|
||||
private static bool UIStationStorage_OnMaxSliderValueChange_Prefix()
|
||||
{
|
||||
if (!_refreshingUIStationStorage && !_skipNextUIStationStorageEvent) return true;
|
||||
_skipNextUIStationStorageEvent = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(UIControlPanelStationStorage), nameof(UIControlPanelStationStorage.OnMaxSliderValueChange))]
|
||||
private static bool UIControlPanelStationStorage_OnMaxSliderValueChange_Prefix()
|
||||
{
|
||||
if (!_refreshingUIControlPanelStationStorage && !_skipNextUIControlPanelStationStorageEvent) return true;
|
||||
_skipNextUIControlPanelStationStorageEvent = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(PlanetTransport), nameof(PlanetTransport.OnTechFunctionUnlocked))]
|
||||
private static bool PlanetTransport_OnTechFunctionUnlocked_Prefix(PlanetTransport __instance, int _funcId, double _valuelf, int _level)
|
||||
{
|
||||
switch (_funcId)
|
||||
{
|
||||
case 30:
|
||||
{
|
||||
var stationPool = __instance.stationPool;
|
||||
var factory = __instance.factory;
|
||||
var history = GameMain.history;
|
||||
for (var i = __instance.stationCursor - 1; i > 0; i--)
|
||||
{
|
||||
if (stationPool[i] == null || stationPool[i].id != i || (stationPool[i].isStellar && !stationPool[i].isCollector && !stationPool[i].isVeinCollector)) continue;
|
||||
var modelIndex = factory.entityPool[stationPool[i].entityId].modelIndex;
|
||||
var maxCount = LDB.models.Select(modelIndex).prefabDesc.stationMaxItemCount;
|
||||
var oldMaxCount = maxCount + history.localStationExtraStorage - _valuelf;
|
||||
if (oldMaxCount < 1.0) continue;
|
||||
var intOldMaxCount = (int)Math.Round(oldMaxCount);
|
||||
var intNewMaxCount = maxCount + history.localStationExtraStorage;
|
||||
var ratio = intNewMaxCount / oldMaxCount;
|
||||
var storage = stationPool[i].storage;
|
||||
for (var j = storage.Length - 1; j >= 0; j--)
|
||||
{
|
||||
var max = storage[j].max;
|
||||
if (max + 10 < intOldMaxCount || max >= intNewMaxCount) continue;
|
||||
storage[j].max = Mathf.RoundToInt((float)(max * ratio / 50.0)) * 50;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 31:
|
||||
{
|
||||
var stationPool = __instance.stationPool;
|
||||
var factory = __instance.factory;
|
||||
var history = GameMain.history;
|
||||
for (var i = __instance.stationCursor - 1; i > 0; i--)
|
||||
{
|
||||
if (stationPool[i] == null || stationPool[i].id != i || !stationPool[i].isStellar || stationPool[i].isCollector || stationPool[i].isVeinCollector) continue;
|
||||
var modelIndex = factory.entityPool[stationPool[i].entityId].modelIndex;
|
||||
var maxCount = LDB.models.Select(modelIndex).prefabDesc.stationMaxItemCount;
|
||||
var oldMaxCount = maxCount + history.remoteStationExtraStorage - _valuelf;
|
||||
if (oldMaxCount < 1.0) continue;
|
||||
var intOldMaxCount = (int)Math.Round(oldMaxCount);
|
||||
var intNewMaxCount = maxCount + history.remoteStationExtraStorage;
|
||||
var ratio = intNewMaxCount / oldMaxCount;
|
||||
var storage = stationPool[i].storage;
|
||||
for (var j = storage.Length - 1; j >= 0; j--)
|
||||
{
|
||||
var max = storage[j].max;
|
||||
if (max + 10 < intOldMaxCount || max >= intNewMaxCount) continue;
|
||||
storage[j].max = Mathf.RoundToInt((float)(max * ratio / 100.0)) * 100;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
internal class GreaterPowerUsageInLogistics : PatchImpl<GreaterPowerUsageInLogistics>
|
||||
{
|
||||
protected override void OnEnable()
|
||||
{
|
||||
var window = UIRoot.instance?.uiGame?.stationWindow;
|
||||
if (window == null) return;
|
||||
window._Close();
|
||||
window.maxMiningSpeedSlider.maxValue = 27f;
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
var window = UIRoot.instance?.uiGame?.stationWindow;
|
||||
if (window == null) return;
|
||||
window._Close();
|
||||
window.maxMiningSpeedSlider.maxValue = 20f;
|
||||
}
|
||||
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(UIStationWindow), nameof(UIStationWindow.OnStationIdChange))]
|
||||
private static IEnumerable<CodeInstruction> UIStationWindow_OnStationIdChange_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
matcher.Start().Insert(
|
||||
new CodeInstruction(OpCodes.Ldarg_0),
|
||||
Transpilers.EmitDelegate((UIStationWindow window) =>
|
||||
{
|
||||
window.maxMiningSpeedSlider.maxValue = 27f;
|
||||
})
|
||||
).MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(UIStationWindow), nameof(UIStationWindow.maxChargePowerSlider))),
|
||||
new CodeMatch(ci => ci.IsLdloc()),
|
||||
new CodeMatch(ci => ci.opcode == OpCodes.Ldc_I4 && ci.OperandIs(0xC350)),
|
||||
new CodeMatch(OpCodes.Conv_I8)
|
||||
);
|
||||
var pos = matcher.Pos + 1;
|
||||
matcher.Advance(5).MatchForward(false,
|
||||
new CodeMatch(OpCodes.Conv_R4),
|
||||
new CodeMatch(OpCodes.Callvirt, AccessTools.PropertySetter(typeof(Slider), nameof(Slider.value)))
|
||||
);
|
||||
var pos2 = matcher.Pos + 2;
|
||||
matcher.Start().Advance(pos);
|
||||
var ldvar = matcher.InstructionAt(1).Clone();
|
||||
var locWorkEnergyPerTick = matcher.InstructionAt(-2).operand;
|
||||
matcher.RemoveInstructions(pos2 - pos).InsertAndAdvance(
|
||||
ldvar,
|
||||
new CodeInstruction(OpCodes.Ldloc_S, locWorkEnergyPerTick),
|
||||
Transpilers.EmitDelegate((UIStationWindow window, long maxWorkEnergy, long workEnergyPerTick) =>
|
||||
{
|
||||
var maxSliderValue = maxWorkEnergy / 50000L;
|
||||
window.maxChargePowerSlider.maxValue = maxSliderValue + 9;
|
||||
window.maxChargePowerSlider.minValue = maxWorkEnergy / 500000L;
|
||||
if (workEnergyPerTick <= maxWorkEnergy)
|
||||
window.maxChargePowerSlider.Set(workEnergyPerTick / 50000L, false);
|
||||
else
|
||||
window.maxChargePowerSlider.Set(maxSliderValue + (workEnergyPerTick - 1) / maxWorkEnergy + 1, false);
|
||||
})
|
||||
);
|
||||
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(UIStationWindow), nameof(UIStationWindow.maxMiningSpeedSlider))),
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(UIStationWindow), nameof(UIStationWindow.factorySystem))),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(FactorySystem), nameof(FactorySystem.minerPool))),
|
||||
new CodeMatch(ci => ci.IsLdloc()),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(StationComponent), nameof(StationComponent.minerId))),
|
||||
new CodeMatch(OpCodes.Ldelema, typeof(MinerComponent)),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(MinerComponent), nameof(MinerComponent.speed)))
|
||||
);
|
||||
pos = matcher.Pos + 9;
|
||||
matcher.Advance(5).MatchForward(false,
|
||||
new CodeMatch(OpCodes.Conv_R4),
|
||||
new CodeMatch(OpCodes.Callvirt, AccessTools.PropertySetter(typeof(Slider), nameof(Slider.value)))
|
||||
);
|
||||
pos2 = matcher.Pos;
|
||||
matcher.Start().Advance(pos).RemoveInstructions(pos2 - pos).Insert(
|
||||
Transpilers.EmitDelegate((int speed) =>
|
||||
{
|
||||
if (speed <= 30000)
|
||||
return (speed - 10000) / 1000;
|
||||
return (speed - 30000) / 10000 + 20;
|
||||
})
|
||||
);
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(UIStationWindow), nameof(UIStationWindow.OnMaxMiningSpeedChange))]
|
||||
private static IEnumerable<CodeInstruction> UIStationWindow_OnMaxMiningSpeedChange_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(ci => ci.opcode == OpCodes.Ldc_I4 && ci.OperandIs(10000)),
|
||||
new CodeMatch(OpCodes.Ldarg_1)
|
||||
);
|
||||
var pos = matcher.Pos;
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Stloc_1)
|
||||
);
|
||||
var pos2 = matcher.Pos;
|
||||
matcher.Start().Advance(pos);
|
||||
var labels = matcher.Labels;
|
||||
matcher.RemoveInstructions(pos2 - pos);
|
||||
matcher.Insert(
|
||||
new CodeInstruction(OpCodes.Ldarg_1).WithLabels(labels),
|
||||
Transpilers.EmitDelegate((float value) =>
|
||||
{
|
||||
var intval = (int)(value + 0.5f);
|
||||
if (intval <= 20)
|
||||
return intval * 1000 + 10000;
|
||||
return (intval - 20) * 10000 + 30000;
|
||||
})
|
||||
);
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(UIStationWindow), nameof(UIStationWindow.OnMaxChargePowerSliderValueChange))]
|
||||
private static IEnumerable<CodeInstruction> UIStationWindow_OnMaxChargePowerSliderValueChange_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldarg_0),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(UIStationWindow), nameof(UIStationWindow.factory))),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(PlanetFactory), nameof(PlanetFactory.powerSystem))),
|
||||
new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(PowerSystem), nameof(PowerSystem.consumerPool)))
|
||||
);
|
||||
var labels = matcher.Labels;
|
||||
matcher.Labels = null;
|
||||
matcher.Insert(
|
||||
new CodeInstruction(OpCodes.Ldarg_0).WithLabels(labels),
|
||||
new CodeInstruction(OpCodes.Ldarg_1),
|
||||
Transpilers.EmitDelegate((UIStationWindow window, float value) =>
|
||||
{
|
||||
float prevMax = window.workEnergyPrefab * 5L / 50000L;
|
||||
if (value <= prevMax)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
return prevMax * (value - prevMax + 1);
|
||||
}),
|
||||
new CodeInstruction(OpCodes.Starg_S, 1)
|
||||
);
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,340 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BepInEx.Configuration;
|
||||
using HarmonyLib;
|
||||
using UnityEngine;
|
||||
using UXAssist.Common;
|
||||
using UXAssist.Common.ModFeatures;
|
||||
using GameLogicProc = UXAssist.Common.GameLogic;
|
||||
|
||||
namespace UXAssist.Patches.Logistics;
|
||||
|
||||
[ModFeature("Logistics", Order = 11)]
|
||||
public static class LogisticsPatch
|
||||
{
|
||||
public static ConfigEntry<bool> AutoConfigLogisticsEnabled;
|
||||
public static ConfigEntry<bool> AutoConfigLimitAutoReplenishCount;
|
||||
// Dispenser config
|
||||
public static ConfigEntry<int> AutoConfigDispenserChargePower; // 3~30, display as 300000.0 * value
|
||||
public static ConfigEntry<int> AutoConfigDispenserCourierCount; // 0~10
|
||||
// Battlefield Analysis Base
|
||||
public static ConfigEntry<int> AutoConfigBattleBaseChargePower; // 4~40, display as 300000.0 * value
|
||||
// PLS config
|
||||
public static ConfigEntry<int> AutoConfigPLSChargePower; // 2~20, display as 3000000.0 * value
|
||||
public static ConfigEntry<int> AutoConfigPLSMaxTripDrone; // 1~180, by degress
|
||||
public static ConfigEntry<int> AutoConfigPLSDroneMinDeliver; // 0~10; 0 = 1%, 1~10 = 10% *value
|
||||
public static ConfigEntry<int> AutoConfigPLSMinPilerValue; // 0~4; 0 = Maximum in tech, 1~4 = piler stacking count
|
||||
public static ConfigEntry<int> AutoConfigPLSDroneCount; // 0~50
|
||||
// ILS config
|
||||
public static ConfigEntry<bool> SetDefaultRemoteLogicToStorage;
|
||||
public static ConfigEntry<int> AutoConfigILSChargePower; // 2~20, display as 15000000.0 * value
|
||||
public static ConfigEntry<int> AutoConfigILSMaxTripDrone; // 1~180, by degress
|
||||
public static ConfigEntry<int> AutoConfigILSMaxTripShip; // 1~41; 1~20 = value LY, 21-40 = 2*value-20LY, 41 = Unlimited
|
||||
public static ConfigEntry<int> AutoConfigILSWarperDistance; // 2~21; 2~7 = value * 0.5 - 0.5AU, 8~16 = value - 4AU, 17~20 = value * 2 - 20AU, 21 = 60AU
|
||||
public static ConfigEntry<int> AutoConfigILSDroneMinDeliver; // 0~10; 0 = 1%, 1~10 = 10% *value
|
||||
public static ConfigEntry<int> AutoConfigILSShipMinDeliver; // 0~10; 0 = 1%, 1~10 = 10% *value
|
||||
public static ConfigEntry<int> AutoConfigILSMinPilerValue; // 0~4; 0 = Maximum in tech, 1~4 = piler stacking count
|
||||
public static ConfigEntry<bool> AutoConfigILSIncludeOrbitCollector;
|
||||
public static ConfigEntry<bool> AutoConfigILSWarperNecessary;
|
||||
public static ConfigEntry<int> AutoConfigILSDroneCount; // 0~100
|
||||
public static ConfigEntry<int> AutoConfigILSShipCount; // 0~10
|
||||
// Vein collector config
|
||||
public static ConfigEntry<int> AutoConfigVeinCollectorHarvestSpeed; // 0-20, 100% + 10% * value
|
||||
public static ConfigEntry<int> AutoConfigVeinCollectorMinPilerValue; // 0~4; 0 = Maximum in tech, 1~4 = piler stacking count
|
||||
|
||||
public static ConfigEntry<bool> LogisticsCapacityTweaksEnabled;
|
||||
public static ConfigEntry<bool> AllowOverflowInLogisticsEnabled;
|
||||
public static ConfigEntry<bool> GreaterPowerUsageInLogisticsEnabled;
|
||||
public static ConfigEntry<bool> LogisticsConstrolPanelImprovementEnabled;
|
||||
public static ConfigEntry<bool> RealtimeLogisticsInfoPanelEnabled;
|
||||
public static ConfigEntry<bool> RealtimeLogisticsInfoPanelBarsEnabled;
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
AutoConfigLogisticsEnabled.SettingChanged += (_, _) => AutoConfigLogistics.Enable(AutoConfigLogisticsEnabled.Value);
|
||||
AutoConfigLimitAutoReplenishCount.SettingChanged += (_, _) => AutoConfigLogistics.ToggleLimitAutoReplenishCount();
|
||||
SetDefaultRemoteLogicToStorage.SettingChanged += (_, _) => AutoConfigLogisticsSetDefaultRemoteLogicToStorage.Enable(SetDefaultRemoteLogicToStorage.Value);
|
||||
LogisticsCapacityTweaksEnabled.SettingChanged += (_, _) => LogisticsCapacityTweaks.Enable(LogisticsCapacityTweaksEnabled.Value);
|
||||
AllowOverflowInLogisticsEnabled.SettingChanged += (_, _) => AllowOverflowInLogistics.Enable(AllowOverflowInLogisticsEnabled.Value);
|
||||
GreaterPowerUsageInLogisticsEnabled.SettingChanged += (_, _) => GreaterPowerUsageInLogistics.Enable(GreaterPowerUsageInLogisticsEnabled.Value);
|
||||
LogisticsConstrolPanelImprovementEnabled.SettingChanged += (_, _) => LogisticsConstrolPanelImprovement.Enable(LogisticsConstrolPanelImprovementEnabled.Value);
|
||||
RealtimeLogisticsInfoPanelEnabled.SettingChanged += (_, _) => RealtimeLogisticsInfoPanel.Enable(RealtimeLogisticsInfoPanelEnabled.Value);
|
||||
RealtimeLogisticsInfoPanelBarsEnabled.SettingChanged += (_, _) => RealtimeLogisticsInfoPanel.EnableBars(RealtimeLogisticsInfoPanelBarsEnabled.Value);
|
||||
}
|
||||
|
||||
public static void Start()
|
||||
{
|
||||
AutoConfigLogistics.Enable(AutoConfigLogisticsEnabled.Value);
|
||||
AutoConfigLogisticsSetDefaultRemoteLogicToStorage.Enable(SetDefaultRemoteLogicToStorage.Value);
|
||||
LogisticsCapacityTweaks.Enable(LogisticsCapacityTweaksEnabled.Value);
|
||||
AllowOverflowInLogistics.Enable(AllowOverflowInLogisticsEnabled.Value);
|
||||
GreaterPowerUsageInLogistics.Enable(GreaterPowerUsageInLogisticsEnabled.Value);
|
||||
LogisticsConstrolPanelImprovement.Enable(LogisticsConstrolPanelImprovementEnabled.Value);
|
||||
RealtimeLogisticsInfoPanel.Enable(RealtimeLogisticsInfoPanelEnabled.Value);
|
||||
RealtimeLogisticsInfoPanel.EnableBars(RealtimeLogisticsInfoPanelBarsEnabled.Value);
|
||||
|
||||
GameLogicProc.OnGameBegin += RealtimeLogisticsInfoPanel.OnGameBegin;
|
||||
GameLogicProc.OnGameEnd += RealtimeLogisticsInfoPanel.OnGameEnd;
|
||||
GameLogicProc.OnDataLoaded += RealtimeLogisticsInfoPanel.OnDataLoaded;
|
||||
}
|
||||
|
||||
public static void Uninit()
|
||||
{
|
||||
GameLogicProc.OnDataLoaded -= RealtimeLogisticsInfoPanel.OnDataLoaded;
|
||||
GameLogicProc.OnGameEnd -= RealtimeLogisticsInfoPanel.OnGameEnd;
|
||||
GameLogicProc.OnGameBegin -= RealtimeLogisticsInfoPanel.OnGameBegin;
|
||||
|
||||
AutoConfigLogistics.Enable(false);
|
||||
AutoConfigLogisticsSetDefaultRemoteLogicToStorage.Enable(false);
|
||||
LogisticsCapacityTweaks.Enable(false);
|
||||
AllowOverflowInLogistics.Enable(false);
|
||||
GreaterPowerUsageInLogistics.Enable(false);
|
||||
LogisticsConstrolPanelImprovement.Enable(false);
|
||||
RealtimeLogisticsInfoPanel.Enable(false);
|
||||
}
|
||||
|
||||
public static void OnUpdate() => RealtimeInfoPanelPatch.OnUpdate();
|
||||
|
||||
public static void OnInputUpdate()
|
||||
{
|
||||
if (VFInput.onGUI && LogisticsCapacityTweaksEnabled.Value)
|
||||
{
|
||||
LogisticsCapacityTweaks.UpdateInput();
|
||||
}
|
||||
}
|
||||
|
||||
#region Apply auto-config values to existing facilities on the current planet
|
||||
|
||||
private enum StationKind
|
||||
{
|
||||
Pls,
|
||||
Ils,
|
||||
VeinCollector
|
||||
}
|
||||
|
||||
// === Per-field setters (single source of truth, shared by auto-config-on-build and apply-to-planet) ===
|
||||
|
||||
internal static void StationSetChargePower(PlanetFactory factory, StationComponent station) =>
|
||||
factory.powerSystem.consumerPool[station.pcId].workEnergyPerTick =
|
||||
(long)((station.isStellar ? 250000.0 * AutoConfigILSChargePower.Value : 50000.0 * AutoConfigPLSChargePower.Value) + 0.5);
|
||||
|
||||
internal static void StationSetTripRangeDrones(PlanetFactory factory, StationComponent station) =>
|
||||
station.tripRangeDrones = Math.Cos((station.isStellar ? AutoConfigILSMaxTripDrone.Value : AutoConfigPLSMaxTripDrone.Value) / 180.0 * Math.PI);
|
||||
|
||||
internal static void StationSetDeliveryDrones(PlanetFactory factory, StationComponent station)
|
||||
{
|
||||
var v = station.isStellar ? AutoConfigILSDroneMinDeliver.Value : AutoConfigPLSDroneMinDeliver.Value;
|
||||
station.deliveryDrones = v == 0 ? 1 : v * 10;
|
||||
}
|
||||
|
||||
internal static void StationSetPilerCount(PlanetFactory factory, StationComponent station) =>
|
||||
station.pilerCount = station.isStellar ? AutoConfigILSMinPilerValue.Value : AutoConfigPLSMinPilerValue.Value;
|
||||
|
||||
internal static void StationFillDrones(PlanetFactory factory, StationComponent station)
|
||||
{
|
||||
var target = station.isStellar ? AutoConfigILSDroneCount.Value : AutoConfigPLSDroneCount.Value;
|
||||
var toFill = Math.Max(0, target - station.idleDroneCount - station.workDroneCount);
|
||||
if (toFill > 0) station.idleDroneCount += GameMain.data.mainPlayer.package.TakeItem((int)KnownItemId.Drone, toFill, out _);
|
||||
}
|
||||
|
||||
internal static void StationSetTripRangeShips(PlanetFactory factory, StationComponent station) =>
|
||||
station.tripRangeShips = AutoConfigILSMaxTripShip.Value switch
|
||||
{
|
||||
<= 20 => AutoConfigILSMaxTripShip.Value,
|
||||
<= 40 => AutoConfigILSMaxTripShip.Value * 2 - 20,
|
||||
_ => 10000,
|
||||
} * 2400000.0;
|
||||
|
||||
internal static void StationSetWarpDistance(PlanetFactory factory, StationComponent station) =>
|
||||
station.warpEnableDist = AutoConfigILSWarperDistance.Value switch
|
||||
{
|
||||
<= 7 => AutoConfigILSWarperDistance.Value * 0.5 - 0.5,
|
||||
<= 16 => AutoConfigILSWarperDistance.Value - 4.0,
|
||||
<= 20 => AutoConfigILSWarperDistance.Value * 2 - 20.0,
|
||||
_ => 60.0,
|
||||
} * 40000.0;
|
||||
|
||||
internal static void StationSetDeliveryShips(PlanetFactory factory, StationComponent station)
|
||||
{
|
||||
var v = AutoConfigILSShipMinDeliver.Value;
|
||||
station.deliveryShips = v == 0 ? 1 : v * 10;
|
||||
}
|
||||
|
||||
internal static void StationFillShips(PlanetFactory factory, StationComponent station)
|
||||
{
|
||||
var toFill = Math.Max(0, AutoConfigILSShipCount.Value - station.idleShipCount - station.workShipCount);
|
||||
if (toFill > 0) station.idleShipCount += GameMain.data.mainPlayer.package.TakeItem((int)KnownItemId.Ship, toFill, out _);
|
||||
}
|
||||
|
||||
internal static void StationSetIncludeOrbitCollector(PlanetFactory factory, StationComponent station) =>
|
||||
station.includeOrbitCollector = AutoConfigILSIncludeOrbitCollector.Value;
|
||||
|
||||
internal static void StationSetWarperNecessary(PlanetFactory factory, StationComponent station) =>
|
||||
station.warperNecessary = AutoConfigILSWarperNecessary.Value;
|
||||
|
||||
/* station.minerId may not be set yet on freshly built collectors, so resolve the minerId from the EntityData. */
|
||||
internal static bool VeinCollectorSetHarvestSpeed(PlanetFactory factory, StationComponent station)
|
||||
{
|
||||
ref var entity = ref factory.entityPool[station.entityId];
|
||||
if (entity.id != station.entityId || entity.minerId <= 0 || entity.minerId >= factory.factorySystem.minerCursor) return false;
|
||||
factory.factorySystem.minerPool[entity.minerId].speed = 10000 + AutoConfigVeinCollectorHarvestSpeed.Value * 1000;
|
||||
return true;
|
||||
}
|
||||
|
||||
internal static void VeinCollectorSetPilerCount(PlanetFactory factory, StationComponent station) =>
|
||||
station.pilerCount = AutoConfigVeinCollectorMinPilerValue.Value;
|
||||
|
||||
internal static void DispenserSetChargePower(PlanetFactory factory, DispenserComponent dispenser) =>
|
||||
factory.powerSystem.consumerPool[dispenser.pcId].workEnergyPerTick = (long)(5000.0 * AutoConfigDispenserChargePower.Value + 0.5);
|
||||
|
||||
internal static void DispenserFillCouriers(PlanetFactory factory, DispenserComponent dispenser)
|
||||
{
|
||||
var toFill = Math.Max(0, AutoConfigDispenserCourierCount.Value - dispenser.idleCourierCount - dispenser.workCourierCount);
|
||||
if (toFill > 0) dispenser.idleCourierCount += GameMain.data.mainPlayer.package.TakeItem((int)KnownItemId.Bot, toFill, out _);
|
||||
}
|
||||
|
||||
internal static void BattleBaseSetChargePower(PlanetFactory factory, BattleBaseComponent battleBase) =>
|
||||
factory.powerSystem.consumerPool[battleBase.pcId].workEnergyPerTick = (long)(5000.0 * AutoConfigBattleBaseChargePower.Value + 0.5);
|
||||
|
||||
// === Per-facility "apply all settings" (also used as auto-config-on-build entry point) ===
|
||||
|
||||
internal static void DoConfigStation(PlanetFactory factory, StationComponent station)
|
||||
{
|
||||
if (station.isCollector) return;
|
||||
if (station.isVeinCollector)
|
||||
{
|
||||
if (VeinCollectorSetHarvestSpeed(factory, station))
|
||||
VeinCollectorSetPilerCount(factory, station);
|
||||
return;
|
||||
}
|
||||
if (!station.isStellar)
|
||||
{
|
||||
StationSetChargePower(factory, station);
|
||||
StationSetTripRangeDrones(factory, station);
|
||||
StationSetDeliveryDrones(factory, station);
|
||||
StationSetPilerCount(factory, station);
|
||||
StationFillDrones(factory, station);
|
||||
return;
|
||||
}
|
||||
StationSetChargePower(factory, station);
|
||||
StationSetTripRangeDrones(factory, station);
|
||||
StationSetTripRangeShips(factory, station);
|
||||
StationSetWarpDistance(factory, station);
|
||||
StationSetDeliveryDrones(factory, station);
|
||||
StationSetDeliveryShips(factory, station);
|
||||
StationSetPilerCount(factory, station);
|
||||
StationSetIncludeOrbitCollector(factory, station);
|
||||
StationSetWarperNecessary(factory, station);
|
||||
StationFillDrones(factory, station);
|
||||
StationFillShips(factory, station);
|
||||
}
|
||||
|
||||
// === Iterate over the current planet's facilities of a given kind ===
|
||||
|
||||
private static void ForEachStation(StationKind kind, Action<PlanetFactory, StationComponent> action)
|
||||
{
|
||||
var factory = GameMain.localPlanet?.factory;
|
||||
var transport = factory?.transport;
|
||||
var stationPool = transport?.stationPool;
|
||||
if (stationPool == null) return;
|
||||
for (var i = transport.stationCursor - 1; i > 0; i--)
|
||||
{
|
||||
var station = stationPool[i];
|
||||
if (station == null || station.id != i || station.isCollector) continue;
|
||||
var skip = kind switch
|
||||
{
|
||||
StationKind.VeinCollector => !station.isVeinCollector,
|
||||
StationKind.Ils => station.isVeinCollector || !station.isStellar,
|
||||
StationKind.Pls => station.isVeinCollector || station.isStellar,
|
||||
_ => true
|
||||
};
|
||||
if (skip) continue;
|
||||
action(factory, station);
|
||||
}
|
||||
RefreshOpenLogisticsWindows();
|
||||
}
|
||||
|
||||
private static void ForEachDispenser(Action<PlanetFactory, DispenserComponent> action)
|
||||
{
|
||||
var factory = GameMain.localPlanet?.factory;
|
||||
var transport = factory?.transport;
|
||||
var dispenserPool = transport?.dispenserPool;
|
||||
if (dispenserPool == null) return;
|
||||
for (var i = transport.dispenserCursor - 1; i > 0; i--)
|
||||
{
|
||||
var dispenser = dispenserPool[i];
|
||||
if (dispenser == null || dispenser.id != i) continue;
|
||||
action(factory, dispenser);
|
||||
}
|
||||
RefreshOpenLogisticsWindows();
|
||||
}
|
||||
|
||||
private static void ForEachBattleBase(Action<PlanetFactory, BattleBaseComponent> action)
|
||||
{
|
||||
var factory = GameMain.localPlanet?.factory;
|
||||
var battleBases = factory?.defenseSystem?.battleBases;
|
||||
if (battleBases?.buffer == null) return;
|
||||
for (var i = battleBases.cursor - 1; i > 0; i--)
|
||||
{
|
||||
var battleBase = battleBases.buffer[i];
|
||||
if (battleBase == null || battleBase.id != i) continue;
|
||||
action(factory, battleBase);
|
||||
}
|
||||
RefreshOpenLogisticsWindows();
|
||||
}
|
||||
|
||||
// Re-populate any open logistic facility detail window so applied values show immediately.
|
||||
internal static void RefreshOpenLogisticsWindows()
|
||||
{
|
||||
var uiRoot = UIRoot.instance;
|
||||
if (!uiRoot) return;
|
||||
var uiGame = uiRoot.uiGame;
|
||||
if (!uiGame) return;
|
||||
var stationWindow = uiGame.stationWindow;
|
||||
if (stationWindow && stationWindow.active) stationWindow.OnStationIdChange();
|
||||
var dispenserWindow = uiGame.dispenserWindow;
|
||||
if (dispenserWindow && dispenserWindow.active) dispenserWindow.OnDispenserIdChange();
|
||||
var battleBaseWindow = uiGame.battleBaseWindow;
|
||||
if (battleBaseWindow && battleBaseWindow.active) battleBaseWindow.OnBattleBaseIdChange();
|
||||
}
|
||||
|
||||
// === Public entry points invoked by the config panel buttons ===
|
||||
|
||||
// Dispenser
|
||||
public static void ApplyDispenserChargePower() => ForEachDispenser(DispenserSetChargePower);
|
||||
public static void ApplyDispenserCourierCount() => ForEachDispenser(DispenserFillCouriers);
|
||||
public static void ApplyAllDispenser() => ForEachDispenser((f, d) => { DispenserSetChargePower(f, d); DispenserFillCouriers(f, d); });
|
||||
|
||||
// Battlefield Analysis Base
|
||||
public static void ApplyBattleBaseChargePower() => ForEachBattleBase(BattleBaseSetChargePower);
|
||||
public static void ApplyAllBattleBase() => ForEachBattleBase(BattleBaseSetChargePower);
|
||||
|
||||
// PLS
|
||||
public static void ApplyPLSChargePower() => ForEachStation(StationKind.Pls, StationSetChargePower);
|
||||
public static void ApplyPLSTripRangeDrones() => ForEachStation(StationKind.Pls, StationSetTripRangeDrones);
|
||||
public static void ApplyPLSDroneMinDeliver() => ForEachStation(StationKind.Pls, StationSetDeliveryDrones);
|
||||
public static void ApplyPLSMinPilerValue() => ForEachStation(StationKind.Pls, StationSetPilerCount);
|
||||
public static void ApplyPLSDroneCount() => ForEachStation(StationKind.Pls, StationFillDrones);
|
||||
public static void ApplyAllPLS() => ForEachStation(StationKind.Pls, DoConfigStation);
|
||||
|
||||
// ILS
|
||||
public static void ApplyILSChargePower() => ForEachStation(StationKind.Ils, StationSetChargePower);
|
||||
public static void ApplyILSTripRangeDrones() => ForEachStation(StationKind.Ils, StationSetTripRangeDrones);
|
||||
public static void ApplyILSTripRangeShips() => ForEachStation(StationKind.Ils, StationSetTripRangeShips);
|
||||
public static void ApplyILSWarpDistance() => ForEachStation(StationKind.Ils, StationSetWarpDistance);
|
||||
public static void ApplyILSDroneMinDeliver() => ForEachStation(StationKind.Ils, StationSetDeliveryDrones);
|
||||
public static void ApplyILSShipMinDeliver() => ForEachStation(StationKind.Ils, StationSetDeliveryShips);
|
||||
public static void ApplyILSMinPilerValue() => ForEachStation(StationKind.Ils, StationSetPilerCount);
|
||||
public static void ApplyILSDroneCount() => ForEachStation(StationKind.Ils, StationFillDrones);
|
||||
public static void ApplyILSShipCount() => ForEachStation(StationKind.Ils, StationFillShips);
|
||||
public static void ApplyILSIncludeOrbitCollector() => ForEachStation(StationKind.Ils, StationSetIncludeOrbitCollector);
|
||||
public static void ApplyILSWarperNecessary() => ForEachStation(StationKind.Ils, StationSetWarperNecessary);
|
||||
public static void ApplyAllILS() => ForEachStation(StationKind.Ils, DoConfigStation);
|
||||
|
||||
// Vein Collector (Advanced Mining Machine)
|
||||
public static void ApplyVeinCollectorHarvestSpeed() => ForEachStation(StationKind.VeinCollector, (f, s) => VeinCollectorSetHarvestSpeed(f, s));
|
||||
public static void ApplyVeinCollectorMinPilerValue() => ForEachStation(StationKind.VeinCollector, VeinCollectorSetPilerCount);
|
||||
public static void ApplyAllVeinCollector() => ForEachStation(StationKind.VeinCollector, DoConfigStation);
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection.Emit;
|
||||
using HarmonyLib;
|
||||
using UnityEngine;
|
||||
using UXAssist.Common;
|
||||
|
||||
namespace UXAssist.Patches.Logistics;
|
||||
|
||||
internal class AllowOverflowInLogistics : PatchImpl<AllowOverflowInLogistics>
|
||||
{
|
||||
private static bool _blueprintPasting;
|
||||
|
||||
// Do not check for overflow when try to send hand items into storages
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(UIControlPanelStationStorage), nameof(UIControlPanelStationStorage.OnItemIconMouseDown))]
|
||||
[HarmonyPatch(typeof(UIStationStorage), nameof(UIStationStorage.OnItemIconMouseDown))]
|
||||
private static IEnumerable<CodeInstruction> UIStationStorage_OnItemIconMouseDown_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Call, AccessTools.PropertyGetter(typeof(LDB), nameof(LDB.items))),
|
||||
new CodeMatch(OpCodes.Ldarg_0)
|
||||
);
|
||||
var pos = matcher.Pos;
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(OpCodes.Ldloc_S),
|
||||
new CodeMatch(OpCodes.Stloc_S)
|
||||
);
|
||||
var inst = matcher.InstructionAt(1).Clone();
|
||||
var pos2 = matcher.Pos + 2;
|
||||
matcher.Start().Advance(pos);
|
||||
var labels = matcher.Labels;
|
||||
matcher.RemoveInstructions(pos2 - pos).Insert(
|
||||
new CodeInstruction(OpCodes.Ldloc_1).WithLabels(labels),
|
||||
new CodeInstruction(OpCodes.Callvirt, AccessTools.PropertyGetter(typeof(Player), nameof(Player.inhandItemCount))),
|
||||
inst
|
||||
);
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
// Remove storage limit check
|
||||
[HarmonyTranspiler]
|
||||
[HarmonyPatch(typeof(PlanetTransport), nameof(PlanetTransport.SetStationStorage))]
|
||||
private static IEnumerable<CodeInstruction> PlanetTransport_SetStationStorage_Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
|
||||
{
|
||||
var matcher = new CodeMatcher(instructions, generator);
|
||||
matcher.MatchForward(false,
|
||||
new CodeMatch(ci => ci.IsLdarg()),
|
||||
new CodeMatch(ci => ci.IsLdloc()),
|
||||
new CodeMatch(ci => ci.IsLdloc()),
|
||||
new CodeMatch(OpCodes.Add),
|
||||
new CodeMatch(ci => ci.Branches(out _)),
|
||||
new CodeMatch(ci => ci.IsLdloc()),
|
||||
new CodeMatch(ci => ci.IsLdloc()),
|
||||
new CodeMatch(OpCodes.Add),
|
||||
new CodeMatch(ci => ci.IsStarg())
|
||||
);
|
||||
var label = generator.DefineLabel();
|
||||
var oldLabels = matcher.Labels;
|
||||
matcher.Labels = [];
|
||||
matcher.InsertAndAdvance(
|
||||
new CodeInstruction(OpCodes.Ldsfld, AccessTools.Field(typeof(AllowOverflowInLogistics), nameof(_blueprintPasting))).WithLabels(oldLabels),
|
||||
new CodeInstruction(OpCodes.Brfalse, label)
|
||||
);
|
||||
matcher.Advance(9).Labels.Add(label);
|
||||
return matcher.InstructionEnumeration();
|
||||
}
|
||||
|
||||
[HarmonyPrefix]
|
||||
[HarmonyPatch(typeof(BuildTool_BlueprintPaste), nameof(BuildTool_BlueprintPaste.CreatePrebuilds))]
|
||||
private static void BuildTool_BlueprintPaste_CreatePrebuilds_Prefix()
|
||||
{
|
||||
_blueprintPasting = true;
|
||||
}
|
||||
|
||||
[HarmonyPostfix]
|
||||
[HarmonyPatch(typeof(BuildTool_BlueprintPaste), nameof(BuildTool_BlueprintPaste.CreatePrebuilds))]
|
||||
private static void BuildTool_BlueprintPaste_CreatePrebuilds_Postfix()
|
||||
{
|
||||
_blueprintPasting = false;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -7,6 +7,7 @@ using UXAssist.Functions;
|
||||
using UXAssist.ModsCompat;
|
||||
using UXAssist.Patches;
|
||||
using UXAssist.Patches.Factory;
|
||||
using UXAssist.Patches.Logistics;
|
||||
using UXAssist.UI;
|
||||
|
||||
namespace UXAssist;
|
||||
|
||||
@@ -14,6 +14,7 @@ using UXAssist.Common.ModFeatures;
|
||||
using UXAssist.Functions;
|
||||
using UXAssist.Patches;
|
||||
using UXAssist.Patches.Factory;
|
||||
using UXAssist.Patches.Logistics;
|
||||
using UXAssist.UI;
|
||||
using Util = UXAssist.Common.Util;
|
||||
using GameLogicProc = UXAssist.Common.GameLogic;
|
||||
|
||||
Reference in New Issue
Block a user