diff --git a/BoneSync/BoneSync.csproj b/BoneSync/BoneSync.csproj index 7055f63..5c8db6c 100644 --- a/BoneSync/BoneSync.csproj +++ b/BoneSync/BoneSync.csproj @@ -93,7 +93,9 @@ + + diff --git a/BoneSync/Networking/Messages/PlugSyncMessage.cs b/BoneSync/Networking/Messages/PlugSyncMessage.cs new file mode 100644 index 0000000..674d45a --- /dev/null +++ b/BoneSync/Networking/Messages/PlugSyncMessage.cs @@ -0,0 +1,67 @@ +using BoneSync.Sync; +using BoneSync.Sync.Components; +using StressLevelZero.Interaction; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BoneSync.Networking.Messages +{ + + public struct PlugSyncMessageData + { + public ushort plugSyncId; + public byte plugIndex; + public ushort socketSyncId; + public byte socketIndex; + } + + [PacketType(PacketType.PlugSync), PacketReliability(PacketReliability.ReliableFast)] + internal class PlugSyncMessage : NetworkMessage + { + private PlugSyncMessageData messageData; + public PlugSyncMessage(PlugSyncMessageData plugSyncMessageData) + { + this.messageData = plugSyncMessageData; + byteEncoder.WriteUShort(plugSyncMessageData.plugSyncId); + byteEncoder.WriteByte(plugSyncMessageData.plugIndex); + byteEncoder.WriteUShort(plugSyncMessageData.socketSyncId); + byteEncoder.WriteByte(plugSyncMessageData.socketIndex); + } + + public PlugSyncMessage(Packet packet) { + byteEncoder.WriteBytes(packet.Data); + messageData.plugSyncId = byteEncoder.ReadUShort(); + messageData.plugIndex = byteEncoder.ReadByte(); + messageData.socketSyncId = byteEncoder.ReadUShort(); + messageData.socketIndex = byteEncoder.ReadByte(); + } + + public override void Execute() + { + Syncable plugSyncable = ObjectSyncCache.GetSyncable(messageData.plugSyncId); + Syncable socketSyncable = ObjectSyncCache.GetSyncable(messageData.socketSyncId); + + if (!plugSyncable || messageData.plugIndex == byte.MaxValue) { return; } + AlignPlug plug = (AlignPlug)plugSyncable.GetPlugFromId(messageData.plugIndex); + if (plug == null) { return; } + + if (!socketSyncable || messageData.socketIndex == byte.MaxValue) { + plug.SafeEject(); + return; + } + + Socket socket = socketSyncable.GetSocketFromId(messageData.socketIndex); + if (socket == null) + { + plug.SafeEject(); + return; + } + + plug.SafeInsert(socket); + } + + } +} diff --git a/BoneSync/Networking/Messages/SimpleSyncableEventMessage.cs b/BoneSync/Networking/Messages/SimpleSyncableEventMessage.cs new file mode 100644 index 0000000..ad7492c --- /dev/null +++ b/BoneSync/Networking/Messages/SimpleSyncableEventMessage.cs @@ -0,0 +1,50 @@ +using BoneSync.Sync; +using BoneSync.Sync.Components; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BoneSync.Networking.Messages +{ + public enum SimpleEventType + { + None = 0, + OnDevicePull = 1, + OnDeviceRelease = 2 + } + public struct SimpleSyncableEvent + { + public ushort syncId; + public SimpleEventType eventType; + //public object[] args; + } + [PacketType(PacketType.SimpleObjectEventSync)] + public class SimpleSyncableEventMessage : NetworkMessage + { + private SimpleSyncableEvent eventData; + public SimpleSyncableEventMessage(SimpleSyncableEvent simpleSyncableEvent) + { + eventData = simpleSyncableEvent; + byteEncoder.WriteULong(simpleSyncableEvent.syncId); + byteEncoder.WriteByte((byte)simpleSyncableEvent.eventType); + } + + public SimpleSyncableEventMessage(Packet packet) + { + byteEncoder.WriteBytes(packet.Data); + eventData.syncId = byteEncoder.ReadUShort(); + eventData.eventType = (SimpleEventType)byteEncoder.ReadByte(); + } + + public override void Execute() + { + Syncable syncable = ObjectSyncCache.GetSyncable(eventData.syncId); + if (syncable == null) return; + syncable.OnSimpleSyncableEvent(eventData); + } + + + } +} diff --git a/BoneSync/Networking/PacketTypes.cs b/BoneSync/Networking/PacketTypes.cs index cb3550e..49ab1bf 100644 --- a/BoneSync/Networking/PacketTypes.cs +++ b/BoneSync/Networking/PacketTypes.cs @@ -18,5 +18,7 @@ namespace BoneSync.Networking DiscardSyncable = 7, MagazineSync = 8, GunSync = 9, + SimpleObjectEventSync = 10, + PlugSync = 11, } } diff --git a/BoneSync/Patching/DebugPatches.cs b/BoneSync/Patching/DebugPatches.cs index 3c0b7b1..9004b3a 100644 --- a/BoneSync/Patching/DebugPatches.cs +++ b/BoneSync/Patching/DebugPatches.cs @@ -11,7 +11,7 @@ using UnityEngine; namespace BoneSync.Patching { - [HarmonyPatch(typeof(PoolSpawner))] + /*[HarmonyPatch(typeof(PoolSpawner))] internal class DebugPatches { // patch the static method "PoolSpawner.SpawnProjectile" @@ -20,5 +20,6 @@ namespace BoneSync.Patching { MelonLoader.MelonLogger.Msg("PoolSpawner.SpawnProjectile " + weaponName); } - } + }*/ + } diff --git a/BoneSync/Patching/PlugPatches.cs b/BoneSync/Patching/PlugPatches.cs index 2f64586..6480cd0 100644 --- a/BoneSync/Patching/PlugPatches.cs +++ b/BoneSync/Patching/PlugPatches.cs @@ -3,11 +3,13 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using BoneSync.Networking.Messages; using BoneSync.Sync; using BoneSync.Sync.Components; using HarmonyLib; using MelonLoader; using StressLevelZero.Interaction; +using static MelonLoader.MelonLogger; namespace BoneSync.Patching { @@ -70,16 +72,66 @@ namespace BoneSync.Patching [HarmonyPatch(typeof(AlignPlug))] public static class AlignPlugPatches { + public static void OnPlugSocketChange(AlignPlug plug, Socket socket) + { + + Syncable plugSyncable = plug.GetComponentInParent(); + Syncable socketSyncable = socket.GetComponentInParent(); + + if (!plugSyncable) + { + MelonLogger.Warning("PlugSyncable not found"); + return; + } + + if (!plugSyncable.Registered) + { + MelonLogger.Warning("PlugSyncable not registered"); + return; + } + + if (!socketSyncable) + { + MelonLogger.Warning("SocketSyncable not found"); + } + + if (socketSyncable && socketSyncable.isOwner && !plugSyncable.isOwner) + { + plugSyncable.TryBecomeOwner(true); // forcefully take ownership of the plug + } + + byte plugId = plugSyncable.GetPlugId(plug); + byte socketId = socketSyncable ? socketSyncable.GetSocketId(socket) : byte.MaxValue; + + MelonLogger.Msg("AlignPlug state: " + plug.transform.GetPath() + " Socket: " + socket.transform.GetPath() + " Plug ID: " + plugId + " Socket ID: " + socketId); + + if (!plugSyncable.isOwner) return; + + PlugSyncMessageData messageData = new PlugSyncMessageData + { + plugSyncId = plugSyncable.GetSyncId(), + plugIndex = plugId, + socketSyncId = socketSyncable ? socketSyncable.GetSyncId() : ushort.MinValue, + socketIndex = socketId + }; + + PlugSyncMessage plugSyncMessage = new PlugSyncMessage(messageData); + plugSyncMessage.Broadcast(); + } + [HarmonyPatch(nameof(AlignPlug.InsertPlug)), HarmonyPostfix] public static void AlignPlugInsertPatch(AlignPlug __instance, Socket socket) { - MelonLogger.Msg("AlignPlug inserted: " + __instance.transform.GetPath() + " Socket: " + socket.transform.GetPath()); + MelonLogger.Msg("AlignPlug inserted: " + __instance.transform.GetPath() + " Socket: " + socket.transform.GetPath()); + OnPlugSocketChange(__instance, socket); + } [HarmonyPatch(nameof(AlignPlug.EjectPlug)), HarmonyPostfix] public static void AlignPlugEjectPatch(AlignPlug __instance) { MelonLogger.Msg("AlignPlug ejected: " + __instance.transform.GetPath()); + OnPlugSocketChange(__instance, null); } } diff --git a/BoneSync/Sync/Components/SyncableBase.cs b/BoneSync/Sync/Components/SyncableBase.cs index 0b1f6a9..70625b0 100644 --- a/BoneSync/Sync/Components/SyncableBase.cs +++ b/BoneSync/Sync/Components/SyncableBase.cs @@ -185,6 +185,7 @@ namespace BoneSync.Sync.Components spawnFragment = GetComponent(); UpdateTransformList(); + _TryPatchPullDevice(); ObjectSyncCache.AddSyncable(this); } diff --git a/BoneSync/Sync/Components/SyncableNetworking.cs b/BoneSync/Sync/Components/SyncableNetworking.cs index 59ecdb9..b3ac98e 100644 --- a/BoneSync/Sync/Components/SyncableNetworking.cs +++ b/BoneSync/Sync/Components/SyncableNetworking.cs @@ -86,19 +86,24 @@ namespace BoneSync.Sync.Components } } - public void TryBecomeOwner() + public void TryBecomeOwner(bool force = false) { if (Registered && !isOwner) { - MelonLogger.Msg("Attempting to become owner of " + _syncId); + ulong localId = BoneSync.lobby.GetLocalId(); + MelonLogger.Msg("Attempting to become owner of " + _syncId + " force: " + force); OwnershipTransferMessageData data = new OwnershipTransferMessageData() { syncId = _syncId, - NewOwnerId = BoneSync.lobby.GetLocalId(), - force = false + NewOwnerId = localId, + force = force }; OwnershipTransferMessage message = new OwnershipTransferMessage(data); message.Broadcast(); + if (force) + { + SetOwner(localId); + } } } @@ -111,6 +116,18 @@ namespace BoneSync.Sync.Components return true; } + private void _SendSimpleEvent(SimpleEventType eType) + { + SimpleSyncableEvent data = new SimpleSyncableEvent() + { + syncId = _syncId, + eventType = eType + }; + + SimpleSyncableEventMessage simpleSyncEvent = new SimpleSyncableEventMessage(data); + simpleSyncEvent.Broadcast(); + } + public ushort GetSyncId() => _syncId; public void SetSyncId(ushort id) { diff --git a/BoneSync/Sync/Components/SyncablePhysics.cs b/BoneSync/Sync/Components/SyncablePhysics.cs index 1bc946b..3c26f83 100644 --- a/BoneSync/Sync/Components/SyncablePhysics.cs +++ b/BoneSync/Sync/Components/SyncablePhysics.cs @@ -17,15 +17,25 @@ namespace BoneSync.Sync.Components { private bool pullDevicePatched = false; - void OnPull() + void DeviceOnPull() { MelonLogger.Msg("OnPull"); + if (!isOwner) { return; } + _SendSimpleEvent(SimpleEventType.OnDevicePull); + } + void DeviceOnRelease() + { + MelonLogger.Msg("OnRelease"); + if (!isOwner) { return; } + _SendSimpleEvent(SimpleEventType.OnDeviceRelease); } private void _TryPatchPullDevice() { if (pullDevicePatched) return; if (!pullDevice) return; - pullDevice.OnHandlePull.AddListener((UnityAction)OnPull); + pullDevice.OnHandlePull.AddListener((UnityAction)DeviceOnPull); + pullDevice.OnHandleReturn.AddListener((UnityAction)DeviceOnRelease); + pullDevicePatched = true; } public bool AllRigidbodiesSleeping() @@ -45,6 +55,7 @@ namespace BoneSync.Sync.Components private void SetKinematic(bool kinematic) { if (!this) return; + if (rigidbodies.Length == 0) return; foreach (Rigidbody rb in rigidbodies) { try @@ -119,6 +130,19 @@ namespace BoneSync.Sync.Components SetKinematic(_ownerId != BoneSync.lobby.GetLocalId() && Registered); } + internal void OnSimpleSyncableEvent(SimpleSyncableEvent eventData) + { + MelonLogger.Msg("OnSimpleSyncableEvent: " + eventData.eventType); + SimpleEventType eType = eventData.eventType; + switch (eType) { + case SimpleEventType.OnDevicePull: + pullDevice?.OnHandlePull?.Invoke(); + break; + case SimpleEventType.OnDeviceRelease: + pullDevice?.OnHandleReturn?.Invoke(); + break; + } + } // on collision } } diff --git a/BoneSync/Sync/Components/SyncablePlugs.cs b/BoneSync/Sync/Components/SyncablePlugs.cs index 183ce2a..a9ac711 100644 --- a/BoneSync/Sync/Components/SyncablePlugs.cs +++ b/BoneSync/Sync/Components/SyncablePlugs.cs @@ -9,6 +9,39 @@ using StressLevelZero.Interaction; namespace BoneSync.Sync.Components { + public static class PlugExtensions + { + public static Socket GetSocket(this AlignPlug plug) + { + Socket socket = plug._lastSocket; + if (!socket) return null; + if (socket.LockedPlug == plug) + { + return socket; + } + return null; + } + + public static bool SafeEject(this AlignPlug plug) + { + if (!plug.GetSocket()) return false; + plug.EjectPlug(); + return true; + } + + public static bool SafeInsert(this AlignPlug plug, Socket socket) + { + if (!socket) return false; + if (socket.LockedPlug) return false; + if (plug.GetSocket() && plug._lastSocket != socket) + { + plug.EjectPlug(); + plug.ClearFromSocket(); + } + plug.InsertPlug(socket); + return true; + } + } public partial class Syncable : MonoBehaviour { public Plug GetPlugFromId(byte id) @@ -55,5 +88,6 @@ namespace BoneSync.Sync.Components } return 255; } + } } diff --git a/BoneSync/Sync/ObjectSyncCache.cs b/BoneSync/Sync/ObjectSyncCache.cs index 10ff950..3f2380c 100644 --- a/BoneSync/Sync/ObjectSyncCache.cs +++ b/BoneSync/Sync/ObjectSyncCache.cs @@ -1,6 +1,7 @@ using BoneSync.Sync.Components; using StressLevelZero.Interaction; using StressLevelZero.Pool; +using StressLevelZero.Props.Weapons; using System; using System.Collections.Generic; using System.Linq; @@ -26,18 +27,27 @@ namespace BoneSync.Sync return component.GetType().Namespace; } - private static bool IsSlzComponent(Component component) + private static bool IsCachableComponent(MonoBehaviour component) { - string ns = GetComponentNamespace(component); - return ns.StartsWith("StressLevelZero") || ns.StartsWith("BoneSync"); + if (component is InteractableHost) return true; + if (component is Poolee) return true; + if (component is Plug) return true; + if (component is Socket) return true; + if (component is AlignPlug) return true; + if (component is Gun) return true; + if (component is Magazine) return true; + + return false; + //string ns = GetComponentNamespace(component); + //return ns.StartsWith("StressLevelZero") || ns.StartsWith("BoneSync"); } - private static MonoBehaviour[] GetSLZComponents(Syncable syncable) + private static MonoBehaviour[] GetComponentsToCache(Syncable syncable) { MonoBehaviour[] components = syncable.GetComponentsInChildren(true); List slzComponents = new List(); for (int i = 0; i < components.Length; i++) { - if (IsSlzComponent(components[i])) + if (IsCachableComponent(components[i])) { slzComponents.Add(components[i]); } @@ -46,7 +56,7 @@ namespace BoneSync.Sync } private static void _AddSyncableComponents(Syncable syncable) { - MonoBehaviour[] components = GetSLZComponents(syncable); + MonoBehaviour[] components = GetComponentsToCache(syncable); _syncableToComponent[syncable] = components; foreach (MonoBehaviour component in components) {