From 3fc3d82c52dcbf4202d460571de4685d0e2c9a63 Mon Sep 17 00:00:00 2001 From: Anton Franzluebbers Date: Thu, 13 Jan 2022 01:09:33 -0500 Subject: [PATCH] fixed some more errors related to not cleaning up properly when switching rooms, catch more errors to prevent everything from breaking at once if the user makes an error, added NetworkSerializedObjectStream to avoid needing to initialize binary readers, updated example to include a shared textbox and leave room button --- Runtime/NetworkObject.cs | 21 ++++++++- Runtime/Util/NetworkSerializedObject.cs | 2 +- Runtime/Util/NetworkSerializedObjectStream.cs | 47 +++++++++++++++++++ .../NetworkSerializedObjectStream.cs.meta | 3 ++ Runtime/VelNetManager.cs | 35 ++++++++++---- package.json | 2 +- 6 files changed, 97 insertions(+), 13 deletions(-) create mode 100644 Runtime/Util/NetworkSerializedObjectStream.cs create mode 100644 Runtime/Util/NetworkSerializedObjectStream.cs.meta diff --git a/Runtime/NetworkObject.cs b/Runtime/NetworkObject.cs index aa39b78..b08e041 100644 --- a/Runtime/NetworkObject.cs +++ b/Runtime/NetworkObject.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; #if UNITY_EDITOR @@ -42,6 +43,12 @@ namespace VelNet } // send the message and an identifier for which component it belongs to + if (!syncedComponents.Contains(component)) + { + Debug.LogError("Can't send message if this component is not registered with the NetworkObject.", this); + return; + } + int index = syncedComponents.IndexOf(component); owner.SendMessage(this, index.ToString(), message, reliable); } @@ -62,7 +69,19 @@ namespace VelNet public void ReceiveBytes(string identifier, byte[] message) { // send the message to the right component - syncedComponents[int.Parse(identifier)].ReceiveBytes(message); + try + { + syncedComponents[int.Parse(identifier)].ReceiveBytes(message); + } + catch (Exception e) + { + Debug.LogError($"Error in handling message:\n{e}", this); + } + } + + public void TakeOwnership() + { + VelNetManager.TakeOwnership(networkId); } } diff --git a/Runtime/Util/NetworkSerializedObject.cs b/Runtime/Util/NetworkSerializedObject.cs index 13037d1..0569eed 100644 --- a/Runtime/Util/NetworkSerializedObject.cs +++ b/Runtime/Util/NetworkSerializedObject.cs @@ -9,7 +9,7 @@ namespace VelNet [Tooltip("Send rate of this object. This caps out at the framerate of the game.")] public float serializationRateHz = 30; - private void Awake() + protected virtual void Awake() { StartCoroutine(SendMessageUpdate()); } diff --git a/Runtime/Util/NetworkSerializedObjectStream.cs b/Runtime/Util/NetworkSerializedObjectStream.cs new file mode 100644 index 0000000..a6929f8 --- /dev/null +++ b/Runtime/Util/NetworkSerializedObjectStream.cs @@ -0,0 +1,47 @@ +using System.Collections; +using System.IO; +using UnityEngine; +using UnityEngine.Serialization; + +namespace VelNet +{ + public abstract class NetworkSerializedObjectStream : NetworkComponent + { + [Tooltip("Send rate of this object. This caps out at the framerate of the game.")] + public float serializationRateHz = 30; + + protected virtual void Awake() + { + StartCoroutine(SendMessageUpdate()); + } + + private IEnumerator SendMessageUpdate() + { + while (true) + { + if (IsMine) + { + using MemoryStream mem = new MemoryStream(); + using BinaryWriter writer = new BinaryWriter(mem); + SendState(writer); + SendBytes(mem.ToArray()); + } + + yield return new WaitForSeconds(1f / serializationRateHz); + } + // ReSharper disable once IteratorNeverReturns + } + + public override void ReceiveBytes(byte[] message) + { + using MemoryStream mem = new MemoryStream(message); + using BinaryReader reader = new BinaryReader(mem); + + ReceiveState(reader); + } + + protected abstract void SendState(BinaryWriter binaryWriter); + + protected abstract void ReceiveState(BinaryReader binaryReader); + } +} \ No newline at end of file diff --git a/Runtime/Util/NetworkSerializedObjectStream.cs.meta b/Runtime/Util/NetworkSerializedObjectStream.cs.meta new file mode 100644 index 0000000..6f4475e --- /dev/null +++ b/Runtime/Util/NetworkSerializedObjectStream.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7da4222cdb03a3e43aceb43ef1e28f7e +timeCreated: 1641514434 \ No newline at end of file diff --git a/Runtime/VelNetManager.cs b/Runtime/VelNetManager.cs index 7fe36d9..71ea086 100644 --- a/Runtime/VelNetManager.cs +++ b/Runtime/VelNetManager.cs @@ -208,6 +208,9 @@ namespace VelNet .Where(kvp => kvp.Value == null || !kvp.Value.isSceneObject) .Select(o => o.Key) .ToList().ForEach(NetworkDestroy); + + // then remove references to the ones that are left + objects.Clear(); // empty all the groups foreach (string group in instance.groups.Keys) @@ -217,7 +220,6 @@ namespace VelNet instance.groups.Clear(); - Debug.Log("Left VelNet Room: " + oldRoom); try { OnLeftRoom?.Invoke(oldRoom); @@ -328,13 +330,9 @@ namespace VelNet masterPlayer.SetAsMasterPlayer(); // master player should take over any objects that do not have an owner - foreach (KeyValuePair kvp in objects) { - if (kvp.Value.owner == null) - { - kvp.Value.owner = masterPlayer; - } + kvp.Value.owner ??= masterPlayer; } break; @@ -659,24 +657,32 @@ namespace VelNet } - public static void InstantiateNetworkObject(string prefabName) + public static NetworkObject InstantiateNetworkObject(string prefabName) { VelNetPlayer localPlayer = LocalPlayer; NetworkObject prefab = instance.prefabs.Find(p => p.name == prefabName); if (prefab == null) { Debug.LogError("Couldn't find a prefab with that name: " + prefabName); - return; + return null; } + string networkId = localPlayer.userid + "-" + localPlayer.lastObjectId++; + if (instance.objects.ContainsKey(networkId)) + { + Debug.LogError("Can't instantiate object. Obj with that network ID was already instantiated.", instance.objects[networkId]); + return null; + } NetworkObject newObject = Instantiate(prefab); - newObject.networkId = localPlayer.userid + "-" + localPlayer.lastObjectId++; + newObject.networkId = networkId; newObject.prefabName = prefabName; newObject.owner = localPlayer; instance.objects.Add(newObject.networkId, newObject); // only sent to others, as I already instantiated this. Nice that it happens immediately. SendTo(MessageType.OTHERS, "7," + newObject.networkId + "," + prefabName); + + return newObject; } public static void SomebodyInstantiatedNetworkObject(string networkId, string prefabName, VelNetPlayer owner) @@ -690,11 +696,20 @@ namespace VelNet instance.objects.Add(newObject.networkId, newObject); } + public static void NetworkDestroy(NetworkObject obj) + { + NetworkDestroy(obj.networkId); + } + public static void NetworkDestroy(string networkId) { if (!instance.objects.ContainsKey(networkId)) return; NetworkObject obj = instance.objects[networkId]; - if (obj == null) return; + if (obj == null) + { + instance.objects.Remove(networkId); + return; + } if (obj.isSceneObject) { instance.deletedSceneObjects.Add(networkId); diff --git a/package.json b/package.json index 4f2b772..b846be2 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "edu.uga.engr.vel.velnet", "displayName": "VelNet", - "version": "1.0.5", + "version": "1.0.6", "unity": "2019.1", "description": "A custom networking library for Unity.", "keywords": [