diff --git a/.github/scripts/thunderstore_bundle.js b/.github/scripts/thunderstore_bundle.js index c01504507..8ef552151 100644 --- a/.github/scripts/thunderstore_bundle.js +++ b/.github/scripts/thunderstore_bundle.js @@ -123,8 +123,8 @@ function generateManifest() { BEPINEX_DEPENDENCY, `nebula-${apiPluginInfo.name}-${apiPluginInfo.version}`, "PhantomGamers-IlLine-1.0.0", - "CommonAPI-CommonAPI-1.5.4", - "starfi5h-BulletTime-1.2.6", + "CommonAPI-CommonAPI-1.5.5", + "starfi5h-BulletTime-1.2.9", ], website_url: "https://github.com/hubastard/nebula" }; diff --git a/CHANGELOG.md b/CHANGELOG.md index ab7cbb804..b615f72d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ ## Changelog +0.8.11: + +- @starfi5h: Added support for DSP 0.9.27 along with syncing for the new logistics distribution system +- @starfi5h: Optimized network traffic +- @starfi5h: Dedicated servers will now save when gracefully exited (ctrl+c on the console window) +- @starfi5h: Fix error when sail capacity increases in dedicated server + 0.8.10: - @starfi5h: Fix compilation with 0.9.26.13034 diff --git a/NebulaAPI/CHANGELOG.md b/NebulaAPI/CHANGELOG.md index 8dabe6520..c6fb49364 100644 --- a/NebulaAPI/CHANGELOG.md +++ b/NebulaAPI/CHANGELOG.md @@ -1,4 +1,9 @@ ## Changelog + +1.3.1: + +- Added DeliveryPackage to IMechaData and IPlayerTechBonuses + 1.3.0: - Add a new event OnDysonSphereLoadFinished to NebulaModAPI diff --git a/NebulaAPI/DataStructures/IMechaData.cs b/NebulaAPI/DataStructures/IMechaData.cs index 2f085b2c5..aedf07cf1 100644 --- a/NebulaAPI/DataStructures/IMechaData.cs +++ b/NebulaAPI/DataStructures/IMechaData.cs @@ -8,6 +8,7 @@ public interface IMechaData : INetSerializable double CoreEnergy { get; set; } double ReactorEnergy { get; set; } StorageComponent Inventory { get; set; } + DeliveryPackage DeliveryPackage { get; set; } StorageComponent ReactorStorage { get; set; } StorageComponent WarpStorage { get; set; } MechaForge Forge { get; set; } diff --git a/NebulaAPI/DataStructures/IPlayerTechBonuses.cs b/NebulaAPI/DataStructures/IPlayerTechBonuses.cs index 0aa0ae58d..1fdae9053 100644 --- a/NebulaAPI/DataStructures/IPlayerTechBonuses.cs +++ b/NebulaAPI/DataStructures/IPlayerTechBonuses.cs @@ -30,5 +30,8 @@ public interface IPlayerTechBonuses : INetSerializable float droneSpeed { get; } int droneMovement { get; } int inventorySize { get; } + bool deliveryPackageUnlocked { get; } + int deliveryPackageColCount { get; set; } + int deliveryPackageStackSizeMultiplier { get; } } } \ No newline at end of file diff --git a/NebulaAPI/version.json b/NebulaAPI/version.json index cf40e88e7..eacd07131 100644 --- a/NebulaAPI/version.json +++ b/NebulaAPI/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "1.3.0", + "version": "1.3.1", "assemblyVersion": { "precision": "build" }, diff --git a/NebulaModel/DataStructures/MechaData.cs b/NebulaModel/DataStructures/MechaData.cs index 5ef02dfc3..8582545a4 100644 --- a/NebulaModel/DataStructures/MechaData.cs +++ b/NebulaModel/DataStructures/MechaData.cs @@ -12,6 +12,7 @@ public class MechaData : IMechaData public double CoreEnergy { get; set; } public double ReactorEnergy { get; set; } public StorageComponent Inventory { get; set; } + public DeliveryPackage DeliveryPackage { get; set; } public StorageComponent ReactorStorage { get; set; } public StorageComponent WarpStorage { get; set; } public MechaForge Forge { get; set; } @@ -27,7 +28,7 @@ public MechaData() TechBonuses = new PlayerTechBonuses(); } - public MechaData(int sandCount, double coreEnergy, double reactorEnergy, StorageComponent inventory, StorageComponent reactorStorage, StorageComponent warpStorage, MechaForge forge) + public MechaData(int sandCount, double coreEnergy, double reactorEnergy, StorageComponent inventory, DeliveryPackage deliveryPackage, StorageComponent reactorStorage, StorageComponent warpStorage, MechaForge forge) { SandCount = sandCount; CoreEnergy = coreEnergy; @@ -36,6 +37,7 @@ public MechaData(int sandCount, double coreEnergy, double reactorEnergy, Storage WarpStorage = warpStorage; Forge = forge; Inventory = inventory; + DeliveryPackage = deliveryPackage; TechBonuses = new PlayerTechBonuses(); } @@ -48,19 +50,18 @@ public void Serialize(INetDataWriter writer) writer.Put(ReactorStorage != null); if (ReactorStorage != null) { - using (MemoryStream ms = new MemoryStream()) + using MemoryStream ms = new MemoryStream(); + using (BinaryWriter wr = new BinaryWriter(ms)) { - using (BinaryWriter wr = new BinaryWriter(ms)) - { - Inventory.Export(wr); - ReactorStorage.Export(wr); - WarpStorage.Export(wr); - Forge.Export(wr); - } - byte[] export = ms.ToArray(); - writer.Put(export.Length); - writer.Put(export); + Inventory.Export(wr); + DeliveryPackage.Export(wr); + ReactorStorage.Export(wr); + WarpStorage.Export(wr); + Forge.Export(wr); } + byte[] export = ms.ToArray(); + writer.Put(export.Length); + writer.Put(export); } } @@ -68,6 +69,8 @@ public void Deserialize(INetDataReader reader) { TechBonuses = new PlayerTechBonuses(); Inventory = new StorageComponent(4); + DeliveryPackage = new DeliveryPackage(); + DeliveryPackage.Init(); ReactorStorage = new StorageComponent(4); WarpStorage = new StorageComponent(1); Forge = new MechaForge @@ -89,6 +92,45 @@ public void Deserialize(INetDataReader reader) using (BinaryReader br = new BinaryReader(ms)) { Inventory.Import(br); + DeliveryPackage.Import(br); + ReactorStorage.Import(br); + WarpStorage.Import(br); + Forge.Import(br); + } + } + } + + public void Import(INetDataReader reader, int revision) + { + TechBonuses = new PlayerTechBonuses(); + Inventory = new StorageComponent(4); + DeliveryPackage = new DeliveryPackage(); + DeliveryPackage.Init(); + ReactorStorage = new StorageComponent(4); + WarpStorage = new StorageComponent(1); + Forge = new MechaForge + { + tasks = new List(), + extraItems = new ItemBundle() + }; + TechBonuses.Import(reader, revision); + SandCount = reader.GetInt(); + CoreEnergy = reader.GetDouble(); + ReactorEnergy = reader.GetDouble(); + bool isPayloadPresent = reader.GetBool(); + if (isPayloadPresent) + { + int mechaLength = reader.GetInt(); + byte[] mechaBytes = new byte[mechaLength]; + reader.GetBytes(mechaBytes, mechaLength); + using (MemoryStream ms = new MemoryStream(mechaBytes)) + using (BinaryReader br = new BinaryReader(ms)) + { + Inventory.Import(br); + if (revision >= 7) + { + DeliveryPackage.Import(br); + } ReactorStorage.Import(br); WarpStorage.Import(br); Forge.Import(br); diff --git a/NebulaModel/DataStructures/PlayerData.cs b/NebulaModel/DataStructures/PlayerData.cs index f72d76022..db5b4bfa8 100644 --- a/NebulaModel/DataStructures/PlayerData.cs +++ b/NebulaModel/DataStructures/PlayerData.cs @@ -20,14 +20,12 @@ public class PlayerData : IPlayerData public int[] DIYItemId { get; set; } public int[] DIYItemValue { get; set; } - private Float4[] MechaColors { get; set; } //Obsoleted by MechaAppearance - public PlayerData() { Appearance = null; DIYAppearance = null; - DIYItemId = new int[0]; - DIYItemValue = new int[0]; + DIYItemId = System.Array.Empty(); + DIYItemValue = System.Array.Empty(); } public PlayerData(ushort playerId, int localPlanetId, string username = null, Float3 localPlanetPosition = new Float3(), Double3 position = new Double3(), Float3 rotation = new Float3(), Float3 bodyRotation = new Float3()) { @@ -41,8 +39,8 @@ public PlayerData() Mecha = new MechaData(); Appearance = null; DIYAppearance = null; - DIYItemId = new int[0]; - DIYItemValue = new int[0]; + DIYItemId = System.Array.Empty(); + DIYItemValue = System.Array.Empty(); } public void Serialize(INetDataWriter writer) @@ -50,11 +48,6 @@ public void Serialize(INetDataWriter writer) writer.Put(Username); writer.Put(PlayerId); writer.Put(LocalPlanetId); - writer.Put(MechaColors?.Length ?? 0); - for (int i = 0; i < (MechaColors?.Length ?? 0); i++) - { - MechaColors[i].Serialize(writer); - } LocalPlanetPosition.Serialize(writer); UPosition.Serialize(writer); Rotation.Serialize(writer); @@ -101,11 +94,6 @@ public void Deserialize(INetDataReader reader) Username = reader.GetString(); PlayerId = reader.GetUShort(); LocalPlanetId = reader.GetInt(); - MechaColors = new Float4[reader.GetInt()]; - for (int i = 0; i < MechaColors.Length; i++) - { - MechaColors[i] = reader.GetFloat4(); - } LocalPlanetPosition = reader.GetFloat3(); UPosition = reader.GetDouble3(); Rotation = reader.GetFloat3(); @@ -150,54 +138,70 @@ public void Deserialize(INetDataReader reader) } } - public void Deserialize_5(INetDataReader reader) + // Backward compatiblity for older versions + public void Import(INetDataReader reader, int revision) { Username = reader.GetString(); PlayerId = reader.GetUShort(); LocalPlanetId = reader.GetInt(); - MechaColors = new Float4[reader.GetInt()]; - for (int i = 0; i < MechaColors.Length; i++) + if (revision < 7) { - MechaColors[i] = reader.GetFloat4(); + // MechaColors is obsoleted by MechaAppearance + Float4[] mechaColors = new Float4[reader.GetInt()]; + for (int i = 0; i < mechaColors.Length; i++) + { + mechaColors[i] = reader.GetFloat4(); + } } LocalPlanetPosition = reader.GetFloat3(); UPosition = reader.GetDouble3(); Rotation = reader.GetFloat3(); BodyRotation = reader.GetFloat3(); - Mecha = new MechaData(); - Mecha.Deserialize(reader); - bool isAppearancePresent = reader.GetBool(); - if (isAppearancePresent) + MechaData mechaData = new(); + mechaData.Import(reader, revision); + Mecha = mechaData; + if (revision >= 5) { - int len = reader.GetInt(); - byte[] data = new byte[len]; - reader.GetBytes(data, len); - using (MemoryStream ms = new MemoryStream(data)) - using (BinaryReader br = new BinaryReader(ms)) + bool isAppearancePresent = reader.GetBool(); + if (isAppearancePresent) { - Appearance = new MechaAppearance(); - Appearance.Init(); - Appearance.Import(br); + int len = reader.GetInt(); + byte[] data = new byte[len]; + reader.GetBytes(data, len); + using (MemoryStream ms = new MemoryStream(data)) + using (BinaryReader br = new BinaryReader(ms)) + { + Appearance = new MechaAppearance(); + Appearance.Init(); + Appearance.Import(br); + } } } - } - - public void Deserialize_4(INetDataReader reader) - { - Username = reader.GetString(); - PlayerId = reader.GetUShort(); - LocalPlanetId = reader.GetInt(); - MechaColors = new Float4[reader.GetInt()]; - for (int i = 0; i < MechaColors.Length; i++) + if (revision >= 6) { - MechaColors[i] = reader.GetFloat4(); + bool isDIYAppearancePresent = reader.GetBool(); + if (isDIYAppearancePresent) + { + int len = reader.GetInt(); + byte[] data = new byte[len]; + reader.GetBytes(data, len); + using (MemoryStream ms = new MemoryStream(data)) + using (BinaryReader br = new BinaryReader(ms)) + { + DIYAppearance = new MechaAppearance(); + DIYAppearance.Init(); + DIYAppearance.Import(br); + } + } + int DIYItemLen = reader.GetInt(); + DIYItemId = new int[DIYItemLen]; + DIYItemValue = new int[DIYItemLen]; + for (int i = 0; i < DIYItemLen; i++) + { + DIYItemId[i] = reader.GetInt(); + DIYItemValue[i] = reader.GetInt(); + } } - LocalPlanetPosition = reader.GetFloat3(); - UPosition = reader.GetDouble3(); - Rotation = reader.GetFloat3(); - BodyRotation = reader.GetFloat3(); - Mecha = new MechaData(); - Mecha.Deserialize(reader); } public IPlayerData CreateCopyWithoutMechaData() diff --git a/NebulaModel/Packets/Factory/CreatePrebuildsRequest.cs b/NebulaModel/Packets/Factory/CreatePrebuildsRequest.cs index 02a506b39..c8e186507 100644 --- a/NebulaModel/Packets/Factory/CreatePrebuildsRequest.cs +++ b/NebulaModel/Packets/Factory/CreatePrebuildsRequest.cs @@ -93,6 +93,7 @@ private static void DeserializeBuildPreview(BuildPreview buildPreview, List= 7) + { + deliveryPackageUnlocked = reader.GetBool(); + deliveryPackageColCount = reader.GetInt(); + deliveryPackageStackSizeMultiplier = reader.GetInt(); + } } } } diff --git a/NebulaNetwork/PacketProcessors/Factory/Entity/EntityBoostSwitchProcessor.cs b/NebulaNetwork/PacketProcessors/Factory/Entity/EntityBoostSwitchProcessor.cs index 4b74ac3aa..85fd1b63e 100644 --- a/NebulaNetwork/PacketProcessors/Factory/Entity/EntityBoostSwitchProcessor.cs +++ b/NebulaNetwork/PacketProcessors/Factory/Entity/EntityBoostSwitchProcessor.cs @@ -24,7 +24,7 @@ public override void ProcessPacket(EntityBoostSwitchPacket packet, NebulaConnect factory.powerSystem.genPool[packet.Id].SetBoost(packet.Enable); if (UIRoot.instance.uiGame.generatorWindow.generatorId == packet.Id) { - UIRoot.instance.uiGame.generatorWindow.boostSwitch.SetImmediately(packet.Enable); + UIRoot.instance.uiGame.generatorWindow.boostSwitch.SetToggleNoEvent(packet.Enable); } } break; @@ -35,7 +35,7 @@ public override void ProcessPacket(EntityBoostSwitchPacket packet, NebulaConnect factory.factorySystem.ejectorPool[packet.Id].SetBoost(packet.Enable); if (UIRoot.instance.uiGame.ejectorWindow.ejectorId == packet.Id) { - UIRoot.instance.uiGame.ejectorWindow.boostSwitch.SetImmediately(packet.Enable); + UIRoot.instance.uiGame.ejectorWindow.boostSwitch.SetToggleNoEvent(packet.Enable); } } break; @@ -46,7 +46,7 @@ public override void ProcessPacket(EntityBoostSwitchPacket packet, NebulaConnect factory.factorySystem.siloPool[packet.Id].SetBoost(packet.Enable); if (UIRoot.instance.uiGame.siloWindow.siloId == packet.Id) { - UIRoot.instance.uiGame.siloWindow.boostSwitch.SetImmediately(packet.Enable); + UIRoot.instance.uiGame.siloWindow.boostSwitch.SetToggleNoEvent(packet.Enable); } } break; diff --git a/NebulaNetwork/PacketProcessors/GameHistory/GameHistoryFeatureKeyProcessor.cs b/NebulaNetwork/PacketProcessors/GameHistory/GameHistoryFeatureKeyProcessor.cs index d9d86b527..719459ca8 100644 --- a/NebulaNetwork/PacketProcessors/GameHistory/GameHistoryFeatureKeyProcessor.cs +++ b/NebulaNetwork/PacketProcessors/GameHistory/GameHistoryFeatureKeyProcessor.cs @@ -30,7 +30,7 @@ public override void ProcessPacket(GameHistoryFeatureKeyPacket packet, NebulaCon if (packet.FeatureId == 1100002) { // Update Quick Build button in dyson editor - UIRoot.instance.uiGame.dysonEditor.controlPanel.inspector.overview.autoConstructSwitch.SetImmediately(packet.Add); + UIRoot.instance.uiGame.dysonEditor.controlPanel.inspector.overview.autoConstructSwitch.SetToggleNoEvent(packet.Add); } } } diff --git a/NebulaNetwork/PacketProcessors/Logistics/DispenserAddTakeProcessor.cs b/NebulaNetwork/PacketProcessors/Logistics/DispenserAddTakeProcessor.cs new file mode 100644 index 000000000..ac45346eb --- /dev/null +++ b/NebulaNetwork/PacketProcessors/Logistics/DispenserAddTakeProcessor.cs @@ -0,0 +1,53 @@ +using NebulaAPI; +using NebulaModel.Logger; +using NebulaModel.Networking; +using NebulaModel.Packets; +using NebulaModel.Packets.Logistics; +using NebulaWorld; +using System; + +namespace NebulaNetwork.PacketProcessors.Logistics +{ + [RegisterPacketProcessor] + internal class DispenserAddTakeProcessor : PacketProcessor + { + public override void ProcessPacket(DispenserAddTakePacket packet, NebulaConnection conn) + { + PlanetFactory factory = GameMain.galaxy.PlanetById(packet.PlanetId)?.factory; + EntityData[] pool = factory?.entityPool; + if (pool != null && packet.EntityId > 0 && packet.EntityId < pool.Length && pool[packet.EntityId].id == packet.EntityId) + { + using (Multiplayer.Session.Storage.IsIncomingRequest.On()) + { + switch (packet.AddTakeEvent) + { + case EDispenserAddTakeEvent.ManualAdd: + factory.InsertIntoStorage(packet.EntityId, packet.ItemId, packet.ItemCount, packet.ItemInc, out int _, false); + break; + + case EDispenserAddTakeEvent.ManualTake: + factory.PickFromStorage(packet.EntityId, packet.ItemId, packet.ItemCount, out int _); + break; + + case EDispenserAddTakeEvent.CourierAdd: + int addCount = factory.InsertIntoStorage(packet.EntityId, packet.ItemId, packet.ItemCount, packet.ItemInc, out int _, false); + int remainCount = packet.ItemCount - addCount; + if (remainCount > 0) + { + Log.Warn($"{GameMain.galaxy.PlanetById(packet.PlanetId)} - CourierAdd remain: {remainCount}"); + } + break; + + case EDispenserAddTakeEvent.CourierTake: + factory.PickFromStorage(packet.EntityId, packet.ItemId, packet.ItemCount, out int _); + break; + } + } + } + else if (pool != null) + { + Log.Warn($"DispenserSettingPacket: Can't find dispenser ({packet.PlanetId}, {packet.EntityId})"); + } + } + } +} diff --git a/NebulaNetwork/PacketProcessors/Logistics/DispenserCourierProcessor.cs b/NebulaNetwork/PacketProcessors/Logistics/DispenserCourierProcessor.cs new file mode 100644 index 000000000..379055689 --- /dev/null +++ b/NebulaNetwork/PacketProcessors/Logistics/DispenserCourierProcessor.cs @@ -0,0 +1,26 @@ +using NebulaAPI; +using NebulaModel.Logger; +using NebulaModel.Networking; +using NebulaModel.Packets; +using NebulaModel.Packets.Logistics; +using NebulaWorld; +using System; + +namespace NebulaNetwork.PacketProcessors.Logistics +{ + [RegisterPacketProcessor] + internal class DispenserCourierProcessor : PacketProcessor + { + public override void ProcessPacket(DispenserCourierPacket packet, NebulaConnection conn) + { + PlanetFactory factory = GameMain.mainPlayer.factory; + DispenserComponent[] pool = factory?.transport.dispenserPool; + if (pool != null && packet.DispenserId > 0 && packet.DispenserId < pool.Length && pool[packet.DispenserId].id == packet.DispenserId) + { + DispenserComponent dispenser = pool[packet.DispenserId]; + Multiplayer.Session.Couriers.AddCourier(packet.PlayerId, factory.entityPool[dispenser.entityId].pos, packet.ItemId, packet.ItemCount); + dispenser.pulseSignal = 2; + } + } + } +} diff --git a/NebulaNetwork/PacketProcessors/Logistics/DispenserSettingProcessor.cs b/NebulaNetwork/PacketProcessors/Logistics/DispenserSettingProcessor.cs new file mode 100644 index 000000000..ad8fbc40d --- /dev/null +++ b/NebulaNetwork/PacketProcessors/Logistics/DispenserSettingProcessor.cs @@ -0,0 +1,92 @@ +using NebulaAPI; +using NebulaModel.Logger; +using NebulaModel.Networking; +using NebulaModel.Packets; +using NebulaModel.Packets.Logistics; +using NebulaWorld; +using System; + +namespace NebulaNetwork.PacketProcessors.Logistics +{ + [RegisterPacketProcessor] + internal class DispenserSettingProcessor : PacketProcessor + { + public override void ProcessPacket(DispenserSettingPacket packet, NebulaConnection conn) + { + PlanetFactory factory = GameMain.galaxy.PlanetById(packet.PlanetId)?.factory; + DispenserComponent[] pool = factory?.transport.dispenserPool; + if (pool != null && packet.DispenserId > 0 && packet.DispenserId < pool.Length && pool[packet.DispenserId].id == packet.DispenserId) + { + ref DispenserComponent dispenserComponent = ref pool[packet.DispenserId]; + + using (Multiplayer.Session.StationsUI.IsIncomingRequest.On()) + { + switch (packet.Event) + { + case EDispenserSettingEvent.SetCourierCount: + int newCourierCount = packet.Parameter1; + if (dispenserComponent.workCourierCount > newCourierCount) + { + string warnText = string.Format("{0} [{1}] Working courier decrease from {2} to {3}", + GameMain.galaxy.PlanetById(packet.PlanetId).displayName, packet.DispenserId, dispenserComponent.workCourierCount, newCourierCount); + Log.Debug(warnText); + dispenserComponent.workCourierCount = newCourierCount; + } + dispenserComponent.idleCourierCount = newCourierCount - dispenserComponent.workCourierCount; + break; + + case EDispenserSettingEvent.ToggleAutoReplenish: + dispenserComponent.courierAutoReplenish = packet.Parameter1 != 0; + break; + + case EDispenserSettingEvent.SetMaxChargePower: + float value = BitConverter.ToSingle(BitConverter.GetBytes(packet.Parameter1), 0); + factory.powerSystem.consumerPool[dispenserComponent.pcId].workEnergyPerTick = (long)(5000.0 * value + 0.5); + break; + + case EDispenserSettingEvent.SetFilter: + int filter = packet.Parameter1; + if (dispenserComponent.filter != filter) + { + dispenserComponent.filter = filter; + factory.transport.RefreshDispenserTraffic(packet.DispenserId); + } + break; + + case EDispenserSettingEvent.SetPlayerDeliveryMode: + EPlayerDeliveryMode playerDeliveryMode = (EPlayerDeliveryMode)packet.Parameter1; + if (dispenserComponent.playerMode != playerDeliveryMode) + { + dispenserComponent.playerMode = playerDeliveryMode; + factory.transport.RefreshDispenserTraffic(packet.DispenserId); + } + break; + + case EDispenserSettingEvent.SetStorageDeliveryMode: + EStorageDeliveryMode storageDeliveryMode = (EStorageDeliveryMode)packet.Parameter1; + if (dispenserComponent.storageMode != storageDeliveryMode) + { + dispenserComponent.storageMode = storageDeliveryMode; + factory.transport.RefreshDispenserTraffic(packet.DispenserId); + } + break; + + default: + Log.Warn($"DispenserSettingPacket: Unkown DispenserSettingEvent {packet.Event}"); + break; + } + + UIDispenserWindow uiWindow = UIRoot.instance.uiGame.dispenserWindow; + if (uiWindow.dispenserId == packet.DispenserId && uiWindow.factory?.planetId == packet.PlanetId) + { + uiWindow.OnDispenserIdChange(); + } + } + } + else if (pool != null) + { + Log.Warn($"DispenserSettingPacket: Can't find dispenser ({packet.PlanetId}, {packet.DispenserId})"); + } + } + } +} diff --git a/NebulaNetwork/PacketProcessors/Logistics/DispenserStoreProcessor.cs b/NebulaNetwork/PacketProcessors/Logistics/DispenserStoreProcessor.cs new file mode 100644 index 000000000..83d7a0091 --- /dev/null +++ b/NebulaNetwork/PacketProcessors/Logistics/DispenserStoreProcessor.cs @@ -0,0 +1,35 @@ +using NebulaAPI; +using NebulaModel.Logger; +using NebulaModel.Networking; +using NebulaModel.Packets; +using NebulaModel.Packets.Logistics; +using System; + +namespace NebulaNetwork.PacketProcessors.Logistics +{ + [RegisterPacketProcessor] + internal class DispenserStoreProcessor : PacketProcessor + { + public override void ProcessPacket(DispenserStorePacket packet, NebulaConnection conn) + { + PlanetFactory factory = GameMain.galaxy.PlanetById(packet.PlanetId)?.factory; + DispenserComponent[] pool = factory?.transport.dispenserPool; + if (pool != null && packet.DispenserId > 0 && packet.DispenserId < pool.Length && pool[packet.DispenserId].id == packet.DispenserId) + { + ref DispenserComponent dispenser = ref pool[packet.DispenserId]; + dispenser.holdupItemCount = packet.HoldupItemCount; + for (int i = 0; i < packet.HoldupItemCount; i++) + { + dispenser.holdupPackage[i].itemId = packet.ItemIds[i]; + dispenser.holdupPackage[i].count = packet.Counts[i]; + dispenser.holdupPackage[i].inc = packet.Incs[i]; + } + Array.Clear(dispenser.holdupPackage, dispenser.holdupItemCount, dispenser.holdupPackage.Length - dispenser.holdupItemCount); + } + else if (pool != null) + { + Log.Warn($"DispenserSettingPacket: Can't find dispenser ({packet.PlanetId}, {packet.DispenserId})"); + } + } + } +} diff --git a/NebulaNetwork/PacketProcessors/Logistics/StationUIInitialSyncProcessor.cs b/NebulaNetwork/PacketProcessors/Logistics/StationUIInitialSyncProcessor.cs index 2b543dc7c..6b3e5d7af 100644 --- a/NebulaNetwork/PacketProcessors/Logistics/StationUIInitialSyncProcessor.cs +++ b/NebulaNetwork/PacketProcessors/Logistics/StationUIInitialSyncProcessor.cs @@ -61,8 +61,11 @@ public override void ProcessPacket(StationUIInitialSync packet, NebulaConnection UIStationWindow stationWindow = UIRoot.instance.uiGame.stationWindow; if (stationWindow.active && stationWindow.factory?.planetId == packet.PlanetId && stationWindow.stationId == packet.StationId) { - //Trigger OnStationIdChange() to refresh window - stationWindow.OnStationIdChange(); + using (Multiplayer.Session.StationsUI.IsIncomingRequest.On()) + { + //Trigger OnStationIdChange() to refresh window + stationWindow.OnStationIdChange(); + } } } } diff --git a/NebulaNetwork/SaveManager.cs b/NebulaNetwork/SaveManager.cs index c147d6269..9029de4c2 100644 --- a/NebulaNetwork/SaveManager.cs +++ b/NebulaNetwork/SaveManager.cs @@ -12,7 +12,7 @@ namespace NebulaNetwork public class SaveManager { private const string FILE_EXTENSION = ".server"; - private const ushort REVISION = 6; + private const ushort REVISION = 7; public static void SaveServerData(string saveName) { @@ -104,11 +104,11 @@ public static void LoadServerData() } revision = netDataReader.GetUShort(); - Log.Info($"Loading server data, revision {revision}"); + Log.Info($"Loading server data revision {revision} (Latest {REVISION})"); if (revision != REVISION) { - // Supported revision: 4~6 - if (revision < 4 || revision > REVISION) + // Supported revision: 5~7 + if (revision < 5 || revision > REVISION) { throw new System.Exception(); } @@ -132,15 +132,10 @@ public static void LoadServerData() { playerData = netDataReader.Get(); } - else if(revision == 4) + else if (revision >= 5) { playerData = new PlayerData(); - playerData.Deserialize_4(netDataReader); - } - else if(revision == 5) - { - playerData = new PlayerData(); - playerData.Deserialize_5(netDataReader); + playerData.Import(netDataReader, revision); } if (!savedPlayerData.ContainsKey(hash) && playerData != null) diff --git a/NebulaPatcher/Patches/Dynamic/BuildTool_Common_Patch.cs b/NebulaPatcher/Patches/Dynamic/BuildTool_Common_Patch.cs index fa7b50a1a..3550b0ea7 100644 --- a/NebulaPatcher/Patches/Dynamic/BuildTool_Common_Patch.cs +++ b/NebulaPatcher/Patches/Dynamic/BuildTool_Common_Patch.cs @@ -13,7 +13,7 @@ internal class BuildTool_Common_Patch [HarmonyPrefix] [HarmonyPatch(typeof(BuildTool_Click), nameof(BuildTool_Click.CreatePrebuilds))] [HarmonyPatch(typeof(BuildTool_Path), nameof(BuildTool_Path.CreatePrebuilds))] - [HarmonyPatch(typeof(BuildTool_PathAddon), nameof(BuildTool_PathAddon.CreatePrebuilds))] + [HarmonyPatch(typeof(BuildTool_Addon), nameof(BuildTool_Addon.CreatePrebuilds))] [HarmonyPatch(typeof(BuildTool_Inserter), nameof(BuildTool_Inserter.CreatePrebuilds))] [HarmonyPatch(typeof(BuildTool_BlueprintPaste), nameof(BuildTool_BlueprintPaste.CreatePrebuilds))] public static bool CreatePrebuilds_Prefix(BuildTool __instance) @@ -29,11 +29,11 @@ public static bool CreatePrebuilds_Prefix(BuildTool __instance) BuildTool_BlueprintPaste bpInstance = __instance as BuildTool_BlueprintPaste; previews = bpInstance.bpPool.Take(bpInstance.bpCursor).ToList(); } - if(__instance is BuildTool_PathAddon) + if(__instance is BuildTool_Addon) { // traffic monitors & sprayers cannot be drag build atm, so its always only one. previews = new List(); - previews.Add(((BuildTool_PathAddon)__instance).handbp); + previews.Add(((BuildTool_Addon)__instance).handbp); } // Host will just broadcast event to other players @@ -61,7 +61,7 @@ public static bool CreatePrebuilds_Prefix(BuildTool __instance) [HarmonyPrefix] [HarmonyPatch(typeof(BuildTool_Click), nameof(BuildTool_Click.CheckBuildConditions))] [HarmonyPatch(typeof(BuildTool_Path), nameof(BuildTool_Path.CheckBuildConditions))] - [HarmonyPatch(typeof(BuildTool_PathAddon), nameof(BuildTool_PathAddon.CheckBuildConditions))] + [HarmonyPatch(typeof(BuildTool_Addon), nameof(BuildTool_Addon.CheckBuildConditions))] [HarmonyPatch(typeof(BuildTool_Inserter), nameof(BuildTool_Inserter.CheckBuildConditions))] [HarmonyPatch(typeof(BuildTool_BlueprintPaste), nameof(BuildTool_BlueprintPaste.CheckBuildConditions))] public static bool CheckBuildConditions(ref bool __result) diff --git a/NebulaPatcher/Patches/Dynamic/Debugging.cs b/NebulaPatcher/Patches/Dynamic/Debugging.cs index 7c3b7bf43..a0be1c2ab 100644 --- a/NebulaPatcher/Patches/Dynamic/Debugging.cs +++ b/NebulaPatcher/Patches/Dynamic/Debugging.cs @@ -1,5 +1,6 @@ #if DEBUG using HarmonyLib; +using NebulaWorld; namespace NebulaPatcher.Patches.Dynamic { @@ -10,6 +11,11 @@ internal class Debug_GameHistoryData_Patch [HarmonyPatch(nameof(GameHistoryData.EnqueueTech))] public static void EnqueueTech_Postfix(GameHistoryData __instance, int techId) { + if (Multiplayer.IsActive && Multiplayer.Session.History.IsIncomingRequest) + { + //Do not run if this was triggered by incomming request + return; + } __instance.UnlockTech(techId); GameMain.mainPlayer.mecha.corePowerGen = 10000000; } diff --git a/NebulaPatcher/Patches/Dynamic/GameData_Patch.cs b/NebulaPatcher/Patches/Dynamic/GameData_Patch.cs index 590f071a3..6f4ac8bdb 100644 --- a/NebulaPatcher/Patches/Dynamic/GameData_Patch.cs +++ b/NebulaPatcher/Patches/Dynamic/GameData_Patch.cs @@ -286,12 +286,16 @@ public static void SetForNewGame_Postfix(GameData __instance) [HarmonyPatch(nameof(GameData.GameTick))] public static void GameTick_Postfix(GameData __instance, long time) { - if (!Multiplayer.IsActive || Multiplayer.Session.LocalPlayer.IsHost) + if (!Multiplayer.IsActive) { - if (Multiplayer.IsActive) - { - Multiplayer.Session.Launch.CollectProjectile(); - } + return; + } + + Multiplayer.Session.Couriers.GameTick(time); + + if (Multiplayer.Session.LocalPlayer.IsHost) + { + Multiplayer.Session.Launch.CollectProjectile(); return; } Multiplayer.Session.Launch.LaunchProjectile(); @@ -301,7 +305,6 @@ public static void GameTick_Postfix(GameData __instance, long time) { timeGene += 60; } - float dt = 0.016666668f; GameHistoryData history = GameMain.history; float shipSailSpeed = history.logisticShipSailSpeedModified; float shipWarpSpeed = (!history.logisticShipWarpDrive) ? shipSailSpeed : history.logisticShipWarpSpeedModified; @@ -316,7 +319,7 @@ public static void GameTick_Postfix(GameData __instance, long time) { if (stationComponent != null && stationComponent.isStellar && !Multiplayer.Session.IsInLobby) { - StationComponent_Transpiler.ILSUpdateShipPos(stationComponent, GameMain.galaxy.PlanetById(stationComponent.planetId).factory, timeGene, dt, shipSailSpeed, shipWarpSpeed, shipCarries, gStationPool, astroPoses, relativePos, relativeRot, starmap, null); + StationComponent_Transpiler.ILSUpdateShipPos(stationComponent, GameMain.galaxy.PlanetById(stationComponent.planetId).factory, timeGene, shipSailSpeed, shipWarpSpeed, shipCarries, gStationPool, astroPoses, ref relativePos, ref relativeRot, starmap, null); } } } diff --git a/NebulaPatcher/Patches/Dynamic/LogisticCourierRendererr_Patch.cs b/NebulaPatcher/Patches/Dynamic/LogisticCourierRendererr_Patch.cs new file mode 100644 index 000000000..80283c9df --- /dev/null +++ b/NebulaPatcher/Patches/Dynamic/LogisticCourierRendererr_Patch.cs @@ -0,0 +1,62 @@ +using HarmonyLib; +using NebulaModel; +using NebulaWorld; +using System; + +namespace NebulaPatcher.Patches.Dynamic +{ + [HarmonyPatch(typeof(LogisticCourierRenderer))] + internal class LogisticCourierRendererr_Patch + { + [HarmonyPrefix] + [HarmonyPatch(nameof(LogisticCourierRenderer.Update))] + public static bool Update_Prefix(LogisticCourierRenderer __instance) + { + if (!Multiplayer.IsActive) + { + return true; + } + + __instance.courierCount = 0; + if (__instance.transport == null) + { + return false; + } + for (int i = 1; i < __instance.transport.dispenserCursor; i++) + { + DispenserComponent dispenserComponent = __instance.transport.dispenserPool[i]; + if (dispenserComponent != null && dispenserComponent.id == i) + { + int num = __instance.courierCount + dispenserComponent.workCourierCount; + if (num > 0) + { + while (__instance.capacity < num) + { + __instance.Expand2x(); + } + Array.Copy(dispenserComponent.workCourierDatas, 0, __instance.couriersArr, __instance.courierCount, dispenserComponent.workCourierCount); + __instance.courierCount = num; + } + } + } + + // Add remote couriers animation + int courierCount = __instance.courierCount + Multiplayer.Session.Couriers.CourierCount; + if (courierCount > 0) + { + while (__instance.capacity < courierCount) + { + __instance.Expand2x(); + } + Array.Copy(Multiplayer.Session.Couriers.CourierDatas, 0, __instance.couriersArr, __instance.courierCount, Multiplayer.Session.Couriers.CourierCount); + __instance.courierCount = courierCount; + } + + if (__instance.couriersBuffer != null) + { + __instance.couriersBuffer.SetData(__instance.couriersArr, 0, 0, __instance.courierCount); + } + return false; + } + } +} diff --git a/NebulaPatcher/Patches/Dynamic/PlanetFactory_Patch.cs b/NebulaPatcher/Patches/Dynamic/PlanetFactory_Patch.cs index 1c2aa07cd..26ca0b726 100644 --- a/NebulaPatcher/Patches/Dynamic/PlanetFactory_Patch.cs +++ b/NebulaPatcher/Patches/Dynamic/PlanetFactory_Patch.cs @@ -297,6 +297,12 @@ public static void EntityFastTakeOut_Postfix(PlanetFactory __instance, int entit } } } + if (entityData.dispenserId > 0) + { + int dispenserId = entityData.dispenserId; + DispenserComponent[] dispenserPool = __instance.transport.dispenserPool; + Multiplayer.Session.Network.SendPacketToLocalStar(new DispenserStorePacket(__instance.planetId, in dispenserPool[dispenserId])); + } if (entityData.ejectorId > 0) { int ejectorId = entityData.ejectorId; @@ -416,6 +422,13 @@ public static void EntityFastFillIn_Postfix(PlanetFactory __instance, int entity Multiplayer.Session.Network.SendPacketToLocalStar(new AssemblerUpdateStoragePacket(__instance.planetId, assemblerId, assemblerPool[assemblerId].served, assemblerPool[assemblerId].incServed)); } } + if (entityData.dispenserId > 0) + { + int dispenserId = entityData.dispenserId; + DispenserComponent[] dispenserPool = __instance.transport.dispenserPool; + int courierCount = dispenserPool[dispenserId].workCourierCount + dispenserPool[dispenserId].idleCourierCount; + Multiplayer.Session.Network.SendPacketToLocalStar(new DispenserSettingPacket(__instance.planetId, dispenserId, EDispenserSettingEvent.SetCourierCount, courierCount)); + } if (entityData.ejectorId > 0) { int ejectorId = entityData.ejectorId; @@ -500,5 +513,102 @@ public static void EntityFastFillIn_Postfix(PlanetFactory __instance, int entity } } } + + [HarmonyPrefix] + [HarmonyPatch(nameof(PlanetFactory.EntityAutoReplenishIfNeeded))] + [HarmonyPatch(nameof(PlanetFactory.StationAutoReplenishIfNeeded))] + public static bool EntityAutoReplenishIfNeeded_Prefix(PlanetFactory __instance, int entityId, ref (int, int, int, int) __state) + { + if (!Multiplayer.IsActive) + { + return true; + } + + // Don't auto replenish if it is from other player's packet + if (Multiplayer.Session.Factories.IsIncomingRequest.Value && Multiplayer.Session.Factories.PacketAuthor != Multiplayer.Session.LocalPlayer.Id) + { + return false; + } + if (Multiplayer.Session.StationsUI.IsIncomingRequest.Value) + { + return false; + } + + __state.Item1 = 1; + ref EntityData ptr = ref __instance.entityPool[entityId]; + if (ptr.dispenserId > 0) + { + DispenserComponent dispenserComponent = __instance.transport.dispenserPool[ptr.dispenserId]; + __state.Item2 = dispenserComponent.idleCourierCount; + } + if (ptr.stationId > 0) + { + StationComponent stationComponent = __instance.transport.stationPool[ptr.stationId]; + __state.Item3 = stationComponent.idleDroneCount; + __state.Item4 = stationComponent.idleShipCount; + } + return true; + } + + [HarmonyPostfix] + [HarmonyPatch(nameof(PlanetFactory.EntityAutoReplenishIfNeeded))] + [HarmonyPatch(nameof(PlanetFactory.StationAutoReplenishIfNeeded))] + public static void EntityAutoReplenishIfNeeded_Postfix(PlanetFactory __instance, int entityId, ref (int, int, int, int) __state) + { + if (__state.Item1 != 1) + { + return; + } + + ref EntityData ptr = ref __instance.entityPool[entityId]; + if (ptr.dispenserId > 0) + { + DispenserComponent dispenserComponent = __instance.transport.dispenserPool[ptr.dispenserId]; + if (__state.Item2 != dispenserComponent.idleCourierCount) + { + Multiplayer.Session.Network.SendPacketToLocalStar( + new DispenserSettingPacket(__instance.planetId, + ptr.dispenserId, + EDispenserSettingEvent.SetCourierCount, + dispenserComponent.workCourierCount + dispenserComponent.idleCourierCount)); + } + } + if (ptr.stationId > 0) + { + StationComponent stationComponent = __instance.transport.stationPool[ptr.stationId]; + if (__state.Item3 != stationComponent.idleDroneCount) + { + Multiplayer.Session.Network.SendPacket( + new StationUI(__instance.planetId, + stationComponent.id, + stationComponent.gid, + StationUI.EUISettings.SetDroneCount, + stationComponent.idleDroneCount + stationComponent.workDroneCount)); + + if (Multiplayer.Session.LocalPlayer.IsClient) + { + // Revert drone count until host verify + stationComponent.idleDroneCount = __state.Item3; + } + } + + if (__state.Item4 != stationComponent.idleShipCount) + { + Multiplayer.Session.Network.SendPacket( + new StationUI(__instance.planetId, + stationComponent.id, + stationComponent.gid, + StationUI.EUISettings.SetShipCount, + stationComponent.idleShipCount + stationComponent.workShipCount)); + + if (Multiplayer.Session.LocalPlayer.IsClient) + { + // Revert drone count until host verify + stationComponent.idleShipCount = __state.Item4; + } + } + } + + } } } diff --git a/NebulaPatcher/Patches/Dynamic/PlanetTransport_Patch.cs b/NebulaPatcher/Patches/Dynamic/PlanetTransport_Patch.cs index 2aab5456b..271191b23 100644 --- a/NebulaPatcher/Patches/Dynamic/PlanetTransport_Patch.cs +++ b/NebulaPatcher/Patches/Dynamic/PlanetTransport_Patch.cs @@ -102,5 +102,35 @@ public static void RemoveStationComponent_Postfix(PlanetTransport __instance, in } Multiplayer.Session.Network.SendPacket(new ILSRemoveStationComponent(id, __instance.planet.id, RemovingStationGId)); } + + [HarmonyPrefix] + [HarmonyPatch(nameof(PlanetTransport.SetDispenserFilter))] + public static void SetDispenserFilter_Prefix(PlanetTransport __instance, int dispenserId, int filter) + { + if (Multiplayer.IsActive) + { + Multiplayer.Session.Network.SendPacketToLocalStar(new DispenserSettingPacket(__instance.planet.id, dispenserId, EDispenserSettingEvent.SetFilter, filter)); + } + } + + [HarmonyPrefix] + [HarmonyPatch(nameof(PlanetTransport.SetDispenserPlayerDeliveryMode))] + public static void SetDispenserPlayerDeliveryMode_Prefix(PlanetTransport __instance, int dispenserId, EPlayerDeliveryMode playerDeliveryMode) + { + if (Multiplayer.IsActive) + { + Multiplayer.Session.Network.SendPacketToLocalStar(new DispenserSettingPacket(__instance.planet.id, dispenserId, EDispenserSettingEvent.SetPlayerDeliveryMode, (int)playerDeliveryMode)); + } + } + + [HarmonyPrefix] + [HarmonyPatch(nameof(PlanetTransport.SetDispenserStorageDeliveryMode))] + public static void SetDispenserStorageDeliveryMode_Prefix(PlanetTransport __instance, int dispenserId, EStorageDeliveryMode storageDeliveryMode) + { + if (Multiplayer.IsActive) + { + Multiplayer.Session.Network.SendPacketToLocalStar(new DispenserSettingPacket(__instance.planet.id, dispenserId, EDispenserSettingEvent.SetStorageDeliveryMode, (int)storageDeliveryMode)); + } + } } } diff --git a/NebulaPatcher/Patches/Dynamic/StationComponent_Patch.cs b/NebulaPatcher/Patches/Dynamic/StationComponent_Patch.cs index 155f3d1bb..bdd6f1121 100644 --- a/NebulaPatcher/Patches/Dynamic/StationComponent_Patch.cs +++ b/NebulaPatcher/Patches/Dynamic/StationComponent_Patch.cs @@ -2,7 +2,6 @@ using NebulaModel.Logger; using NebulaModel.Packets.Logistics; using NebulaWorld; -using UnityEngine; namespace NebulaPatcher.Patches.Dynamic { @@ -11,7 +10,7 @@ internal class StationComponent_Patch { [HarmonyPrefix] [HarmonyPatch(nameof(StationComponent.InternalTickRemote))] - public static bool InternalTickRemote_Prefix(StationComponent __instance, int timeGene, double dt, float shipSailSpeed, float shipWarpSpeed, int shipCarries, StationComponent[] gStationPool, AstroData[] astroPoses, VectorLF3 relativePos, Quaternion relativeRot, bool starmap, int[] consumeRegister) + public static bool InternalTickRemote_Prefix(StationComponent __instance) { if (Multiplayer.IsActive && !Multiplayer.Session.LocalPlayer.IsHost) { @@ -20,6 +19,28 @@ public static bool InternalTickRemote_Prefix(StationComponent __instance, int ti // we dont have every PlanetFactory at hand. // so iterate over the GameMain.data.galacticTransport.stationPool array which should also include the fake entries for factories we have not loaded yet. // but do this at another place to not trigger it more often than needed (GameData::GameTick()) + if (__instance.warperCount < __instance.warperMaxCount) + { + // refill warpers from ILS storage + for (int i = 0; i < __instance.storage.Length; i++) + { + if (__instance.storage[i].itemId == 1210 && __instance.storage[i].count > 0) + { + __instance.warperCount++; + lock (__instance.storage) + { + int num = __instance.storage[i].inc / __instance.storage[i].count; + StationStore[] array = __instance.storage; + int num2 = i; + array[num2].count = array[num2].count - 1; + StationStore[] array2 = __instance.storage; + int num3 = i; + array2[num3].inc = array2[num3].inc - num; + } + break; + } + } + } return false; } return true; @@ -27,7 +48,7 @@ public static bool InternalTickRemote_Prefix(StationComponent __instance, int ti [HarmonyPrefix] [HarmonyPatch(nameof(StationComponent.RematchRemotePairs))] - public static bool RematchRemotePairs_Prefix(StationComponent __instance, StationComponent[] gStationPool, int gStationCursor, int keyStationGId, int shipCarries) + public static bool RematchRemotePairs_Prefix() { if (Multiplayer.IsActive && !Multiplayer.Session.LocalPlayer.IsHost) { @@ -39,7 +60,7 @@ public static bool RematchRemotePairs_Prefix(StationComponent __instance, Statio [HarmonyPostfix] [HarmonyPatch(nameof(StationComponent.IdleShipGetToWork))] - public static void IdleShipGetToWork_Postfix(StationComponent __instance, int index) + public static void IdleShipGetToWork_Postfix(StationComponent __instance) { if (Multiplayer.IsActive && Multiplayer.Session.LocalPlayer.IsHost) { diff --git a/NebulaPatcher/Patches/Dynamic/UIDispenserWindow_Patch.cs b/NebulaPatcher/Patches/Dynamic/UIDispenserWindow_Patch.cs new file mode 100644 index 000000000..b6a6a2a8b --- /dev/null +++ b/NebulaPatcher/Patches/Dynamic/UIDispenserWindow_Patch.cs @@ -0,0 +1,166 @@ +using HarmonyLib; +using NebulaModel.Packets.Logistics; +using NebulaWorld; +using System; +using UnityEngine; +using UnityEngine.EventSystems; + +namespace NebulaPatcher.Patches.Dynamic +{ + [HarmonyPatch(typeof(UIDispenserWindow))] + internal class UIDispenserWindow_Patch + { + [HarmonyPostfix] + [HarmonyPatch(nameof(UIDispenserWindow.OnCourierIconClick))] + public static void OnCourierIconClick_Postfix(UIDispenserWindow __instance) + { + if (Multiplayer.IsActive) + { + DispenserComponent dispenserComponent = __instance.transport.dispenserPool[__instance.dispenserId]; + Multiplayer.Session.Network.SendPacketToLocalStar( + new DispenserSettingPacket(__instance.factory.planetId, + __instance.dispenserId, + EDispenserSettingEvent.SetCourierCount, + dispenserComponent.workCourierCount + dispenserComponent.idleCourierCount)); + } + } + + [HarmonyPostfix] + [HarmonyPatch(nameof(UIDispenserWindow.OnCourierAutoReplenishButtonClick))] + public static void OnCourierAutoReplenishButtonClick_Postfix(UIDispenserWindow __instance) + { + if (Multiplayer.IsActive) + { + DispenserComponent dispenserComponent = __instance.transport.dispenserPool[__instance.dispenserId]; + Multiplayer.Session.Network.SendPacketToLocalStar( + new DispenserSettingPacket(__instance.factory.planetId, + __instance.dispenserId, + EDispenserSettingEvent.ToggleAutoReplenish, + dispenserComponent.courierAutoReplenish ? 1 : 0)); + } + } + + [HarmonyPostfix] + [HarmonyPatch(nameof(UIDispenserWindow.OnHoldupItemClick))] + public static void OnHoldupItemClick_Postfix(UIDispenserWindow __instance) + { + if (Multiplayer.IsActive) + { + DispenserComponent dispenserComponent = __instance.transport.dispenserPool[__instance.dispenserId]; + if (__instance.player.inhandItemId == 0 && __instance.player.inhandItemCount == 0) + { + Multiplayer.Session.Network.SendPacketToLocalStar( + new DispenserStorePacket(__instance.factory.planetId, + in dispenserComponent)); + } + } + } + + [HarmonyPostfix] + [HarmonyPatch(nameof(UIDispenserWindow.OnMaxChargePowerSliderValueChange))] + public static void OnMaxChargePowerSliderValueChange_Postfix(UIDispenserWindow __instance, float value) + { + if (Multiplayer.IsActive && !Multiplayer.Session.StationsUI.IsIncomingRequest.Value) + { + Multiplayer.Session.Network.SendPacketToLocalStar( + new DispenserSettingPacket(__instance.factory.planetId, + __instance.dispenserId, + EDispenserSettingEvent.SetMaxChargePower, + BitConverter.ToInt32(BitConverter.GetBytes(value), 0))); + } + } + + [HarmonyPrefix] + [HarmonyPatch(nameof(UIDispenserWindow.OnItemIconMouseDown))] + public static bool OnItemIconMouseDown_Prefix(UIDispenserWindow __instance, BaseEventData evt) + { + if (!Multiplayer.IsActive || __instance.dispenserId == 0 || __instance.factory == null) + { + return true; + } + DispenserComponent dispenserComponent = __instance.transport.dispenserPool[__instance.dispenserId]; + if (dispenserComponent == null || dispenserComponent.id != __instance.dispenserId) + { + return false; + } + PointerEventData pointerEventData = evt as PointerEventData; + if (pointerEventData == null) + { + return false; + } + + if (__instance.player.inhandItemId == 0) + { + if (pointerEventData.button == PointerEventData.InputButton.Right) + { + __instance.CalculateStorageTotalCount(dispenserComponent, out int count, out int _); + if (count > 0) + { + UIRoot.instance.uiGame.OpenGridSplit(dispenserComponent.filter, count, Input.mousePosition); + __instance.insplit = true; + return false; + } + } + } + else if (__instance.player.inhandItemId == dispenserComponent.filter && dispenserComponent.filter > 0 && pointerEventData.button == PointerEventData.InputButton.Left) + { + int entityId = dispenserComponent.storage.bottomStorage.entityId; + int itemCount = __instance.factory.InsertIntoStorage(entityId, __instance.player.inhandItemId, __instance.player.inhandItemCount, __instance.player.inhandItemInc, out int handItemInc_Unsafe, false); + + // Player put itemCount into storage, broadcast the change to all users + Multiplayer.Session.Network.SendPacketToLocalStar( + new DispenserAddTakePacket(__instance.factory.planetId, + entityId, + EDispenserAddTakeEvent.ManualAdd, + __instance.player.inhandItemId, itemCount, __instance.player.inhandItemInc)); + + __instance.player.AddHandItemCount_Unsafe(-itemCount); + __instance.player.SetHandItemInc_Unsafe(handItemInc_Unsafe); + if (__instance.player.inhandItemCount <= 0) + { + __instance.player.SetHandItems(0, 0, 0); + } + } + + return false; + } + + [HarmonyPrefix] + [HarmonyPatch(nameof(UIDispenserWindow.OnItemIconMouseUp))] + public static bool OnItemIconMouseUp_Prefix(UIDispenserWindow __instance) + { + if (!Multiplayer.IsActive || __instance.dispenserId == 0 || __instance.factory == null) + { + return true; + } + DispenserComponent dispenserComponent = __instance.transport.dispenserPool[__instance.dispenserId]; + if (dispenserComponent == null || dispenserComponent.id != __instance.dispenserId) + { + return false; + } + + if (__instance.insplit) + { + int count = UIRoot.instance.uiGame.CloseGridSplit(); + if (__instance.player.inhandItemId == 0 && __instance.player.inhandItemCount == 0 && dispenserComponent.filter > 0) + { + int entityId = dispenserComponent.storage.bottomStorage.entityId; + int handItemCount_Unsafe = __instance.factory.PickFromStorage(entityId, dispenserComponent.filter, count, out int handItemInc_Unsafe); + __instance.player.SetHandItemId_Unsafe(dispenserComponent.filter); + __instance.player.SetHandItemCount_Unsafe(handItemCount_Unsafe); + __instance.player.SetHandItemInc_Unsafe(handItemInc_Unsafe); + + // Player grab itemCount from storage, broadcast the change to all users + Multiplayer.Session.Network.SendPacketToLocalStar( + new DispenserAddTakePacket(__instance.factory.planetId, + entityId, + EDispenserAddTakeEvent.ManualTake, + __instance.player.inhandItemId, __instance.player.inhandItemCount, 0)); + } + __instance.insplit = false; + } + + return false; + } + } +} diff --git a/NebulaPatcher/Patches/Dynamic/UIStarmap_Patch.cs b/NebulaPatcher/Patches/Dynamic/UIStarmap_Patch.cs index ba6bc78ee..6ee9cfbe2 100644 --- a/NebulaPatcher/Patches/Dynamic/UIStarmap_Patch.cs +++ b/NebulaPatcher/Patches/Dynamic/UIStarmap_Patch.cs @@ -29,7 +29,7 @@ public static void _OnClose_Postfix() } [HarmonyPrefix] - [HarmonyPatch(nameof(UIStarmap.TeleportToUPosition))] + [HarmonyPatch(nameof(UIStarmap.StartFastTravelToUPosition))] public static bool TeleportToUPosition_Prefix(VectorLF3 uPos) { if (Multiplayer.IsActive && Multiplayer.Session.LocalPlayer.IsClient) diff --git a/NebulaPatcher/Patches/Dynamic/UIStationWindow_Patch.cs b/NebulaPatcher/Patches/Dynamic/UIStationWindow_Patch.cs index 436280a6c..e70a56242 100644 --- a/NebulaPatcher/Patches/Dynamic/UIStationWindow_Patch.cs +++ b/NebulaPatcher/Patches/Dynamic/UIStationWindow_Patch.cs @@ -256,6 +256,20 @@ public static void OnDroneIconClick_Posfix(UIStationWindow __instance, int __sta } } + [HarmonyPostfix] + [HarmonyPatch(nameof(UIStationWindow.OnDroneAutoReplenishButtonClick))] + public static void OnDroneAutoReplenishButtonClick_Postfix(UIStationWindow __instance) + { + if (__instance.event_lock || !Multiplayer.IsActive || Multiplayer.Session.Ships.PatchLockILS) + { + return; + } + + StationComponent stationComponent = __instance.transport.stationPool[__instance.stationId]; + StationUI packet = new StationUI(__instance.factory.planet.id, stationComponent.id, stationComponent.gid, StationUI.EUISettings.DroneAutoReplenish, stationComponent.droneAutoReplenish ? 1f : 0f); + Multiplayer.Session.Network.SendPacket(packet); + } + [HarmonyPrefix] [HarmonyPatch(nameof(UIStationWindow.OnShipIconClick))] [HarmonyPriority(Priority.First)] @@ -290,6 +304,20 @@ public static void OnShipIconClick_Posfix(UIStationWindow __instance, int __stat } } + [HarmonyPostfix] + [HarmonyPatch(nameof(UIStationWindow.OnShipAutoReplenishButtonClick))] + public static void OnShipAutoReplenishButtonClick_Postfix(UIStationWindow __instance) + { + if (__instance.event_lock || !Multiplayer.IsActive || Multiplayer.Session.Ships.PatchLockILS) + { + return; + } + + StationComponent stationComponent = __instance.transport.stationPool[__instance.stationId]; + StationUI packet = new StationUI(__instance.factory.planet.id, stationComponent.id, stationComponent.gid, StationUI.EUISettings.ShipAutoReplenish, stationComponent.shipAutoReplenish ? 1f : 0f); + Multiplayer.Session.Network.SendPacket(packet); + } + [HarmonyPrefix] [HarmonyPatch(nameof(UIStationWindow.OnWarperIconClick))] [HarmonyPriority(Priority.First)] diff --git a/NebulaPatcher/Patches/Transpilers/BuildTool_Common_Transpiler .cs b/NebulaPatcher/Patches/Transpilers/BuildTool_Common_Transpiler .cs index 95caeb869..4685c247c 100644 --- a/NebulaPatcher/Patches/Transpilers/BuildTool_Common_Transpiler .cs +++ b/NebulaPatcher/Patches/Transpilers/BuildTool_Common_Transpiler .cs @@ -21,6 +21,7 @@ internal class BuildTool_Common_Transpiler [HarmonyPatch(typeof(BuildTool_Click), nameof(BuildTool_Click.CreatePrebuilds))] [HarmonyPatch(typeof(BuildTool_Path), nameof(BuildTool_Path.CreatePrebuilds))] [HarmonyPatch(typeof(BuildTool_Inserter), nameof(BuildTool_Inserter.CreatePrebuilds))] + [HarmonyPatch(typeof(BuildTool_Addon), nameof(BuildTool_Inserter.CreatePrebuilds))] private static IEnumerable CreatePrebuilds_Transpiler(IEnumerable instructions) { CodeMatcher codeMatcher = new CodeMatcher(instructions) diff --git a/NebulaPatcher/Patches/Transpilers/DispenserComponent_Transpiler.cs b/NebulaPatcher/Patches/Transpilers/DispenserComponent_Transpiler.cs new file mode 100644 index 000000000..65cff9066 --- /dev/null +++ b/NebulaPatcher/Patches/Transpilers/DispenserComponent_Transpiler.cs @@ -0,0 +1,129 @@ +using HarmonyLib; +using NebulaModel.Packets.Logistics; +using NebulaWorld; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; + +namespace NebulaPatcher.Patches.Transpilers +{ + [HarmonyPatch(typeof(DispenserComponent))] + public class DispenserComponent_Transpiler + { + [HarmonyTranspiler] + [HarmonyPatch(nameof(DispenserComponent.InternalTick))] + public static IEnumerable InternalTick_Transpiler(IEnumerable instructions) + { + CodeMatcher matcher = new CodeMatcher(instructions); + + // When courier go from idle to work, test if it is sent to player. If true, broadcast item decrease in distributor storage. + // c# 87: + // int num11 = factory.PickFromStorage(num, itemId, num9, out inc); + // >> Replace with PickFromStorage(factory, num, itemId, num9, out inc) => DispenserAddTakePacket packet + // if (num11 > 0) + matcher + .MatchForward(true, + new CodeMatch(OpCodes.Ldarg_1), + new CodeMatch(i => i.IsLdloc()), + new CodeMatch(OpCodes.Ldloc_S), + new CodeMatch(OpCodes.Ldloc_S), + new CodeMatch(OpCodes.Ldloca_S), + new CodeMatch(i => i.opcode == OpCodes.Callvirt && ((MethodInfo)i.operand).Name == "PickFromStorage")) + .RemoveInstruction() + .Insert(new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(DispenserComponent_Transpiler), "PickFromStorage"))); + + // When courier go from idle to work for player order, broadcast to all players on the same planet + // c# 107: + //>> Insert IdleCourierToWork(this) => IdleCourierToWork + // this.workCourierCount++; + matcher + .MatchForward(false, + new CodeMatch(OpCodes.Ldarg_0), + new CodeMatch(OpCodes.Ldarg_0), + new CodeMatch(i => i.opcode == OpCodes.Ldfld && ((FieldInfo)i.operand).Name == "workCourierCount"), + new CodeMatch(OpCodes.Ldc_I4_1), + new CodeMatch(OpCodes.Add), + new CodeMatch(i => i.opcode == OpCodes.Stfld && ((FieldInfo)i.operand).Name == "workCourierCount")) + .Insert( + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(DispenserComponent_Transpiler), "IdleCourierToWork"))); + + // c# 170: (same as above) + matcher + .Advance(8) + .MatchForward(false, + new CodeMatch(OpCodes.Ldarg_0), + new CodeMatch(OpCodes.Ldarg_0), + new CodeMatch(i => i.opcode == OpCodes.Ldfld && ((FieldInfo)i.operand).Name == "workCourierCount"), + new CodeMatch(OpCodes.Ldc_I4_1), + new CodeMatch(OpCodes.Add), + new CodeMatch(i => i.opcode == OpCodes.Stfld && ((FieldInfo)i.operand).Name == "workCourierCount")) + .Insert( + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(DispenserComponent_Transpiler), "IdleCourierToWork"))); + + // When courier back to home, test if it recycles items from player. If true, broadcast item increase in distributor storage. + // c# 604: + // bool useBan = this.orders[j].otherId >= 0; + // int num66; + // int num65 = factory.InsertIntoStorage(num, itemId6, itemCount2, this.workCourierDatas[j].inc, out num66, useBan); + // >> Replace with InsertIntoStorage(factory, entityId, itemId, count, inc, useBan) => DispenserAddTakePacket packet + matcher.End() + .MatchBack(true, + new CodeMatch(OpCodes.Ldarg_1), // factory + new CodeMatch(i => i.IsLdloc()), // entityId + new CodeMatch(OpCodes.Ldloc_S), // itmeId + new CodeMatch(OpCodes.Ldloc_S), // itemCount + new CodeMatch(OpCodes.Ldarg_0), // this.workCourierDatas[j].inc, + new CodeMatch(OpCodes.Ldfld), + new CodeMatch(OpCodes.Ldloc_S), + new CodeMatch(OpCodes.Ldelema), + new CodeMatch(OpCodes.Ldfld), + new CodeMatch(OpCodes.Ldloca_S), // remainInc + new CodeMatch(OpCodes.Ldloc_S), // useBan + new CodeMatch(i => i.opcode == OpCodes.Callvirt && ((MethodInfo)i.operand).Name == "InsertIntoStorage")) + .RemoveInstruction() + .Insert(new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(DispenserComponent_Transpiler), "InsertIntoStorage"))); + + return matcher.InstructionEnumeration(); + } + + public static int PickFromStorage(PlanetFactory factory, int entityId, int itemId, int count, out int inc) + { + if (Multiplayer.IsActive) + { + Multiplayer.Session.Network.SendPacketToLocalStar( + new DispenserAddTakePacket(factory.planetId, + entityId, + EDispenserAddTakeEvent.CourierTake, + itemId, count, 0)); + } + return factory.PickFromStorage(entityId, itemId, count, out inc); + } + + public static int InsertIntoStorage(PlanetFactory factory, int entityId, int itemId, int count, int inc, out int remainInc, bool useBan) + { + if (Multiplayer.IsActive && useBan == false) + { + Multiplayer.Session.Network.SendPacketToLocalStar( + new DispenserAddTakePacket(factory.planetId, + entityId, + EDispenserAddTakeEvent.CourierAdd, + itemId, count, inc)); + } + return factory.InsertIntoStorage(entityId, itemId, count, inc, out remainInc, useBan); + } + + public static void IdleCourierToWork(DispenserComponent dispenser) + { + if (Multiplayer.IsActive) + { + Multiplayer.Session.Network.SendPacketToLocalPlanet( + new DispenserCourierPacket(Multiplayer.Session.LocalPlayer.Id, + dispenser.id, + dispenser.workCourierDatas[dispenser.workCourierCount].itemId, + dispenser.workCourierDatas[dispenser.workCourierCount].itemCount)); + } + } + } +} \ No newline at end of file diff --git a/NebulaPatcher/Patches/Transpilers/StationComponent_Transpiler.cs b/NebulaPatcher/Patches/Transpilers/StationComponent_Transpiler.cs index 6cb538fa8..818cb918a 100644 --- a/NebulaPatcher/Patches/Transpilers/StationComponent_Transpiler.cs +++ b/NebulaPatcher/Patches/Transpilers/StationComponent_Transpiler.cs @@ -9,26 +9,24 @@ // thanks tanu and Therzok for the tipps! namespace NebulaPatcher.Patches.Transpilers { -#pragma warning disable Harmony003 // Harmony non-ref patch parameters modified +#pragma warning disable Harmony003, IDE0060 // Harmony non-ref patch parameters modified [HarmonyPatch(typeof(StationComponent))] public class StationComponent_Transpiler { delegate void ShipEnterWarpState(StationComponent stationComponent, int j); - delegate void AddItem(StationComponent stationComponent, ShipData shipData); - delegate void TakeItem(StationComponent stationComponent, int itemId, int itemCount, int j); + delegate void AddItem(StationComponent stationComponent, ref ShipData shipData); + delegate void TakeItem(StationComponent stationComponent, ref int itemId, ref int itemCount, int j); delegate void UpdateStorage(StationComponent stationComponent, int index); - delegate void WorkShipBackToIdle(StationComponent stationComponent, int j, ShipData shipData); + delegate void WorkShipBackToIdle(StationComponent stationComponent, int j, ref ShipData shipData); delegate void RematchRemotePairs(StationComponent stationComponent, int index); delegate void SendRematchPacket(StationComponent stationComponent); - private static int UpdateStorageMatchCounter = 0; - // theese are needed to craft the ILSRematchRemotePairs packet - private static List ShipIndex = new List(); - private static List OtherGId = new List(); - private static List ItemId = new List(); - private static List Direction = new List(); + private static readonly List ShipIndex = new List(); + private static readonly List OtherGId = new List(); + private static readonly List ItemId = new List(); + private static readonly List Direction = new List(); [HarmonyTranspiler] [HarmonyPatch(nameof(StationComponent.RematchRemotePairs))] @@ -48,7 +46,7 @@ public static IEnumerable RematchRemotePairs_Transpiler(IEnumer localMatcher .Advance(1) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_0)) - .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 10)) + .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, localMatcher.InstructionAt(-5).operand)) .Insert(HarmonyLib.Transpilers.EmitDelegate((StationComponent stationComponent, int index) => { ShipIndex.Add(index); @@ -72,7 +70,7 @@ public static IEnumerable RematchRemotePairs_Transpiler(IEnumer localMatcher .Advance(1) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_0)) - .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 10)) + .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, localMatcher.InstructionAt(-5).operand)) .Insert(HarmonyLib.Transpilers.EmitDelegate((StationComponent stationComponent, int index) => { ShipIndex.Add(index); @@ -88,7 +86,7 @@ public static IEnumerable RematchRemotePairs_Transpiler(IEnumer .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_0)) .Insert(HarmonyLib.Transpilers.EmitDelegate((StationComponent stationComponent) => { - if(Multiplayer.IsActive && Multiplayer.Session.LocalPlayer.IsHost && ShipIndex.Count > 0) + if (Multiplayer.IsActive && Multiplayer.Session.LocalPlayer.IsHost && ShipIndex.Count > 0) { Multiplayer.Session.Network.SendPacket(new ILSRematchRemotePairs(stationComponent.gid, ShipIndex, OtherGId, Direction, ItemId)); } @@ -105,52 +103,28 @@ public static IEnumerable RematchRemotePairs_Transpiler(IEnumer [HarmonyPatch(nameof(StationComponent.InternalTickRemote))] public static IEnumerable InternalTickRemote_Transpiler(IEnumerable instructions, ILGenerator il) { - // tell client when a ship enters warp state. for some reason client gets messed up with warp counter on ships. - CodeMatcher matcher = new CodeMatcher(instructions, il) - .MatchForward(true, - new CodeMatch(OpCodes.Ldloca_S), - new CodeMatch(OpCodes.Ldflda, AccessTools.Field(typeof(ShipData), "warperCnt")), - new CodeMatch(OpCodes.Dup), - new CodeMatch(OpCodes.Ldind_I4), - new CodeMatch(OpCodes.Ldc_I4_1), - new CodeMatch(OpCodes.Sub), - new CodeMatch(OpCodes.Stind_I4), - new CodeMatch(OpCodes.Ldloca_S), - new CodeMatch(OpCodes.Ldflda, AccessTools.Field(typeof(ShipData), "warpState"))) - .Advance(-1) - .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_0)) - .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 59)) - .Insert(HarmonyLib.Transpilers.EmitDelegate ((StationComponent stationComponent, int j) => - { - if (Multiplayer.IsActive && Multiplayer.Session.LocalPlayer.IsHost) - { - Multiplayer.Session.Network.SendPacket(new ILSShipEnterWarp(stationComponent.gid, j)); - } - })); + CodeMatcher matcher = new CodeMatcher(instructions, il); - // tell client about WorkShipBackToIdle here as we need to tell him j too - // c# 522 - matcher.Start() - .MatchForward(true, - new CodeMatch(OpCodes.Ldarg_0), + // Capture the workship index variable (j) in the big while loop + // c# 500: + // while (j < this.workShipCount) + matcher.End() + .MatchBack(false, new CodeMatch(OpCodes.Ldloc_S), - new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(ShipData), "shipIndex")), - new CodeMatch(i => i.opcode == OpCodes.Call && ((MethodInfo)i.operand).Name == "WorkShipBackToIdle")) - .Advance(1) - .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_0)) - .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 59)) - .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 60)) - .Insert(HarmonyLib.Transpilers.EmitDelegate((StationComponent stationComponent, int j, ShipData shipData) => - { - if(Multiplayer.IsActive && Multiplayer.Session.LocalPlayer.IsHost) - { - ILSWorkShipBackToIdle packet = new ILSWorkShipBackToIdle(stationComponent, shipData, j); - Multiplayer.Session.Network.SendPacket(packet); - } - })); + new CodeMatch(OpCodes.Ldarg_0), + new CodeMatch(i => i.opcode == OpCodes.Ldfld && ((FieldInfo)i.operand).Name == "workShipCount"), + new CodeMatch(OpCodes.Blt)); + var loadWorkShipId = new CodeInstruction(matcher.Instruction.opcode, matcher.Instruction.operand); // j => (OpCodes.Ldloc_S, 66) + + #region ILSShipAddTake - // tell clients about AddItem() calls on host - // c# 502 + // tell clients about AddItem() calls on host + // c# 537: + // ... + // this.AddItem(ptr3.itemId, ptr3.itemCount, ptr3.inc); + // >> Insert (this, ptr3) => ILSShipAddTake packet + // factory.NotifyShipDelivery(ptr3.planetB, gStationPool[ptr3.otherGId], ptr3.planetA, this, ptr3.itemId, ptr3.itemCount); + // ... matcher.Start() .MatchForward(true, new CodeMatch(OpCodes.Ldarg_0), @@ -162,17 +136,23 @@ public static IEnumerable InternalTickRemote_Transpiler(IEnumer new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(ShipData), "inc")), new CodeMatch(i => i.opcode == OpCodes.Call && ((MethodInfo)i.operand).Name == "AddItem")) .Advance(2) // also skip Pop call - .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_0)) - .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 60)) - .Insert(HarmonyLib.Transpilers.EmitDelegate((StationComponent stationComponent, ShipData shipData) => + .InsertAndAdvance(matcher.InstructionAt(-9)) // this + .InsertAndAdvance(matcher.InstructionAt(-9)) // ref ShipData ptr3 + .Insert(HarmonyLib.Transpilers.EmitDelegate((StationComponent stationComponent, ref ShipData shipData) => { if (Multiplayer.IsActive && Multiplayer.Session.LocalPlayer.IsHost) { Multiplayer.Session.Network.SendPacketToStar(new ILSShipAddTake(true, shipData.itemId, shipData.itemCount, stationComponent.gid, shipData.inc), GameMain.galaxy.PlanetById(stationComponent.planetId).star.id); } })); + int backToStationPos = matcher.Pos; - // c# 970 + // c# 1117: + // ... + // stationComponent3.AddItem(ptr3.itemId, ptr3.itemCount, ptr3.inc); + // >> Insert (stationComponent3, ptr3) => ILSShipAddTake packet + // factory.NotifyShipDelivery(ptr3.planetA, this, ptr3.planetB, stationComponent3, ptr3.itemId, ptr3.itemCount); + // ... matcher .MatchForward(true, new CodeMatch(OpCodes.Ldloc_S), @@ -182,11 +162,17 @@ public static IEnumerable InternalTickRemote_Transpiler(IEnumer new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(ShipData), "itemCount")), new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(ShipData), "inc")), - new CodeMatch(i => i.opcode == OpCodes.Callvirt && ((MethodInfo)i.operand).Name == "AddItem")) + new CodeMatch(i => i.opcode == OpCodes.Callvirt && ((MethodInfo)i.operand).Name == "AddItem")); + + // Capture local variables to use later + var loadOtherStation = new CodeInstruction(OpCodes.Ldloc_S, matcher.InstructionAt(-7).operand); + var loadCurrentShip = new CodeInstruction(OpCodes.Ldloc_S, matcher.InstructionAt(-6).operand); + + matcher .Advance(2) // also skip Pop call - .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 147)) - .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 60)) - .Insert(HarmonyLib.Transpilers.EmitDelegate((StationComponent stationComponent, ShipData shipData) => + .InsertAndAdvance(matcher.InstructionAt(-9)) // stationComponent3 + .InsertAndAdvance(matcher.InstructionAt(-9)) // ref ShipData ptr3 + .Insert(HarmonyLib.Transpilers.EmitDelegate((StationComponent stationComponent, ref ShipData shipData) => { if (Multiplayer.IsActive && Multiplayer.Session.LocalPlayer.IsHost) { @@ -195,55 +181,74 @@ public static IEnumerable InternalTickRemote_Transpiler(IEnumer })); // tell clients about TakeItem() calls on host + // c# 1208: + // ... + // int inc; + // >> Insert (stationComponent3, itemId3, num120, j) => ILSShipAddTake packet + // stationComponent3.TakeItem(ref itemId3, ref num120, out inc); + // ... matcher .MatchForward(true, + new CodeMatch(OpCodes.Ldloc_S), + new CodeMatch(OpCodes.Ldloca_S), + new CodeMatch(OpCodes.Ldloca_S), + new CodeMatch(OpCodes.Ldloca_S), new CodeMatch(i => i.opcode == OpCodes.Callvirt && ((MethodInfo)i.operand).Name == "TakeItem")) // just before the call to TakeItem() - .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 147)) - .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 60)) - .InsertAndAdvance(new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(ShipData), "itemId"))) - .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 157)) - .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 59)) - .Insert(HarmonyLib.Transpilers.EmitDelegate((StationComponent stationComponent, int itemId, int itemCount, int j) => + .InsertAndAdvance(matcher.InstructionAt(-4)) + .InsertAndAdvance(matcher.InstructionAt(-4)) + .InsertAndAdvance(matcher.InstructionAt(-4)) + .InsertAndAdvance(loadWorkShipId) + .Insert(HarmonyLib.Transpilers.EmitDelegate((StationComponent stationComponent, ref int itemId, ref int itemCount, int j) => { - if(Multiplayer.IsActive && Multiplayer.Session.LocalPlayer.IsHost) + if (Multiplayer.IsActive && Multiplayer.Session.LocalPlayer.IsHost) { Multiplayer.Session.Network.SendPacketToStar(new ILSShipAddTake(false, itemId, itemCount, stationComponent.gid, j), GameMain.galaxy.PlanetById(stationComponent.planetId).star.id); } })); + #endregion + + #region ILSWorkShipBackToIdle - // tell client about StationSTorage[] updates - // c# 17 + // tell client about WorkShipBackToIdle here as we need to tell him j too. + // because ptr3 is reference, we need to call it before the values get overwritten + // c# 537: + // this.AddItem(ptr3.itemId, ptr3.itemCount, ptr3.inc); + // >> Insert (this, j, ptr3) => ILSWorkShipBackToIdle packet + // ... + // this.WorkShipBackToIdle(shipIndex); matcher.Start() - .MatchForward(true, - new CodeMatch(OpCodes.Ldarg_0), - new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(StationComponent), "storage")), - new CodeMatch(OpCodes.Ldloc_S), - new CodeMatch(OpCodes.Ldelema), - new CodeMatch(OpCodes.Ldflda, AccessTools.Field(typeof(StationStore), "inc")), - new CodeMatch(OpCodes.Dup), - new CodeMatch(OpCodes.Ldind_I4), - new CodeMatch(OpCodes.Ldloc_S), - new CodeMatch(OpCodes.Sub), - new CodeMatch(OpCodes.Stind_I4)) - .Advance(1) + .Advance(backToStationPos + 1) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_0)) - .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 26)) - .Insert(HarmonyLib.Transpilers.EmitDelegate((StationComponent stationComponent, int index) => + .InsertAndAdvance(loadWorkShipId) + .InsertAndAdvance(loadCurrentShip) + .Insert(HarmonyLib.Transpilers.EmitDelegate((StationComponent stationComponent, int j, ref ShipData shipData) => { - if(Multiplayer.IsActive && Multiplayer.Session.LocalPlayer.IsHost) + if (Multiplayer.IsActive && Multiplayer.Session.LocalPlayer.IsHost) { - Multiplayer.Session.Network.SendPacketToStar(new ILSUpdateStorage(stationComponent.gid, index, stationComponent.storage[index].count, stationComponent.storage[index].inc), GameMain.galaxy.PlanetById(stationComponent.planetId).star.id); + ILSWorkShipBackToIdle packet = new ILSWorkShipBackToIdle(stationComponent, shipData, j); + Multiplayer.Session.Network.SendPacket(packet); } })); - // c# 242, 367 - matcher + #endregion + + #region ILSUpdateStorage + + // tell clients about StationStorage[] updates + // c# 253, 378, 1181 IL# 688, 1365, 5032 + // lock (obj) + // { + // ... + // StationStore[] array = this.storage; (or array = stationComponent3.storage;) + // int supplyIndex = supplyDemandPair.supplyIndex; (or supplyIndex = ptr.supplyIndex;) + // array[supplyIndex].inc = array[supplyIndex].inc - num; + // >> Insert (stationComponent, supplyIndex) => ILSUpdateStorage packet + // } + matcher.Start() .MatchForward(true, - new CodeMatch(OpCodes.Ldarg_0), - new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(StationComponent), "storage")), new CodeMatch(OpCodes.Ldloc_S), - new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(SupplyDemandPair), "supplyIndex")), + new CodeMatch(OpCodes.Ldfld), new CodeMatch(OpCodes.Ldelema), new CodeMatch(OpCodes.Ldflda, AccessTools.Field(typeof(StationStore), "inc")), new CodeMatch(OpCodes.Dup), @@ -253,11 +258,21 @@ public static IEnumerable InternalTickRemote_Transpiler(IEnumer new CodeMatch(OpCodes.Stind_I4)) .Repeat(localMatcher => { + CodeInstruction loadStation; + if (localMatcher.InstructionAt(-10).opcode == OpCodes.Ldarg_0) + { + loadStation = new CodeInstruction(OpCodes.Ldarg_0, null); //this + } + else + { + loadStation = loadOtherStation; //stationComponent3 + } + localMatcher .Advance(1) - .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_0)) - .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, UpdateStorageMatchCounter == 0 ? 30 : 52)) - .InsertAndAdvance(new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(SupplyDemandPair), "supplyIndex"))) + .InsertAndAdvance(loadStation) + .InsertAndAdvance(localMatcher.InstructionAt(-10)) + .InsertAndAdvance(localMatcher.InstructionAt(-10)) .Insert(HarmonyLib.Transpilers.EmitDelegate((StationComponent stationComponent, int index) => { if (Multiplayer.IsActive && Multiplayer.Session.LocalPlayer.IsHost) @@ -265,92 +280,73 @@ public static IEnumerable InternalTickRemote_Transpiler(IEnumer Multiplayer.Session.Network.SendPacketToStar(new ILSUpdateStorage(stationComponent.gid, index, stationComponent.storage[index].count, stationComponent.storage[index].inc), GameMain.galaxy.PlanetById(stationComponent.planetId).star.id); } })); - - UpdateStorageMatchCounter++; }); - UpdateStorageMatchCounter = 0; // resetting here as it seems our patches are done twice - - // c# 1034 - matcher.Start() - .MatchForward(true, - new CodeMatch(OpCodes.Ldloc_S), - new CodeMatch(OpCodes.Ldloc_S), - new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(SupplyDemandPair), "supplyIndex")), - new CodeMatch(OpCodes.Ldelema), - new CodeMatch(OpCodes.Ldflda, AccessTools.Field(typeof(StationStore), "inc")), - new CodeMatch(OpCodes.Dup), - new CodeMatch(OpCodes.Ldind_I4), - new CodeMatch(OpCodes.Ldloc_S), - new CodeMatch(OpCodes.Sub), - new CodeMatch(OpCodes.Stind_I4)) - .Advance(1) - .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 147)) - .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 151)) - .InsertAndAdvance(new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(SupplyDemandPair), "supplyIndex"))) - .Insert(HarmonyLib.Transpilers.EmitDelegate((StationComponent stationComponent, int index) => - { - if (Multiplayer.IsActive && Multiplayer.Session.LocalPlayer.IsHost) - { - Multiplayer.Session.Network.SendPacketToStar(new ILSUpdateStorage(stationComponent.gid, index, stationComponent.storage[index].count, stationComponent.storage[index].inc), GameMain.galaxy.PlanetById(stationComponent.planetId).star.id); - } - })); + #endregion return matcher.InstructionEnumeration(); } - + [HarmonyReversePatch] [HarmonyPatch(nameof(StationComponent.InternalTickRemote))] - public static void ILSUpdateShipPos(StationComponent stationComponent, PlanetFactory factory, int timeGene, double dt, float shipSailSpeed, float shipWarpSpeed, int shipCarries, StationComponent[] gStationPool, AstroData[] astroPoses, VectorLF3 relativePos, Quaternion relativeRot, bool starmap, int[] consumeRegister) + public static void ILSUpdateShipPos(StationComponent stationComponent, PlanetFactory factory, int timeGene, float shipSailSpeed, float shipWarpSpeed, int shipCarries, StationComponent[] gStationPool, AstroData[] astroPoses, ref VectorLF3 relativePos, ref Quaternion relativeRot, bool starmap, int[] consumeRegister) { IEnumerable Transpiler(IEnumerable instructions, ILGenerator il) { - // find begin of ship movement computation, c# 460 IL 2090 + // find begin of ship movement computation, remove all content in if (timeGene == this.gene) {...} + // remove c# 10 - 473 CodeMatcher matcher = new CodeMatcher(instructions, il); int indexStart = matcher .MatchForward(false, - new CodeMatch(i => i.IsLdarg()), + new CodeMatch(i => i.IsLdarg()), // float num47 = shipSailSpeed / 600f; new CodeMatch(OpCodes.Ldc_R4), new CodeMatch(OpCodes.Div), - new CodeMatch(i => i.opcode == OpCodes.Call && ((MethodInfo)i.operand).Name == "Sqrt"), new CodeMatch(OpCodes.Stloc_S), - new CodeMatch(OpCodes.Ldloc_S), - new CodeMatch(OpCodes.Stloc_S), - new CodeMatch(OpCodes.Ldloc_S), + new CodeMatch(OpCodes.Ldloc_S), // float num48 = Mathf.Pow(num47, 0.4f); new CodeMatch(OpCodes.Ldc_R4), - new CodeMatch(OpCodes.Ble_Un)) + new CodeMatch(OpCodes.Call, AccessTools.Method(typeof(Mathf), "Pow"))) .Pos; // cut out only that part of original function, but keep the first 5 IL lines (they create the 'bool flag' which is needed) for (matcher.Start().Advance(6); matcher.Pos < indexStart;) { matcher.SetAndAdvance(OpCodes.Nop, null); } - - // add null check at the beginning of the while(){} for gStationPool[shipData.otherGId] and if it is null skip this shipData until all data received from server + + // c# 502: add null check at the beginning of the while(){} for gStationPool[shipData.otherGId] and if it is null skip this shipData until all data received from server + // + // while (j < this.workShipCount) + // { + // ref ShipData ptr3 = ref this.workShipDatas[j]; + // >> insert if (gStationPool[shipData.otherGId] == null) { j++; continue; } matcher - .MatchForward(true, + .MatchForward(true, new CodeMatch(OpCodes.Br), new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(StationComponent), "workShipDatas")), new CodeMatch(OpCodes.Ldloc_S), - new CodeMatch(OpCodes.Ldelem, typeof(ShipData)), + new CodeMatch(OpCodes.Ldelema, typeof(ShipData)), new CodeMatch(OpCodes.Stloc_S)); + + object shipDataRef = matcher.Instruction.operand; + object loopIndex = matcher.InstructionAt(-2).operand; object jmpNextLoopIter = matcher.InstructionAt(-5).operand; matcher.CreateLabelAt(matcher.Pos + 1, out Label jmpNormalFlow); matcher .Advance(1) - .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_S, 7)) // gStationPool - .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 60)) // shipData + .InsertAndAdvance(new CodeInstruction(OpCodes.Ldarg_S, 6)) // gStationPool + .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, shipDataRef)) // shipData .InsertAndAdvance(new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(ShipData), "otherGId"))) .InsertAndAdvance(new CodeInstruction(OpCodes.Ldelem, typeof(StationComponent))) .InsertAndAdvance(new CodeInstruction(OpCodes.Brtrue, jmpNormalFlow)) - .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, 59)) // j + .InsertAndAdvance(new CodeInstruction(OpCodes.Ldloc_S, loopIndex)) // j .InsertAndAdvance(new CodeInstruction(OpCodes.Ldc_I4_1)) .InsertAndAdvance(new CodeInstruction(OpCodes.Add)) - .InsertAndAdvance(new CodeInstruction(OpCodes.Stloc_S, 59)) + .InsertAndAdvance(new CodeInstruction(OpCodes.Stloc_S, loopIndex)) .InsertAndAdvance(new CodeInstruction(OpCodes.Br, jmpNextLoopIter)); - - // remove c# 502-525 (adding item from landing ship to station and modify remote order and shifitng those arrays AND j-- (as we end up in an endless loop if not)) + + // remove c# 537-561 (adding item from landing ship to station and modify remote order and shifitng those arrays AND j-- (as we end up in an endless loop if not)) + // start: this.AddItem(ptr3.itemId, ptr3.itemCount, ptr3.inc); + // end: j--; indexStart = matcher .MatchForward(false, new CodeMatch(OpCodes.Ldarg_0), @@ -366,7 +362,7 @@ IEnumerable Transpiler(IEnumerable instruction .MatchForward(true, new CodeMatch(OpCodes.Sub), new CodeMatch(i => i.opcode == OpCodes.Call && ((MethodInfo)i.operand).Name == "Clear"), - new CodeMatch(OpCodes.Ldloc_S), + new CodeMatch(OpCodes.Ldloc_S), // j-- new CodeMatch(OpCodes.Ldc_I4_1), new CodeMatch(OpCodes.Sub), new CodeMatch(OpCodes.Stloc_S)) @@ -377,24 +373,9 @@ IEnumerable Transpiler(IEnumerable instruction matcher.SetAndAdvance(OpCodes.Nop, null); } - // c# 621 remove warp state entering as we do this triggered by host. client always messed up here for whatever reason so just tell him what to do. - matcher - .MatchForward(false, - new CodeMatch(OpCodes.Ldloca_S), - new CodeMatch(OpCodes.Ldflda, AccessTools.Field(typeof(ShipData), "warperCnt")), - new CodeMatch(OpCodes.Dup), - new CodeMatch(OpCodes.Ldind_I4), - new CodeMatch(OpCodes.Ldc_I4_1), - new CodeMatch(OpCodes.Sub), - new CodeMatch(OpCodes.Stind_I4), - new CodeMatch(OpCodes.Ldloca_S), - new CodeMatch(OpCodes.Ldflda, AccessTools.Field(typeof(ShipData), "warpState"))); - for(int i = 0; i < 15; i++) - { - matcher.SetAndAdvance(OpCodes.Nop, null); - } - - // remove c# 956 - 1054 (adding item from landing ship to station and modify remote order) + // remove c# 1103 - 1201 (adding item from landing ship to station and modify remote order) + // start: StationComponent stationComponent3 = gStationPool[ptr3.otherGId]; StationStore[] array21 = stationComponent3.storage; + // end: if (this.remotePairCount > 0) {...} indexStart = matcher .MatchForward(false, new CodeMatch(OpCodes.Ldarg_S), @@ -403,11 +384,7 @@ IEnumerable Transpiler(IEnumerable instruction new CodeMatch(OpCodes.Ldelem_Ref), new CodeMatch(OpCodes.Stloc_S), new CodeMatch(OpCodes.Ldloc_S), - new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(StationComponent), "storage")), - new CodeMatch(OpCodes.Stloc_S), - new CodeMatch(OpCodes.Ldarg_S), - new CodeMatch(OpCodes.Ldloc_S), - new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(ShipData), "planetA"))) + new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(StationComponent), "storage"))) .Pos; indexEnd = matcher .MatchForward(true, @@ -419,25 +396,22 @@ IEnumerable Transpiler(IEnumerable instruction new CodeMatch(OpCodes.Ldloc_S), new CodeMatch(OpCodes.Bne_Un)) .Pos; - for(matcher.Start().Advance(indexStart); matcher.Pos <= indexEnd;) + for (matcher.Start().Advance(indexStart); matcher.Pos <= indexEnd;) { matcher.SetAndAdvance(OpCodes.Nop, null); } - - // remove c# 1058 - 1093 (taking item from station and modify remote order) + + // remove c# 1208 - 1093 (taking item from station and modify remote order) + // start: stationComponent3.TakeItem(ref itemId3, ref num120, out inc); + // end: lock (obj) {...} indexStart = matcher - .MatchForward(false, - new CodeMatch(OpCodes.Ldloc_S), - new CodeMatch(OpCodes.Ldfld, AccessTools.Field(typeof(ShipData), "itemId")), - new CodeMatch(OpCodes.Stloc_S), - new CodeMatch(OpCodes.Ldarg_S), - new CodeMatch(OpCodes.Stloc_S), - new CodeMatch(OpCodes.Ldloc_S), - new CodeMatch(OpCodes.Ldloca_S), - new CodeMatch(OpCodes.Ldloca_S), - new CodeMatch(OpCodes.Ldloca_S), - new CodeMatch(i => i.opcode == OpCodes.Callvirt && ((MethodInfo)i.operand).Name == "TakeItem")) - .Pos; + .MatchForward(false, + new CodeMatch(OpCodes.Ldloc_S), + new CodeMatch(OpCodes.Ldloca_S), + new CodeMatch(OpCodes.Ldloca_S), + new CodeMatch(OpCodes.Ldloca_S), + new CodeMatch(i => i.opcode == OpCodes.Callvirt && ((MethodInfo)i.operand).Name == "TakeItem")) + .Pos; indexEnd = matcher .MatchForward(true, new CodeMatch(OpCodes.Stind_I4), @@ -448,7 +422,7 @@ IEnumerable Transpiler(IEnumerable instruction new CodeMatch(OpCodes.Call), new CodeMatch(OpCodes.Endfinally)) .Pos; - for(matcher.Start().Advance(indexStart); matcher.Pos <= indexEnd;) + for (matcher.Start().Advance(indexStart); matcher.Pos <= indexEnd;) { matcher.SetAndAdvance(OpCodes.Nop, null); } @@ -459,5 +433,5 @@ IEnumerable Transpiler(IEnumerable instruction _ = Transpiler(null, null); } } -#pragma warning restore Harmony003 // Harmony non-ref patch parameters modified +#pragma warning restore Harmony003, IDE0060 // Harmony non-ref patch parameters modified } \ No newline at end of file diff --git a/NebulaWorld/Factory/BuildToolManager.cs b/NebulaWorld/Factory/BuildToolManager.cs index f9c18eebf..ac8af1a71 100644 --- a/NebulaWorld/Factory/BuildToolManager.cs +++ b/NebulaWorld/Factory/BuildToolManager.cs @@ -129,10 +129,10 @@ public void CreatePrebuildsRequest(CreatePrebuildsRequest packet) { ((BuildTool_Path)buildTool).CreatePrebuilds(); } - else if(packet.BuildToolType == typeof(BuildTool_PathAddon).ToString()) + else if(packet.BuildToolType == typeof(BuildTool_Addon).ToString()) { - ((BuildTool_PathAddon)buildTool).handbp = buildTool.buildPreviews[0]; // traffic monitors cannot be drag build atm, so its always only one. - ((BuildTool_PathAddon)buildTool).CreatePrebuilds(); + ((BuildTool_Addon)buildTool).handbp = buildTool.buildPreviews[0]; // traffic monitors cannot be drag build atm, so its always only one. + ((BuildTool_Addon)buildTool).CreatePrebuilds(); } else if (packet.BuildToolType == typeof(BuildTool_Inserter).ToString()) { diff --git a/NebulaWorld/Logistics/CourierManager.cs b/NebulaWorld/Logistics/CourierManager.cs new file mode 100644 index 000000000..0e16b9fff --- /dev/null +++ b/NebulaWorld/Logistics/CourierManager.cs @@ -0,0 +1,193 @@ +using NebulaAPI; +using NebulaModel.Logger; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace NebulaWorld.Logistics +{ + public class CourierManager + { + public int CourierCount { get; private set; } + public CourierData[] CourierDatas { get; private set; } + + private Vector3[] EntityPositions; + private Dictionary PlayerPostions; + private int tmp_iter; + private float courierSpeed; + + public CourierManager() + { + CourierCount = 0; + CourierDatas = new CourierData[10]; + EntityPositions = new Vector3[10]; + PlayerPostions = new Dictionary(); + tmp_iter = 0; + } + + public void Dispose() + { + CourierCount = 0; + CourierDatas = null; + EntityPositions = null; + PlayerPostions = null; + } + + public void AddCourier(int playerId, in Vector3 entityPos, int itemId, int itemCount) + { + if (CourierCount >= CourierDatas.Length) + { + CourierData[] sourceArray = CourierDatas; + CourierDatas = new CourierData[CourierDatas.Length * 2]; + Array.Copy(sourceArray, CourierDatas, CourierCount); + Vector3[] sourceArray2 = EntityPositions; + EntityPositions = new Vector3[CourierDatas.Length * 2]; + Array.Copy(sourceArray2, EntityPositions, CourierCount); + } + CourierDatas[CourierCount].begin = entityPos; + CourierDatas[CourierCount].end = entityPos; + CourierDatas[CourierCount].endId = playerId; + CourierDatas[CourierCount].direction = 1f; + CourierDatas[CourierCount].maxt = 1f; + CourierDatas[CourierCount].t = 0f; + CourierDatas[CourierCount].itemId = itemId; + CourierDatas[CourierCount].itemCount = itemCount; + CourierDatas[CourierCount].gene = tmp_iter++; + EntityPositions[CourierCount] = entityPos; + CourierCount++; + DeterminePosition(); + + courierSpeed = GameMain.history.logisticCourierSpeedModified; + } + + private void DeterminePosition() + { + PlayerPostions.Clear(); + using (Multiplayer.Session.World.GetRemotePlayersModels(out Dictionary remotePlayersModels)) + { + foreach (RemotePlayerModel model in remotePlayersModels.Values) + { + // Check only players on the same planet + if (model.Movement.GetLastPosition().LocalPlanetId != GameMain.mainPlayer.planetId) + { + continue; + } + // Cache players positions for courier position updating + PlayerPostions.Add(model.Movement.PlayerID, model.PlayerTransform.position); + } + } + } + + public void GameTick(long time) + { + if (CourierCount <= 0 || GameMain.mainPlayer.factory == null) + { + return; + } + + DeterminePosition(); + + // Calculate extra couriers position for animation + for (int j = 0; j < CourierCount; j++) + { + if (CourierDatas[j].maxt <= 0f) + { + continue; + } + if (!PlayerPostions.ContainsKey(CourierDatas[j].endId)) + { + // player does not exist, mark to remove later on + CourierDatas[j].maxt = 0; + continue; + } + if (CourierDatas[j].direction > 0f) // (CourierDatas[j].endId < 0 && CourierDatas[j].direction > 0f) + { + Vector3 EntityPos = EntityPositions[j]; + ref Vector3 courierPtr = ref CourierDatas[j].end; + Vector3 playerPos = PlayerPostions[CourierDatas[j].endId]; + Vector3 vector1 = playerPos - courierPtr; + Vector3 vector2 = playerPos - EntityPos; + float courierToPlayerDist = vector1.magnitude; + float entityToPlayerDist = vector2.magnitude; + float courierHeight = courierPtr.magnitude; + float playerHeight = playerPos.magnitude; + if (courierToPlayerDist < 1.4f) + { + float entityHeight = EntityPos.magnitude; + double cosValue = (double)(EntityPos.x * playerPos.x + EntityPos.y * playerPos.y + EntityPos.z * playerPos.z) / (entityHeight * playerHeight); + if (cosValue < -1.0) + { + cosValue = -1.0; + } + else if (cosValue > 1.0) + { + cosValue = 1.0; + } + // courier reach player + CourierDatas[j].begin = EntityPos; + CourierDatas[j].maxt = (float)(Math.Acos(cosValue) * ((entityHeight + playerHeight) * 0.5)); + CourierDatas[j].maxt = (float)Math.Sqrt((double)(CourierDatas[j].maxt * CourierDatas[j].maxt) + (entityHeight - playerHeight) * (entityHeight - playerHeight)); + CourierDatas[j].t = CourierDatas[j].maxt; + } + else + { + CourierDatas[j].begin = courierPtr; + float progress = courierSpeed * 0.016666668f / courierToPlayerDist; + if (progress > 1f) + { + progress = 1f; + } + Vector3 vector3 = new(vector1.x * progress, vector1.y * progress, vector1.z * progress); + float totalTime = courierToPlayerDist / courierSpeed; + if (totalTime < 0.03333333f) + { + totalTime = 0.03333333f; + } + float deltaHeight = (playerHeight - courierHeight) / totalTime * 0.016666668f; + courierPtr += vector3; + courierPtr = courierPtr.normalized * (courierHeight + deltaHeight); + if (entityToPlayerDist > CourierDatas[j].maxt) + { + CourierDatas[j].maxt = entityToPlayerDist; + } + CourierDatas[j].t = courierToPlayerDist; + if (CourierDatas[j].t >= CourierDatas[j].maxt * 0.99f) + { + CourierDatas[j].t = CourierDatas[j].maxt * 0.99f; + } + } + } + else + { + CourierDatas[j].t += 0.016666668f * courierSpeed * CourierDatas[j].direction; + } + + + if (CourierDatas[j].t >= CourierDatas[j].maxt) + { + // Courier reach remote player + CourierDatas[j].t = CourierDatas[j].maxt; + CourierDatas[j].direction = -1f; + } + else if (CourierDatas[j].t <= 0f) + { + // Courier back to home + CourierDatas[j].maxt = 0; + } + } + + // Remove marked couriers + int i = 0; + for (int j = 0; j < CourierCount; j++) + { + if (CourierDatas[j].maxt > 0) + { + CourierDatas[i++] = CourierDatas[j]; + EntityPositions[i++] = EntityPositions[j]; + } + } + CourierCount = i; + } + + } +} diff --git a/NebulaWorld/Logistics/StationUIManager.cs b/NebulaWorld/Logistics/StationUIManager.cs index d61d24491..0b35cda45 100644 --- a/NebulaWorld/Logistics/StationUIManager.cs +++ b/NebulaWorld/Logistics/StationUIManager.cs @@ -1,4 +1,5 @@ -using NebulaModel.Logger; +using NebulaModel.DataStructures; +using NebulaModel.Logger; using NebulaModel.Packets.Logistics; using System; @@ -9,6 +10,8 @@ public class StationUIManager : IDisposable public bool UIRequestedShipDronWarpChange { get; set; } // when receiving a ship, drone or warp change only take/add items from the one issuing the request public StationUI SliderBarPacket { get; set; } // store the change of slider bar temporary, only send it when mouse button is released. public int StorageMaxChangeId { get; set; } // index of the storage that its slider value changed by the user. -1: None, -2: Syncing + public ToggleSwitch IsIncomingRequest { get; } = new ToggleSwitch(); + public StationUIManager() { @@ -48,7 +51,10 @@ private static void RefreshWindow(int planetId, int stationId) { if (stationWindow.factory?.planetId == planetId && stationWindow.stationId == stationId) { - stationWindow.OnStationIdChange(); + using (Multiplayer.Session.StationsUI.IsIncomingRequest.On()) + { + stationWindow.OnStationIdChange(); + } } } } @@ -221,6 +227,16 @@ private static void UpdateSettingsUI(StationComponent stationComponent, ref Stat stationComponent.name = packet.SettingString; break; } + case StationUI.EUISettings.DroneAutoReplenish: + { + stationComponent.droneAutoReplenish = packet.SettingValue != 0; + break; + } + case StationUI.EUISettings.ShipAutoReplenish: + { + stationComponent.shipAutoReplenish = packet.SettingValue != 0; + break; + } } } diff --git a/NebulaWorld/MonoBehaviours/Local/Chat/ChatManager.cs b/NebulaWorld/MonoBehaviours/Local/Chat/ChatManager.cs index e51525633..8186390ad 100644 --- a/NebulaWorld/MonoBehaviours/Local/Chat/ChatManager.cs +++ b/NebulaWorld/MonoBehaviours/Local/Chat/ChatManager.cs @@ -18,7 +18,7 @@ public class ChatManager : MonoBehaviour private void Awake() { Instance = this; - Transform parent = UIRoot.instance.uiGame.inventory.transform.parent; + Transform parent = UIRoot.instance.uiGame.inventoryWindow.transform.parent; GameObject chatGo = parent.Find("Chat Window") ? parent.Find("Chat Window").gameObject : null; if (chatGo == null) { diff --git a/NebulaWorld/MultiplayerSession.cs b/NebulaWorld/MultiplayerSession.cs index 4a4c11467..6791367e9 100644 --- a/NebulaWorld/MultiplayerSession.cs +++ b/NebulaWorld/MultiplayerSession.cs @@ -29,6 +29,7 @@ public class MultiplayerSession : IDisposable, IMultiplayerSession public DroneManager Drones { get; private set; } public GameDataHistoryManager History { get; private set; } public GameStatesManager State { get; private set; } + public CourierManager Couriers { get; set; } public ILSShipManager Ships { get; private set; } public StationUIManager StationsUI { get; private set; } public PlanetManager Planets { get; private set; } @@ -70,6 +71,7 @@ public MultiplayerSession(NetworkProvider networkProvider) Drones = new DroneManager(); History = new GameDataHistoryManager(); State = new GameStatesManager(); + Couriers = new CourierManager(); Ships = new ILSShipManager(); StationsUI = new StationUIManager(); Planets = new PlanetManager(); @@ -117,6 +119,9 @@ public void Dispose() State?.Dispose(); State = null; + Couriers?.Dispose(); + Couriers = null; + Ships?.Dispose(); Ships = null; diff --git a/NebulaWorld/SimulatedWorld.cs b/NebulaWorld/SimulatedWorld.cs index f9a273a40..278fa1fd7 100644 --- a/NebulaWorld/SimulatedWorld.cs +++ b/NebulaWorld/SimulatedWorld.cs @@ -14,6 +14,7 @@ using NebulaWorld.SocialIntegration; using System; using System.Collections.Generic; +using System.IO; using UnityEngine; using UnityEngine.UI; @@ -96,6 +97,15 @@ public void SetupInitialPlayerState() // Load client's saved data from the last session. GameMain.mainPlayer.package = player.Data.Mecha.Inventory; + using (MemoryStream ms = new MemoryStream()) + { + BinaryWriter bw = new BinaryWriter(ms); + player.Data.Mecha.DeliveryPackage.Export(bw); + ms.Seek(0, SeekOrigin.Begin); + BinaryReader br = new BinaryReader(ms); + GameMain.mainPlayer.deliveryPackage.Import(br); + player.Data.Mecha.DeliveryPackage = GameMain.mainPlayer.deliveryPackage; + } GameMain.mainPlayer.mecha.forge = player.Data.Mecha.Forge; GameMain.mainPlayer.mecha.coreEnergy = player.Data.Mecha.CoreEnergy; GameMain.mainPlayer.mecha.reactorEnergy = player.Data.Mecha.ReactorEnergy; @@ -129,6 +139,12 @@ public void SetupInitialPlayerState() } } + // Refresh Logistics Distributor traffic for player delivery package changes + if (GameMain.mainPlayer.factory != null) + { + GameMain.mainPlayer.factory.transport.RefreshDispenserTraffic(0); + } + // Enable Ping Indicator for Clients DisplayPingIndicator(); diff --git a/version.json b/version.json index 99e31ee3f..98d5fcf9d 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "0.8.10", + "version": "0.8.11", "assemblyVersion": { "precision": "build" },