1
0
mirror of https://github.com/soarqin/DSP_Mods.git synced 2025-12-09 00:53:39 +08:00
Files
DSP_Mods/Dustbin/TankPatch.cs
2025-09-21 15:38:03 +08:00

251 lines
8.5 KiB
C#

using System.IO;
using System.Runtime.CompilerServices;
using HarmonyLib;
using NebulaAPI;
namespace Dustbin;
[HarmonyPatch]
public static class TankPatch
{
private static UI.MyCheckBox _tankDustbinCheckBox;
private static int _lastTankId;
private static Harmony _patch;
public static void Enable(bool on)
{
if (on)
{
_patch ??= Harmony.CreateAndPatchAll(typeof(TankPatch));
}
else
{
_patch?.UnpatchSelf();
_patch = null;
}
}
public static void Reset()
{
_lastTankId = 0;
}
public static void Export(BinaryWriter w)
{
var tempStream = new MemoryStream();
var tempWriter = new BinaryWriter(tempStream);
var factories = GameMain.data.factories;
var factoryCount = GameMain.data.factoryCount;
for (var i = 0; i < factoryCount; i++)
{
var factory = factories[i];
if (factory == null) continue;
var storage = factory.factoryStorage;
var tankPool = storage.tankPool;
var cursor = storage.tankCursor;
var count = 0;
for (var j = 1; j < cursor; j++)
{
if (tankPool[j].id != j) continue;
if (!tankPool[j].IsDustbin) continue;
tempWriter.Write(j);
count++;
}
if (count == 0) continue;
tempWriter.Flush();
tempStream.Position = 0;
w.Write((byte)2);
w.Write(factory.planetId);
w.Write(count);
/* FixMe: May BinaryWriter not sync with its BaseStream while subclass overrides Write()? */
tempStream.CopyTo(w.BaseStream);
tempStream.SetLength(0);
}
tempWriter.Dispose();
tempStream.Dispose();
}
public static void Import(BinaryReader r)
{
while (r.PeekChar() == 2)
{
r.ReadByte();
var planetId = r.ReadInt32();
var planet = GameMain.data.galaxy.PlanetById(planetId);
var tankPool = planet?.factory.factoryStorage.tankPool;
if (tankPool == null)
{
for (var count = r.ReadInt32(); count > 0; count--)
{
r.ReadInt32();
}
continue;
}
for (var count = r.ReadInt32(); count > 0; count--)
{
var id = r.ReadInt32();
if (id > 0 && id < tankPool.Length && tankPool[id].id == id)
{
tankPool[id].IsDustbin = true;
}
}
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(GameMain), nameof(GameMain.Start))]
private static void GameMain_Start_Prefix()
{
Reset();
}
[HarmonyPostfix]
[HarmonyPatch(typeof(UITankWindow), nameof(UITankWindow._OnCreate))]
private static void UITankWindow__OnCreate_Postfix(UITankWindow __instance)
{
_tankDustbinCheckBox = UI.MyCheckBox.CreateCheckBox(false, __instance.transform, 120f, 20f, Localization.CurrentLanguageLCID == Localization.LCID_ZHCN ? "垃圾桶" : "Dustbin");
var window = __instance;
_tankDustbinCheckBox.OnChecked += () =>
{
var tankId = window.tankId;
if (tankId <= 0) return;
var tankPool = window.storage.tankPool;
if (tankPool[tankId].id != tankId) return;
var enabled = _tankDustbinCheckBox.Checked;
tankPool[tankId].IsDustbin = enabled;
if (!NebulaModAPI.IsMultiplayerActive) return;
var planetId = window.factory.planetId;
NebulaModAPI.MultiplayerSession.Network.SendPacketToLocalStar(new NebulaSupport.Packet.ToggleEvent(planetId, -tankId, enabled));
};
}
[HarmonyPostfix]
[HarmonyPatch(typeof(UITankWindow), nameof(UITankWindow._OnUpdate))]
private static void UITankWindow__OnUpdate_Postfix(UITankWindow __instance)
{
var tankId = __instance.tankId;
if (_lastTankId == tankId) return;
_lastTankId = tankId;
if (tankId <= 0) return;
var tankPool = __instance.storage.tankPool;
ref var tank = ref tankPool[tankId];
if (tank.id != tankId) return;
_tankDustbinCheckBox.Checked = tank.IsDustbin;
}
[HarmonyPrefix]
[HarmonyPatch(typeof(TankComponent), nameof(TankComponent.GameTick))]
private static bool TankComponent_GameTick_Prefix(ref TankComponent __instance, PlanetFactory factory)
{
if (__instance.fluidInc < 0)
__instance.fluidInc = 0;
if (!__instance.isBottom)
return false;
var cargoTraffic = factory.cargoTraffic;
var tankPool = factory.factoryStorage.tankPool;
var belt = __instance.belt0;
if (belt > 0)
{
TankComponentUpdateBelt(ref __instance, belt, __instance.isOutput0, ref cargoTraffic, ref tankPool);
}
belt = __instance.belt1;
if (belt > 0)
{
TankComponentUpdateBelt(ref __instance, belt, __instance.isOutput1, ref cargoTraffic, ref tankPool);
}
belt = __instance.belt2;
if (belt > 0)
{
TankComponentUpdateBelt(ref __instance, belt, __instance.isOutput2, ref cargoTraffic, ref tankPool);
}
belt = __instance.belt3;
if (belt > 0)
{
TankComponentUpdateBelt(ref __instance, belt, __instance.isOutput3, ref cargoTraffic, ref tankPool);
}
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void TankComponentUpdateBelt(ref TankComponent thisTank, int belt, bool isOutput, ref CargoTraffic cargoTraffic, ref TankComponent[] tankPool)
{
if (isOutput)
{
if (thisTank.outputSwitch)
{
if (thisTank.fluidId <= 0 || thisTank.fluidCount <= 0) return;
var inc = thisTank.fluidInc == 0 ? 0 : thisTank.fluidInc / thisTank.fluidCount;
if (!cargoTraffic.TryInsertItemAtHead(belt, thisTank.fluidId, 1, (byte)inc)) return;
thisTank.fluidCount--;
thisTank.fluidInc -= inc;
}
}
else
{
if (thisTank.inputSwitch)
{
byte stack;
byte inc;
var thisFluidId = thisTank.fluidId;
if (thisTank.fluidCount <= 0)
{
var fluidId = cargoTraffic.TryPickItemAtRear(belt, 0, ItemProto.fluids, out stack, out inc);
if (fluidId <= 0 || thisTank.IsDustbin) return;
thisTank.fluidId = fluidId;
thisTank.fluidCount = stack;
thisTank.fluidInc = inc;
return;
}
if (thisTank.fluidCount < thisTank.fluidCapacity || thisTank.IsDustbin)
{
if (cargoTraffic.GetItemIdAtRear(belt) != thisFluidId || thisTank.nextTankId <= 0) return;
if (cargoTraffic.TryPickItemAtRear(belt, thisFluidId, null, out stack, out inc) <= 0 || thisTank.IsDustbin) return;
thisTank.fluidCount += stack;
thisTank.fluidInc += inc;
return;
}
if (thisTank.nextTankId <= 0) return;
ref var targetTank = ref tankPool[thisTank.nextTankId];
while (true)
{
if (targetTank.fluidCount < targetTank.fluidCapacity || targetTank.IsDustbin)
{
if (!targetTank.inputSwitch) return;
var targetFluidId = targetTank.fluidId;
if (targetFluidId != 0 && targetFluidId != thisFluidId) return;
break;
}
if (targetTank.nextTankId <= 0) return;
targetTank = ref tankPool[targetTank.nextTankId];
}
if (cargoTraffic.TryPickItemAtRear(belt, thisFluidId, null, out stack, out inc) <= 0 || targetTank.IsDustbin) return;
if (targetTank.fluidCount <= 0)
{
targetTank.fluidId = thisFluidId;
targetTank.fluidCount = stack;
targetTank.fluidInc = inc;
}
else
{
targetTank.fluidCount += stack;
targetTank.fluidInc += inc;
}
}
}
}
}