diff --git a/BoneSync/MelonLoaderMod.cs b/BoneSync/MelonLoaderMod.cs index 7b79639..0ee9f2b 100644 --- a/BoneSync/MelonLoaderMod.cs +++ b/BoneSync/MelonLoaderMod.cs @@ -35,6 +35,7 @@ namespace BoneSync transport = new SteamTransport(); SceneSync.Initialize(); + NetworkMessage.RegisterPacketTypes(); } public static void PatchAll() @@ -62,21 +63,12 @@ namespace BoneSync { transport.Tick(); - PlayerRig.Tick(); + //PlayerRig.Tick(); if (Input.GetKeyDown(KeyCode.P)) { MelonLogger.Msg("P key pressed"); - PlayerRig playerRig = PlayerRig.InstantiatePlayerRigPrefab(); - if (playerRig == null) - { - MelonLogger.Error("Failed to instantiate player rig prefab"); - return; - } - else - { - MelonLogger.Msg("Player rig instantiated"); - } + //PlayerRig playerRig = PlayerRig.InstantiatePlayerRigPrefab(); } if (Input.GetKeyDown(KeyCode.I)) { diff --git a/BoneSync/Networking/ByteEncoder.cs b/BoneSync/Networking/ByteEncoder.cs index 6021e0f..664947c 100644 --- a/BoneSync/Networking/ByteEncoder.cs +++ b/BoneSync/Networking/ByteEncoder.cs @@ -36,6 +36,10 @@ namespace BoneSync.Networking } public byte[] ReadBytes(int count) { + if (Data.Count < count) + { + throw new Exception("Not enough data to read, expected " + count + " but only have " + Data.Count); + } byte[] value = Data.GetRange(0, count).ToArray(); Data.RemoveRange(0, count); return value; diff --git a/BoneSync/Networking/LobbyManager/LobbyManager.cs b/BoneSync/Networking/LobbyManager/LobbyManager.cs index 88eeee3..55a2ffe 100644 --- a/BoneSync/Networking/LobbyManager/LobbyManager.cs +++ b/BoneSync/Networking/LobbyManager/LobbyManager.cs @@ -12,6 +12,8 @@ namespace BoneSync.Networking.LobbyManager public abstract ulong GetLobbyId(); public abstract ulong GetHostId(); public abstract ulong GetLocalId(); + public bool IsHost => GetLocalId() == GetHostId(); + public abstract bool IsConnected(); public abstract void CreateLobby(); public abstract void JoinLobby(ulong lobbyId); diff --git a/BoneSync/Networking/LobbyManager/SteamLobbyManager.cs b/BoneSync/Networking/LobbyManager/SteamLobbyManager.cs index 38ce6bb..46f9254 100644 --- a/BoneSync/Networking/LobbyManager/SteamLobbyManager.cs +++ b/BoneSync/Networking/LobbyManager/SteamLobbyManager.cs @@ -42,8 +42,22 @@ namespace BoneSync.Networking.LobbyManager UpdateLobbyData(); }; MelonLogger.Msg("SteamLobbyManager initialized"); - } + SteamFriends.OnGameLobbyJoinRequested += (Lobby lobby, SteamId friend) => + { + MelonLogger.Msg("Joining lobby " + lobby.Id); + JoinLobby(lobby.Id.Value); + }; + + SteamFriends.OnGameRichPresenceJoinRequested += (Friend friend, string connectString) => + { + MelonLogger.Msg("Joining lobby " + connectString); + ulong lobbyId = ulong.Parse(connectString.Split(':')[1]); + JoinLobby(lobbyId); + }; + + SteamNetworkingUtils.InitRelayNetworkAccess(); + } private Lobby _lobbyInstance; public Friend[] LobbyMembers @@ -57,6 +71,11 @@ namespace BoneSync.Networking.LobbyManager private set; } + public override bool IsConnected() + { + return _lobbyInstance.Id.IsValid; + } + public override ulong[] GetPeers() => steamIds.Select(x => x.Value).ToArray(); public override ulong GetLocalId() => SteamClient.SteamId.Value; public override ulong GetHostId() => _lobbyInstance.Owner.Id.Value; @@ -88,6 +107,7 @@ namespace BoneSync.Networking.LobbyManager public override void CreateLobby() { + LeaveLobby(); MelonLogger.Msg("Trying to create lobby"); _ = SteamMatchmaking.CreateLobbyAsync(16); @@ -95,13 +115,16 @@ namespace BoneSync.Networking.LobbyManager public override void JoinLobby(ulong lobbyId) { + LeaveLobby(); MelonLogger.Msg("Trying to join lobby " + lobbyId); _ = SteamMatchmaking.JoinLobbyAsync(lobbyId); } public override void LeaveLobby() { + if (!IsConnected()) return; _lobbyInstance.Leave(); + _lobbyInstance = new Lobby(); BoneSync.transport.CleanUp(); } diff --git a/BoneSync/Networking/Messages/ObjectSyncMessage.cs b/BoneSync/Networking/Messages/ObjectSyncMessage.cs index 4b0db66..66caf86 100644 --- a/BoneSync/Networking/Messages/ObjectSyncMessage.cs +++ b/BoneSync/Networking/Messages/ObjectSyncMessage.cs @@ -1,4 +1,5 @@ -using System; +using BoneSync.Sync; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -15,9 +16,11 @@ namespace BoneSync.Networking.Messages } public struct ObjectSyncMessageData { - public ulong objectId; + public ushort objectId; public ObjectSyncTransform[] objectSyncTransforms; } + + [PacketType(PacketType.ObjectSync), PacketReliability(PacketReliability.UnreliableNoDelay)] internal class ObjectSyncMessage : NetworkMessage { private ObjectSyncMessageData _objectSyncMessageData = new ObjectSyncMessageData(); @@ -26,7 +29,7 @@ namespace BoneSync.Networking.Messages public ObjectSyncMessage(ObjectSyncMessageData objectSyncMessageData) { _objectSyncMessageData = objectSyncMessageData; - byteEncoder.WriteUlong(_objectSyncMessageData.objectId); + byteEncoder.WriteUShort(_objectSyncMessageData.objectId); byte length = (byte)_objectSyncMessageData.objectSyncTransforms.Length; byteEncoder.WriteByte(length); for (int i = 0; i < length; i++) @@ -39,7 +42,7 @@ namespace BoneSync.Networking.Messages public ObjectSyncMessage(Packet packet) { byteEncoder.WriteBytes(packet.Data); - _objectSyncMessageData.objectId = byteEncoder.ReadUlong(); + _objectSyncMessageData.objectId = byteEncoder.ReadUShort(); byte length = byteEncoder.ReadByte(); _objectSyncMessageData.objectSyncTransforms = new ObjectSyncTransform[length]; for (int i = 0; i < length; i++) @@ -49,11 +52,9 @@ namespace BoneSync.Networking.Messages } } - - public override void Execute() { - throw new NotImplementedException(); + ObjectSync.OnObjectSyncMessage(this); } } } diff --git a/BoneSync/Networking/Messages/RegisterSyncableMessage.cs b/BoneSync/Networking/Messages/RegisterSyncableMessage.cs index 6b94170..8275f30 100644 --- a/BoneSync/Networking/Messages/RegisterSyncableMessage.cs +++ b/BoneSync/Networking/Messages/RegisterSyncableMessage.cs @@ -7,18 +7,30 @@ using System.Threading.Tasks; namespace BoneSync.Networking.Messages { + public enum RegisterSyncType + { + RegisterFromPath = 0, + RegisterAndSpawn = 1, + } public struct RegisterSyncableInfo { public string transformPath; public ushort id; + public ulong ownerId; + public RegisterSyncType type; } + + [PacketType(PacketType.RegisterSyncable)] internal class RegisterSyncableMessage : NetworkMessage { private RegisterSyncableInfo _info; + public RegisterSyncableInfo info => _info; public RegisterSyncableMessage(RegisterSyncableInfo info) { _info = info; + byteEncoder.WriteByte((byte)_info.type); byteEncoder.WriteString(_info.transformPath); + byteEncoder.WriteUlong(_info.ownerId); byteEncoder.WriteUShort(_info.id); } @@ -26,13 +38,15 @@ namespace BoneSync.Networking.Messages public RegisterSyncableMessage(Packet packet) { byteEncoder.WriteBytes(packet.Data); + _info.type = (RegisterSyncType)byteEncoder.ReadByte(); _info.transformPath = byteEncoder.ReadString(); + _info.ownerId = byteEncoder.ReadUlong(); _info.id = byteEncoder.ReadUShort(); } public override void Execute() { - + ObjectSync.OnRegisterSyncMessage(this); } } } diff --git a/BoneSync/Networking/NetworkMessage.cs b/BoneSync/Networking/NetworkMessage.cs index 92d69f9..c3534f7 100644 --- a/BoneSync/Networking/NetworkMessage.cs +++ b/BoneSync/Networking/NetworkMessage.cs @@ -21,6 +21,16 @@ namespace BoneSync.Networking public PacketType packetType { get; } } + public class PacketReliabilityAttribute : Attribute + { + public PacketReliabilityAttribute(PacketReliability reliability) + { + this.reliability = reliability; + } + + public PacketReliability reliability { get; } + } + public abstract class NetworkMessage { public ulong senderId @@ -33,6 +43,7 @@ namespace BoneSync.Networking internal static Dictionary PacketTypeMap = new Dictionary(); internal PacketType _packetType; + internal PacketReliability? _reliability; internal ByteEncoder byteEncoder = new ByteEncoder(); public byte[] GetBytes() => byteEncoder.ToArray(); @@ -53,6 +64,20 @@ namespace BoneSync.Networking return _packetType; } + public PacketReliability GetPacketReliability() + { + if (_reliability.HasValue) return _reliability.Value; + PacketReliabilityAttribute reliabilityAttribute = GetType().GetCustomAttribute(); + if (reliabilityAttribute == null) + { + _reliability = PacketReliability.Reliable; + return PacketReliability.Reliable; + } + + _reliability = reliabilityAttribute.reliability; + return _reliability.Value; + } + public static void RegisterPacketTypes() { if (PacketTypesRegistered) @@ -73,6 +98,7 @@ namespace BoneSync.Networking } public static NetworkMessage ParsePacket(Packet packet) { + MelonLogger.Msg("Received packet of type " + packet.Info.packetType + " from " + packet.Info.senderId + " Length: " + packet.Data.Length); // find a class that can parse this packet using Reflection // and return it if (!PacketTypeMap.ContainsKey(packet.Info.packetType)) @@ -92,7 +118,7 @@ namespace BoneSync.Networking public Packet GetPacket(int id, ulong senderId, ulong receiverId) { - PacketInfo packetInfo = new PacketInfo(id, senderId, receiverId, GetPacketType()); + PacketInfo packetInfo = new PacketInfo(id, senderId, receiverId, GetPacketType(), GetPacketReliability()); Packet packet = new Packet(packetInfo, GetBytes()); return packet; } @@ -102,6 +128,11 @@ namespace BoneSync.Networking } public void Send(ulong receiverId) { + if (BoneSync.lobby.IsConnected() == false) + { + 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); diff --git a/BoneSync/Networking/Packet.cs b/BoneSync/Networking/Packet.cs index 87b3946..244190d 100644 --- a/BoneSync/Networking/Packet.cs +++ b/BoneSync/Networking/Packet.cs @@ -1,4 +1,5 @@ using BoneSync.Networking.Messages; +using Facepunch.Steamworks; using System; using System.Collections.Generic; using System.Linq; @@ -8,20 +9,35 @@ using Xunit; namespace BoneSync.Networking { - + + public enum PacketReliability + { + Unreliable = 0, + UnreliableNoDelay = 1, + Reliable = 2, + ReliableWithBuffering = 3, + } public struct PacketInfo { public int id; public ulong senderId; public ulong receiverId; public PacketType packetType; + public PacketReliability reliability; - public PacketInfo(int id, ulong senderId, ulong receiverId, PacketType packetType) + public PacketInfo( + int id, + ulong senderId, + ulong receiverId, + PacketType packetType, + PacketReliability reliability = PacketReliability.Reliable + ) { this.id = id; this.senderId = senderId; this.receiverId = receiverId; this.packetType = packetType; + this.reliability = reliability; } } public class Packet @@ -46,19 +62,21 @@ namespace BoneSync.Networking ByteEncoder byteEncoder = new ByteEncoder(); byteEncoder.WriteBytes(bytes); - int packetType = byteEncoder.ReadInt(); + byte packetType = byteEncoder.ReadByte(); + byte reliability = byteEncoder.ReadByte(); int id = byteEncoder.ReadInt(); ulong senderId = byteEncoder.ReadUlong(); ulong receiverId = byteEncoder.ReadUlong(); - PacketInfo packetInfo = new PacketInfo(id, senderId, receiverId, (PacketType)packetType); + PacketInfo packetInfo = new PacketInfo(id, senderId, receiverId, (PacketType)packetType, (PacketReliability)reliability); return new Packet(packetInfo, byteEncoder.ToArray()); } public byte[] ToBytes() { ByteEncoder byteEncoder = new ByteEncoder(); - byteEncoder.WriteInt((int)_packetInfo.packetType); + byteEncoder.WriteByte((byte)_packetInfo.packetType); + byteEncoder.WriteByte((byte)_packetInfo.reliability); byteEncoder.WriteInt(_packetInfo.id); byteEncoder.WriteUlong(_packetInfo.senderId); byteEncoder.WriteUlong(_packetInfo.receiverId); diff --git a/BoneSync/Networking/PacketTypes.cs b/BoneSync/Networking/PacketTypes.cs index 48704bb..8f681f3 100644 --- a/BoneSync/Networking/PacketTypes.cs +++ b/BoneSync/Networking/PacketTypes.cs @@ -11,5 +11,7 @@ namespace BoneSync.Networking Unknown = 0, LobbyInfo = 1, PlayerSync = 2, + RegisterSyncable = 3, + ObjectSync = 4, } } diff --git a/BoneSync/Patching/InteractableHostPatches.cs b/BoneSync/Patching/InteractableHostPatches.cs index 8d99cd4..02130c8 100644 --- a/BoneSync/Patching/InteractableHostPatches.cs +++ b/BoneSync/Patching/InteractableHostPatches.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using BoneSync.Sync; using BoneSync.Sync.Components; using HarmonyLib; +using MelonLoader; using StressLevelZero.Interaction; using UnityEngine; @@ -24,8 +25,29 @@ namespace BoneSync.Patching [HarmonyPatch(nameof(InteractableHost.OnDestroy)), HarmonyPostfix] public static void OnDestroyPatch(InteractableHost __instance) { - MelonLoader.MelonLogger.Msg("InteractableHost destroyed: " + __instance.name); + MelonLogger.Msg("InteractableHost destroyed: " + __instance.name); } + + [HarmonyPatch(nameof(InteractableHost.AttachHand)), HarmonyPostfix] + public static void AttachHandPatch(InteractableHost __instance, Hand hand) + { + MelonLogger.Msg("InteractableHost attached to hand: " + __instance.name + " Hand: " + hand.name); + Syncable syncable = ObjectSync.MakeOrGetSyncable(__instance); + if (syncable == null) + { + MelonLogger.Error("Syncable is null for " + __instance.name); + return; + } + syncable.RegisterSyncable(); + + } + + /*[HarmonyPatch(nameof(InteractableHost.AddForcePullGrip)), HarmonyPostfix] + public static void AddForcePullGripPatch(InteractableHost __instance, ForcePullGrip grip) + { + MelonLoader.MelonLogger.Msg("AddForcePullGrip to hand: " + __instance.name + " Hand: " + grip.name); + }*/ + } [HarmonyPatch(typeof(InteractableHostManager))] diff --git a/BoneSync/Player/PlayerRig.cs b/BoneSync/Player/PlayerRig.cs index cc54b6f..fc430ab 100644 --- a/BoneSync/Player/PlayerRig.cs +++ b/BoneSync/Player/PlayerRig.cs @@ -17,9 +17,8 @@ namespace BoneSync.Player { internal class PlayerRig { - public const string RIGMANAGER_SCENE_NAME = "[RigManager (Default Brett)]"; + //public const string RIGMANAGER_SCENE_NAME = "[RigManager (Default Brett)]"; - private static GameObject _rigPrefabCache = null; private static List _playerRigs = new List(); private GameObject playerRig; @@ -29,100 +28,18 @@ namespace BoneSync.Player private Animator repAnimator; - public void UpdatePlayerSync(PlayerSyncInfo playerSyncInfo) { - playerRig.transform.ApplySimpleTransform(playerSyncInfo.headPos); + //playerRig.transform.ApplySimpleTransform(playerSyncInfo.headPos); } - public static void Tick() + public PlayerRig() { - TryRegisterRigPrefab(); - foreach (PlayerRig playerRig in _playerRigs) - { - try - { - playerRig.UpdateRig(); - } catch (Exception e) - { - MelonLogger.Error(e.Message); - //MelonLogger.Error("Failed to update player rig"); - } - - } - } - public static void TryRegisterRigPrefab() - { - return; // disable this for now - if (_rigPrefabCache) return; - GetPlayerRigPrefab(); - } - public static GameObject GetPlayerRigPrefab() - { - if (_rigPrefabCache == null) - { - // find the rig game object in the scene - GameObject playerRig = GameObject.Find(RIGMANAGER_SCENE_NAME); - if (playerRig == null) - { - MelonLogger.Error("Failed to find RigManager scene object"); - return null; - } - // create a clone of the rig - GameObject playerRep = GameObject.Instantiate(playerRig); - playerRep.gameObject.SetActive(false); - playerRep.name = "[RigManager (Networked)]"; - RigManager repRigManager = playerRep.GetComponent(); - repRigManager.oculusControllerRig.gameObject.SetActive(false); - repRigManager.steamControllerRig.gameObject.SetActive(false); - repRigManager.uiRig.gameObject.SetActive(false); - repRigManager.enabled = false; - - - _rigPrefabCache = playerRep; - MelonLogger.Msg("Player rig prefab created"); - } - return _rigPrefabCache; - } - - public static PlayerRig InstantiatePlayerRigPrefab() - { - GameObject prefab = GetPlayerRigPrefab(); - if (prefab == null) - { - return null; - } - GameObject go = GameObject.Instantiate(prefab); - go.SetActive(true); - PlayerRig playerRig = new PlayerRig(go); - - return playerRig; - - } - - private void UpdateRig() - { - Vector3 velocity = Vector3.zero; - Vector3 acceleration = Vector3.zero; - //SkeletonRig skeletonRig = rigManager.gameWorldSkeletonRig; - //skeletonRig.OnLateUpdate(); - rigManager.ControllerRig.gameObject.SetActive(false); - characterAnimationManager.OnLateUpdate(); - body.FullBodyUpdate(velocity, acceleration); - body.ArtToBlender.UpdateBlender(); - repAnimator.Update(Time.deltaTime); - } - private PlayerRig(GameObject go) - { - playerRig = go; - rigManager = playerRig.GetComponent(); - rigManager.enabled = true; - - UpdateRig(); _playerRigs.Add(this); } + public void Destroy() { _playerRigs.Remove(this); diff --git a/BoneSync/Sync/Components/Syncable.cs b/BoneSync/Sync/Components/Syncable.cs index fe8575c..ec728dd 100644 --- a/BoneSync/Sync/Components/Syncable.cs +++ b/BoneSync/Sync/Components/Syncable.cs @@ -11,6 +11,7 @@ using UnityEngine.Experimental.PlayerLoop; using BoneSync.Networking.Messages; using BoneSync.Networking; using StressLevelZero.Data; +using System.Collections; namespace BoneSync.Sync.Components @@ -46,22 +47,95 @@ namespace BoneSync.Sync.Components [RegisterTypeInIl2Cpp] public class Syncable : MonoBehaviour { - - public Syncable(IntPtr intPtr) : base(intPtr) { } + public const int SYNC_FPS = 20; + public static List syncablesCache = new List(); + public Syncable(IntPtr intPtr) : base(intPtr) { + syncablesCache.Add(this); + } + + private bool _syncCoroutineRunning; + + public ulong _ownerId + { + private set; + get; + } private ushort _syncId; - public bool Registered => _syncId != 0; - private ulong _lastSyncTime; - private ulong _ownerId; + private bool _attemptedRegister; + + public bool Registered => _syncId != 0; public bool isStale => Time.time - _lastSyncTime > 5f; + public bool isOwner => _ownerId == BoneSync.lobby.GetLocalId(); + + public ushort GetSyncId() => _syncId; + public void SetSyncId(ushort id) + { + + _syncId = id; + ObjectSyncCache.UpdateSyncId(this); + } public InteractableHost interactableHost; public InteractableHostManager interactableManager; public Poolee poolee; + private Rigidbody[] rigidbodies; private Transform[] transforms; + + private void SetKinematic(bool kinematic) + { + foreach (Rigidbody rb in rigidbodies) + { + rb.isKinematic = kinematic; + } + } + + public ObjectSyncTransform[] GetObjectSyncTransforms() + { + ObjectSyncTransform[] objectSyncTransforms = new ObjectSyncTransform[transforms.Length]; + for (int i = 0; i < transforms.Length; i++) + { + objectSyncTransforms[i] = new ObjectSyncTransform() + { + transform = new SimpleTransform(transforms[i]), + velocity = Vector3.zero + }; + } + return objectSyncTransforms; + } + + public void ApplyObjectSyncTransforms(ObjectSyncTransform[] objectSyncTransforms) + { + if (objectSyncTransforms.Length != transforms.Length) + { + MelonLogger.Warning("ObjectSyncTransforms length mismatch: " + objectSyncTransforms.Length + " != " + transforms.Length); + return; + } + for (int i = 0; i < objectSyncTransforms.Length; i++) + { + ObjectSyncTransform objectSyncTransform = objectSyncTransforms[i]; + transforms[i].ApplySimpleTransform(objectSyncTransform.transform); + } + } + + public async Task SyncCoroutineAsync() + { + MelonLogger.Msg("Running sync coroutine for: " + gameObject.name); + if (_syncCoroutineRunning) return; + _syncCoroutineRunning = true; + while (isOwner) + { + MelonLogger.Msg("Sending object sync message for: " + gameObject.name); + ObjectSync.SendObjectSyncMessage(this); + await Task.Delay( GetSyncId() == 0 ? 1000 : 1000 / SYNC_FPS); + } + _syncCoroutineRunning = false; + return; + } + public void OnEnable() { FindComponents(); @@ -88,22 +162,26 @@ namespace BoneSync.Sync.Components { if (poolee && poolee.pool) { - return null; + return ""; } - if (interactableHost) + if (interactableHost || interactableManager) { - // get full path from root - return interactableHost.transform.GetPath(); + return transform.GetPath(); } - return null; + return ""; } public void FindComponents() { + ObjectSyncCache.RemoveSyncable(this); + interactableManager = GetComponent(); interactableHost = GetComponent(); poolee = GetComponent(); + rigidbodies = GetComponentsInChildren(); UpdateTransformList(); + + ObjectSyncCache.AddSyncable(this); } public bool ShouldSync() @@ -123,39 +201,48 @@ namespace BoneSync.Sync.Components public void DiscardSyncable() { + ObjectSyncCache.RemoveSyncable(this); Destroy(this); } public void OnDisable() { - DiscardSyncable(); - } - - public ObjectSyncMessageData GetObjectSyncData() - { - ObjectSyncMessageData data = new ObjectSyncMessageData() + if (!Registered) { - objectId = _syncId, - objectSyncTransforms = new ObjectSyncTransform[transforms.Length], - }; - - for (int i = 0; i < transforms.Length; i++) - { - data.objectSyncTransforms[i] = new ObjectSyncTransform() - { - transform = new SimpleTransform(transforms[i]), - velocity = Vector3.zero - }; + DiscardSyncable(); + return; } - return data; + + MelonLogger.Warning("Registered Syncable disabled: " + transform.GetPath()); } + public void SetOwner(ulong ownerId) + { + _ownerId = ownerId; + MelonLogger.Msg("Set owner for " + gameObject.name + " to " + ownerId); + _ = SyncCoroutineAsync(); + UpdateKinematic(); + } + + private void UpdateKinematic() + { + SetKinematic(_ownerId != BoneSync.lobby.GetLocalId() && Registered); + } + + private void _SendRegisterSync() + { + MelonLogger.Msg("Registering syncable object: " + gameObject.name); + SetOwner(BoneSync.lobby.GetLocalId()); + SetSyncId(ObjectSync.SendRegisterSyncableMessage(this)); + } public void RegisterSyncable() { + if (!BoneSync.lobby.IsConnected()) return; + if (_attemptedRegister) return; if (Registered) return; if (!ShouldSync()) return; - MelonLogger.Msg("Registering syncable object: " + gameObject.name); - ObjectSync.RegisterSyncable(this); + _attemptedRegister = true; + _SendRegisterSync(); } } diff --git a/BoneSync/Sync/ObjectSync.cs b/BoneSync/Sync/ObjectSync.cs index 45689fa..0d72c10 100644 --- a/BoneSync/Sync/ObjectSync.cs +++ b/BoneSync/Sync/ObjectSync.cs @@ -1,5 +1,8 @@ -using BoneSync.Sync.Components; +using BoneSync.Networking.Messages; +using BoneSync.Sync.Components; +using MelonLoader; using StressLevelZero.Interaction; +using StressLevelZero.Pool; using System; using System.Collections.Generic; using System.Linq; @@ -9,12 +12,206 @@ using UnityEngine; namespace BoneSync.Sync { + + public static class ObjectSyncCache + { + private static Dictionary _pathToSyncable = new Dictionary(); + private static Dictionary _idToSyncable = new Dictionary(); + private static Dictionary _pooleeToSyncable = new Dictionary(); + private static Dictionary _interactableHostToSyncable = new Dictionary(); + private static Dictionary _interactableHostManagerToSyncable = new Dictionary(); + + + public static void AddSyncable(Syncable syncable) + { + string path = syncable.transform.GetPath(); + if (path != null && path != "") + { + _pathToSyncable[path] = syncable; + } + if (syncable.GetSyncId() != 0) + { + _idToSyncable[syncable.GetSyncId()] = syncable; + } + if (syncable.interactableHost) + { + _interactableHostToSyncable[syncable.interactableHost] = syncable; + } + if (syncable.interactableManager) + { + _interactableHostManagerToSyncable[syncable.interactableManager] = syncable; + } + if (syncable.poolee) + { + _pooleeToSyncable[syncable.poolee] = syncable; + } + } + + public static void RemoveSyncable(Syncable syncable) + { + if (syncable.transform) + { + _pathToSyncable.Remove(syncable.transform.GetPath()); + } + if (syncable.GetSyncId() != 0) + { + _idToSyncable.Remove(syncable.GetSyncId()); + } + if (syncable.interactableHost) + { + _interactableHostToSyncable.Remove(syncable.interactableHost); + } + if (syncable.interactableManager) + { + _interactableHostManagerToSyncable.Remove(syncable.interactableManager); + } + if (syncable.poolee) + { + _pooleeToSyncable.Remove(syncable.poolee); + } + } + + public static void UpdateSyncId(Syncable syncable) + { + // remove other enties where value is the same + foreach (KeyValuePair entry in _idToSyncable) + { + if (entry.Value == syncable) + { + _idToSyncable.Remove(entry.Key); + } + } + ushort id = syncable.GetSyncId(); + if (_idToSyncable.ContainsKey(id)) + { + _idToSyncable.Remove(id); + } + _idToSyncable[id] = syncable; + } + + public static Syncable GetSyncable(string path) + { + if (_pathToSyncable.ContainsKey(path)) + { + return _pathToSyncable[path]; + } + return null; + } + + public static Syncable GetSyncable(ushort id) + { + if (_idToSyncable.ContainsKey(id)) + { + return _idToSyncable[id]; + } + return null; + } + + public static Syncable GetSyncable(Poolee poolee) + { + if (_pooleeToSyncable.ContainsKey(poolee)) + { + return _pooleeToSyncable[poolee]; + } + return null; + } + + public static Syncable GetSyncable(InteractableHost interactableHost) + { + if (_interactableHostToSyncable.ContainsKey(interactableHost)) + { + return _interactableHostToSyncable[interactableHost]; + } + return null; + } + + public static Syncable GetSyncable(InteractableHostManager interactableHostManager) + { + if (_interactableHostManagerToSyncable.ContainsKey(interactableHostManager)) + { + return _interactableHostManagerToSyncable[interactableHostManager]; + } + return null; + } + + public static void DISCARD_ALL_SYNCABLES() { + foreach (Syncable syncable in Syncable.syncablesCache) + { + syncable.DiscardSyncable(); + } + } + } internal class ObjectSync { - - public static void RegisterSyncable(Syncable syncable) + private static ushort _nextSyncableId = 1; + public static ushort GetNextId() { + return _nextSyncableId++; + } + public static RegisterSyncableInfo? GetRegisterInfo(Syncable syncable) + { + RegisterSyncableInfo? info = null; + string path = syncable.GetSyncableWorldPath(); + if (path.Length > 0) + { + info = new RegisterSyncableInfo() + { + type = RegisterSyncType.RegisterFromPath, + transformPath = path, + ownerId = syncable._ownerId, + }; + } + else if (syncable.poolee) + { + info = new RegisterSyncableInfo() + { + type = RegisterSyncType.RegisterAndSpawn, + transformPath = syncable.poolee.transform.GetPath(), + }; + } + return info; + } + + public static ushort SendRegisterSyncableMessage(Syncable syncable) + { + RegisterSyncableInfo? infoNullable = GetRegisterInfo(syncable); + + if (infoNullable == null) + { + MelonLogger.Msg("No valid registeration method for syncable"); + return 0; + } + + RegisterSyncableInfo info = infoNullable.Value; + + RegisterSyncableMessage message = new RegisterSyncableMessage(info); + if (BoneSync.lobby.IsHost) + { + info.id = GetNextId(); + message.Broadcast(); + } + else + { + info.id = 0; + message.Send(BoneSync.lobby.GetHostId()); + } + return info.id; + } + + public static void SendObjectSyncMessage(Syncable syncable) + { + MelonLogger.Msg("Sending object sync message for: " + syncable.transform.name); + ObjectSyncTransform[] objectSyncTransforms = syncable.GetObjectSyncTransforms(); + + ObjectSyncMessageData data = new ObjectSyncMessageData() + { + objectId = syncable.GetSyncId(), + objectSyncTransforms = objectSyncTransforms, + }; + + ObjectSyncMessage message = new ObjectSyncMessage(data); + message.Broadcast(); } private static Syncable _MakeOrGetSyncable(GameObject gameObject, bool deleteSubSyncabled = true) { @@ -34,6 +231,10 @@ namespace BoneSync.Sync { syncable = gameObject.AddComponent(); } + else + { + syncable.FindComponents(); + } return syncable; } @@ -47,5 +248,41 @@ namespace BoneSync.Sync { return _MakeOrGetSyncable(interactableHostManager.gameObject); } + + public static void OnRegisterSyncMessage(RegisterSyncableMessage registerSyncableMessage) + { + Syncable syncable = null; + RegisterSyncableInfo info = registerSyncableMessage.info; + if (BoneSync.lobby.IsHost) + { + info.id = GetNextId(); + new RegisterSyncableMessage(info).Broadcast(); + } + + 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: + break; + } + + syncable.SetSyncId(info.id); + syncable.SetOwner(info.ownerId); + } + + public static void OnObjectSyncMessage(ObjectSyncMessage objectSyncMessage) + { + ObjectSyncMessageData data = objectSyncMessage.objectSyncMessageData; + Syncable syncable = ObjectSyncCache.GetSyncable(data.objectId); + if (syncable == null) + { + MelonLogger.Msg("Syncable not found for id: " + data.objectId); + return; + } + syncable.ApplyObjectSyncTransforms(data.objectSyncTransforms); + } } } diff --git a/BoneSync/Sync/PlayerSync.cs b/BoneSync/Sync/PlayerSync.cs index 2af3204..12cea52 100644 --- a/BoneSync/Sync/PlayerSync.cs +++ b/BoneSync/Sync/PlayerSync.cs @@ -20,7 +20,7 @@ namespace BoneSync.Sync { if (!_playerRigMap.ContainsKey(playerId)) { - PlayerRig playerRig = PlayerRig.InstantiatePlayerRigPrefab(); + PlayerRig playerRig = new PlayerRig(); _playerRigMap.Add(playerId, playerRig); } @@ -38,12 +38,8 @@ namespace BoneSync.Sync public static void SyncPlayer() { - if (!_localPlayerRig) - { - _localPlayerRig = GameObject.Find(PlayerRig.RIGMANAGER_SCENE_NAME); - } PlayerSyncInfo playerSyncInfo = new PlayerSyncInfo(); - playerSyncInfo.headPos = new SimpleTransform(_localPlayerRig.transform); + playerSyncInfo.headPos = new SimpleTransform(); playerSyncInfo.leftHandPos = new SimpleTransform(); playerSyncInfo.rightHandPos = new SimpleTransform();