diff --git a/BoneSync/BoneSync.csproj b/BoneSync/BoneSync.csproj index e72b72e..17f46e4 100644 --- a/BoneSync/BoneSync.csproj +++ b/BoneSync/BoneSync.csproj @@ -86,6 +86,7 @@ + diff --git a/BoneSync/Networking/ByteEncoder.cs b/BoneSync/Networking/ByteEncoder.cs index 7d7ca75..114944e 100644 --- a/BoneSync/Networking/ByteEncoder.cs +++ b/BoneSync/Networking/ByteEncoder.cs @@ -124,7 +124,7 @@ namespace BoneSync.Networking return Encoding.UTF8.GetString(ReadBytes(length)); } - public void WriteUlong(ulong value) + public void WriteULong(ulong value) { WriteBytes(BitConverter.GetBytes(value)); } diff --git a/BoneSync/Networking/LobbyManager/SteamLobbyManager.cs b/BoneSync/Networking/LobbyManager/SteamLobbyManager.cs index 46f9254..afd656c 100644 --- a/BoneSync/Networking/LobbyManager/SteamLobbyManager.cs +++ b/BoneSync/Networking/LobbyManager/SteamLobbyManager.cs @@ -39,6 +39,7 @@ namespace BoneSync.Networking.LobbyManager SteamMatchmaking.OnLobbyMemberJoined += (Lobby lobby, Friend friend) => { MelonLogger.Msg("Member joined " + friend.Id); + SteamFriends.SetPlayedWith(friend.Id); UpdateLobbyData(); }; MelonLogger.Msg("SteamLobbyManager initialized"); @@ -55,8 +56,6 @@ namespace BoneSync.Networking.LobbyManager ulong lobbyId = ulong.Parse(connectString.Split(':')[1]); JoinLobby(lobbyId); }; - - SteamNetworkingUtils.InitRelayNetworkAccess(); } private Lobby _lobbyInstance; diff --git a/BoneSync/Networking/Messages/ObjectDamageMessage.cs b/BoneSync/Networking/Messages/ObjectDamageMessage.cs index b5b277d..c3308df 100644 --- a/BoneSync/Networking/Messages/ObjectDamageMessage.cs +++ b/BoneSync/Networking/Messages/ObjectDamageMessage.cs @@ -41,7 +41,7 @@ namespace BoneSync.Networking.Messages public ObjectHealthInfo objectHealthInfo; } - [PacketType(PacketType.ObjectEvent), PacketReliability(PacketReliability.UnreliableNoDelay)] + [PacketType(PacketType.ObjectEvent), PacketReliability(PacketReliability.Unreliable)] public class ObjectDamageMessage : NetworkMessage { public ObjectDamageInfo objectEventInfo => _objectEventInfo; diff --git a/BoneSync/Networking/Messages/ObjectSyncMessage.cs b/BoneSync/Networking/Messages/ObjectSyncMessage.cs index 8bdcc42..6bbfa2e 100644 --- a/BoneSync/Networking/Messages/ObjectSyncMessage.cs +++ b/BoneSync/Networking/Messages/ObjectSyncMessage.cs @@ -21,7 +21,7 @@ namespace BoneSync.Networking.Messages public ObjectSyncTransform[] objectSyncTransforms; } - [PacketType(PacketType.ObjectSync), PacketReliability(PacketReliability.UnreliableNoDelay)] + [PacketType(PacketType.ObjectSync), PacketReliability(PacketReliability.Unreliable)] internal class ObjectSyncMessage : NetworkMessage { private ObjectSyncMessageData _objectSyncMessageData = new ObjectSyncMessageData(); diff --git a/BoneSync/Networking/Messages/OnwershipTransferMessage.cs b/BoneSync/Networking/Messages/OnwershipTransferMessage.cs new file mode 100644 index 0000000..46ed38b --- /dev/null +++ b/BoneSync/Networking/Messages/OnwershipTransferMessage.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using BoneSync.Sync; + +namespace BoneSync.Networking.Messages +{ + public struct OnwershipTransferMessageData + { + public ushort SyncId; + public bool force; + public ulong NewOwnerId; + } + + [PacketType(PacketType.ObjectOwnership)] + internal class OnwershipTransferMessage : NetworkMessage + { + private OnwershipTransferMessageData Data; + public OnwershipTransferMessage(OnwershipTransferMessageData data) + { + Data = data; + byteEncoder.WriteUShort(Data.SyncId); + byteEncoder.WriteULong(Data.NewOwnerId); + byteEncoder.WriteBool(Data.force); + } + + public OnwershipTransferMessage(Packet packet) + { + byteEncoder.WriteBytes(packet.Data); + Data.SyncId = byteEncoder.ReadUShort(); + Data.NewOwnerId = byteEncoder.ReadUlong(); + Data.force = byteEncoder.ReadBool(); + } + + override public void Execute() + { + ObjectSync.OnOwnershipChangeMessage(Data.SyncId, Data.NewOwnerId, Data.force); + } + + } +} diff --git a/BoneSync/Networking/Messages/RegisterSyncableMessage.cs b/BoneSync/Networking/Messages/RegisterSyncableMessage.cs index 6b758f1..48faaba 100644 --- a/BoneSync/Networking/Messages/RegisterSyncableMessage.cs +++ b/BoneSync/Networking/Messages/RegisterSyncableMessage.cs @@ -23,12 +23,13 @@ namespace BoneSync.Networking.Messages { public string transformPath; public ushort id; + public ushort callbackId; public ulong ownerId; public RegisterSyncType type; public SpawnPoolableInfo? spawnInfo; } - [PacketType(PacketType.RegisterSyncable)] + [PacketType(PacketType.RegisterSyncable), PacketReliability(PacketReliability.ReliableFast)] internal class RegisterSyncableMessage : NetworkMessage { private RegisterSyncableInfo _info; @@ -37,8 +38,9 @@ namespace BoneSync.Networking.Messages { _info = info; byteEncoder.WriteByte((byte)_info.type); - byteEncoder.WriteUlong(_info.ownerId); + byteEncoder.WriteULong(_info.ownerId); byteEncoder.WriteUShort(_info.id); + byteEncoder.WriteUShort(_info.callbackId); switch (_info.type) { case RegisterSyncType.RegisterAndSpawn: @@ -58,6 +60,7 @@ namespace BoneSync.Networking.Messages _info.type = (RegisterSyncType)byteEncoder.ReadByte(); _info.ownerId = byteEncoder.ReadUlong(); _info.id = byteEncoder.ReadUShort(); + _info.callbackId = byteEncoder.ReadUShort(); switch (_info.type) { case RegisterSyncType.RegisterAndSpawn: diff --git a/BoneSync/Networking/NetworkMessage.cs b/BoneSync/Networking/NetworkMessage.cs index 95f5b66..7ca5dc9 100644 --- a/BoneSync/Networking/NetworkMessage.cs +++ b/BoneSync/Networking/NetworkMessage.cs @@ -118,9 +118,9 @@ namespace BoneSync.Networking - public Packet GetPacket(int id, ulong senderId, ulong receiverId) + public Packet GetPacket(ulong senderId, ulong receiverId) { - PacketInfo packetInfo = new PacketInfo(id, senderId, receiverId, GetPacketType(), GetPacketReliability()); + PacketInfo packetInfo = new PacketInfo(senderId, receiverId, GetPacketType(), GetPacketReliability()); Packet packet = new Packet(packetInfo, GetBytes()); return packet; } @@ -140,9 +140,8 @@ namespace BoneSync.Networking MelonLogger.Warning("Cannot send packet, not connected to lobby"); return; } - int PacketId = Packet.GenerateId(); ulong senderId = BoneSync.lobby.GetLocalId(); - Packet packet = GetPacket(PacketId, senderId, receiverId); + Packet packet = GetPacket(senderId, receiverId); BoneSync.transport.Send(packet); } diff --git a/BoneSync/Networking/Packet.cs b/BoneSync/Networking/Packet.cs index 9c14d51..a63ac39 100644 --- a/BoneSync/Networking/Packet.cs +++ b/BoneSync/Networking/Packet.cs @@ -15,35 +15,61 @@ namespace BoneSync.Networking public enum PacketReliability { Unreliable = 0, - UnreliableNoDelay = 1, - Reliable = 2, - ReliableWithBuffering = 3, + Reliable = 1, + ReliableFast = 2, } public struct PacketInfo { - public int id; + public ulong id; public ulong senderId; public ulong receiverId; public PacketType packetType; public PacketReliability reliability; public PacketInfo( - int id, ulong senderId, ulong receiverId, PacketType packetType, - PacketReliability reliability = PacketReliability.Reliable + PacketReliability reliability = PacketReliability.Reliable, + ulong id = 0 ) { - this.id = id; this.senderId = senderId; this.receiverId = receiverId; this.packetType = packetType; this.reliability = reliability; + this.id = id == 0 ? Packet.GenerateId() : id; + } } public class Packet { + private static ulong _packetId = 1; + + private static Dictionary> _latestPacketIds = new Dictionary>(); + + private static void SetLatestPacketId(ulong id, PacketType packetType, ulong value) + { + if (!_latestPacketIds.ContainsKey(id)) + { + _latestPacketIds.Add(id, new Dictionary()); + } + _latestPacketIds[id][packetType] = value; + } + + private static ulong GetLatestPacketId(ulong id, PacketType packetType) + { + if (!_latestPacketIds.ContainsKey(id)) + { + return 0; + } + if (!_latestPacketIds[id].ContainsKey(packetType)) + { + return 0; + } + return _latestPacketIds[id][packetType]; + } + public PacketInfo Info { get => _packetInfo; @@ -66,11 +92,11 @@ namespace BoneSync.Networking byte packetType = byteEncoder.ReadByte(); byte reliability = byteEncoder.ReadByte(); - int id = byteEncoder.ReadInt(); + ulong id = byteEncoder.ReadUlong(); ulong senderId = byteEncoder.ReadUlong(); ulong receiverId = byteEncoder.ReadUlong(); - PacketInfo packetInfo = new PacketInfo(id, senderId, receiverId, (PacketType)packetType, (PacketReliability)reliability); + PacketInfo packetInfo = new PacketInfo(senderId, receiverId, (PacketType)packetType, (PacketReliability)reliability, id); return new Packet(packetInfo, byteEncoder.ToArray()); } @@ -79,15 +105,24 @@ namespace BoneSync.Networking ByteEncoder byteEncoder = new ByteEncoder(); byteEncoder.WriteByte((byte)_packetInfo.packetType); byteEncoder.WriteByte((byte)_packetInfo.reliability); - byteEncoder.WriteInt(_packetInfo.id); - byteEncoder.WriteUlong(_packetInfo.senderId); - byteEncoder.WriteUlong(_packetInfo.receiverId); + byteEncoder.WriteULong(_packetInfo.id); + byteEncoder.WriteULong(_packetInfo.senderId); + byteEncoder.WriteULong(_packetInfo.receiverId); byteEncoder.WriteBytes(_dataBytes); return byteEncoder.ToArray(); } public static bool OnPacketReceived(Packet packet) { + if (packet._packetInfo.reliability == PacketReliability.ReliableFast) + { + if (packet.Info.id <= GetLatestPacketId(packet.Info.senderId, packet.Info.packetType)) + { + return false; + } + SetLatestPacketId(packet.Info.senderId, packet.Info.packetType, packet.Info.id); + } + NetworkMessage networkMessage = NetworkMessage.ParsePacket(packet); networkMessage.Execute(); return true; @@ -95,9 +130,9 @@ namespace BoneSync.Networking public byte[] Data => _dataBytes; - public static int GenerateId() + public static ulong GenerateId() { - return new Random().Next(); + return _packetId++; } } #if TEST diff --git a/BoneSync/Networking/PacketTypes.cs b/BoneSync/Networking/PacketTypes.cs index 3ebf0ae..ef89bd3 100644 --- a/BoneSync/Networking/PacketTypes.cs +++ b/BoneSync/Networking/PacketTypes.cs @@ -14,5 +14,6 @@ namespace BoneSync.Networking RegisterSyncable = 3, ObjectSync = 4, ObjectEvent = 5, + ObjectOwnership = 6, } } diff --git a/BoneSync/Networking/Transport/SteamTransport.cs b/BoneSync/Networking/Transport/SteamTransport.cs index e1998d5..0382671 100644 --- a/BoneSync/Networking/Transport/SteamTransport.cs +++ b/BoneSync/Networking/Transport/SteamTransport.cs @@ -8,6 +8,7 @@ using BoneSync.Networking.LobbyManager; using Facepunch.Steamworks; using Facepunch.Steamworks.Data; using MelonLoader; +using Oculus.Platform; namespace BoneSync.Networking.Transport { @@ -17,6 +18,7 @@ namespace BoneSync.Networking.Transport public SteamTransport() { SteamNetworking.OnP2PSessionRequest += OnP2PSessionRequest; + SteamNetworkingUtils.InitRelayNetworkAccess(); } private List OpenP2PConnections = new List(); private void OnP2PSessionRequest(SteamId steamId) @@ -72,18 +74,44 @@ namespace BoneSync.Networking.Transport return processed > 0; } - public void SendP2P(SteamId peer, byte[] data, P2PSend sendType) + public P2PSend GetSteamSendType(PacketReliability packetReliability) { + switch (packetReliability) + { + case PacketReliability.Unreliable: + return P2PSend.UnreliableNoDelay; + case PacketReliability.Reliable: + return P2PSend.Reliable; + default: + return P2PSend.Reliable; + } + } + + public void SendP2P(SteamId peer, byte[] data, PacketReliability sendType) + { + if (peer == BoneSync.lobby.GetLocalId()) { //MelonLogger.Msg("Trying to send packet to self"); return; } - SteamNetworking.SendP2PPacket(peer, data, data.Length, 0, sendType); + + if (sendType == PacketReliability.ReliableFast) + { + SteamNetworking.SendP2PPacket(peer, data, data.Length, 0, P2PSend.UnreliableNoDelay); + SteamNetworking.SendP2PPacket(peer, data, data.Length, 0, P2PSend.Reliable); + return; + } + + P2PSend steamSendType = GetSteamSendType(sendType); + SteamNetworking.SendP2PPacket(peer, data, data.Length, 0, steamSendType); + + + } public override void Send(Packet packet) { - P2PSend sendType = (P2PSend)packet.Info.reliability; + LobbyManager.LobbyManager _instance = BoneSync.lobby; if (_instance == null) { @@ -94,14 +122,14 @@ namespace BoneSync.Networking.Transport { foreach (SteamId peer in _instance.GetPeers()) { - SendP2P(peer, packet.ToBytes(), sendType); + SendP2P(peer, packet.ToBytes(), packet.Info.reliability); } return; } else { - SendP2P(packet.Info.receiverId, packet.ToBytes(), sendType); + SendP2P(packet.Info.receiverId, packet.ToBytes(), packet.Info.reliability); } } diff --git a/BoneSync/Patching/PoolPatches.cs b/BoneSync/Patching/PoolPatches.cs index 93c2dc7..9f361f4 100644 --- a/BoneSync/Patching/PoolPatches.cs +++ b/BoneSync/Patching/PoolPatches.cs @@ -19,7 +19,8 @@ namespace BoneSync.Patching { public static class PoolBlacklist { - private static Dictionary _blacklistedCache = new Dictionary(); + private static Dictionary _blacklistedCache = new Dictionary(); + private static Dictionary _clientSpawnCache = new Dictionary(); private static bool _isBlacklistedPool(Pool pool) { @@ -31,10 +32,15 @@ namespace BoneSync.Patching if (pool.Prefab.GetComponent() != null) return true; if (pool.Prefab.GetComponent() != null) return true; - if (pool.Prefab.GetComponent() != null) return true; return false; } + + private static bool _isClientSpawnPool(Pool pool) + { + if (pool.Prefab.GetComponent() != null) return true; + return false; + } public static bool isBlacklistedPool(Pool pool) { if (_blacklistedCache.ContainsKey(pool)) @@ -42,6 +48,14 @@ namespace BoneSync.Patching _blacklistedCache[pool] = _isBlacklistedPool(pool); return _blacklistedCache[pool]; } + + public static bool IsClientSpawnPool(Pool pool) + { + if (_clientSpawnCache.ContainsKey(pool)) + return _clientSpawnCache[pool]; + _clientSpawnCache[pool] = _isClientSpawnPool(pool); + return _clientSpawnCache[pool]; + } } [HarmonyPatch(typeof(Pool))] @@ -110,19 +124,19 @@ namespace BoneSync.Patching public static void OnSpawnPatchPost(Poolee __instance) { if (CallPatchedMethods.allowPatchedMethodCall) return; - if (__instance.pool == null) return; - if (PoolBlacklist.isBlacklistedPool(__instance.pool)) return; - MelonLogger.Msg("Poolee.OnSpawn: " + __instance.gameObject.transform.GetPath()); if (!BoneSync.lobby.IsConnected()) return; - Syncable syncable = ObjectSync.MakeOrGetSyncable(__instance); - if (BoneSync.lobby.IsHost) - { - //syncable.RegisterSyncable(); - } else - { - MelonCoroutines.Start(OnSpawnClient(__instance)); - } + MelonLogger.Msg("Poolee.OnSpawn: " + __instance.gameObject.transform.GetPath()); + + ObjectSync.MakeOrGetSyncable(__instance); + + bool spawnNormally = BoneSync.lobby.IsHost || PoolBlacklist.IsClientSpawnPool(__instance.pool); + + if (spawnNormally) return; + + + MelonCoroutines.Start(OnSpawnClient(__instance)); // block object from spawning + } public static IEnumerator OnSpawnClient(Poolee poolee) @@ -135,8 +149,6 @@ namespace BoneSync.Patching go.SetActive(false); yield return null; } - - } for (int i = 0; i < 2; i++) diff --git a/BoneSync/Sync/Components/SyncableBase.cs b/BoneSync/Sync/Components/SyncableBase.cs index f24ee84..d8a1710 100644 --- a/BoneSync/Sync/Components/SyncableBase.cs +++ b/BoneSync/Sync/Components/SyncableBase.cs @@ -72,23 +72,6 @@ namespace BoneSync.Sync.Components return false; } - public bool ShouldSendSync() - { - if (!Registered) return false; - if (!isOwner) return false; - if (isStale) return true; - if (AllRigidbodiesSleeping()) return false; - return true; - } - - public ushort GetSyncId() => _syncId; - public void SetSyncId(ushort id) - { - - _syncId = id; - ObjectSyncCache.UpdateSyncId(this); - } - public InteractableHost interactableHost { private set; get; } public InteractableHostManager interactableManager { private set; get; } public Poolee poolee { private set; get; } @@ -117,7 +100,7 @@ namespace BoneSync.Sync.Components FindComponents(); bool shouldAutoSync = CheckIfShouldAutoSync(); - if (shouldAutoSync && BoneSync.lobby.IsHost) + if (shouldAutoSync && (BoneSync.lobby.IsHost || ClientSpawningAllowed())) { MelonLogger.Msg("AutoSyncing: " + transform.GetPath()); RegisterSyncable(); @@ -181,6 +164,10 @@ namespace BoneSync.Sync.Components public void DiscardSyncable() { + if (Registered) + { + MelonLogger.Warning("Discarding registered syncable: " + transform.GetPath()); + } syncablesCache.Remove(gameObject); ObjectSyncCache.RemoveSyncable(this); Destroy(this); @@ -188,20 +175,18 @@ namespace BoneSync.Sync.Components public void OnDisable() { - if (!Registered) - { - DiscardSyncable(); - return; - } - - MelonLogger.Warning("Registered Syncable disabled: " + transform.GetPath()); + DiscardSyncable(); } public void RegisterSyncable() { if (!BoneSync.lobby.IsConnected()) return; + if (Registered) + { + TryBecomeOwner(); + return; + } if (_attemptedRegister) return; - if (Registered) return; if (!CanBeSynced()) return; _attemptedRegister = true; _SendRegisterSync(); diff --git a/BoneSync/Sync/Components/SyncableNetworking.cs b/BoneSync/Sync/Components/SyncableNetworking.cs index fa15d3a..3c432d3 100644 --- a/BoneSync/Sync/Components/SyncableNetworking.cs +++ b/BoneSync/Sync/Components/SyncableNetworking.cs @@ -1,4 +1,6 @@ -using MelonLoader; +using BoneSync.Networking.Messages; +using BoneSync.Patching; +using MelonLoader; using System; using System.Collections; using System.Collections.Generic; @@ -37,6 +39,16 @@ namespace BoneSync.Sync.Components MelonCoroutines.Start(SyncCoroutineAsync()); UpdateKinematic(); } + + public bool ClientSpawningAllowed() + { + if (poolee && poolee.pool) + { + return PoolBlacklist.IsClientSpawnPool(poolee.pool); + } + return false; + } + private void _SendRegisterSync() { MelonLogger.Msg("Registering syncable object: " + gameObject.name); @@ -46,12 +58,53 @@ namespace BoneSync.Sync.Components public void OnOwnershipTransferRequest(ulong newOwnerId) { - MelonLogger.Msg("Ownership transfer request for " + _syncId + " to " + newOwnerId); - if (isOwner) + //MelonLogger.Msg("Ownership transfer request for " + _syncId + " to " + newOwnerId); + if (isOwner && !IsHolding()) { MelonLogger.Msg("Sending ownership transfer for " + _syncId + " to " + newOwnerId); - //BoneSync.lobby.SendOwnershipTransferMessage(_syncId, newOwnerId); + OnwershipTransferMessageData data = new OnwershipTransferMessageData() + { + SyncId = _syncId, + NewOwnerId = newOwnerId, + force = true + }; + OnwershipTransferMessage message = new OnwershipTransferMessage(data); + message.Broadcast(); + SetOwner(newOwnerId); } } + + public void TryBecomeOwner() + { + if (!isOwner) + { + MelonLogger.Msg("Attempting to become owner of " + _syncId); + OnwershipTransferMessageData data = new OnwershipTransferMessageData() + { + SyncId = _syncId, + NewOwnerId = BoneSync.lobby.GetLocalId(), + force = false + }; + OnwershipTransferMessage message = new OnwershipTransferMessage(data); + message.Broadcast(); + } + } + + public bool ShouldSendSync() + { + if (!Registered) return false; + if (!isOwner) return false; + if (isStale) return true; + if (AllRigidbodiesSleeping()) return false; + return true; + } + + public ushort GetSyncId() => _syncId; + public void SetSyncId(ushort id) + { + + _syncId = id; + ObjectSyncCache.UpdateSyncId(this); + } } } diff --git a/BoneSync/Sync/Components/SyncablePhysics.cs b/BoneSync/Sync/Components/SyncablePhysics.cs index 551aebf..dff9d71 100644 --- a/BoneSync/Sync/Components/SyncablePhysics.cs +++ b/BoneSync/Sync/Components/SyncablePhysics.cs @@ -17,15 +17,25 @@ namespace BoneSync.Sync.Components { foreach (Rigidbody rb in rigidbodies) { - if (!rb.IsSleeping()) return false; + try + { + if (!rb.IsSleeping()) return false; + } + catch { } // ignore null rigidbodies + } + return true; } private void SetKinematic(bool kinematic) { foreach (Rigidbody rb in rigidbodies) { - rb.isKinematic = kinematic; + try + { + rb.isKinematic = kinematic; + } + catch { } // ignore null rigidbodies } } diff --git a/BoneSync/Sync/ObjectSync.cs b/BoneSync/Sync/ObjectSync.cs index 6bd9a5e..62db004 100644 --- a/BoneSync/Sync/ObjectSync.cs +++ b/BoneSync/Sync/ObjectSync.cs @@ -12,6 +12,7 @@ using System.Text; using System.Threading.Tasks; using UnityEngine; using UnityEngine.SceneManagement; +using Random = UnityEngine.Random; namespace BoneSync.Sync { @@ -22,9 +23,11 @@ namespace BoneSync.Sync { return _nextSyncableId++; } + - public static RegisterSyncableInfo? GetRegisterInfo(Syncable syncable) + public static RegisterSyncableInfo? GetRegisterInfo(Syncable syncable, bool allowClientRegister) { + ulong ownerId = BoneSync.lobby.GetLocalId(); RegisterSyncableInfo? info = null; string path = syncable.GetSyncableWorldPath(); if (path.Length > 0) @@ -33,13 +36,14 @@ namespace BoneSync.Sync { type = RegisterSyncType.RegisterFromPath, transformPath = path, - ownerId = syncable._ownerId, + ownerId = ownerId, }; } - else if (syncable.poolee && syncable.poolee.pool && BoneSync.lobby.IsHost) + else if (syncable.poolee && syncable.poolee.pool && (BoneSync.lobby.IsHost || allowClientRegister)) { info = new RegisterSyncableInfo() { + ownerId = ownerId, type = RegisterSyncType.RegisterAndSpawn, spawnInfo = new SpawnPoolableInfo() { @@ -53,7 +57,7 @@ namespace BoneSync.Sync public static ushort SendRegisterSyncableMessage(Syncable syncable) { - RegisterSyncableInfo? infoNullable = GetRegisterInfo(syncable); + RegisterSyncableInfo? infoNullable = GetRegisterInfo(syncable, syncable.ClientSpawningAllowed()); if (infoNullable == null) { @@ -71,7 +75,8 @@ namespace BoneSync.Sync new RegisterSyncableMessage(info).Broadcast(); } else { - info.id = 0; + info.callbackId = (ushort)Random.Range(1, ushort.MaxValue); + ObjectSyncCache._callbackIdToSyncable[info.callbackId] = syncable; new RegisterSyncableMessage(info).SendToHost(); } @@ -100,15 +105,19 @@ namespace BoneSync.Sync //Scene scene = gameObject.scene; //MelonLogger.Msg("Making or getting syncable for: " + gameObject.name + " in scene: " + scene.name); - Syncable[] subSyncables = gameObject.GetComponentsInChildren(); + Syncable syncable = gameObject.GetComponent(); // delete all sub syncables - for (int i = 0; i < subSyncables.Length; i++) + if (deleteSubSyncabled) { - if (subSyncables[i] != syncable) + Syncable[] subSyncables = gameObject.GetComponentsInChildren(true); + for (int i = 0; i < subSyncables.Length; i++) { - subSyncables[i].DiscardSyncable(); + if (subSyncables[i] != syncable) + { + subSyncables[i].DiscardSyncable(); + } } } @@ -116,10 +125,6 @@ namespace BoneSync.Sync { syncable = gameObject.AddComponent(); } - else - { - syncable.FindComponents(); - } return syncable; } @@ -158,10 +163,9 @@ namespace BoneSync.Sync return _MakeOrGetSyncable(interactableHostManager.gameObject); } - public static Syncable SpawnPooleeAndMakeSyncable(RegisterSyncableInfo info) + public static Syncable SpawnPooleeAndMakeSyncable(SpawnPoolableInfo spawnInfo) { - SpawnPoolableInfo spawnInfo = info.spawnInfo.Value; SimpleTransform spawnLocation = spawnInfo.spawnLocation; // !! This is a bit of a hack, but it works for now @@ -180,6 +184,7 @@ namespace BoneSync.Sync Poolee poolee = CallPatchedMethods.InstantiatePoolee(pool, spawnLocation.position, spawnLocation.rotation, pool.Prefab.transform.localScale); Syncable syncable = MakeOrGetSyncable(poolee); + MelonLogger.Msg("Spawned poolee with syncable: " + poolee.transform.GetPath()); return syncable; } public static void OnRegisterSyncMessage(RegisterSyncableMessage registerSyncableMessage) @@ -192,6 +197,7 @@ namespace BoneSync.Sync new RegisterSyncableMessage(info).Broadcast(); } else { + // only host can register syncables, all spawn requests should be sent to host if (registerSyncableMessage.senderId != BoneSync.lobby.GetHostId()) { MelonLogger.Warning("Received register sync message from non-host: " + registerSyncableMessage.senderId); @@ -199,16 +205,30 @@ namespace BoneSync.Sync } } - switch (info.type) + bool hasCallback = info.callbackId != 0; + if (hasCallback) { - case RegisterSyncType.RegisterFromPath: - MelonLogger.Msg("Registering syncable from path: " + info.transformPath + " with id: " + info.id); - syncable = ObjectSyncCache.GetSyncable(info.transformPath); - break; - case RegisterSyncType.RegisterAndSpawn: - MelonLogger.Msg("Registering and spawning syncable from pool: " + info.spawnInfo.Value.poolName + " with id: " + info.id); - syncable = SpawnPooleeAndMakeSyncable(info); - break; + MelonLogger.Msg("Received register sync message with callback id: " + info.callbackId); + } + + if (hasCallback && ObjectSyncCache._callbackIdToSyncable.ContainsKey(info.callbackId)) + { + MelonLogger.Msg("Found syncable for callback id: " + info.callbackId); + syncable = ObjectSyncCache._callbackIdToSyncable[info.callbackId]; + ObjectSyncCache._callbackIdToSyncable.Remove(info.callbackId); + } else + { + switch (info.type) + { + case RegisterSyncType.RegisterFromPath: + MelonLogger.Msg("Registering syncable from path: " + info.transformPath + " with id: " + info.id); + syncable = ObjectSyncCache.GetSyncable(info.transformPath); + break; + case RegisterSyncType.RegisterAndSpawn: + MelonLogger.Msg("Registering and spawning syncable from pool: " + info.spawnInfo.Value.poolName + " with id: " + info.id); + syncable = SpawnPooleeAndMakeSyncable(info.spawnInfo.Value); + break; + } } if (!syncable) @@ -241,7 +261,7 @@ namespace BoneSync.Sync Syncable syncable = ObjectSyncCache.GetSyncable(damageInfo.objectId); if (syncable == null) { - MelonLogger.Msg("DamageEvent: Syncable not found for id: " + damageInfo.objectId); + //MelonLogger.Msg("DamageEvent: Syncable not found for id: " + damageInfo.objectId); return; } syncable.Damage(damageInfo); @@ -259,5 +279,23 @@ namespace BoneSync.Sync message.Broadcast(); message.Execute(); } + + internal static void OnOwnershipChangeMessage(ushort syncId, ulong newOwnerId, bool force) + { + Syncable syncable = ObjectSyncCache.GetSyncable(syncId); + if (syncable == null) + { + MelonLogger.Warning("Ownership transfer request for non-existant syncable: " + syncId); + return; + } + if (force) + { + syncable.SetOwner(newOwnerId); + } + else + { + syncable.OnOwnershipTransferRequest(newOwnerId); + } + } } } diff --git a/BoneSync/Sync/ObjectSyncCache.cs b/BoneSync/Sync/ObjectSyncCache.cs index 363635a..26e51cf 100644 --- a/BoneSync/Sync/ObjectSyncCache.cs +++ b/BoneSync/Sync/ObjectSyncCache.cs @@ -17,6 +17,8 @@ namespace BoneSync.Sync private static Dictionary _interactableHostToSyncable = new Dictionary(); private static Dictionary _interactableHostManagerToSyncable = new Dictionary(); + public static Dictionary _callbackIdToSyncable = new Dictionary(); + public static void AddSyncable(Syncable syncable) { string path = syncable.GetSyncableWorldPath();