diff --git a/Fika.Core/Coop/ClientClasses/CoopClientGameWorld.cs b/Fika.Core/Coop/ClientClasses/CoopClientGameWorld.cs index e350b758..8ee7a5f4 100644 --- a/Fika.Core/Coop/ClientClasses/CoopClientGameWorld.cs +++ b/Fika.Core/Coop/ClientClasses/CoopClientGameWorld.cs @@ -1,11 +1,9 @@ using Comfort.Common; using EFT; -using EFT.Interactive; using EFT.InventoryLogic; using EFT.SynchronizableObjects; using Fika.Core.Coop.Utils; using HarmonyLib; -using JetBrains.Annotations; using UnityEngine; namespace Fika.Core.Coop.ClientClasses @@ -30,18 +28,6 @@ public static CoopClientGameWorld Create(GameObject gameObject, PoolManager obje return gameWorld; } - public override LootItem CreateLootWithRigidbody(GameObject lootObject, Item item, string objectName, bool randomRotation, [CanBeNull] string[] validProfiles, out BoxCollider objectCollider, bool syncable, bool performPickUpValidation = true, float makeVisibleAfterDelay = 0) - { - if (syncable) - { - ObservedLootItem observedLootItem = ObservedLootItem.CreateLootWithRigidbody(lootObject, item, objectName, this, randomRotation, validProfiles, out objectCollider, performPickUpValidation, makeVisibleAfterDelay); - Traverse.Create(observedLootItem).Field("bool_3").Value = true; - return observedLootItem; - } - - return base.CreateLootWithRigidbody(lootObject, item, objectName, randomRotation, validProfiles, out objectCollider, true, performPickUpValidation, makeVisibleAfterDelay); - } - public override GClass722 CreateGrenadeFactory() { return new GClass723(); diff --git a/Fika.Core/Coop/Components/ItemPositionSyncer.cs b/Fika.Core/Coop/Components/ItemPositionSyncer.cs new file mode 100644 index 00000000..d4e48a08 --- /dev/null +++ b/Fika.Core/Coop/Components/ItemPositionSyncer.cs @@ -0,0 +1,101 @@ +using Comfort.Common; +using EFT.Interactive; +using Fika.Core.Networking; +using LiteNetLib; +using UnityEngine; + +namespace Fika.Core.Coop.Components +{ + public class ItemPositionSyncer : MonoBehaviour + { + private FikaServer server; + private FikaClient client; + private bool isServer; + private ObservedLootItem lootItem; + private GStruct128 data; + + private Rigidbody Rigidbody + { + get + { + return lootItem.RigidBody; + } + } + + public static void Create(GameObject gameObject, bool isServer, ObservedLootItem lootItem) + { + ItemPositionSyncer posSync = gameObject.AddComponent(); + posSync.isServer = isServer; + if (isServer) + { + posSync.server = Singleton.Instance; + } + else + { + posSync.client = Singleton.Instance; + } + posSync.lootItem = lootItem; + posSync.data = new() + { + Id = lootItem.GetNetId() + }; + } + + public void Start() + { + if (lootItem == null) + { + FikaPlugin.Instance.FikaLogger.LogError("HostItemPositionSync::Start: LootItem was null!"); + Destroy(this); + } + + if (Rigidbody == null) + { + FikaPlugin.Instance.FikaLogger.LogError("HostItemPositionSync::Start: Rigidbody was null!"); + Destroy(this); + } + } + + public void FixedUpdate() + { + if (Rigidbody == null) + { + data.Position = lootItem.transform.position; + data.Rotation = lootItem.transform.rotation; + data.Velocity = Vector3.zero; + data.AngularVelocity = Vector3.zero; + data.Done = true; + LootSyncPacket endPacket = new() + { + Data = data + }; + if (isServer) + { + server.SendDataToAll(ref endPacket, DeliveryMethod.ReliableOrdered); + Destroy(this); + return; + } + + client.SendData(ref endPacket, DeliveryMethod.ReliableOrdered); + Destroy(this); + return; + } + + data.Position = lootItem.transform.position; + data.Rotation = lootItem.transform.rotation; + data.Velocity = Rigidbody.velocity; + data.AngularVelocity = Rigidbody.angularVelocity; + LootSyncPacket packet = new() + { + Data = data + }; + if (isServer) + { + server.SendDataToAll(ref packet, DeliveryMethod.Unreliable); + return; + } + + client.SendData(ref packet, DeliveryMethod.Unreliable); + } + } +} diff --git a/Fika.Core/Coop/HostClasses/CoopHostGameWorld.cs b/Fika.Core/Coop/HostClasses/CoopHostGameWorld.cs index b2f936b9..29361d88 100644 --- a/Fika.Core/Coop/HostClasses/CoopHostGameWorld.cs +++ b/Fika.Core/Coop/HostClasses/CoopHostGameWorld.cs @@ -1,13 +1,11 @@ using Comfort.Common; using EFT; -using EFT.Interactive; using EFT.InventoryLogic; using EFT.SynchronizableObjects; using Fika.Core.Coop.HostClasses; using Fika.Core.Coop.Utils; using Fika.Core.Networking; using HarmonyLib; -using JetBrains.Annotations; using LiteNetLib; using System; using System.Collections.Generic; @@ -41,22 +39,10 @@ public static CoopHostGameWorld Create(GameObject gameObject, PoolManager object gameWorld.CurrentProfileId = currentProfileId; gameWorld.UnityTickListener = GameWorldUnityTickListener.Create(gameObject, gameWorld); gameWorld.AudioSourceCulling = gameObject.GetOrAddComponent(); - gameObject.AddComponent(); + FikaHostWorld.Create(gameWorld); return gameWorld; } - public override LootItem CreateLootWithRigidbody(GameObject lootObject, Item item, string objectName, bool randomRotation, [CanBeNull] string[] validProfiles, out BoxCollider objectCollider, bool syncable, bool performPickUpValidation = true, float makeVisibleAfterDelay = 0) - { - if (syncable) - { - ObservedLootItem lootItem = ObservedLootItem.CreateLootWithRigidbody(lootObject, item, objectName, this, randomRotation, validProfiles, out objectCollider, performPickUpValidation, makeVisibleAfterDelay); - HostItemPositionSync.Create(lootObject, Server, lootItem); - return lootItem; - } - - return base.CreateLootWithRigidbody(lootObject, item, objectName, randomRotation, validProfiles, out objectCollider, syncable, performPickUpValidation, makeVisibleAfterDelay); - } - public override GClass722 CreateGrenadeFactory() { return new HostGrenadeFactory(); diff --git a/Fika.Core/Coop/HostClasses/FikaHostWorld.cs b/Fika.Core/Coop/HostClasses/FikaHostWorld.cs index f7596ac2..1bc2af7b 100644 --- a/Fika.Core/Coop/HostClasses/FikaHostWorld.cs +++ b/Fika.Core/Coop/HostClasses/FikaHostWorld.cs @@ -1,8 +1,10 @@ using Comfort.Common; using EFT; using EFT.Interactive; +using Fika.Core.Coop.ClientClasses; using Fika.Core.Networking; using LiteNetLib; +using System.Collections.Generic; namespace Fika.Core.Coop.HostClasses { @@ -11,13 +13,24 @@ namespace Fika.Core.Coop.HostClasses /// public class FikaHostWorld : World { + public List LootSyncPackets; + private FikaServer server; private GameWorld gameWorld; - protected void Start() + public static FikaHostWorld Create(CoopHostGameWorld gameWorld) + { + FikaHostWorld hostWorld = gameWorld.gameObject.AddComponent(); + hostWorld.server = Singleton.Instance; + hostWorld.server.FikaHostWorld = hostWorld; + hostWorld.gameWorld = gameWorld; + hostWorld.LootSyncPackets = new List(8); + return hostWorld; + } + + protected void Update() { - server = Singleton.Instance; - gameWorld = GetComponent(); + UpdateLootItems(gameWorld.LootItems); } protected void FixedUpdate() @@ -60,6 +73,22 @@ protected void FixedUpdate() gameWorld.ArtilleryProjectilesStates.Clear(); } + public void UpdateLootItems(GClass770 lootItems) + { + for (int i = LootSyncPackets.Count - 1; i >= 0; i--) + { + GStruct128 gstruct = LootSyncPackets[i]; + if (lootItems.TryGetByKey(gstruct.Id, out LootItem lootItem)) + { + if (lootItem is ObservedLootItem observedLootItem) + { + observedLootItem.ApplyNetPacket(gstruct); + } + LootSyncPackets.RemoveAt(i); + } + } + } + /// /// Sets up all the s on the map /// diff --git a/Fika.Core/Coop/HostClasses/HostItemPositionSync.cs b/Fika.Core/Coop/HostClasses/HostItemPositionSync.cs deleted file mode 100644 index 6f059274..00000000 --- a/Fika.Core/Coop/HostClasses/HostItemPositionSync.cs +++ /dev/null @@ -1,77 +0,0 @@ -using EFT.Interactive; -using Fika.Core.Networking; -using LiteNetLib; -using UnityEngine; - -namespace Fika.Core.Coop.HostClasses -{ - public class HostItemPositionSync : MonoBehaviour - { - private FikaServer server; - private ObservedLootItem lootItem; - private GStruct128 data; - - private Rigidbody Rigidbody - { - get - { - return lootItem.RigidBody; - } - } - - public static void Create(GameObject gameObject, FikaServer server, ObservedLootItem lootItem) - { - HostItemPositionSync posSync = gameObject.AddComponent(); - posSync.server = server; - posSync.lootItem = lootItem; - posSync.data = new() - { - Id = lootItem.GetNetId() - }; - } - - public void Start() - { - if (lootItem == null) - { - FikaPlugin.Instance.FikaLogger.LogError("HostItemPositionSync::Start: LootItem was null!"); - Destroy(this); - } - - if (Rigidbody == null) - { - FikaPlugin.Instance.FikaLogger.LogError("HostItemPositionSync::Start: Rigidbody was null!"); - Destroy(this); - } - } - - public void FixedUpdate() - { - if (Rigidbody == null) - { - data.Position = lootItem.transform.position; - data.Rotation = lootItem.transform.rotation; - data.Velocity = Vector3.zero; - data.AngularVelocity = Vector3.zero; - data.Done = true; - LootSyncPacket endPacket = new() - { - Data = data - }; - server.SendDataToAll(ref endPacket, DeliveryMethod.ReliableOrdered); - Destroy(this); - return; - } - - data.Position = lootItem.transform.position; - data.Rotation = lootItem.transform.rotation; - data.Velocity = Rigidbody.velocity; - data.AngularVelocity = Rigidbody.angularVelocity; - LootSyncPacket packet = new() - { - Data = data - }; - server.SendDataToAll(ref packet, DeliveryMethod.Unreliable); - } - } -} diff --git a/Fika.Core/Coop/Patches/GameWorld/GameWorld_ThrowItem_Patch.cs b/Fika.Core/Coop/Patches/GameWorld/GameWorld_ThrowItem_Patch.cs new file mode 100644 index 00000000..54bce42d --- /dev/null +++ b/Fika.Core/Coop/Patches/GameWorld/GameWorld_ThrowItem_Patch.cs @@ -0,0 +1,34 @@ +using EFT; +using EFT.Interactive; +using Fika.Core.Coop.Components; +using Fika.Core.Coop.Utils; +using HarmonyLib; +using SPT.Reflection.Patching; +using System.Linq; +using System.Reflection; + +namespace Fika.Core.Coop.Patches +{ + public class GameWorld_ThrowItem_Patch : ModulePatch + { + protected override MethodBase GetTargetMethod() + { + return typeof(GameWorld).GetMethods().First(x => x.Name == nameof(GameWorld.ThrowItem) && x.GetParameters().Length == 3); + } + + [PatchPostfix] + public static void Postfix(LootItem __result, IPlayer player) + { + if (__result is ObservedLootItem observedLootItem) + { + if (player.IsYourPlayer || player.IsAI) + { + ItemPositionSyncer.Create(observedLootItem.gameObject, FikaBackendUtils.IsServer, observedLootItem); + return; + } + + Traverse.Create(observedLootItem).Field("bool_3").Value = true; + } + } + } +} diff --git a/Fika.Core/FikaPlugin.cs b/Fika.Core/FikaPlugin.cs index da144459..7148e682 100644 --- a/Fika.Core/FikaPlugin.cs +++ b/Fika.Core/FikaPlugin.cs @@ -326,6 +326,7 @@ private static void EnableFikaPatches() new MatchmakerPlayerControllerClass_GetCoopBlockReason_Patch().Enable(); new CoopSettingsWindow_Show_Patch().Enable(); new MainMenuController_method_48_Patch().Enable(); + new GameWorld_ThrowItem_Patch().Enable(); #if DEBUG TasksExtensions_HandleFinishedTask_Patches.Enable(); diff --git a/Fika.Core/Networking/FikaServer.cs b/Fika.Core/Networking/FikaServer.cs index 369e06a5..6a2ef99c 100644 --- a/Fika.Core/Networking/FikaServer.cs +++ b/Fika.Core/Networking/FikaServer.cs @@ -15,6 +15,7 @@ using Fika.Core.Coop.Custom; using Fika.Core.Coop.Factories; using Fika.Core.Coop.GameMode; +using Fika.Core.Coop.HostClasses; using Fika.Core.Coop.ObservedClasses; using Fika.Core.Coop.ObservedClasses.Snapshotting; using Fika.Core.Coop.Players; @@ -50,6 +51,7 @@ public class FikaServer : MonoBehaviour, INetEventListener, INetLogger, INatPunc public DateTime TimeSinceLastPeerDisconnected = DateTime.Now.AddDays(1); public bool HasHadPeer = false; public bool RaidInitialized = false; + public FikaHostWorld FikaHostWorld { get; set; } public bool Started { get @@ -171,6 +173,7 @@ public async Task Init() packetProcessor.SubscribeNetSerializable(OnSubscribeNetSerializableReceived); packetProcessor.SubscribeNetSerializable(OnBotStatePacketReceived); packetProcessor.SubscribeNetSerializable(OnPingPacketReceived); + packetProcessor.SubscribeNetSerializable(OnLootSyncPacketReceived); #if DEBUG AddDebugPackets(); @@ -278,6 +281,16 @@ public async Task Init() FikaEventDispatcher.DispatchEvent(new FikaServerCreatedEvent(this)); } + private void OnLootSyncPacketReceived(LootSyncPacket packet, NetPeer peer) + { + SendDataToAll(ref packet, packet.Data.Done ? DeliveryMethod.ReliableOrdered : DeliveryMethod.Unreliable, peer); + + if (FikaHostWorld != null) + { + FikaHostWorld.LootSyncPackets.Add(packet.Data); + } + } + private void OnPingPacketReceived(PingPacket packet, NetPeer peer) { SendDataToAll(ref packet, DeliveryMethod.ReliableOrdered, peer);