mirror of
https://github.com/soarqin/DSP_Mods.git
synced 2026-08-06 07:40:23 +08:00
399 lines
15 KiB
C#
399 lines
15 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using HarmonyLib;
|
|
using UXAssist.Common;
|
|
using UXAssist.Common.GameConstants;
|
|
using UXAssist.Common.ModFeatures;
|
|
using GameLogicProc = UXAssist.Common.GameLogic;
|
|
|
|
namespace UXAssist.Patches.Factory;
|
|
|
|
[ModFeature("BeltSignalsForBuyOut")]
|
|
internal static class BeltSignalPatch
|
|
{
|
|
public static void Enable(bool enable)
|
|
{
|
|
BeltSignalsForBuyOut.Enable(enable);
|
|
}
|
|
|
|
public static void InitPersist()
|
|
{
|
|
BeltSignalsForBuyOut.InitPersist();
|
|
}
|
|
|
|
public static void UninitPersist()
|
|
{
|
|
BeltSignalsForBuyOut.UninitPersist();
|
|
}
|
|
|
|
public static void Export(BinaryWriter w)
|
|
{
|
|
var storage = BeltSignalsForBuyOut.DarkFogItemsInVoid;
|
|
for (var i = 0; i < 6; i++)
|
|
w.Write(storage[i]);
|
|
}
|
|
|
|
public static void Import(BinaryReader r)
|
|
{
|
|
var storage = BeltSignalsForBuyOut.DarkFogItemsInVoid;
|
|
for (var i = 0; i < 6; i++)
|
|
storage[i] = r.ReadInt32();
|
|
}
|
|
|
|
public static void Init()
|
|
{
|
|
GameLogicProc.OnGameEnd += BeltSignalsForBuyOut.ResetState;
|
|
}
|
|
|
|
public static void Uninit()
|
|
{
|
|
GameLogicProc.OnGameEnd -= BeltSignalsForBuyOut.ResetState;
|
|
}
|
|
|
|
internal class BeltSignalsForBuyOut : PatchImpl<BeltSignalsForBuyOut>
|
|
{
|
|
private static bool _initialized;
|
|
private static bool _loaded;
|
|
private static long _clusterSeedKey;
|
|
private static readonly int[] DarkFogItemIds = ItemIds.DarkFogItemIds;
|
|
private static readonly int[] DarkFogItemExchangeRate = [20, 60, 30, 30, 30, 10];
|
|
public static readonly int[] DarkFogItemsInVoid = [0, 0, 0, 0, 0, 0];
|
|
private static Dictionary<int, uint>[] _signalBelts = new Dictionary<int, uint>[64];
|
|
private static readonly HashSet<int> SignalBeltFactoryIndices = [];
|
|
|
|
internal static void ResetState()
|
|
{
|
|
_clusterSeedKey = 0L;
|
|
_signalBelts = new Dictionary<int, uint>[64];
|
|
SignalBeltFactoryIndices.Clear();
|
|
for (var i = 0; i < DarkFogItemsInVoid.Length; i++)
|
|
DarkFogItemsInVoid[i] = 0;
|
|
}
|
|
|
|
public static void InitPersist()
|
|
{
|
|
Persist.Enable(true);
|
|
}
|
|
|
|
public static void UninitPersist()
|
|
{
|
|
Persist.Enable(false);
|
|
}
|
|
|
|
private static void AddBeltSignalProtos()
|
|
{
|
|
if (!_initialized || _loaded) return;
|
|
var assembly = Assembly.GetExecutingAssembly();
|
|
var signals = LDB._signals;
|
|
SignalProto[] protos =
|
|
[
|
|
new SignalProto
|
|
{
|
|
ID = 301,
|
|
Name = "Memory Unit",
|
|
GridIndex = 3801,
|
|
IconPath = "assets/signal/memory.png",
|
|
_iconSprite = Util.LoadEmbeddedSprite("assets/signal/memory.png", assembly),
|
|
SID = ""
|
|
},
|
|
new SignalProto
|
|
{
|
|
ID = 302,
|
|
Name = "Energy Fragment",
|
|
GridIndex = 3802,
|
|
IconPath = "assets/signal/energy-fragment.png",
|
|
_iconSprite = Util.LoadEmbeddedSprite("assets/signal/energy-fragment.png", assembly),
|
|
SID = ""
|
|
},
|
|
new SignalProto
|
|
{
|
|
ID = 303,
|
|
Name = "Silicon Neuron",
|
|
GridIndex = 3803,
|
|
IconPath = "assets/signal/silicon-neuron.png",
|
|
_iconSprite = Util.LoadEmbeddedSprite("assets/signal/silicon-neuron.png", assembly),
|
|
SID = ""
|
|
},
|
|
new SignalProto
|
|
{
|
|
ID = 304,
|
|
Name = "Negentropy Singularity",
|
|
GridIndex = 3804,
|
|
IconPath = "assets/signal/negentropy.png",
|
|
_iconSprite = Util.LoadEmbeddedSprite("assets/signal/negentropy.png", assembly),
|
|
SID = ""
|
|
},
|
|
new SignalProto
|
|
{
|
|
ID = 305,
|
|
Name = "Matter Reassembler",
|
|
GridIndex = 3805,
|
|
IconPath = "assets/signal/reassembler.png",
|
|
_iconSprite = Util.LoadEmbeddedSprite("assets/signal/reassembler.png", assembly),
|
|
SID = ""
|
|
},
|
|
new SignalProto
|
|
{
|
|
ID = 306,
|
|
Name = "Virtual Particle",
|
|
GridIndex = 3806,
|
|
IconPath = "assets/signal/virtual-particle.png",
|
|
_iconSprite = Util.LoadEmbeddedSprite("assets/signal/virtual-particle.png", assembly),
|
|
SID = ""
|
|
},
|
|
];
|
|
foreach (var proto in protos)
|
|
{
|
|
proto.name = proto.Name.Translate();
|
|
}
|
|
|
|
var index = signals.dataArray.Length;
|
|
signals.dataArray = [.. signals.dataArray, .. protos];
|
|
foreach (var proto in protos)
|
|
{
|
|
signals.dataIndices[proto.ID] = index;
|
|
index++;
|
|
}
|
|
|
|
_loaded = true;
|
|
}
|
|
|
|
private static void RemoveBeltSignalProtos()
|
|
{
|
|
if (!_initialized || !_loaded) return;
|
|
var signals = LDB._signals;
|
|
if (signals.dataIndices.TryGetValue(301, out var index))
|
|
{
|
|
signals.dataArray = [.. signals.dataArray.Take(index), .. signals.dataArray.Skip(index + 6)];
|
|
for (var id = 301; id <= 306; id++)
|
|
signals.dataIndices.Remove(id);
|
|
var len = signals.dataArray.Length;
|
|
for (; index < len; index++)
|
|
signals.dataIndices[signals.dataArray[index].ID] = index;
|
|
}
|
|
|
|
_loaded = false;
|
|
}
|
|
|
|
private static void InitSignalBelts()
|
|
{
|
|
if (!GameMain.isRunning) return;
|
|
|
|
var factories = GameMain.data?.factories;
|
|
if (factories == null) return;
|
|
foreach (var factory in factories)
|
|
{
|
|
var entitySignPool = factory?.entitySignPool;
|
|
if (entitySignPool == null) continue;
|
|
var cargoTraffic = factory.cargoTraffic;
|
|
var beltPool = cargoTraffic.beltPool;
|
|
for (var i = cargoTraffic.beltCursor - 1; i > 0; i--)
|
|
{
|
|
if (beltPool[i].id != i) continue;
|
|
ref var signal = ref entitySignPool[beltPool[i].entityId];
|
|
var signalId = signal.iconId0;
|
|
if (signalId is < 301U or > 306U) continue;
|
|
SetSignalBelt(factory.index, i, signalId - 301U);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void SetSignalBelt(int factory, int beltId, uint signal)
|
|
{
|
|
var signalBelts = GetOrCreateSignalBelts(factory);
|
|
if (signalBelts.Count == 0)
|
|
SignalBeltFactoryIndices.Add(factory);
|
|
signalBelts[beltId] = signal;
|
|
}
|
|
|
|
private static Dictionary<int, uint> GetOrCreateSignalBelts(int index)
|
|
{
|
|
Dictionary<int, uint> obj;
|
|
if (index < 0) return null;
|
|
if (index >= _signalBelts.Length)
|
|
{
|
|
Array.Resize(ref _signalBelts, (index + 1) * 2);
|
|
}
|
|
else
|
|
{
|
|
obj = _signalBelts[index];
|
|
if (obj != null) return obj;
|
|
}
|
|
|
|
obj = [];
|
|
_signalBelts[index] = obj;
|
|
return obj;
|
|
}
|
|
|
|
private static Dictionary<int, uint> GetSignalBelts(int index)
|
|
{
|
|
return index >= 0 && index < _signalBelts.Length ? _signalBelts[index] : null;
|
|
}
|
|
|
|
private static void RemoveSignalBelt(int factory, int beltId)
|
|
{
|
|
var signalBelts = GetSignalBelts(factory);
|
|
if (signalBelts == null) return;
|
|
signalBelts.Remove(beltId);
|
|
if (signalBelts.Count == 0)
|
|
SignalBeltFactoryIndices.Remove(factory);
|
|
}
|
|
|
|
private static void RemovePlanetSignalBelts(int factory)
|
|
{
|
|
var signalBelts = GetSignalBelts(factory);
|
|
if (signalBelts == null) return;
|
|
signalBelts.Clear();
|
|
SignalBeltFactoryIndices.Remove(factory);
|
|
}
|
|
|
|
private class Persist : PatchImpl<Persist>
|
|
{
|
|
protected override void OnEnable()
|
|
{
|
|
AddBeltSignalProtos();
|
|
GameLogicProc.OnDataLoaded += VFPreload_InvokeOnLoadWorkEnded_Postfix;
|
|
GameLogicProc.OnGameBegin += OnGameBegin;
|
|
}
|
|
|
|
protected override void OnDisable()
|
|
{
|
|
GameLogicProc.OnGameBegin -= OnGameBegin;
|
|
GameLogicProc.OnDataLoaded -= VFPreload_InvokeOnLoadWorkEnded_Postfix;
|
|
}
|
|
|
|
private static void VFPreload_InvokeOnLoadWorkEnded_Postfix()
|
|
{
|
|
if (_initialized) return;
|
|
_initialized = true;
|
|
AddBeltSignalProtos();
|
|
}
|
|
|
|
[HarmonyPostfix]
|
|
[HarmonyPatch(typeof(DigitalSystem), MethodType.Constructor, typeof(PlanetData))]
|
|
private static void DigitalSystem_Constructor_Postfix(PlanetData _planet)
|
|
{
|
|
var player = GameMain.mainPlayer;
|
|
if (player == null) return;
|
|
var factory = _planet?.factory;
|
|
if (factory == null) return;
|
|
RemovePlanetSignalBelts(factory.index);
|
|
}
|
|
|
|
private static void OnGameBegin()
|
|
{
|
|
_clusterSeedKey = GameMain.data.GetClusterSeedKey();
|
|
InitSignalBelts();
|
|
}
|
|
|
|
[HarmonyPrefix]
|
|
[HarmonyPatch(typeof(CargoTraffic), nameof(CargoTraffic.RemoveBeltComponent))]
|
|
public static void CargoTraffic_RemoveBeltComponent_Prefix(int id)
|
|
{
|
|
var planet = GameMain.localPlanet;
|
|
if (planet == null) return;
|
|
RemoveSignalBelt(planet.factoryIndex, id);
|
|
}
|
|
|
|
[HarmonyPostfix]
|
|
[HarmonyPatch(typeof(CargoTraffic), nameof(CargoTraffic.SetBeltSignalIcon))]
|
|
public static void CargoTraffic_SetBeltSignalIcon_Postfix(CargoTraffic __instance, int entityId, int signalId)
|
|
{
|
|
var planet = GameMain.localPlanet;
|
|
if (planet == null) return;
|
|
var factory = __instance.factory;
|
|
var factoryIndex = planet.factoryIndex;
|
|
var beltId = factory.entityPool[entityId].beltId;
|
|
if (signalId is < 301 or > 306)
|
|
{
|
|
RemoveSignalBelt(factoryIndex, beltId);
|
|
}
|
|
else
|
|
{
|
|
SetSignalBelt(factoryIndex, beltId, (uint)signalId - 301U);
|
|
}
|
|
}
|
|
}
|
|
|
|
[HarmonyPostfix]
|
|
[HarmonyPatch(typeof(GameLogic), nameof(GameLogic.OnFactoryFrameBegin))]
|
|
public static void GameLogic_OnFactoryFrameBegin_Postfix()
|
|
{
|
|
var factories = GameMain.data?.factories;
|
|
if (factories == null) return;
|
|
var factoriesCount = factories.Length;
|
|
var propertySystem = DSPGame.propertySystem;
|
|
List<int> factoriesToRemove = null;
|
|
foreach (var factoryIndex in SignalBeltFactoryIndices)
|
|
{
|
|
if (factoryIndex >= factoriesCount)
|
|
{
|
|
if (factoriesToRemove == null)
|
|
factoriesToRemove = [factoryIndex];
|
|
else
|
|
factoriesToRemove.Add(factoryIndex);
|
|
continue;
|
|
}
|
|
var signalBelts = GetSignalBelts(factoryIndex);
|
|
if (signalBelts == null) continue;
|
|
var factory = factories[factoryIndex];
|
|
if (factory == null) continue;
|
|
var cargoTraffic = factory.cargoTraffic;
|
|
var beltCount = cargoTraffic.beltCursor;
|
|
List<int> beltsToRemove = null;
|
|
foreach (var kvp in signalBelts)
|
|
{
|
|
if (kvp.Key >= beltCount)
|
|
{
|
|
if (beltsToRemove == null)
|
|
beltsToRemove = [kvp.Key];
|
|
else
|
|
beltsToRemove.Add(kvp.Key);
|
|
continue;
|
|
}
|
|
ref var belt = ref cargoTraffic.beltPool[kvp.Key];
|
|
var cargoPath = cargoTraffic.GetCargoPath(belt.segPathId);
|
|
var itemIdx = kvp.Value;
|
|
if (cargoPath == null) continue;
|
|
var itemId = DarkFogItemIds[itemIdx];
|
|
var consume = (byte)Math.Min(DarkFogItemsInVoid[itemIdx], 4);
|
|
if (consume < 4)
|
|
{
|
|
var metaverseLong = propertySystem.GetItemAvaliableProperty(_clusterSeedKey, ItemIds.Metaverse);
|
|
if (metaverseLong > 0L)
|
|
{
|
|
var metaverse = metaverseLong > 10 ? 10 : (int)metaverseLong;
|
|
propertySystem.AddItemConsumption(_clusterSeedKey, ItemIds.Metaverse, metaverse);
|
|
var mainPlayer = GameMain.mainPlayer;
|
|
GameMain.history.AddPropertyItemConsumption(ItemIds.Metaverse, metaverse, true);
|
|
var count = DarkFogItemExchangeRate[itemIdx] * metaverse;
|
|
DarkFogItemsInVoid[itemIdx] += count;
|
|
consume = (byte)Math.Min(DarkFogItemsInVoid[itemIdx], 4);
|
|
mainPlayer.mecha.AddProductionStat(itemId, count, mainPlayer.nearestFactory);
|
|
}
|
|
}
|
|
|
|
if (consume > 0 && cargoPath.TryInsertItem(belt.segIndex + belt.segPivotOffset, itemId, consume, 0))
|
|
DarkFogItemsInVoid[itemIdx] -= consume;
|
|
}
|
|
if (beltsToRemove == null) continue;
|
|
foreach (var beltId in beltsToRemove)
|
|
signalBelts.Remove(beltId);
|
|
if (signalBelts.Count > 0) continue;
|
|
if (factoriesToRemove == null)
|
|
factoriesToRemove = [factoryIndex];
|
|
else
|
|
factoriesToRemove.Add(factoryIndex);
|
|
}
|
|
if (factoriesToRemove == null) return;
|
|
foreach (var factoryIndex in factoriesToRemove)
|
|
{
|
|
RemovePlanetSignalBelts(factoryIndex);
|
|
}
|
|
}
|
|
}
|
|
}
|