From f429bfdcf320ae341f92109de07d62f4433ae844 Mon Sep 17 00:00:00 2001 From: Anton Franzluebbers Date: Tue, 11 Jan 2022 22:42:57 -0500 Subject: [PATCH 1/2] added mouse dragging script for testing, move networkdestroy and takeownership to static methods in the manager so not everybody needs references to the player, added a custom inspector to NetworkObject for showing owner and a button for automatically finding and assigning networkcomponents, better interpolation for synctransform based on serialization rate, synctransform can send local transforms, find new scene objects on scene load --- .../VelNet/1.0.4/Example/MouseDragger.cs | 44 +++++++++++ .../VelNet/1.0.4/Example/MouseDragger.cs.meta | 11 +++ .../VelNet/1.0.4/Example/PlayerController.cs | 4 +- .../VelNet/1.0.4/Example/PlayerPrefab.prefab | 4 +- .../Samples/VelNet/1.0.4/Example/test.unity | 39 +++++++--- .../VelNetUnity/Runtime/NetworkObject.cs | 48 +++++++++++- .../Runtime/Util/NetworkSerializedObject.cs | 8 +- .../VelNetUnity/Runtime/Util/SyncTransform.cs | 77 +++++++++++++++++-- .../VelNetUnity/Runtime/VelNetManager.cs | 50 +++++++++--- .../VelNetUnity/Runtime/VelNetPlayer.cs | 26 +++---- 10 files changed, 260 insertions(+), 51 deletions(-) create mode 100644 TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/MouseDragger.cs create mode 100644 TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/MouseDragger.cs.meta diff --git a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/MouseDragger.cs b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/MouseDragger.cs new file mode 100644 index 0000000..6802b65 --- /dev/null +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/MouseDragger.cs @@ -0,0 +1,44 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using VelNet; + +public class MouseDragger : MonoBehaviour +{ + private Camera cam; + public string[] draggableTags = { "draggable" }; + private NetworkObject draggingObject; + + private void Start() + { + cam = Camera.main; + } + + private void Update() + { + if (Input.GetMouseButtonDown(0)) + { + if (Physics.Raycast(cam.ScreenPointToRay(Input.mousePosition), out RaycastHit hit)) + { + foreach (string draggableTag in draggableTags) + { + if (!hit.transform.CompareTag(draggableTag) && !hit.transform.parent?.CompareTag(draggableTag) == true) continue; + NetworkObject netObj = hit.transform.GetComponent(); + netObj ??= hit.transform.GetComponentInParent(); + if (netObj == null) break; + VelNetManager.TakeOwnership(netObj.networkId); + draggingObject = netObj; + break; + } + } + } + else if (Input.GetMouseButtonUp(0)) + { + draggingObject = null; + } + else if (Input.GetMouseButton(0) && draggingObject != null) + { + draggingObject.transform.position = cam.ScreenPointToRay(Input.mousePosition).direction * Vector3.Distance(draggingObject.transform.position, cam.transform.position) + cam.transform.position; + } + } +} \ No newline at end of file diff --git a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/MouseDragger.cs.meta b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/MouseDragger.cs.meta new file mode 100644 index 0000000..dcc6a81 --- /dev/null +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/MouseDragger.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c9d312e1088769143a72b0c13d5aee32 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/PlayerController.cs b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/PlayerController.cs index b33a15f..3420680 100644 --- a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/PlayerController.cs +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/PlayerController.cs @@ -36,7 +36,7 @@ namespace VelNet { foreach (KeyValuePair kvp in VelNetManager.instance.objects) { - Owner.TakeOwnership(kvp.Key); + VelNetManager.TakeOwnership(kvp.Key); } } @@ -47,7 +47,7 @@ namespace VelNet // don't destroy player objects if (!kvp.Value.ownershipLocked) { - Owner.NetworkDestroy(kvp.Key); + VelNetManager.NetworkDestroy(kvp.Key); } } } diff --git a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/PlayerPrefab.prefab b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/PlayerPrefab.prefab index a82c290..8c7fb3c 100644 --- a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/PlayerPrefab.prefab +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/PlayerPrefab.prefab @@ -32,7 +32,7 @@ Transform: m_GameObject: {fileID: 6139051692386484099} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 0.1, y: 0.1, z: 0.1} + m_LocalScale: {x: 0.5, y: 0.5, z: 0.5} m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 @@ -117,8 +117,8 @@ MonoBehaviour: isSceneObject: 0 syncedComponents: - {fileID: -4404668399269848200} - - {fileID: 1181612843795795320} - {fileID: 7564913803199044469} + - {fileID: 1181612843795795320} --- !u!114 &-4404668399269848200 MonoBehaviour: m_ObjectHideFlags: 0 diff --git a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test.unity b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test.unity index 52c9e3e..5c5a1e3 100644 --- a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test.unity +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test.unity @@ -38,7 +38,7 @@ RenderSettings: m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} - m_IndirectSpecularColor: {r: 0.44657874, g: 0.49641275, b: 0.5748172, a: 1} + m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: @@ -148,7 +148,7 @@ MonoBehaviour: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 2034436} - m_Enabled: 1 + m_Enabled: 0 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} m_Name: @@ -469,7 +469,7 @@ MonoBehaviour: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 162005663} - m_Enabled: 1 + m_Enabled: 0 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} m_Name: @@ -851,7 +851,7 @@ MonoBehaviour: m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} m_CustomCaretColor: 0 m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} - m_Text: + m_Text: TEST USER m_CaretBlinkRate: 0.85 m_CaretWidth: 1 m_ReadOnly: 0 @@ -1108,7 +1108,7 @@ MonoBehaviour: m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} m_CustomCaretColor: 0 m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} - m_Text: + m_Text: 0 m_CaretBlinkRate: 0.85 m_CaretWidth: 1 m_ReadOnly: 0 @@ -1241,6 +1241,7 @@ GameObject: - component: {fileID: 903768657} - component: {fileID: 903768656} - component: {fileID: 903768655} + - component: {fileID: 903768654} m_Layer: 0 m_Name: Main Camera m_TagString: MainCamera @@ -1248,6 +1249,20 @@ GameObject: m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 +--- !u!114 &903768654 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 903768653} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c9d312e1088769143a72b0c13d5aee32, type: 3} + m_Name: + m_EditorClassIdentifier: + draggableTags: + - TestSphere --- !u!81 &903768655 AudioListener: m_ObjectHideFlags: 0 @@ -1834,7 +1849,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 03a4d4e1a7fd74c7ab2eccca4ce168db, type: 3} m_Name: m_EditorClassIdentifier: - host: 129.159.107.234 + host: velnet.ugavel.com port: 3290 udpConnected: 0 userid: -1 @@ -2323,8 +2338,8 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: _lastPrefabError: - _isMuted: 0 - _isDeafened: 0 + _isMuted: 1 + _isDeafened: 1 _oneMinusBaseRemoteVoiceVolume: 0 _playbackPrefab: {fileID: 0} _playbackPrefab2: {fileID: 1041743830464418, guid: 7b8de751a39894b0c8e1cfc9ef961a5b, type: 3} @@ -2454,7 +2469,7 @@ MonoBehaviour: m_HorizontalOverflow: 1 m_VerticalOverflow: 0 m_LineSpacing: 1 - m_Text: + m_Text: 0 --- !u!222 &1484033258 CanvasRenderer: m_ObjectHideFlags: 0 @@ -2616,7 +2631,7 @@ MonoBehaviour: m_HorizontalOverflow: 1 m_VerticalOverflow: 0 m_LineSpacing: 1 - m_Text: + m_Text: TEST USER --- !u!1 &1679565283 GameObject: m_ObjectHideFlags: 0 @@ -3392,6 +3407,10 @@ PrefabInstance: m_Modification: m_TransformParent: {fileID: 0} m_Modifications: + - target: {fileID: 3951900052977689805, guid: 6e4a023f70e01405e8b249a4488fe319, type: 3} + propertyPath: isSceneObject + value: 1 + objectReference: {fileID: 0} - target: {fileID: 8565720275311462453, guid: 6e4a023f70e01405e8b249a4488fe319, type: 3} propertyPath: m_Name value: TestNetworkedGameObject diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/NetworkObject.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/NetworkObject.cs index 15c4de1..aa39b78 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/NetworkObject.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/NetworkObject.cs @@ -1,5 +1,8 @@ using System.Collections.Generic; using System.Linq; +#if UNITY_EDITOR +using UnityEditor; +#endif using UnityEngine; namespace VelNet @@ -9,10 +12,11 @@ namespace VelNet /// public class NetworkObject : MonoBehaviour { - [Header("NetworkObject properties")] - public VelNetPlayer owner; + [Header("NetworkObject properties")] public VelNetPlayer owner; + [Tooltip("Whether this object's ownership is transferrable. Should be true for player objects.")] public bool ownershipLocked; + public bool IsMine => owner != null && owner.isLocal; /// @@ -61,4 +65,44 @@ namespace VelNet syncedComponents[int.Parse(identifier)].ReceiveBytes(message); } } + +#if UNITY_EDITOR + /// + /// Sets up the interface for the CopyTransform script. + /// + [CustomEditor(typeof(NetworkObject))] + public class NetworkObjectEditor : Editor + { + public override void OnInspectorGUI() + { + NetworkObject t = target as NetworkObject; + + EditorGUILayout.Space(); + + if (t == null) return; + + EditorGUILayout.HelpBox("Network Object. One per prefab pls.\nAssign components to the list to be synced.", MessageType.Info); + + EditorGUI.BeginDisabledGroup(true); + EditorGUILayout.Toggle("IsMine", t.IsMine); + EditorGUILayout.TextField("Owner ID", t.owner?.userid.ToString() ?? "No owner"); + EditorGUI.EndDisabledGroup(); + EditorGUILayout.Space(); + + if (GUILayout.Button("Find Network Components and add backreferences.")) + { + NetworkComponent[] comps = t.GetComponents(); + t.syncedComponents = comps.ToList(); + foreach (NetworkComponent c in comps) + { + c.networkObject = t; + } + } + + EditorGUILayout.Space(); + + DrawDefaultInspector(); + } + } +#endif } \ No newline at end of file diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObject.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObject.cs index ef1aa14..13037d1 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObject.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObject.cs @@ -6,10 +6,10 @@ namespace VelNet { public abstract class NetworkSerializedObject : NetworkComponent { - [FormerlySerializedAs("updateRateHz")] [Tooltip("Send rate of this object")] + [Tooltip("Send rate of this object. This caps out at the framerate of the game.")] public float serializationRateHz = 30; - private void Start() + private void Awake() { StartCoroutine(SendMessageUpdate()); } @@ -23,11 +23,11 @@ namespace VelNet SendBytes(SendState()); } - yield return new WaitForSeconds(1 / serializationRateHz); + yield return new WaitForSeconds(1f / serializationRateHz); } // ReSharper disable once IteratorNeverReturns } - + public override void ReceiveBytes(byte[] message) { ReceiveState(message); diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/SyncTransform.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/SyncTransform.cs index 231a0eb..162a9c9 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/SyncTransform.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/SyncTransform.cs @@ -10,21 +10,47 @@ namespace VelNet [AddComponentMenu("VelNet/VelNet Sync Transform")] public class SyncTransform : NetworkSerializedObject { - public Vector3 targetPosition; - public Quaternion targetRotation; - public float smoothness = .1f; + public bool useLocalTransform; + private Vector3 targetPosition; + private Quaternion targetRotation; + private float distanceAtReceiveTime; + private float angleAtReceiveTime; + + private void Start() + { + if (useLocalTransform) + { + targetPosition = transform.localPosition; + targetRotation = transform.localRotation; + } + else + { + targetPosition = transform.position; + targetRotation = transform.rotation; + } + } + + /// + /// This gets called at serializationRateHz when the object is locally owned + /// + /// The state of this object to send across the network protected override byte[] SendState() { using MemoryStream mem = new MemoryStream(); using BinaryWriter writer = new BinaryWriter(mem); - writer.Write(transform.position); - writer.Write(transform.rotation); + writer.Write(transform.localPosition); + writer.Write(transform.localRotation); return mem.ToArray(); } + /// + /// This gets called whenever a message about the state of this object is received. + /// Usually at serializationRateHz. + /// + /// The network state of this object protected override void ReceiveState(byte[] message) { using MemoryStream mem = new MemoryStream(message); @@ -32,13 +58,50 @@ namespace VelNet targetPosition = reader.ReadVector3(); targetRotation = reader.ReadQuaternion(); + + // record the distance from the target for interpolation + if (useLocalTransform) + { + distanceAtReceiveTime = Vector3.Distance(targetPosition, transform.localPosition); + angleAtReceiveTime = Quaternion.Angle(targetRotation, transform.localRotation); + } + else + { + distanceAtReceiveTime = Vector3.Distance(targetPosition, transform.position); + angleAtReceiveTime = Quaternion.Angle(targetRotation, transform.rotation); + } } private void Update() { if (IsMine) return; - transform.position = Vector3.Lerp(transform.position, targetPosition, 1 / smoothness / serializationRateHz); - transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, 1 / smoothness / serializationRateHz); + + if (useLocalTransform) + { + transform.localPosition = Vector3.MoveTowards( + transform.localPosition, + targetPosition, + Time.deltaTime * distanceAtReceiveTime * serializationRateHz + ); + transform.localRotation = Quaternion.RotateTowards( + transform.localRotation, + targetRotation, + Time.deltaTime * angleAtReceiveTime * serializationRateHz + ); + } + else + { + transform.position = Vector3.MoveTowards( + transform.position, + targetPosition, + Time.deltaTime * distanceAtReceiveTime * serializationRateHz + ); + transform.rotation = Quaternion.RotateTowards( + transform.rotation, + targetRotation, + Time.deltaTime * angleAtReceiveTime * serializationRateHz + ); + } } } } \ No newline at end of file diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs index c8b2a41..7fe36d9 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs @@ -7,6 +7,7 @@ using System.Text; using System.Threading; using UnityEngine; using System.Net; +using UnityEngine.SceneManagement; namespace VelNet { @@ -104,12 +105,17 @@ namespace VelNet } instance = this; + + SceneManager.sceneLoaded += (scene, mode) => + { + // add all local network objects + sceneObjects = FindObjectsOfType().Where(o=>o.isSceneObject).ToArray(); + }; } private IEnumerator Start() { ConnectToTcpServer(); - sceneObjects = FindObjectsOfType(); //add all local network objects yield return null; try @@ -169,6 +175,7 @@ namespace VelNet // we clear the list, but will recreate as we get messages from people in our room players.Clear(); + masterPlayer = null; if (m.text != "") { @@ -200,7 +207,7 @@ namespace VelNet objects .Where(kvp => kvp.Value == null || !kvp.Value.isSceneObject) .Select(o => o.Key) - .ToList().ForEach(DeleteNetworkObject); + .ToList().ForEach(NetworkDestroy); // empty all the groups foreach (string group in instance.groups.Keys) @@ -246,7 +253,7 @@ namespace VelNet // I'm the local master player, so can take ownership immediately else if (me.isLocal && me == masterPlayer) { - me.TakeOwnership(kvp.Key); + TakeOwnership(kvp.Key); } // the master player left, so everyone should set the owner null (we should get a new master shortly) else if (players[m.sender] == masterPlayer) @@ -257,7 +264,7 @@ namespace VelNet } // TODO this may check for ownership in the future. We don't need ownership here - deleteObjects.ForEach(DeleteNetworkObject); + deleteObjects.ForEach(NetworkDestroy); players.Remove(m.sender); } @@ -683,18 +690,43 @@ namespace VelNet instance.objects.Add(newObject.networkId, newObject); } - public void DeleteNetworkObject(string networkId) + public static void NetworkDestroy(string networkId) { - if (!objects.ContainsKey(networkId)) return; - NetworkObject obj = objects[networkId]; + if (!instance.objects.ContainsKey(networkId)) return; + NetworkObject obj = instance.objects[networkId]; if (obj == null) return; if (obj.isSceneObject) { - deletedSceneObjects.Add(networkId); + instance.deletedSceneObjects.Add(networkId); } Destroy(obj.gameObject); - objects.Remove(networkId); + instance.objects.Remove(networkId); + } + + /// + /// Takes local ownership of an object by id. + /// + /// Network ID of the object to transfer + /// True if successfully transferred, False if transfer message not sent + public static bool TakeOwnership(string networkId) + { + // local player must exist + if (LocalPlayer == null) return false; + + // obj must exist + if (!instance.objects.ContainsKey(networkId)) return false; + + // if the ownership is locked, fail + if (instance.objects[networkId].ownershipLocked) return false; + + // immediately successful + instance.objects[networkId].owner = LocalPlayer; + + // must be ordered, so that ownership transfers are not confused. Also sent to all players, so that multiple simultaneous requests will result in the same outcome. + SendTo(MessageType.ALL_ORDERED, "6," + networkId); + + return true; } } } \ No newline at end of file diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetPlayer.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetPlayer.cs index 0fb7216..fae5623 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetPlayer.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetPlayer.cs @@ -113,14 +113,14 @@ namespace VelNet { string networkId = sections[1]; - manager.DeleteNetworkObject(networkId); + VelNetManager.NetworkDestroy(networkId); break; } case "9": //deleted scene objects { for (int k = 1; k < sections.Length; k++) { - manager.DeleteNetworkObject(sections[k]); + VelNetManager.NetworkDestroy(sections[k]); } break; @@ -146,9 +146,12 @@ namespace VelNet VelNetManager.SendTo(VelNetManager.MessageType.OTHERS, "5," + obj.networkId + "," + identifier + "," + Convert.ToBase64String(data), reliable); } - /// - /// TODO could move this to a static method in VelNetManager - /// + public void SendSceneUpdate() + { + VelNetManager.SendTo(VelNetManager.MessageType.OTHERS, "9," + string.Join(",", manager.deletedSceneObjects)); + } + + [Obsolete("Use VelNetManager.NetworkDestroy() instead.")] public void NetworkDestroy(string networkId) { // must be the local owner of the object to destroy it @@ -158,10 +161,8 @@ namespace VelNet VelNetManager.SendTo(VelNetManager.MessageType.ALL_ORDERED, "8," + networkId); } - /// - /// TODO could move this to a static method in VelNetManager - /// /// True if successful, False if failed to transfer ownership + [Obsolete("Use VelNetManager.TakeOwnership() instead.")] public bool TakeOwnership(string networkId) { // must exist and be the the local player @@ -169,19 +170,14 @@ namespace VelNet // if the ownership is locked, fail if (manager.objects[networkId].ownershipLocked) return false; - + // immediately successful manager.objects[networkId].owner = this; // must be ordered, so that ownership transfers are not confused. Also sent to all players, so that multiple simultaneous requests will result in the same outcome. VelNetManager.SendTo(VelNetManager.MessageType.ALL_ORDERED, "6," + networkId); - - return true; - } - public void SendSceneUpdate() - { - VelNetManager.SendTo(VelNetManager.MessageType.OTHERS, "9," + string.Join(",", manager.deletedSceneObjects)); + return true; } } } \ No newline at end of file From de26857357874193b86351443fad709105b6b0d1 Mon Sep 17 00:00:00 2001 From: Anton Franzluebbers Date: Thu, 13 Jan 2022 01:09:33 -0500 Subject: [PATCH 2/2] 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 --- .../VelNet/1.0.4/Example/NetworkGUI.cs | 5 + .../VelNet/1.0.4/Example/SyncedTextbox.cs | 19 + .../1.0.4/Example/SyncedTextbox.cs.meta | 11 + .../Samples/VelNet/1.0.4/Example/test.unity | 568 +++++++++++++++++- .../VelNetUnity/Runtime/NetworkObject.cs | 21 +- .../Runtime/Util/NetworkSerializedObject.cs | 2 +- .../Util/NetworkSerializedObjectStream.cs | 47 ++ .../NetworkSerializedObjectStream.cs.meta | 3 + .../VelNetUnity/Runtime/VelNetManager.cs | 35 +- .../Packages/VelNetUnity/package.json | 2 +- 10 files changed, 691 insertions(+), 22 deletions(-) create mode 100644 TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/SyncedTextbox.cs create mode 100644 TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/SyncedTextbox.cs.meta create mode 100644 TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObjectStream.cs create mode 100644 TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObjectStream.cs.meta diff --git a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/NetworkGUI.cs b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/NetworkGUI.cs index 46387bf..f009324 100644 --- a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/NetworkGUI.cs +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/NetworkGUI.cs @@ -41,6 +41,11 @@ namespace VelNet } } + public void HandleLeave() + { + VelNetManager.Leave(); + } + // Start is called before the first frame update private void Start() { diff --git a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/SyncedTextbox.cs b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/SyncedTextbox.cs new file mode 100644 index 0000000..73c526b --- /dev/null +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/SyncedTextbox.cs @@ -0,0 +1,19 @@ +using System.IO; +using UnityEngine.UI; +using VelNet; + +public class SyncedTextbox : NetworkSerializedObjectStream +{ + public InputField text; + + + protected override void SendState(BinaryWriter binaryWriter) + { + binaryWriter.Write(text.text); + } + + protected override void ReceiveState(BinaryReader binaryReader) + { + text.text = binaryReader.ReadString(); + } +} \ No newline at end of file diff --git a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/SyncedTextbox.cs.meta b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/SyncedTextbox.cs.meta new file mode 100644 index 0000000..2e95173 --- /dev/null +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/SyncedTextbox.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0a7b2180d3fffdc459417bfc24b179b8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test.unity b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test.unity index 5c5a1e3..a31295b 100644 --- a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test.unity +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test.unity @@ -602,8 +602,10 @@ RectTransform: - {fileID: 1278634767} - {fileID: 626742070} - {fileID: 711524767} + - {fileID: 864104176} - {fileID: 945446556} - {fileID: 1843597586} + - {fileID: 948755938} m_Father: {fileID: 0} m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -631,6 +633,85 @@ MonoBehaviour: messages: {fileID: 1894247854} messageBuffer: [] microphones: {fileID: 117638564} +--- !u!1 &359309140 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 359309141} + - component: {fileID: 359309143} + - component: {fileID: 359309142} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &359309141 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 359309140} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 948755938} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5000038} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &359309142 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 359309140} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.5} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 2 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Enter text... +--- !u!222 &359309143 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 359309140} + m_CullTransparentMesh: 1 --- !u!1 &440509381 GameObject: m_ObjectHideFlags: 0 @@ -864,7 +945,7 @@ RectTransform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 626742068} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalPosition: {x: 0, y: 0, z: -0} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: - {fileID: 2034439} @@ -874,7 +955,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} - m_AnchoredPosition: {x: 242.09998, y: 51} + m_AnchoredPosition: {x: 213.2, y: 51} m_SizeDelta: {x: 160, y: 30} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &626742071 @@ -1045,7 +1126,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} - m_AnchoredPosition: {x: 240.09998, y: 15.5} + m_AnchoredPosition: {x: 211.20001, y: 15.5} m_SizeDelta: {x: 160, y: 30} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &711524768 @@ -1230,6 +1311,139 @@ RectTransform: m_AnchoredPosition: {x: 5, y: -0.5} m_SizeDelta: {x: -30, y: -3} m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &864104175 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 864104176} + - component: {fileID: 864104179} + - component: {fileID: 864104178} + - component: {fileID: 864104177} + m_Layer: 5 + m_Name: LeaveRoom + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &864104176 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 864104175} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1401860307} + m_Father: {fileID: 244561620} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 356.07678, y: 15.5} + m_SizeDelta: {x: 125.7535, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &864104177 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 864104175} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 864104178} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 244561621} + m_TargetAssemblyTypeName: VelNet.NetworkGUI, Assembly-CSharp + m_MethodName: HandleLeave + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!114 &864104178 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 864104175} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &864104179 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 864104175} + m_CullTransparentMesh: 1 --- !u!1 &903768653 GameObject: m_ObjectHideFlags: 0 @@ -1624,7 +1838,7 @@ RectTransform: - {fileID: 1954037272} - {fileID: 1235343401} m_Father: {fileID: 244561620} - m_RootOrder: 6 + m_RootOrder: 7 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} @@ -1669,6 +1883,184 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 945446554} m_CullTransparentMesh: 1 +--- !u!1 &948755937 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 948755938} + - component: {fileID: 948755943} + - component: {fileID: 948755942} + - component: {fileID: 948755941} + - component: {fileID: 948755940} + - component: {fileID: 948755939} + m_Layer: 5 + m_Name: Synced Textbox + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &948755938 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 948755937} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 359309141} + - {fileID: 1840952814} + m_Father: {fileID: 244561620} + m_RootOrder: 9 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: -10, y: 10} + m_SizeDelta: {x: 309.08167, y: 65.9} + m_Pivot: {x: 1, y: 0} +--- !u!114 &948755939 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 948755937} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0a7b2180d3fffdc459417bfc24b179b8, type: 3} + m_Name: + m_EditorClassIdentifier: + networkObject: {fileID: 948755940} + serializationRateHz: 30 + text: {fileID: 948755941} +--- !u!114 &948755940 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 948755937} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5515094c5c544b6b8ed7fd51a86548d4, type: 3} + m_Name: + m_EditorClassIdentifier: + ownershipLocked: 0 + networkId: + prefabName: + isSceneObject: 1 + syncedComponents: + - {fileID: 948755939} +--- !u!114 &948755941 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 948755937} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 948755942} + m_TextComponent: {fileID: 1840952815} + m_Placeholder: {fileID: 359309142} + m_ContentType: 0 + m_InputType: 0 + m_AsteriskChar: 42 + m_KeyboardType: 0 + m_LineType: 2 + m_HideMobileInput: 0 + m_CharacterValidation: 0 + m_CharacterLimit: 0 + m_OnEndEdit: + m_PersistentCalls: + m_Calls: [] + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] + m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_CustomCaretColor: 0 + m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} + m_Text: + m_CaretBlinkRate: 0.85 + m_CaretWidth: 1 + m_ReadOnly: 0 + m_ShouldActivateOnSelect: 1 +--- !u!114 &948755942 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 948755937} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &948755943 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 948755937} + m_CullTransparentMesh: 1 --- !u!1 &1047954371 GameObject: m_ObjectHideFlags: 0 @@ -2101,8 +2493,8 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} - m_AnchoredPosition: {x: 80, y: 15.5} - m_SizeDelta: {x: 160, y: 30} + m_AnchoredPosition: {x: 65.39307, y: 15.5} + m_SizeDelta: {x: 130.7862, y: 30} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &1278634768 MonoBehaviour: @@ -2277,6 +2669,85 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1295274440} m_CullTransparentMesh: 1 +--- !u!1 &1401860306 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1401860307} + - component: {fileID: 1401860309} + - component: {fileID: 1401860308} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1401860307 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1401860306} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 864104176} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1401860308 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1401860306} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Leave Room +--- !u!222 &1401860309 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1401860306} + m_CullTransparentMesh: 1 --- !u!1 &1434745018 GameObject: m_ObjectHideFlags: 0 @@ -2704,8 +3175,8 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} - m_AnchoredPosition: {x: 82, y: 51} - m_SizeDelta: {x: 160, y: 30} + m_AnchoredPosition: {x: 67.02789, y: 51} + m_SizeDelta: {x: 130.7862, y: 30} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &1760805526 MonoBehaviour: @@ -2801,6 +3272,85 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1760805524} m_CullTransparentMesh: 1 +--- !u!1 &1840952813 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1840952814} + - component: {fileID: 1840952816} + - component: {fileID: 1840952815} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1840952814 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1840952813} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 948755938} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5000038} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1840952815 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1840952813} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &1840952816 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1840952813} + m_CullTransparentMesh: 1 --- !u!1 &1843597585 GameObject: m_ObjectHideFlags: 0 @@ -2833,7 +3383,7 @@ RectTransform: m_Children: - {fileID: 1852007163} m_Father: {fileID: 244561620} - m_RootOrder: 7 + m_RootOrder: 8 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/NetworkObject.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/NetworkObject.cs index aa39b78..b08e041 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/NetworkObject.cs +++ b/TestVelGameServer/Packages/VelNetUnity/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/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObject.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObject.cs index 13037d1..0569eed 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObject.cs +++ b/TestVelGameServer/Packages/VelNetUnity/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/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObjectStream.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObjectStream.cs new file mode 100644 index 0000000..a6929f8 --- /dev/null +++ b/TestVelGameServer/Packages/VelNetUnity/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/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObjectStream.cs.meta b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObjectStream.cs.meta new file mode 100644 index 0000000..6f4475e --- /dev/null +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObjectStream.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7da4222cdb03a3e43aceb43ef1e28f7e +timeCreated: 1641514434 \ No newline at end of file diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs index 7fe36d9..71ea086 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs +++ b/TestVelGameServer/Packages/VelNetUnity/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/TestVelGameServer/Packages/VelNetUnity/package.json b/TestVelGameServer/Packages/VelNetUnity/package.json index 4f2b772..b846be2 100644 --- a/TestVelGameServer/Packages/VelNetUnity/package.json +++ b/TestVelGameServer/Packages/VelNetUnity/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": [