From 013b8ccbdac761f5966d107d0faff6bc209aa90f Mon Sep 17 00:00:00 2001 From: Kyle Johnsen Date: Mon, 17 Jan 2022 18:18:23 -0500 Subject: [PATCH 01/14] added binary server tester --- .../Assets/Plugins/Dissonance.meta | 2 +- .../VelNet/1.0.4/Example/test_binary.unity | 323 ++++++++ .../1.0.4/Example/test_binary.unity.meta | 7 + .../Runtime/VelNetBinaryManager.cs | 775 ++++++++++++++++++ .../Runtime/VelNetBinaryManager.cs.meta | 11 + TestVelGameServer/Packages/manifest.json | 2 +- TestVelGameServer/Packages/packages-lock.json | 2 +- .../ProjectSettings/EditorBuildSettings.asset | 4 +- .../ProjectSettings/ProjectVersion.txt | 4 +- 9 files changed, 1123 insertions(+), 7 deletions(-) create mode 100644 TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test_binary.unity create mode 100644 TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test_binary.unity.meta create mode 100644 TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetBinaryManager.cs create mode 100644 TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetBinaryManager.cs.meta diff --git a/TestVelGameServer/Assets/Plugins/Dissonance.meta b/TestVelGameServer/Assets/Plugins/Dissonance.meta index accd5b8..701466a 100644 --- a/TestVelGameServer/Assets/Plugins/Dissonance.meta +++ b/TestVelGameServer/Assets/Plugins/Dissonance.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 8adda10125f861c4ab834bb9bd2056b5 +guid: b34f6c4b68ec079449bfb4be05fbfec7 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test_binary.unity b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test_binary.unity new file mode 100644 index 0000000..13b93be --- /dev/null +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test_binary.unity @@ -0,0 +1,323 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &516411417 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 516411421} + - component: {fileID: 516411420} + - component: {fileID: 516411419} + - component: {fileID: 516411418} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &516411418 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 516411417} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 233344de094f11341bdb834d564708dc, type: 3} + m_Name: + m_EditorClassIdentifier: + host: 127.0.0.1 + port: 80 + udpConnected: 0 + userid: -1 + room: + connected: 0 + prefabs: [] + sceneObjects: [] + deletedSceneObjects: [] +--- !u!81 &516411419 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 516411417} + m_Enabled: 1 +--- !u!20 &516411420 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 516411417} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &516411421 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 516411417} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &756322628 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 756322630} + - component: {fileID: 756322629} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &756322629 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 756322628} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &756322630 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 756322628} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} diff --git a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test_binary.unity.meta b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test_binary.unity.meta new file mode 100644 index 0000000..276a764 --- /dev/null +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test_binary.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 2e6e0ddeb76e51b46afc0f0a43386ff2 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetBinaryManager.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetBinaryManager.cs new file mode 100644 index 0000000..ec4c4b4 --- /dev/null +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetBinaryManager.cs @@ -0,0 +1,775 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using UnityEngine; +using System.Net; +using UnityEngine.SceneManagement; +using System.Runtime.Serialization.Formatters.Binary; +using System.Runtime.Serialization; +using System.IO; + +namespace VelNet +{ + [AddComponentMenu("VelNet/VelNet Manager")] + public class VelNetBinaryManager : MonoBehaviour + { + public enum MessageType + { + OTHERS = 0, + ALL = 1, + OTHERS_ORDERED = 2, + ALL_ORDERED = 3 + }; + + public string host; + public int port; + + public static VelNetBinaryManager instance; + + private TcpClient socketConnection; + private Socket udpSocket; + public bool udpConnected; + private IPEndPoint RemoteEndPoint; + private Thread clientReceiveThread; + private Thread clientReceiveThreadUDP; + public int userid = -1; + public string room; + private int messagesReceived = 0; + + public readonly Dictionary players = new Dictionary(); + + /// + /// We just joined a room + /// string - the room name + /// + public static Action OnJoinedRoom; + + /// + /// We just left a room + /// string - the room name we left + /// + public static Action OnLeftRoom; + + /// + /// Somebody else just joined our room + /// + public static Action OnPlayerJoined; + + /// + /// Somebody else just left our room + /// + public static Action OnPlayerLeft; + + public static Action OnConnectedToServer; + public static Action MessageReceived; + public static Action LoggedIn; + public static Action RoomsReceived; + + public bool connected; + + public List prefabs = new List(); + public NetworkObject[] sceneObjects; + public List deletedSceneObjects = new List(); + + /// + /// Maintains a list of all known objects on the server (ones that have ids) + /// + public readonly Dictionary objects = new Dictionary(); + + /// + /// Maintains a list of all known groups on the server + /// + public readonly Dictionary> groups = new Dictionary>(); + + private VelNetPlayer masterPlayer; + public static VelNetPlayer LocalPlayer => instance.players.Where(p => p.Value.isLocal).Select(p => p.Value).FirstOrDefault(); + public static bool InRoom => LocalPlayer != null && LocalPlayer.room != "-1" && LocalPlayer.room != ""; + + + // Use this for initialization + public class Message + { + public int type; + public string text; + public int sender; + } + + public readonly List receivedMessages = new List(); + + private void Awake() + { + if (instance != null) + { + Debug.LogError("Multiple NetworkManagers detected! Bad!", this); + } + + instance = this; + + SceneManager.sceneLoaded += (scene, mode) => + { + // add all local network objects + sceneObjects = FindObjectsOfType().Where(o => o.isSceneObject).ToArray(); + }; + } + + private IEnumerator Start() + { + ConnectToTcpServer(); + yield return null; + + try + { + OnConnectedToServer?.Invoke(); + } + // prevent errors in subscribers from breaking our code + catch (Exception e) + { + Debug.LogError(e); + } + } + + + private void AddMessage(Message m) + { + lock (receivedMessages) + { + //Debug.Log(messagesReceived++); + receivedMessages.Add(m); + } + } + + private void Update() + { + lock (receivedMessages) + { + ////the main thread, which can do Unity stuff + //foreach (Message m in receivedMessages) + //{ + // switch (m.type) + // { + // // when you join the server + // case 0: + // userid = m.sender; + // Debug.Log("joined server"); + + // try + // { + // LoggedIn?.Invoke(); + // } + // // prevent errors in subscribers from breaking our code + // catch (Exception e) + // { + // Debug.LogError(e); + // } + + // //start the udp thread + // clientReceiveThreadUDP = new Thread(ListenForDataUDP); + // clientReceiveThreadUDP.IsBackground = true; + // clientReceiveThreadUDP.Start(); + // break; + // // if this message is for me, that means I joined a new room... + // case 2 when userid == m.sender: + // { + // string oldRoom = LocalPlayer?.room; + + // // we clear the list, but will recreate as we get messages from people in our room + // players.Clear(); + // masterPlayer = null; + + // if (m.text != "") + // { + // VelNetPlayer player = new VelNetPlayer + // { + // isLocal = true, + // userid = m.sender, + // room = m.text + // }; + + // players.Add(userid, player); + // if (m.text != "") + // { + // try + // { + // OnJoinedRoom?.Invoke(m.text); + // } + // // prevent errors in subscribers from breaking our code + // catch (Exception e) + // { + // Debug.LogError(e); + // } + // } + // } + // // we just left a room + // else + // { + // // delete all networkobjects that aren't sceneobjects or are null now + // objects + // .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) + // { + // SetupMessageGroup(group, new List()); + // } + + // instance.groups.Clear(); + + // try + // { + // OnLeftRoom?.Invoke(oldRoom); + // } + // // prevent errors in subscribers from breaking our code + // catch (Exception e) + // { + // Debug.LogError(e); + // } + // } + + // break; + // } + // // not for me, a player is joining or leaving + // case 2: + // { + // VelNetPlayer me = players[userid]; + + // if (me.room != m.text) + // { + // // we got a left message, kill it + // // change ownership of all objects to master + // List deleteObjects = new List(); + // foreach (KeyValuePair kvp in objects) + // { + // if (kvp.Value.owner == players[m.sender]) // the owner is the player that left + // { + // // if this object has locked ownership, delete it + // if (kvp.Value.ownershipLocked) + // { + // deleteObjects.Add(kvp.Value.networkId); + // } + // // I'm the local master player, so can take ownership immediately + // else if (me.isLocal && me == masterPlayer) + // { + // 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) + // { + // kvp.Value.owner = null; + // } + // } + // } + + // // TODO this may check for ownership in the future. We don't need ownership here + // deleteObjects.ForEach(NetworkDestroy); + + // players.Remove(m.sender); + // } + // else + // { + // // we got a join message, create it + // VelNetPlayer player = new VelNetPlayer + // { + // isLocal = false, + // room = m.text, + // userid = m.sender + // }; + // players.Add(m.sender, player); + // try + // { + // OnPlayerJoined?.Invoke(player); + // } + // // prevent errors in subscribers from breaking our code + // catch (Exception e) + // { + // Debug.LogError(e); + // } + // } + + // break; + // } + // // generic message + // case 3: + // if (players.ContainsKey(m.sender)) + // { + // players[m.sender]?.HandleMessage(m); + // } + // else + // { + // Debug.LogError("Received message from player that doesn't exist: " + m.text); + // } + + // break; + // // change master player (this should only happen when the first player joins or if the master player leaves) + // case 4: + // { + // if (masterPlayer == null) + // { + // masterPlayer = players[m.sender]; + + // // no master player yet, add the scene objects + + // for (int i = 0; i < sceneObjects.Length; i++) + // { + // sceneObjects[i].networkId = -1 + "-" + i; + // sceneObjects[i].owner = masterPlayer; + // sceneObjects[i].isSceneObject = true; // needed for special handling when deleted + // objects.Add(sceneObjects[i].networkId, sceneObjects[i]); + // } + // } + // else + // { + // masterPlayer = players[m.sender]; + // } + + // masterPlayer.SetAsMasterPlayer(); + + // // master player should take over any objects that do not have an owner + // foreach (KeyValuePair kvp in objects) + // { + // kvp.Value.owner ??= masterPlayer; + // } + + // break; + // } + // } + + // MessageReceived?.Invoke(m); + //} + + //receivedMessages.Clear(); + } + } + + private void OnApplicationQuit() + { + socketConnection.Close(); + } + + /// + /// Setup socket connection. + /// + private void ConnectToTcpServer() + { + try + { + clientReceiveThread = new Thread(ListenForData); + clientReceiveThread.IsBackground = true; + clientReceiveThread.Start(); + } + catch (Exception e) + { + Debug.Log("On client connect exception " + e); + } + } + + private void HandleMessage(string s) // this parses messages from the server, and adds them to a queue to be processed on the main thread + { + // Debug.Log("Received: " + s); + Message m = new Message(); + string[] sections = s.Split(':'); + if (sections.Length <= 0) return; + + int type = int.Parse(sections[0]); + + switch (type) + { + case 0: // logged in message + { + if (sections.Length > 1) + { + m.type = type; + m.sender = int.Parse(sections[1]); + m.text = ""; + AddMessage(m); + } + + break; + } + case 1: // room info message + { + break; + } + case 2: // joined room message + { + if (sections.Length > 2) + { + m.type = 2; + int user_id = int.Parse(sections[1]); + m.sender = user_id; + string new_room = sections[2]; + m.text = new_room; + + AddMessage(m); + } + + break; + } + case 3: // text message + { + if (sections.Length > 2) + { + m.type = 3; + m.sender = int.Parse(sections[1]); + m.text = sections[2]; + AddMessage(m); + } + + break; + } + case 4: // change master client + { + if (sections.Length > 1) + { + m.type = 4; + m.sender = int.Parse(sections[1]); + AddMessage(m); + } + + break; + } + } + } + + /// + /// Runs in background clientReceiveThread; Listens for incomming data. + /// + private void ListenForData() + { + connected = true; + try + { + socketConnection = new TcpClient(host, port); + socketConnection.NoDelay = true; + byte[] bytes = new byte[1024]; + string partialMessage = ""; + Login("Kyle", "Johnsen"); + while (true) + { + + // Get a stream object for reading + using NetworkStream stream = socketConnection.GetStream(); + int length; + // Read incomming stream into byte arrary. + while ((length = stream.Read(bytes, 0, bytes.Length)) != 0) + { + Debug.Log("read " + length + " bytes!"); + //byte[] incommingData = new byte[length]; + //Array.Copy(bytes, 0, incommingData, 0, length); + //// Convert byte array to string message. + //string serverMessage = Encoding.ASCII.GetString(incommingData); + //string[] sections = serverMessage.Split('\n'); + //if (sections.Length > 1) + //{ + // lock (receivedMessages) + // { + // for (int i = 0; i < sections.Length - 1; i++) + // { + // if (i == 0) + // { + // HandleMessage(partialMessage + sections[0]); + // partialMessage = ""; + // } + // else + // { + // HandleMessage(sections[i]); + // } + // } + // } + //} + + //partialMessage = partialMessage + sections[sections.Length - 1]; + } + } + } + + + catch (Exception socketException) + { + Debug.Log("Socket exception: " + socketException); + } + + connected = false; + } + + private void ListenForDataUDP() + { + //I don't yet have a UDP connection + try + { + IPAddress[] addresses = Dns.GetHostAddresses(host); + Debug.Assert(addresses.Length > 0); + RemoteEndPoint = new IPEndPoint(addresses[0], port); + + + udpSocket = new Socket(AddressFamily.InterNetwork, + SocketType.Dgram, ProtocolType.Udp); + + + udpConnected = false; + byte[] buffer = new byte[1024]; + while (true) + { + string welcome = userid + ":0:Hello"; + byte[] data = Encoding.ASCII.GetBytes(welcome); + udpSocket.SendTo(data, data.Length, SocketFlags.None, RemoteEndPoint); + + if (udpSocket.Available == 0) + { + Thread.Sleep(100); + Debug.Log("Waiting for UDP response"); + } + else + { + break; + } + } + + udpConnected = true; + while (true) + { + int numReceived = udpSocket.Receive(buffer); + + string message = Encoding.UTF8.GetString(buffer, 0, numReceived); + + string[] sections = message.Split(':'); + if (sections[0] == "0") + { + Debug.Log("UDP connected"); + } + + if (sections[0] == "3") + { + HandleMessage(message); + } + } + } + catch (Exception socketException) + { + Debug.Log("Socket exception: " + socketException); + } + } + + private static void SendUdpMessage(string message) + { + if (instance.udpSocket == null || !instance.udpConnected) + { + return; + } + + byte[] data = Encoding.UTF8.GetBytes(message); + //Debug.Log("Attempting to send: " + message); + instance.udpSocket.SendTo(data, data.Length, SocketFlags.None, instance.RemoteEndPoint); + } + + /// + /// Send message to server using socket connection. + /// + private static void SendNetworkMessage(byte[] message) + { + // Debug.Log("Sent: " + clientMessage); + if (instance.socketConnection == null) + { + return; + } + + try + { + // Get a stream object for writing. + NetworkStream stream = instance.socketConnection.GetStream(); + if (stream.CanWrite) + { + + stream.Write(message,0,message.Length); + } + } + catch (SocketException socketException) + { + Debug.Log("Socket exception: " + socketException); + } + } + + /// + /// Connects to the server with a username + /// + /// + public static byte[] get_be_bytes(int n) + { + return BitConverter.GetBytes(n).Reverse().ToArray(); + } + public static void Login(string username, string password) + { + + MemoryStream stream = new MemoryStream(); + BinaryWriter writer = new BinaryWriter(stream); + + byte[] uB = Encoding.UTF8.GetBytes(username); + byte[] uP = Encoding.UTF8.GetBytes(password); + writer.Write((byte)0); + writer.Write(get_be_bytes(uB.Length)); + writer.Write(uB); + writer.Write(get_be_bytes(uP.Length)); + writer.Write(uP); + + SendNetworkMessage(stream.ToArray()); + Join("MyRoom"); + } + + /// + /// Joins a room by name + /// + /// The name of the room to join + public static void Join(string roomname) + { + MemoryStream stream = new MemoryStream(); + BinaryWriter writer = new BinaryWriter(stream); + + byte[] R = Encoding.UTF8.GetBytes(roomname); + writer.Write((byte)2); + writer.Write(get_be_bytes(R.Length)); + writer.Write(R); + SendNetworkMessage(stream.ToArray()); + } + + /// + /// Leaves a room if we're in one + /// + public static void Leave() + { + //if (InRoom) SendNetworkMessage("2:-1"); + } + + public static void SendTo(MessageType type, string message, bool reliable = true) + { + if (reliable) + { + //SendNetworkMessage("3:" + (int)type + ":" + message); + } + else + { + SendUdpMessage(instance.userid + ":3:" + (int)type + ":" + message); + } + } + + public static void SendToGroup(string group, string message, bool reliable = true) + { + if (reliable) + { + //SendNetworkMessage("4:" + group + ":" + message); + } + else + { + SendUdpMessage(instance.userid + ":4:" + group + ":" + message); + } + } + + /// + /// changes the designated group that sendto(4) will go to + /// + public static void SetupMessageGroup(string groupName, List userIds) + { + if (userIds.Count > 0) + { + instance.groups[groupName] = userIds.ToList(); + } + + //SendNetworkMessage($"5:{groupName}:{string.Join(":", userIds)}"); + } + + + 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 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 = 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) + { + NetworkObject prefab = instance.prefabs.Find(p => p.name == prefabName); + if (prefab == null) return; + NetworkObject newObject = Instantiate(prefab); + newObject.networkId = networkId; + newObject.prefabName = prefabName; + newObject.owner = owner; + 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) + { + instance.objects.Remove(networkId); + return; + } + if (obj.isSceneObject) + { + instance.deletedSceneObjects.Add(networkId); + } + + Destroy(obj.gameObject); + 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/VelNetBinaryManager.cs.meta b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetBinaryManager.cs.meta new file mode 100644 index 0000000..014ff23 --- /dev/null +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetBinaryManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 233344de094f11341bdb834d564708dc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestVelGameServer/Packages/manifest.json b/TestVelGameServer/Packages/manifest.json index 0da73bc..9dde81b 100644 --- a/TestVelGameServer/Packages/manifest.json +++ b/TestVelGameServer/Packages/manifest.json @@ -8,7 +8,7 @@ "com.unity.textmeshpro": "3.0.6", "com.unity.timeline": "1.4.8", "com.unity.ugui": "1.0.0", - "edu.uga.engr.vel.velnet.dissonance": "file:S:/git_repo/VelNetDissonanceIntegration", + "edu.uga.engr.vel.velnet.dissonance": "file:c:/git_repo/VelNetDissonanceIntegration", "com.unity.modules.ai": "1.0.0", "com.unity.modules.androidjni": "1.0.0", "com.unity.modules.animation": "1.0.0", diff --git a/TestVelGameServer/Packages/packages-lock.json b/TestVelGameServer/Packages/packages-lock.json index afe1934..0a48dcc 100644 --- a/TestVelGameServer/Packages/packages-lock.json +++ b/TestVelGameServer/Packages/packages-lock.json @@ -106,7 +106,7 @@ "dependencies": {} }, "edu.uga.engr.vel.velnet.dissonance": { - "version": "file:S:/git_repo/VelNetDissonanceIntegration", + "version": "file:c:/git_repo/VelNetDissonanceIntegration", "depth": 0, "source": "local", "dependencies": { diff --git a/TestVelGameServer/ProjectSettings/EditorBuildSettings.asset b/TestVelGameServer/ProjectSettings/EditorBuildSettings.asset index ba9b4aa..b07974f 100644 --- a/TestVelGameServer/ProjectSettings/EditorBuildSettings.asset +++ b/TestVelGameServer/ProjectSettings/EditorBuildSettings.asset @@ -6,6 +6,6 @@ EditorBuildSettings: serializedVersion: 2 m_Scenes: - enabled: 1 - path: Assets/Samples/VelNet/1.0.4/Example/test.unity - guid: e4e43899246c941c78acfc59ce2f664a + path: Assets/Samples/VelNet/1.0.4/Example/test_binary.unity + guid: 2e6e0ddeb76e51b46afc0f0a43386ff2 m_configObjects: {} diff --git a/TestVelGameServer/ProjectSettings/ProjectVersion.txt b/TestVelGameServer/ProjectSettings/ProjectVersion.txt index 24993f7..e610e28 100644 --- a/TestVelGameServer/ProjectSettings/ProjectVersion.txt +++ b/TestVelGameServer/ProjectSettings/ProjectVersion.txt @@ -1,2 +1,2 @@ -m_EditorVersion: 2020.3.23f1 -m_EditorVersionWithRevision: 2020.3.23f1 (c5d91304a876) +m_EditorVersion: 2020.3.11f1 +m_EditorVersionWithRevision: 2020.3.11f1 (99c7afb366b3) From acf99582df33408755b4c8f83cec5d391c5e1367 Mon Sep 17 00:00:00 2001 From: Kyle Johnsen Date: Mon, 17 Jan 2022 22:32:06 -0500 Subject: [PATCH 02/14] make small string sends --- .../VelNetUnity/Runtime/VelNetBinaryManager.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetBinaryManager.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetBinaryManager.cs index ec4c4b4..43f2de1 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetBinaryManager.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetBinaryManager.cs @@ -612,12 +612,12 @@ namespace VelNet BinaryWriter writer = new BinaryWriter(stream); byte[] uB = Encoding.UTF8.GetBytes(username); - byte[] uP = Encoding.UTF8.GetBytes(password); + byte[] pB = Encoding.UTF8.GetBytes(password); writer.Write((byte)0); - writer.Write(get_be_bytes(uB.Length)); + writer.Write((byte)uB.Length); writer.Write(uB); - writer.Write(get_be_bytes(uP.Length)); - writer.Write(uP); + writer.Write((byte)pB.Length); + writer.Write(pB); SendNetworkMessage(stream.ToArray()); Join("MyRoom"); @@ -634,7 +634,7 @@ namespace VelNet byte[] R = Encoding.UTF8.GetBytes(roomname); writer.Write((byte)2); - writer.Write(get_be_bytes(R.Length)); + writer.Write((byte)R.Length); writer.Write(R); SendNetworkMessage(stream.ToArray()); } From f48efad8d0605828741a10811c1ff43a937da18c Mon Sep 17 00:00:00 2001 From: Kyle Johnsen Date: Tue, 18 Jan 2022 02:11:16 -0500 Subject: [PATCH 03/14] test binary server with sending tcp messages --- .../Runtime/VelNetBinaryManager.cs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetBinaryManager.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetBinaryManager.cs index 43f2de1..c1c2e55 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetBinaryManager.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetBinaryManager.cs @@ -462,6 +462,12 @@ namespace VelNet while ((length = stream.Read(bytes, 0, bytes.Length)) != 0) { Debug.Log("read " + length + " bytes!"); + string t = ""; + for(int i = 0; i < length; i++) + { + t = t + "," + bytes[i]; + } + Debug.Log(t); //byte[] incommingData = new byte[length]; //Array.Copy(bytes, 0, incommingData, 0, length); //// Convert byte array to string message. @@ -621,6 +627,7 @@ namespace VelNet SendNetworkMessage(stream.ToArray()); Join("MyRoom"); + } /// @@ -637,6 +644,8 @@ namespace VelNet writer.Write((byte)R.Length); writer.Write(R); SendNetworkMessage(stream.ToArray()); + + SendTo(MessageType.OTHERS, Encoding.UTF8.GetBytes("Hello")); } /// @@ -647,6 +656,27 @@ namespace VelNet //if (InRoom) SendNetworkMessage("2:-1"); } + public static void SendTo(MessageType type, byte[] message, bool reliable = true) + { + MemoryStream stream = new MemoryStream(); + BinaryWriter writer = new BinaryWriter(stream); + + writer.Write((byte)3); + writer.Write(get_be_bytes(message.Length)); + writer.Write(message); + + if (reliable) + { + SendNetworkMessage(stream.ToArray()); + + //SendNetworkMessage("3:" + (int)type + ":" + message); + } + else + { + SendUdpMessage(instance.userid + ":3:" + (int)type + ":" + message); + } + } + public static void SendTo(MessageType type, string message, bool reliable = true) { if (reliable) From d983b34817db604ce6f8f8ff2cc890c05d2d47b8 Mon Sep 17 00:00:00 2001 From: Kyle Johnsen Date: Tue, 18 Jan 2022 19:02:07 -0500 Subject: [PATCH 04/14] progress updating binary manager --- .../Runtime/VelNetBinaryManager.cs | 538 +++++++++++------- 1 file changed, 330 insertions(+), 208 deletions(-) diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetBinaryManager.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetBinaryManager.cs index c1c2e55..4671de8 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetBinaryManager.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetBinaryManager.cs @@ -17,12 +17,22 @@ namespace VelNet [AddComponentMenu("VelNet/VelNet Manager")] public class VelNetBinaryManager : MonoBehaviour { - public enum MessageType + public enum MessageSendType { - OTHERS = 0, - ALL = 1, - OTHERS_ORDERED = 2, - ALL_ORDERED = 3 + LOGIN = 0, + GET_ROOMS = 1, + JOIN_ROOM = 2, + MESSAGE_OTHERS = 3, + MESSAGE_ALL = 4, + MESSAGE_GROUP = 5, + FORM_GROUP = 6 + }; + public enum MessageReceiveType + { + LOGGED_IN = 0, + ROOM_LIST = 1, + CLIENT_JOINED = 2, + MESSAGE = 3 }; public string host; @@ -93,11 +103,14 @@ namespace VelNet // Use this for initialization public class Message { - public int type; - public string text; + public MessageReceiveType type; + //public string text; + public byte[] data; public int sender; } + + public readonly List receivedMessages = new List(); private void Awake() @@ -146,206 +159,208 @@ namespace VelNet { lock (receivedMessages) { - ////the main thread, which can do Unity stuff - //foreach (Message m in receivedMessages) - //{ - // switch (m.type) - // { - // // when you join the server - // case 0: - // userid = m.sender; - // Debug.Log("joined server"); + //the main thread, which can do Unity stuff + foreach (Message m in receivedMessages) + { + switch (m.type) + { + // when you join the server + case 0: + userid = m.sender; + Debug.Log("joined server " + userid); - // try - // { - // LoggedIn?.Invoke(); - // } - // // prevent errors in subscribers from breaking our code - // catch (Exception e) - // { - // Debug.LogError(e); - // } + try + { + LoggedIn?.Invoke(); + } + // prevent errors in subscribers from breaking our code + catch (Exception e) + { + Debug.LogError(e); + } - // //start the udp thread - // clientReceiveThreadUDP = new Thread(ListenForDataUDP); - // clientReceiveThreadUDP.IsBackground = true; - // clientReceiveThreadUDP.Start(); - // break; - // // if this message is for me, that means I joined a new room... - // case 2 when userid == m.sender: - // { - // string oldRoom = LocalPlayer?.room; + //start the udp thread + clientReceiveThreadUDP = new Thread(ListenForDataUDP); + clientReceiveThreadUDP.IsBackground = true; + clientReceiveThreadUDP.Start(); + break; + /* + // if this message is for me, that means I joined a new room... + case 2 when userid == m.sender: + { + string oldRoom = LocalPlayer?.room; - // // we clear the list, but will recreate as we get messages from people in our room - // players.Clear(); - // masterPlayer = null; + // we clear the list, but will recreate as we get messages from people in our room + players.Clear(); + masterPlayer = null; - // if (m.text != "") - // { - // VelNetPlayer player = new VelNetPlayer - // { - // isLocal = true, - // userid = m.sender, - // room = m.text - // }; + if (m.text != "") + { + VelNetPlayer player = new VelNetPlayer + { + isLocal = true, + userid = m.sender, + room = m.text + }; - // players.Add(userid, player); - // if (m.text != "") - // { - // try - // { - // OnJoinedRoom?.Invoke(m.text); - // } - // // prevent errors in subscribers from breaking our code - // catch (Exception e) - // { - // Debug.LogError(e); - // } - // } - // } - // // we just left a room - // else - // { - // // delete all networkobjects that aren't sceneobjects or are null now - // objects - // .Where(kvp => kvp.Value == null || !kvp.Value.isSceneObject) - // .Select(o => o.Key) - // .ToList().ForEach(NetworkDestroy); + players.Add(userid, player); + if (m.text != "") + { + try + { + OnJoinedRoom?.Invoke(m.text); + } + // prevent errors in subscribers from breaking our code + catch (Exception e) + { + Debug.LogError(e); + } + } + } + // we just left a room + else + { + // delete all networkobjects that aren't sceneobjects or are null now + objects + .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(); + // then remove references to the ones that are left + objects.Clear(); - // // empty all the groups - // foreach (string group in instance.groups.Keys) - // { - // SetupMessageGroup(group, new List()); - // } + // empty all the groups + foreach (string group in instance.groups.Keys) + { + SetupMessageGroup(group, new List()); + } - // instance.groups.Clear(); + instance.groups.Clear(); - // try - // { - // OnLeftRoom?.Invoke(oldRoom); - // } - // // prevent errors in subscribers from breaking our code - // catch (Exception e) - // { - // Debug.LogError(e); - // } - // } + try + { + OnLeftRoom?.Invoke(oldRoom); + } + // prevent errors in subscribers from breaking our code + catch (Exception e) + { + Debug.LogError(e); + } + } - // break; - // } - // // not for me, a player is joining or leaving - // case 2: - // { - // VelNetPlayer me = players[userid]; + break; + } + // not for me, a player is joining or leaving + case 2: + { + VelNetPlayer me = players[userid]; - // if (me.room != m.text) - // { - // // we got a left message, kill it - // // change ownership of all objects to master - // List deleteObjects = new List(); - // foreach (KeyValuePair kvp in objects) - // { - // if (kvp.Value.owner == players[m.sender]) // the owner is the player that left - // { - // // if this object has locked ownership, delete it - // if (kvp.Value.ownershipLocked) - // { - // deleteObjects.Add(kvp.Value.networkId); - // } - // // I'm the local master player, so can take ownership immediately - // else if (me.isLocal && me == masterPlayer) - // { - // 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) - // { - // kvp.Value.owner = null; - // } - // } - // } + if (me.room != m.text) + { + // we got a left message, kill it + // change ownership of all objects to master + List deleteObjects = new List(); + foreach (KeyValuePair kvp in objects) + { + if (kvp.Value.owner == players[m.sender]) // the owner is the player that left + { + // if this object has locked ownership, delete it + if (kvp.Value.ownershipLocked) + { + deleteObjects.Add(kvp.Value.networkId); + } + // I'm the local master player, so can take ownership immediately + else if (me.isLocal && me == masterPlayer) + { + 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) + { + kvp.Value.owner = null; + } + } + } - // // TODO this may check for ownership in the future. We don't need ownership here - // deleteObjects.ForEach(NetworkDestroy); + // TODO this may check for ownership in the future. We don't need ownership here + deleteObjects.ForEach(NetworkDestroy); - // players.Remove(m.sender); - // } - // else - // { - // // we got a join message, create it - // VelNetPlayer player = new VelNetPlayer - // { - // isLocal = false, - // room = m.text, - // userid = m.sender - // }; - // players.Add(m.sender, player); - // try - // { - // OnPlayerJoined?.Invoke(player); - // } - // // prevent errors in subscribers from breaking our code - // catch (Exception e) - // { - // Debug.LogError(e); - // } - // } + players.Remove(m.sender); + } + else + { + // we got a join message, create it + VelNetPlayer player = new VelNetPlayer + { + isLocal = false, + room = m.text, + userid = m.sender + }; + players.Add(m.sender, player); + try + { + OnPlayerJoined?.Invoke(player); + } + // prevent errors in subscribers from breaking our code + catch (Exception e) + { + Debug.LogError(e); + } + } - // break; - // } - // // generic message - // case 3: - // if (players.ContainsKey(m.sender)) - // { - // players[m.sender]?.HandleMessage(m); - // } - // else - // { - // Debug.LogError("Received message from player that doesn't exist: " + m.text); - // } + break; + } + // generic message + case 3: + if (players.ContainsKey(m.sender)) + { + players[m.sender]?.HandleMessage(m); + } + else + { + Debug.LogError("Received message from player that doesn't exist: " + m.text); + } - // break; - // // change master player (this should only happen when the first player joins or if the master player leaves) - // case 4: - // { - // if (masterPlayer == null) - // { - // masterPlayer = players[m.sender]; + break; + // change master player (this should only happen when the first player joins or if the master player leaves) + case 4: + { + if (masterPlayer == null) + { + masterPlayer = players[m.sender]; - // // no master player yet, add the scene objects + // no master player yet, add the scene objects - // for (int i = 0; i < sceneObjects.Length; i++) - // { - // sceneObjects[i].networkId = -1 + "-" + i; - // sceneObjects[i].owner = masterPlayer; - // sceneObjects[i].isSceneObject = true; // needed for special handling when deleted - // objects.Add(sceneObjects[i].networkId, sceneObjects[i]); - // } - // } - // else - // { - // masterPlayer = players[m.sender]; - // } + for (int i = 0; i < sceneObjects.Length; i++) + { + sceneObjects[i].networkId = -1 + "-" + i; + sceneObjects[i].owner = masterPlayer; + sceneObjects[i].isSceneObject = true; // needed for special handling when deleted + objects.Add(sceneObjects[i].networkId, sceneObjects[i]); + } + } + else + { + masterPlayer = players[m.sender]; + } - // masterPlayer.SetAsMasterPlayer(); + masterPlayer.SetAsMasterPlayer(); - // // master player should take over any objects that do not have an owner - // foreach (KeyValuePair kvp in objects) - // { - // kvp.Value.owner ??= masterPlayer; - // } + // master player should take over any objects that do not have an owner + foreach (KeyValuePair kvp in objects) + { + kvp.Value.owner ??= masterPlayer; + } - // break; - // } - // } + break; + } + */ + } - // MessageReceived?.Invoke(m); - //} + MessageReceived?.Invoke(m); + } - //receivedMessages.Clear(); + receivedMessages.Clear(); } } @@ -373,6 +388,7 @@ namespace VelNet private void HandleMessage(string s) // this parses messages from the server, and adds them to a queue to be processed on the main thread { + /* // Debug.Log("Received: " + s); Message m = new Message(); string[] sections = s.Split(':'); @@ -436,12 +452,38 @@ namespace VelNet break; } - } + }*/ } /// /// Runs in background clientReceiveThread; Listens for incomming data. /// + /// + private byte[] ReadExact(NetworkStream stream, int N) + { + byte[] toReturn = new byte[N]; + + int numRead = 0; + int numLeft = N; + while (numLeft > 0) + { + numRead += stream.Read(toReturn, numRead, numLeft); + numLeft = N - numRead; + } + return toReturn; + } + + private uint GetUintFromBytes(byte[] bytes) + { + if (BitConverter.IsLittleEndian) + { + return BitConverter.ToUInt32(bytes.Reverse().ToArray(),0); + } + else + { + return BitConverter.ToUInt32(bytes, 0); + } + } private void ListenForData() { connected = true; @@ -450,14 +492,44 @@ namespace VelNet socketConnection = new TcpClient(host, port); socketConnection.NoDelay = true; byte[] bytes = new byte[1024]; - string partialMessage = ""; + Login("Kyle", "Johnsen"); + //Join("MyRoom"); + //SendTo(MessageSendType.MESSAGE_OTHERS, Encoding.UTF8.GetBytes("Hello")); + //FormGroup("close", new List { 1 }); + //SendToGroup("close", Encoding.UTF8.GetBytes("HelloGroup")); while (true) { // Get a stream object for reading using NetworkStream stream = socketConnection.GetStream(); int length; + + //read a byte + byte type = (byte)stream.ReadByte(); + + if(type == 0) + { + //read the id (this is my network id) + + Message m = new Message(); + m.sender = (int)GetUintFromBytes(ReadExact(stream, 4)); + m.data = new byte[0]; //no data + m.type = 0; + AddMessage(m); + + } + else if(type == 1) + { + //rooms message + }else if(type == 2) + { + //join message + }else if(type == 3) + { + //message from client over tcp + } + // Read incomming stream into byte arrary. while ((length = stream.Read(bytes, 0, bytes.Length)) != 0) { @@ -524,9 +596,9 @@ namespace VelNet byte[] buffer = new byte[1024]; while (true) { - string welcome = userid + ":0:Hello"; - byte[] data = Encoding.ASCII.GetBytes(welcome); - udpSocket.SendTo(data, data.Length, SocketFlags.None, RemoteEndPoint); + buffer[0] = 0; + Array.Copy(get_be_bytes((uint)userid), 0, buffer, 1, 4); + udpSocket.SendTo(buffer, 5, SocketFlags.None, RemoteEndPoint); if (udpSocket.Available == 0) { @@ -544,18 +616,27 @@ namespace VelNet { int numReceived = udpSocket.Receive(buffer); - string message = Encoding.UTF8.GetString(buffer, 0, numReceived); - - string[] sections = message.Split(':'); - if (sections[0] == "0") + + if (buffer[0] == 0) { Debug.Log("UDP connected"); + }else if (buffer[0] == 3) + { + //we should get the sender address + byte[] senderBytes = new byte[4]; + Array.Copy(buffer, 1, senderBytes, 0, 4); + uint senderId = GetUintFromBytes(senderBytes); + byte[] messageBytes = new byte[numReceived - 5]; + Array.Copy(buffer, 5, messageBytes, 0, messageBytes.Length); + Message m = new Message(); + m.sender = (int)senderId; + m.data = messageBytes; + m.type = MessageReceiveType.MESSAGE; } - if (sections[0] == "3") - { - HandleMessage(message); - } + + + } } catch (Exception socketException) @@ -607,7 +688,7 @@ namespace VelNet /// Connects to the server with a username /// /// - public static byte[] get_be_bytes(int n) + public static byte[] get_be_bytes(uint n) { return BitConverter.GetBytes(n).Reverse().ToArray(); } @@ -619,15 +700,15 @@ namespace VelNet byte[] uB = Encoding.UTF8.GetBytes(username); byte[] pB = Encoding.UTF8.GetBytes(password); - writer.Write((byte)0); + writer.Write((byte)MessageSendType.LOGIN); writer.Write((byte)uB.Length); writer.Write(uB); writer.Write((byte)pB.Length); writer.Write(pB); SendNetworkMessage(stream.ToArray()); - Join("MyRoom"); + } /// @@ -640,12 +721,30 @@ namespace VelNet BinaryWriter writer = new BinaryWriter(stream); byte[] R = Encoding.UTF8.GetBytes(roomname); - writer.Write((byte)2); + writer.Write((byte)MessageSendType.JOIN_ROOM); writer.Write((byte)R.Length); writer.Write(R); SendNetworkMessage(stream.ToArray()); - SendTo(MessageType.OTHERS, Encoding.UTF8.GetBytes("Hello")); + + + + } + + public static void FormGroup(string groupname, List client_ids) + { + MemoryStream stream = new MemoryStream(); + BinaryWriter writer = new BinaryWriter(stream); + byte[] R = Encoding.UTF8.GetBytes(groupname); + writer.Write((byte)MessageSendType.FORM_GROUP); + writer.Write((byte)R.Length); + writer.Write(R); + writer.Write(get_be_bytes((uint)client_ids.Count*4)); + for(int i = 0; i < client_ids.Count; i++) + { + writer.Write(get_be_bytes(client_ids[i])); + } + SendNetworkMessage(stream.ToArray()); } /// @@ -656,13 +755,13 @@ namespace VelNet //if (InRoom) SendNetworkMessage("2:-1"); } - public static void SendTo(MessageType type, byte[] message, bool reliable = true) + public static void SendTo(MessageSendType type, byte[] message, bool reliable = true) { MemoryStream stream = new MemoryStream(); BinaryWriter writer = new BinaryWriter(stream); writer.Write((byte)3); - writer.Write(get_be_bytes(message.Length)); + writer.Write(get_be_bytes((uint)message.Length)); writer.Write(message); if (reliable) @@ -677,7 +776,7 @@ namespace VelNet } } - public static void SendTo(MessageType type, string message, bool reliable = true) + public static void SendTo(MessageSendType type, string message, bool reliable = true) { if (reliable) { @@ -689,6 +788,29 @@ namespace VelNet } } + public static void SendToGroup(string group, byte[] message, bool reliable = true) + { + MemoryStream stream = new MemoryStream(); + BinaryWriter writer = new BinaryWriter(stream); + + writer.Write((byte)MessageSendType.MESSAGE_GROUP); + writer.Write(get_be_bytes((uint)message.Length)); + writer.Write(message); + writer.Write((byte)group.Length); + writer.Write(Encoding.UTF8.GetBytes(group)); + + if (reliable) + { + SendNetworkMessage(stream.ToArray()); + + //SendNetworkMessage("3:" + (int)type + ":" + message); + } + else + { + //SendUdpMessage(instance.userid + ":3:" + (int)type + ":" + message); + } + } + public static void SendToGroup(string group, string message, bool reliable = true) { if (reliable) @@ -738,7 +860,7 @@ namespace VelNet 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); + SendTo(MessageSendType.MESSAGE_OTHERS, "7," + newObject.networkId + "," + prefabName); return newObject; } @@ -797,7 +919,7 @@ namespace VelNet 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); + SendTo(MessageSendType.MESSAGE_ALL, "6," + networkId); return true; } From e94ee146e5161c4cd6fac4e20e70de72af28874f Mon Sep 17 00:00:00 2001 From: Kyle Johnsen Date: Wed, 19 Jan 2022 00:30:37 -0500 Subject: [PATCH 05/14] Mostly working, except for dissonance speech --- .../VelNet/1.0.4/Example/NetworkGUI.cs | 6 +- .../VelNet/1.0.4/Example/PlayerPrefab.prefab | 6 +- .../Samples/VelNet/1.0.4/Example/test.unity | 12 +- .../Runtime/VelNetBinaryManager.cs | 927 ------------------ .../Runtime/VelNetBinaryManager.cs.meta | 11 - .../VelNetUnity/Runtime/VelNetManager.cs | 752 +++++++------- .../VelNetUnity/Runtime/VelNetManager.cs.meta | 2 +- .../VelNetUnity/Runtime/VelNetPlayer.cs | 24 +- .../ProjectSettings/EditorBuildSettings.asset | 4 +- 9 files changed, 454 insertions(+), 1290 deletions(-) delete mode 100644 TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetBinaryManager.cs delete mode 100644 TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetBinaryManager.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 f009324..53f4d1e 100644 --- a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/NetworkGUI.cs +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/NetworkGUI.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Text; using Dissonance; using UnityEngine; using UnityEngine.Serialization; @@ -21,7 +22,7 @@ namespace VelNet { if (sendInput.text != "") { - VelNetManager.SendTo(VelNetManager.MessageType.OTHERS, sendInput.text); + VelNetManager.SendToRoom(Encoding.UTF8.GetBytes(sendInput.text)); } } @@ -51,6 +52,8 @@ namespace VelNet { comms = FindObjectOfType(); microphones.AddOptions(new List(Microphone.devices)); + + /* todo VelNetManager.MessageReceived += (m) => { string s = m.type + ":" + m.sender + ":" + m.text; @@ -68,6 +71,7 @@ namespace VelNet messages.text = messages.text + msg + "\n"; } }; + */ } public void handleMicrophoneSelection() 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 8c7fb3c..2d9733f 100644 --- a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/PlayerPrefab.prefab +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/PlayerPrefab.prefab @@ -163,7 +163,5 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: networkObject: {fileID: 9102273340480352682} - serializationRateHz: 30 - targetPosition: {x: 0, y: 0, z: 0} - targetRotation: {x: 0, y: 0, z: 0, w: 0} - smoothness: 0.1 + serializationRateHz: 1 + useLocalTransform: 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 a31295b..34763ce 100644 --- a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test.unity +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test.unity @@ -2238,18 +2238,18 @@ MonoBehaviour: m_GameObject: {fileID: 1099803612} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 03a4d4e1a7fd74c7ab2eccca4ce168db, type: 3} + m_Script: {fileID: 11500000, guid: 233344de094f11341bdb834d564708dc, type: 3} m_Name: m_EditorClassIdentifier: - host: velnet.ugavel.com - port: 3290 + host: 127.0.0.1 + port: 80 udpConnected: 0 userid: -1 room: connected: 0 prefabs: - - {fileID: 3951900052977689805, guid: 6e4a023f70e01405e8b249a4488fe319, type: 3} - {fileID: 9102273340480352682, guid: d4158ab9c4a204cdbba28d3273fc1fb3, type: 3} + - {fileID: 3951900052977689805, guid: 6e4a023f70e01405e8b249a4488fe319, type: 3} sceneObjects: [] deletedSceneObjects: [] --- !u!1 &1154194181 @@ -3961,6 +3961,10 @@ PrefabInstance: propertyPath: isSceneObject value: 1 objectReference: {fileID: 0} + - target: {fileID: 8565720275311462452, guid: 6e4a023f70e01405e8b249a4488fe319, type: 3} + propertyPath: serializationRateHz + value: 1 + objectReference: {fileID: 0} - target: {fileID: 8565720275311462453, guid: 6e4a023f70e01405e8b249a4488fe319, type: 3} propertyPath: m_Name value: TestNetworkedGameObject diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetBinaryManager.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetBinaryManager.cs deleted file mode 100644 index 4671de8..0000000 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetBinaryManager.cs +++ /dev/null @@ -1,927 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Net.Sockets; -using System.Text; -using System.Threading; -using UnityEngine; -using System.Net; -using UnityEngine.SceneManagement; -using System.Runtime.Serialization.Formatters.Binary; -using System.Runtime.Serialization; -using System.IO; - -namespace VelNet -{ - [AddComponentMenu("VelNet/VelNet Manager")] - public class VelNetBinaryManager : MonoBehaviour - { - public enum MessageSendType - { - LOGIN = 0, - GET_ROOMS = 1, - JOIN_ROOM = 2, - MESSAGE_OTHERS = 3, - MESSAGE_ALL = 4, - MESSAGE_GROUP = 5, - FORM_GROUP = 6 - }; - public enum MessageReceiveType - { - LOGGED_IN = 0, - ROOM_LIST = 1, - CLIENT_JOINED = 2, - MESSAGE = 3 - }; - - public string host; - public int port; - - public static VelNetBinaryManager instance; - - private TcpClient socketConnection; - private Socket udpSocket; - public bool udpConnected; - private IPEndPoint RemoteEndPoint; - private Thread clientReceiveThread; - private Thread clientReceiveThreadUDP; - public int userid = -1; - public string room; - private int messagesReceived = 0; - - public readonly Dictionary players = new Dictionary(); - - /// - /// We just joined a room - /// string - the room name - /// - public static Action OnJoinedRoom; - - /// - /// We just left a room - /// string - the room name we left - /// - public static Action OnLeftRoom; - - /// - /// Somebody else just joined our room - /// - public static Action OnPlayerJoined; - - /// - /// Somebody else just left our room - /// - public static Action OnPlayerLeft; - - public static Action OnConnectedToServer; - public static Action MessageReceived; - public static Action LoggedIn; - public static Action RoomsReceived; - - public bool connected; - - public List prefabs = new List(); - public NetworkObject[] sceneObjects; - public List deletedSceneObjects = new List(); - - /// - /// Maintains a list of all known objects on the server (ones that have ids) - /// - public readonly Dictionary objects = new Dictionary(); - - /// - /// Maintains a list of all known groups on the server - /// - public readonly Dictionary> groups = new Dictionary>(); - - private VelNetPlayer masterPlayer; - public static VelNetPlayer LocalPlayer => instance.players.Where(p => p.Value.isLocal).Select(p => p.Value).FirstOrDefault(); - public static bool InRoom => LocalPlayer != null && LocalPlayer.room != "-1" && LocalPlayer.room != ""; - - - // Use this for initialization - public class Message - { - public MessageReceiveType type; - //public string text; - public byte[] data; - public int sender; - } - - - - public readonly List receivedMessages = new List(); - - private void Awake() - { - if (instance != null) - { - Debug.LogError("Multiple NetworkManagers detected! Bad!", this); - } - - instance = this; - - SceneManager.sceneLoaded += (scene, mode) => - { - // add all local network objects - sceneObjects = FindObjectsOfType().Where(o => o.isSceneObject).ToArray(); - }; - } - - private IEnumerator Start() - { - ConnectToTcpServer(); - yield return null; - - try - { - OnConnectedToServer?.Invoke(); - } - // prevent errors in subscribers from breaking our code - catch (Exception e) - { - Debug.LogError(e); - } - } - - - private void AddMessage(Message m) - { - lock (receivedMessages) - { - //Debug.Log(messagesReceived++); - receivedMessages.Add(m); - } - } - - private void Update() - { - lock (receivedMessages) - { - //the main thread, which can do Unity stuff - foreach (Message m in receivedMessages) - { - switch (m.type) - { - // when you join the server - case 0: - userid = m.sender; - Debug.Log("joined server " + userid); - - try - { - LoggedIn?.Invoke(); - } - // prevent errors in subscribers from breaking our code - catch (Exception e) - { - Debug.LogError(e); - } - - //start the udp thread - clientReceiveThreadUDP = new Thread(ListenForDataUDP); - clientReceiveThreadUDP.IsBackground = true; - clientReceiveThreadUDP.Start(); - break; - /* - // if this message is for me, that means I joined a new room... - case 2 when userid == m.sender: - { - string oldRoom = LocalPlayer?.room; - - // we clear the list, but will recreate as we get messages from people in our room - players.Clear(); - masterPlayer = null; - - if (m.text != "") - { - VelNetPlayer player = new VelNetPlayer - { - isLocal = true, - userid = m.sender, - room = m.text - }; - - players.Add(userid, player); - if (m.text != "") - { - try - { - OnJoinedRoom?.Invoke(m.text); - } - // prevent errors in subscribers from breaking our code - catch (Exception e) - { - Debug.LogError(e); - } - } - } - // we just left a room - else - { - // delete all networkobjects that aren't sceneobjects or are null now - objects - .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) - { - SetupMessageGroup(group, new List()); - } - - instance.groups.Clear(); - - try - { - OnLeftRoom?.Invoke(oldRoom); - } - // prevent errors in subscribers from breaking our code - catch (Exception e) - { - Debug.LogError(e); - } - } - - break; - } - // not for me, a player is joining or leaving - case 2: - { - VelNetPlayer me = players[userid]; - - if (me.room != m.text) - { - // we got a left message, kill it - // change ownership of all objects to master - List deleteObjects = new List(); - foreach (KeyValuePair kvp in objects) - { - if (kvp.Value.owner == players[m.sender]) // the owner is the player that left - { - // if this object has locked ownership, delete it - if (kvp.Value.ownershipLocked) - { - deleteObjects.Add(kvp.Value.networkId); - } - // I'm the local master player, so can take ownership immediately - else if (me.isLocal && me == masterPlayer) - { - 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) - { - kvp.Value.owner = null; - } - } - } - - // TODO this may check for ownership in the future. We don't need ownership here - deleteObjects.ForEach(NetworkDestroy); - - players.Remove(m.sender); - } - else - { - // we got a join message, create it - VelNetPlayer player = new VelNetPlayer - { - isLocal = false, - room = m.text, - userid = m.sender - }; - players.Add(m.sender, player); - try - { - OnPlayerJoined?.Invoke(player); - } - // prevent errors in subscribers from breaking our code - catch (Exception e) - { - Debug.LogError(e); - } - } - - break; - } - // generic message - case 3: - if (players.ContainsKey(m.sender)) - { - players[m.sender]?.HandleMessage(m); - } - else - { - Debug.LogError("Received message from player that doesn't exist: " + m.text); - } - - break; - // change master player (this should only happen when the first player joins or if the master player leaves) - case 4: - { - if (masterPlayer == null) - { - masterPlayer = players[m.sender]; - - // no master player yet, add the scene objects - - for (int i = 0; i < sceneObjects.Length; i++) - { - sceneObjects[i].networkId = -1 + "-" + i; - sceneObjects[i].owner = masterPlayer; - sceneObjects[i].isSceneObject = true; // needed for special handling when deleted - objects.Add(sceneObjects[i].networkId, sceneObjects[i]); - } - } - else - { - masterPlayer = players[m.sender]; - } - - masterPlayer.SetAsMasterPlayer(); - - // master player should take over any objects that do not have an owner - foreach (KeyValuePair kvp in objects) - { - kvp.Value.owner ??= masterPlayer; - } - - break; - } - */ - } - - MessageReceived?.Invoke(m); - } - - receivedMessages.Clear(); - } - } - - private void OnApplicationQuit() - { - socketConnection.Close(); - } - - /// - /// Setup socket connection. - /// - private void ConnectToTcpServer() - { - try - { - clientReceiveThread = new Thread(ListenForData); - clientReceiveThread.IsBackground = true; - clientReceiveThread.Start(); - } - catch (Exception e) - { - Debug.Log("On client connect exception " + e); - } - } - - private void HandleMessage(string s) // this parses messages from the server, and adds them to a queue to be processed on the main thread - { - /* - // Debug.Log("Received: " + s); - Message m = new Message(); - string[] sections = s.Split(':'); - if (sections.Length <= 0) return; - - int type = int.Parse(sections[0]); - - switch (type) - { - case 0: // logged in message - { - if (sections.Length > 1) - { - m.type = type; - m.sender = int.Parse(sections[1]); - m.text = ""; - AddMessage(m); - } - - break; - } - case 1: // room info message - { - break; - } - case 2: // joined room message - { - if (sections.Length > 2) - { - m.type = 2; - int user_id = int.Parse(sections[1]); - m.sender = user_id; - string new_room = sections[2]; - m.text = new_room; - - AddMessage(m); - } - - break; - } - case 3: // text message - { - if (sections.Length > 2) - { - m.type = 3; - m.sender = int.Parse(sections[1]); - m.text = sections[2]; - AddMessage(m); - } - - break; - } - case 4: // change master client - { - if (sections.Length > 1) - { - m.type = 4; - m.sender = int.Parse(sections[1]); - AddMessage(m); - } - - break; - } - }*/ - } - - /// - /// Runs in background clientReceiveThread; Listens for incomming data. - /// - /// - private byte[] ReadExact(NetworkStream stream, int N) - { - byte[] toReturn = new byte[N]; - - int numRead = 0; - int numLeft = N; - while (numLeft > 0) - { - numRead += stream.Read(toReturn, numRead, numLeft); - numLeft = N - numRead; - } - return toReturn; - } - - private uint GetUintFromBytes(byte[] bytes) - { - if (BitConverter.IsLittleEndian) - { - return BitConverter.ToUInt32(bytes.Reverse().ToArray(),0); - } - else - { - return BitConverter.ToUInt32(bytes, 0); - } - } - private void ListenForData() - { - connected = true; - try - { - socketConnection = new TcpClient(host, port); - socketConnection.NoDelay = true; - byte[] bytes = new byte[1024]; - - Login("Kyle", "Johnsen"); - //Join("MyRoom"); - //SendTo(MessageSendType.MESSAGE_OTHERS, Encoding.UTF8.GetBytes("Hello")); - //FormGroup("close", new List { 1 }); - //SendToGroup("close", Encoding.UTF8.GetBytes("HelloGroup")); - while (true) - { - - // Get a stream object for reading - using NetworkStream stream = socketConnection.GetStream(); - int length; - - //read a byte - byte type = (byte)stream.ReadByte(); - - if(type == 0) - { - //read the id (this is my network id) - - Message m = new Message(); - m.sender = (int)GetUintFromBytes(ReadExact(stream, 4)); - m.data = new byte[0]; //no data - m.type = 0; - AddMessage(m); - - } - else if(type == 1) - { - //rooms message - }else if(type == 2) - { - //join message - }else if(type == 3) - { - //message from client over tcp - } - - // Read incomming stream into byte arrary. - while ((length = stream.Read(bytes, 0, bytes.Length)) != 0) - { - Debug.Log("read " + length + " bytes!"); - string t = ""; - for(int i = 0; i < length; i++) - { - t = t + "," + bytes[i]; - } - Debug.Log(t); - //byte[] incommingData = new byte[length]; - //Array.Copy(bytes, 0, incommingData, 0, length); - //// Convert byte array to string message. - //string serverMessage = Encoding.ASCII.GetString(incommingData); - //string[] sections = serverMessage.Split('\n'); - //if (sections.Length > 1) - //{ - // lock (receivedMessages) - // { - // for (int i = 0; i < sections.Length - 1; i++) - // { - // if (i == 0) - // { - // HandleMessage(partialMessage + sections[0]); - // partialMessage = ""; - // } - // else - // { - // HandleMessage(sections[i]); - // } - // } - // } - //} - - //partialMessage = partialMessage + sections[sections.Length - 1]; - } - } - } - - - catch (Exception socketException) - { - Debug.Log("Socket exception: " + socketException); - } - - connected = false; - } - - private void ListenForDataUDP() - { - //I don't yet have a UDP connection - try - { - IPAddress[] addresses = Dns.GetHostAddresses(host); - Debug.Assert(addresses.Length > 0); - RemoteEndPoint = new IPEndPoint(addresses[0], port); - - - udpSocket = new Socket(AddressFamily.InterNetwork, - SocketType.Dgram, ProtocolType.Udp); - - - udpConnected = false; - byte[] buffer = new byte[1024]; - while (true) - { - buffer[0] = 0; - Array.Copy(get_be_bytes((uint)userid), 0, buffer, 1, 4); - udpSocket.SendTo(buffer, 5, SocketFlags.None, RemoteEndPoint); - - if (udpSocket.Available == 0) - { - Thread.Sleep(100); - Debug.Log("Waiting for UDP response"); - } - else - { - break; - } - } - - udpConnected = true; - while (true) - { - int numReceived = udpSocket.Receive(buffer); - - - if (buffer[0] == 0) - { - Debug.Log("UDP connected"); - }else if (buffer[0] == 3) - { - //we should get the sender address - byte[] senderBytes = new byte[4]; - Array.Copy(buffer, 1, senderBytes, 0, 4); - uint senderId = GetUintFromBytes(senderBytes); - byte[] messageBytes = new byte[numReceived - 5]; - Array.Copy(buffer, 5, messageBytes, 0, messageBytes.Length); - Message m = new Message(); - m.sender = (int)senderId; - m.data = messageBytes; - m.type = MessageReceiveType.MESSAGE; - } - - - - - } - } - catch (Exception socketException) - { - Debug.Log("Socket exception: " + socketException); - } - } - - private static void SendUdpMessage(string message) - { - if (instance.udpSocket == null || !instance.udpConnected) - { - return; - } - - byte[] data = Encoding.UTF8.GetBytes(message); - //Debug.Log("Attempting to send: " + message); - instance.udpSocket.SendTo(data, data.Length, SocketFlags.None, instance.RemoteEndPoint); - } - - /// - /// Send message to server using socket connection. - /// - private static void SendNetworkMessage(byte[] message) - { - // Debug.Log("Sent: " + clientMessage); - if (instance.socketConnection == null) - { - return; - } - - try - { - // Get a stream object for writing. - NetworkStream stream = instance.socketConnection.GetStream(); - if (stream.CanWrite) - { - - stream.Write(message,0,message.Length); - } - } - catch (SocketException socketException) - { - Debug.Log("Socket exception: " + socketException); - } - } - - /// - /// Connects to the server with a username - /// - /// - public static byte[] get_be_bytes(uint n) - { - return BitConverter.GetBytes(n).Reverse().ToArray(); - } - public static void Login(string username, string password) - { - - MemoryStream stream = new MemoryStream(); - BinaryWriter writer = new BinaryWriter(stream); - - byte[] uB = Encoding.UTF8.GetBytes(username); - byte[] pB = Encoding.UTF8.GetBytes(password); - writer.Write((byte)MessageSendType.LOGIN); - writer.Write((byte)uB.Length); - writer.Write(uB); - writer.Write((byte)pB.Length); - writer.Write(pB); - - SendNetworkMessage(stream.ToArray()); - - - } - - /// - /// Joins a room by name - /// - /// The name of the room to join - public static void Join(string roomname) - { - MemoryStream stream = new MemoryStream(); - BinaryWriter writer = new BinaryWriter(stream); - - byte[] R = Encoding.UTF8.GetBytes(roomname); - writer.Write((byte)MessageSendType.JOIN_ROOM); - writer.Write((byte)R.Length); - writer.Write(R); - SendNetworkMessage(stream.ToArray()); - - - - - } - - public static void FormGroup(string groupname, List client_ids) - { - MemoryStream stream = new MemoryStream(); - BinaryWriter writer = new BinaryWriter(stream); - byte[] R = Encoding.UTF8.GetBytes(groupname); - writer.Write((byte)MessageSendType.FORM_GROUP); - writer.Write((byte)R.Length); - writer.Write(R); - writer.Write(get_be_bytes((uint)client_ids.Count*4)); - for(int i = 0; i < client_ids.Count; i++) - { - writer.Write(get_be_bytes(client_ids[i])); - } - SendNetworkMessage(stream.ToArray()); - } - - /// - /// Leaves a room if we're in one - /// - public static void Leave() - { - //if (InRoom) SendNetworkMessage("2:-1"); - } - - public static void SendTo(MessageSendType type, byte[] message, bool reliable = true) - { - MemoryStream stream = new MemoryStream(); - BinaryWriter writer = new BinaryWriter(stream); - - writer.Write((byte)3); - writer.Write(get_be_bytes((uint)message.Length)); - writer.Write(message); - - if (reliable) - { - SendNetworkMessage(stream.ToArray()); - - //SendNetworkMessage("3:" + (int)type + ":" + message); - } - else - { - SendUdpMessage(instance.userid + ":3:" + (int)type + ":" + message); - } - } - - public static void SendTo(MessageSendType type, string message, bool reliable = true) - { - if (reliable) - { - //SendNetworkMessage("3:" + (int)type + ":" + message); - } - else - { - SendUdpMessage(instance.userid + ":3:" + (int)type + ":" + message); - } - } - - public static void SendToGroup(string group, byte[] message, bool reliable = true) - { - MemoryStream stream = new MemoryStream(); - BinaryWriter writer = new BinaryWriter(stream); - - writer.Write((byte)MessageSendType.MESSAGE_GROUP); - writer.Write(get_be_bytes((uint)message.Length)); - writer.Write(message); - writer.Write((byte)group.Length); - writer.Write(Encoding.UTF8.GetBytes(group)); - - if (reliable) - { - SendNetworkMessage(stream.ToArray()); - - //SendNetworkMessage("3:" + (int)type + ":" + message); - } - else - { - //SendUdpMessage(instance.userid + ":3:" + (int)type + ":" + message); - } - } - - public static void SendToGroup(string group, string message, bool reliable = true) - { - if (reliable) - { - //SendNetworkMessage("4:" + group + ":" + message); - } - else - { - SendUdpMessage(instance.userid + ":4:" + group + ":" + message); - } - } - - /// - /// changes the designated group that sendto(4) will go to - /// - public static void SetupMessageGroup(string groupName, List userIds) - { - if (userIds.Count > 0) - { - instance.groups[groupName] = userIds.ToList(); - } - - //SendNetworkMessage($"5:{groupName}:{string.Join(":", userIds)}"); - } - - - 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 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 = 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(MessageSendType.MESSAGE_OTHERS, "7," + newObject.networkId + "," + prefabName); - - return newObject; - } - - public static void SomebodyInstantiatedNetworkObject(string networkId, string prefabName, VelNetPlayer owner) - { - NetworkObject prefab = instance.prefabs.Find(p => p.name == prefabName); - if (prefab == null) return; - NetworkObject newObject = Instantiate(prefab); - newObject.networkId = networkId; - newObject.prefabName = prefabName; - newObject.owner = owner; - 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) - { - instance.objects.Remove(networkId); - return; - } - if (obj.isSceneObject) - { - instance.deletedSceneObjects.Add(networkId); - } - - Destroy(obj.gameObject); - 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(MessageSendType.MESSAGE_ALL, "6," + networkId); - - return true; - } - } -} \ No newline at end of file diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetBinaryManager.cs.meta b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetBinaryManager.cs.meta deleted file mode 100644 index 014ff23..0000000 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetBinaryManager.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 233344de094f11341bdb834d564708dc -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs index 71ea086..546fe36 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs @@ -8,18 +8,24 @@ using System.Threading; using UnityEngine; using System.Net; using UnityEngine.SceneManagement; +using System.Runtime.Serialization.Formatters.Binary; +using System.Runtime.Serialization; +using System.IO; namespace VelNet { [AddComponentMenu("VelNet/VelNet Manager")] public class VelNetManager : MonoBehaviour { - public enum MessageType + public enum MessageSendType { - OTHERS = 0, - ALL = 1, - OTHERS_ORDERED = 2, - ALL_ORDERED = 3 + MESSAGE_LOGIN = 0, + MESSAGE_GETROOMS = 1, + MESSAGE_JOINROOM = 2, + MESSAGE_OTHERS = 3, + MESSAGE_ALL = 4, + MESSAGE_GROUP = 5, + MESSAGE_SETGROUP = 6 }; public string host; @@ -62,7 +68,6 @@ namespace VelNet public static Action OnPlayerLeft; public static Action OnConnectedToServer; - public static Action MessageReceived; public static Action LoggedIn; public static Action RoomsReceived; @@ -87,12 +92,40 @@ namespace VelNet public static bool InRoom => LocalPlayer != null && LocalPlayer.room != "-1" && LocalPlayer.room != ""; + //this is for sending udp packets + static byte[] toSend = new byte[1024]; + // Use this for initialization - public class Message + public abstract class Message { - public int type; - public string text; - public int sender; + + } + public class ListedRoom + { + public string name; + public int numUsers; + } + public class LoginMessage: Message + { + public int userId; + } + public class RoomsMessage: Message + { + public List rooms; + } + public class JoinMessage: Message + { + public int userId; + public string room; + } + public class DataMessage: Message + { + public int senderId; + public byte[] data; + } + public class ChangeMasterMessage: Message + { + public int masterId; } public readonly List receivedMessages = new List(); @@ -109,7 +142,7 @@ namespace VelNet SceneManager.sceneLoaded += (scene, mode) => { // add all local network objects - sceneObjects = FindObjectsOfType().Where(o=>o.isSceneObject).ToArray(); + sceneObjects = FindObjectsOfType().Where(o => o.isSceneObject).ToArray(); }; } @@ -146,200 +179,206 @@ namespace VelNet //the main thread, which can do Unity stuff foreach (Message m in receivedMessages) { - switch (m.type) + switch (m) { - // when you join the server - case 0: - userid = m.sender; - Debug.Log("joined server"); - - try + case LoginMessage lm: { - LoggedIn?.Invoke(); - } - // prevent errors in subscribers from breaking our code - catch (Exception e) - { - Debug.LogError(e); - } - - //start the udp thread - clientReceiveThreadUDP = new Thread(ListenForDataUDP); - clientReceiveThreadUDP.IsBackground = true; - clientReceiveThreadUDP.Start(); - break; - // if this message is for me, that means I joined a new room... - case 2 when userid == m.sender: - { - string oldRoom = LocalPlayer?.room; - - // we clear the list, but will recreate as we get messages from people in our room - players.Clear(); - masterPlayer = null; - - if (m.text != "") - { - VelNetPlayer player = new VelNetPlayer - { - isLocal = true, - userid = m.sender, - room = m.text - }; - - players.Add(userid, player); - if (m.text != "") - { - try - { - OnJoinedRoom?.Invoke(m.text); - } - // prevent errors in subscribers from breaking our code - catch (Exception e) - { - Debug.LogError(e); - } - } - } - // we just left a room - else - { - // delete all networkobjects that aren't sceneobjects or are null now - objects - .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) - { - SetupMessageGroup(group, new List()); - } - - instance.groups.Clear(); + userid = lm.userId; + Debug.Log("joined server " + userid); try { - OnLeftRoom?.Invoke(oldRoom); + LoggedIn?.Invoke(); } // prevent errors in subscribers from breaking our code catch (Exception e) { Debug.LogError(e); } + + //start the udp thread + clientReceiveThreadUDP = new Thread(ListenForDataUDP); + clientReceiveThreadUDP.IsBackground = true; + clientReceiveThreadUDP.Start(); + + break; } + case RoomsMessage rm: { + Debug.Log("Got Rooms Message"); + + break; + } + case JoinMessage jm: { + if(userid == jm.userId) //this is us + { + string oldRoom = LocalPlayer?.room; - break; - } - // not for me, a player is joining or leaving - case 2: - { - VelNetPlayer me = players[userid]; + // we clear the list, but will recreate as we get messages from people in our room + players.Clear(); + masterPlayer = null; - if (me.room != m.text) - { - // we got a left message, kill it - // change ownership of all objects to master - List deleteObjects = new List(); + if (jm.room != "") + { + VelNetPlayer player = new VelNetPlayer + { + isLocal = true, + userid = jm.userId, + room = jm.room + }; + + players.Add(userid, player); + + try + { + OnJoinedRoom?.Invoke(jm.room); + } + // prevent errors in subscribers from breaking our code + catch (Exception e) + { + Debug.LogError(e); + } + + } + // we just left a room + else + { + // delete all networkobjects that aren't sceneobjects or are null now + objects + .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) + { + SetupMessageGroup(group, new List()); + } + + instance.groups.Clear(); + + try + { + OnLeftRoom?.Invoke(oldRoom); + } + // prevent errors in subscribers from breaking our code + catch (Exception e) + { + Debug.LogError(e); + } + } + } + else + { + VelNetPlayer me = players[userid]; + + if (me.room != jm.room) + { + // we got a left message, kill it + // change ownership of all objects to master + List deleteObjects = new List(); + foreach (KeyValuePair kvp in objects) + { + if (kvp.Value.owner == players[jm.userId]) // the owner is the player that left + { + // if this object has locked ownership, delete it + if (kvp.Value.ownershipLocked) + { + deleteObjects.Add(kvp.Value.networkId); + } + // I'm the local master player, so can take ownership immediately + else if (me.isLocal && me == masterPlayer) + { + TakeOwnership(kvp.Key); + } + // the master player left, so everyone should set the owner null (we should get a new master shortly) + else if (players[jm.userId] == masterPlayer) + { + kvp.Value.owner = null; + } + } + } + + // TODO this may check for ownership in the future. We don't need ownership here + deleteObjects.ForEach(NetworkDestroy); + + players.Remove(jm.userId); + } + else + { + // we got a join message, create it + VelNetPlayer player = new VelNetPlayer + { + isLocal = false, + room = jm.room, + userid = jm.userId + }; + players.Add(jm.userId, player); + try + { + OnPlayerJoined?.Invoke(player); + } + // prevent errors in subscribers from breaking our code + catch (Exception e) + { + Debug.LogError(e); + } + } + } + break; + + } + case DataMessage dm: { + if (players.ContainsKey(dm.senderId)) + { + players[dm.senderId]?.HandleMessage(dm); //todo + } + else + { + Debug.LogError("Received message from player that doesn't exist "); + } + + break; + + + } + case ChangeMasterMessage cm: { + + if (masterPlayer == null) + { + masterPlayer = players[cm.masterId]; + + // no master player yet, add the scene objects + + for (int i = 0; i < sceneObjects.Length; i++) + { + sceneObjects[i].networkId = -1 + "-" + i; + sceneObjects[i].owner = masterPlayer; + sceneObjects[i].isSceneObject = true; // needed for special handling when deleted + objects.Add(sceneObjects[i].networkId, sceneObjects[i]); + } + } + else + { + masterPlayer = players[cm.masterId]; + } + + masterPlayer.SetAsMasterPlayer(); + + // master player should take over any objects that do not have an owner foreach (KeyValuePair kvp in objects) { - if (kvp.Value.owner == players[m.sender]) // the owner is the player that left - { - // if this object has locked ownership, delete it - if (kvp.Value.ownershipLocked) - { - deleteObjects.Add(kvp.Value.networkId); - } - // I'm the local master player, so can take ownership immediately - else if (me.isLocal && me == masterPlayer) - { - 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) - { - kvp.Value.owner = null; - } - } + kvp.Value.owner ??= masterPlayer; } - // TODO this may check for ownership in the future. We don't need ownership here - deleteObjects.ForEach(NetworkDestroy); - - players.Remove(m.sender); + break; + } - else - { - // we got a join message, create it - VelNetPlayer player = new VelNetPlayer - { - isLocal = false, - room = m.text, - userid = m.sender - }; - players.Add(m.sender, player); - try - { - OnPlayerJoined?.Invoke(player); - } - // prevent errors in subscribers from breaking our code - catch (Exception e) - { - Debug.LogError(e); - } - } - - break; - } - // generic message - case 3: - if (players.ContainsKey(m.sender)) - { - players[m.sender]?.HandleMessage(m); - } - else - { - Debug.LogError("Received message from player that doesn't exist: " + m.text); - } - - break; - // change master player (this should only happen when the first player joins or if the master player leaves) - case 4: - { - if (masterPlayer == null) - { - masterPlayer = players[m.sender]; - - // no master player yet, add the scene objects - - for (int i = 0; i < sceneObjects.Length; i++) - { - sceneObjects[i].networkId = -1 + "-" + i; - sceneObjects[i].owner = masterPlayer; - sceneObjects[i].isSceneObject = true; // needed for special handling when deleted - objects.Add(sceneObjects[i].networkId, sceneObjects[i]); - } - } - else - { - masterPlayer = players[m.sender]; - } - - masterPlayer.SetAsMasterPlayer(); - - // master player should take over any objects that do not have an owner - foreach (KeyValuePair kvp in objects) - { - kvp.Value.owner ??= masterPlayer; - } - - break; - } } - - MessageReceived?.Invoke(m); + + //MessageReceived?.Invoke(m); } receivedMessages.Clear(); @@ -368,77 +407,36 @@ namespace VelNet } } - private void HandleMessage(string s) // this parses messages from the server, and adds them to a queue to be processed on the main thread - { - // Debug.Log("Received: " + s); - Message m = new Message(); - string[] sections = s.Split(':'); - if (sections.Length <= 0) return; - - int type = int.Parse(sections[0]); - - switch (type) - { - case 0: // logged in message - { - if (sections.Length > 1) - { - m.type = type; - m.sender = int.Parse(sections[1]); - m.text = ""; - AddMessage(m); - } - - break; - } - case 1: // room info message - { - break; - } - case 2: // joined room message - { - if (sections.Length > 2) - { - m.type = 2; - int user_id = int.Parse(sections[1]); - m.sender = user_id; - string new_room = sections[2]; - m.text = new_room; - - AddMessage(m); - } - - break; - } - case 3: // text message - { - if (sections.Length > 2) - { - m.type = 3; - m.sender = int.Parse(sections[1]); - m.text = sections[2]; - AddMessage(m); - } - - break; - } - case 4: // change master client - { - if (sections.Length > 1) - { - m.type = 4; - m.sender = int.Parse(sections[1]); - AddMessage(m); - } - - break; - } - } - } /// /// Runs in background clientReceiveThread; Listens for incomming data. /// + /// + private byte[] ReadExact(NetworkStream stream, int N) + { + byte[] toReturn = new byte[N]; + + int numRead = 0; + int numLeft = N; + while (numLeft > 0) + { + numRead += stream.Read(toReturn, numRead, numLeft); + numLeft = N - numRead; + } + return toReturn; + } + + private int GetIntFromBytes(byte[] bytes) + { + if (BitConverter.IsLittleEndian) + { + return BitConverter.ToInt32(bytes.Reverse().ToArray(),0); + } + else + { + return BitConverter.ToInt32(bytes, 0); + } + } private void ListenForData() { connected = true; @@ -446,41 +444,65 @@ namespace VelNet { socketConnection = new TcpClient(host, port); socketConnection.NoDelay = true; - byte[] bytes = new byte[1024]; - string partialMessage = ""; + NetworkStream stream = socketConnection.GetStream(); + //Join("MyRoom"); + //SendTo(MessageSendType.MESSAGE_OTHERS, Encoding.UTF8.GetBytes("Hello")); + //FormGroup("close", new List { 1 }); + //SendToGroup("close", Encoding.UTF8.GetBytes("HelloGroup")); while (true) { + // Get a stream object for reading - using NetworkStream stream = socketConnection.GetStream(); - int length; - // Read incomming stream into byte arrary. - while ((length = stream.Read(bytes, 0, bytes.Length)) != 0) - { - byte[] incommingData = new byte[length]; - Array.Copy(bytes, 0, incommingData, 0, length); - // Convert byte array to string message. - string serverMessage = Encoding.ASCII.GetString(incommingData); - string[] sections = serverMessage.Split('\n'); - if (sections.Length > 1) - { - lock (receivedMessages) - { - for (int i = 0; i < sections.Length - 1; i++) - { - if (i == 0) - { - HandleMessage(partialMessage + sections[0]); - partialMessage = ""; - } - else - { - HandleMessage(sections[i]); - } - } - } - } + - partialMessage = partialMessage + sections[sections.Length - 1]; + //read a byte + byte type = (byte)stream.ReadByte(); + + if (type == 0) //login + { + LoginMessage m = new LoginMessage(); + m.userId = GetIntFromBytes(ReadExact(stream, 4)); //not really the sender... + AddMessage(m); + } + else if(type == 1) //rooms + { + RoomsMessage m = new RoomsMessage(); + m.rooms = new List(); + int N = GetIntFromBytes(ReadExact(stream, 4)); //the size of the payload + byte[] utf8data = ReadExact(stream, N); + string roomMessage = Encoding.UTF8.GetString(utf8data); + string[] sections = roomMessage.Split(','); + foreach(string s in sections) + { + string[] pieces = s.Split(':'); + ListedRoom lr = new ListedRoom(); + lr.name = pieces[0]; + lr.numUsers = int.Parse(pieces[1]); + m.rooms.Add(lr); + } + AddMessage(m); + } + else if(type == 2) //joined + { + JoinMessage m = new JoinMessage(); + m.userId = GetIntFromBytes(ReadExact(stream, 4)); + int N = stream.ReadByte(); + byte[] utf8data = ReadExact(stream, N); //the room name, encoded as utf-8 + m.room = Encoding.UTF8.GetString(utf8data); + AddMessage(m); + }else if(type == 3) //data + { + DataMessage m = new DataMessage(); + m.senderId = GetIntFromBytes(ReadExact(stream, 4)); + int N = GetIntFromBytes(ReadExact(stream, 4)); //the size of the payload + m.data = ReadExact(stream, N); //the message + AddMessage(m); + } + else if(type == 4) //new master + { + ChangeMasterMessage m = new ChangeMasterMessage(); + m.masterId = (int)GetIntFromBytes(ReadExact(stream, 4)); //sender is the new master + AddMessage(m); } } } @@ -512,9 +534,9 @@ namespace VelNet byte[] buffer = new byte[1024]; while (true) { - string welcome = userid + ":0:Hello"; - byte[] data = Encoding.ASCII.GetBytes(welcome); - udpSocket.SendTo(data, data.Length, SocketFlags.None, RemoteEndPoint); + buffer[0] = 0; + Array.Copy(get_be_bytes(userid), 0, buffer, 1, 4); + udpSocket.SendTo(buffer, 5, SocketFlags.None, RemoteEndPoint); if (udpSocket.Available == 0) { @@ -531,18 +553,20 @@ namespace VelNet while (true) { int numReceived = udpSocket.Receive(buffer); - - string message = Encoding.UTF8.GetString(buffer, 0, numReceived); - - string[] sections = message.Split(':'); - if (sections[0] == "0") + if (buffer[0] == 0) { Debug.Log("UDP connected"); - } - - if (sections[0] == "3") + }else if (buffer[0] == 3) { - HandleMessage(message); + DataMessage m = new DataMessage(); + //we should get the sender address + byte[] senderBytes = new byte[4]; + Array.Copy(buffer, 1, senderBytes, 0, 4); + m.senderId = GetIntFromBytes(senderBytes); + byte[] messageBytes = new byte[numReceived - 5]; + Array.Copy(buffer, 5, messageBytes, 0, messageBytes.Length); + m.data = messageBytes; + AddMessage(m); } } } @@ -552,22 +576,20 @@ namespace VelNet } } - private static void SendUdpMessage(string message) + private static void SendUdpMessage(byte[] message, int N) { if (instance.udpSocket == null || !instance.udpConnected) { return; } - byte[] data = Encoding.UTF8.GetBytes(message); - //Debug.Log("Attempting to send: " + message); - instance.udpSocket.SendTo(data, data.Length, SocketFlags.None, instance.RemoteEndPoint); + instance.udpSocket.SendTo(message, N, SocketFlags.None, instance.RemoteEndPoint); } /// /// Send message to server using socket connection. /// - private static void SendNetworkMessage(string clientMessage) + private static void SendTcpMessage(byte[] message) //we can assume that this message is already formatted, so we just send it { // Debug.Log("Sent: " + clientMessage); if (instance.socketConnection == null) @@ -581,11 +603,8 @@ namespace VelNet NetworkStream stream = instance.socketConnection.GetStream(); if (stream.CanWrite) { - // Convert string message to byte array. - clientMessage += "\n"; // append a new line to delineate the message - byte[] clientMessageAsByteArray = Encoding.ASCII.GetBytes(clientMessage); - // Write byte array to socketConnection stream. - stream.Write(clientMessageAsByteArray, 0, clientMessageAsByteArray.Length); + + stream.Write(message,0,message.Length); } } catch (SocketException socketException) @@ -597,9 +616,28 @@ namespace VelNet /// /// Connects to the server with a username /// + /// + public static byte[] get_be_bytes(int n) + { + return BitConverter.GetBytes(n).Reverse().ToArray(); + } public static void Login(string username, string password) { - SendNetworkMessage("0:" + username + ":" + password); + + MemoryStream stream = new MemoryStream(); + BinaryWriter writer = new BinaryWriter(stream); + + byte[] uB = Encoding.UTF8.GetBytes(username); + byte[] pB = Encoding.UTF8.GetBytes(password); + writer.Write((byte)0); + writer.Write((byte)uB.Length); + writer.Write(uB); + writer.Write((byte)pB.Length); + writer.Write(pB); + + SendTcpMessage(stream.ToArray()); + + } /// @@ -608,52 +646,104 @@ namespace VelNet /// The name of the room to join public static void Join(string roomname) { - SendNetworkMessage("2:" + roomname); + MemoryStream stream = new MemoryStream(); + BinaryWriter writer = new BinaryWriter(stream); + + byte[] R = Encoding.UTF8.GetBytes(roomname); + writer.Write((byte)2); + writer.Write((byte)R.Length); + writer.Write(R); + SendTcpMessage(stream.ToArray()); + + + + } + + /// /// Leaves a room if we're in one /// public static void Leave() { - if (InRoom) SendNetworkMessage("2:-1"); - } - - public static void SendTo(MessageType type, string message, bool reliable = true) - { - if (reliable) + if (InRoom) { - SendNetworkMessage("3:" + (int)type + ":" + message); - } - else - { - SendUdpMessage(instance.userid + ":3:" + (int)type + ":" + message); + Join(""); //super secret way to leave } } - public static void SendToGroup(string group, string message, bool reliable = true) + public static void SendToRoom(byte[] message, bool include_self = false, bool reliable = true) { + byte sendType = (byte)(include_self ? MessageSendType.MESSAGE_ALL : MessageSendType.MESSAGE_OTHERS); if (reliable) { - SendNetworkMessage("4:" + group + ":" + message); + MemoryStream stream = new MemoryStream(); + BinaryWriter writer = new BinaryWriter(stream); + writer.Write(sendType); + writer.Write(get_be_bytes(message.Length)); + writer.Write(message); + SendTcpMessage(stream.ToArray()); } else { - SendUdpMessage(instance.userid + ":4:" + group + ":" + message); + //udp message needs the type + toSend[0] = sendType; //we don't + Array.Copy(get_be_bytes(instance.userid), 0, toSend, 1, 4); + Array.Copy(message, 0, toSend, 5, message.Length); + SendUdpMessage(toSend,message.Length+5); //shouldn't be over 1024... + } + } + + + public static void SendToGroup(string group, byte[] message, bool reliable = true) + { + byte[] utf8bytes = Encoding.UTF8.GetBytes(group); + if (reliable) + { + MemoryStream stream = new MemoryStream(); + BinaryWriter writer = new BinaryWriter(stream); + writer.Write((byte)MessageSendType.MESSAGE_GROUP); + writer.Write(get_be_bytes(message.Length)); + writer.Write(message); + writer.Write((byte)utf8bytes.Length); + writer.Write(utf8bytes); + SendTcpMessage(stream.ToArray()); + } + else + { + toSend[0] = (byte)MessageSendType.MESSAGE_GROUP; + Array.Copy(get_be_bytes(instance.userid), 0, toSend, 1, 4); + //also need to send the group + toSend[5] = (byte)utf8bytes.Length; + Array.Copy(utf8bytes, 0, toSend, 6, utf8bytes.Length); + Array.Copy(message, 0, toSend, 6+utf8bytes.Length, message.Length); + SendUdpMessage(toSend, 6 + utf8bytes.Length + message.Length); } } /// /// changes the designated group that sendto(4) will go to /// - public static void SetupMessageGroup(string groupName, List userIds) + public static void SetupMessageGroup(string groupname, List client_ids) { - if (userIds.Count > 0) + if (client_ids.Count > 0) { - instance.groups[groupName] = userIds.ToList(); + instance.groups[groupname] = client_ids.ToList(); } - SendNetworkMessage($"5:{groupName}:{string.Join(":", userIds)}"); + MemoryStream stream = new MemoryStream(); + BinaryWriter writer = new BinaryWriter(stream); + byte[] R = Encoding.UTF8.GetBytes(groupname); + writer.Write((byte)6); + writer.Write((byte)R.Length); + writer.Write(R); + writer.Write(get_be_bytes(client_ids.Count * 4)); + for (int i = 0; i < client_ids.Count; i++) + { + writer.Write(get_be_bytes(client_ids[i])); + } + SendTcpMessage(stream.ToArray()); } @@ -680,7 +770,7 @@ namespace VelNet 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); + SendToRoom(Encoding.UTF8.GetBytes("7," + newObject.networkId + "," + prefabName),false,true); return newObject; } @@ -718,7 +808,7 @@ namespace VelNet Destroy(obj.gameObject); instance.objects.Remove(networkId); } - + /// /// Takes local ownership of an object by id. /// @@ -728,19 +818,19 @@ namespace VelNet { // 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); - + SendToRoom(Encoding.UTF8.GetBytes("6," + networkId)); + return true; } } diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs.meta b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs.meta index 56f31aa..014ff23 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs.meta +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 03a4d4e1a7fd74c7ab2eccca4ce168db +guid: 233344de094f11341bdb834d564708dc MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetPlayer.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetPlayer.cs index fae5623..c31ab89 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetPlayer.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetPlayer.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System; +using System.Text; namespace VelNet { @@ -41,7 +42,7 @@ namespace VelNet { if (kvp.Value.owner == this && kvp.Value.prefabName != "") { - VelNetManager.SendTo(VelNetManager.MessageType.OTHERS, "7," + kvp.Value.networkId + "," + kvp.Value.prefabName); + VelNetManager.SendToRoom(Encoding.UTF8.GetBytes("7," + kvp.Value.networkId + "," + kvp.Value.prefabName),false,true); } } @@ -56,12 +57,14 @@ namespace VelNet /// /// These are generally things that come from the "owner" and should be enacted locally, where appropriate /// - public void HandleMessage(VelNetManager.Message m) + public void HandleMessage(VelNetManager.DataMessage m) { - //we need to parse the message + //for now, we can just convert to text...because + + string text = Encoding.UTF8.GetString(m.data); //types of messages - string[] messages = m.text.Split(';'); //messages are split by ; + string[] messages = text.Split(';'); //messages are split by ; foreach (string s in messages) { //individual message parameters separated by comma @@ -138,17 +141,20 @@ namespace VelNet public void SendGroupMessage(NetworkObject obj, string group, string identifier, byte[] data, bool reliable = true) { - VelNetManager.SendToGroup(group, "5," + obj.networkId + "," + identifier + "," + Convert.ToBase64String(data), reliable); + string message = "5," + obj.networkId + "," + identifier + "," + Convert.ToBase64String(data); + VelNetManager.SendToGroup(group, Encoding.UTF8.GetBytes(message), reliable); } public void SendMessage(NetworkObject obj, string identifier, byte[] data, bool reliable = true) { - VelNetManager.SendTo(VelNetManager.MessageType.OTHERS, "5," + obj.networkId + "," + identifier + "," + Convert.ToBase64String(data), reliable); + string message = "5," + obj.networkId + "," + identifier + "," + Convert.ToBase64String(data); + VelNetManager.SendToRoom(Encoding.UTF8.GetBytes(message), false, reliable); } public void SendSceneUpdate() { - VelNetManager.SendTo(VelNetManager.MessageType.OTHERS, "9," + string.Join(",", manager.deletedSceneObjects)); + string message = "9," + string.Join(",", manager.deletedSceneObjects); + VelNetManager.SendToRoom( Encoding.UTF8.GetBytes(message)); } [Obsolete("Use VelNetManager.NetworkDestroy() instead.")] @@ -158,7 +164,7 @@ namespace VelNet if (!manager.objects.ContainsKey(networkId) || manager.objects[networkId].owner != this || !isLocal) return; // send to all, which will make me delete as well - VelNetManager.SendTo(VelNetManager.MessageType.ALL_ORDERED, "8," + networkId); + VelNetManager.SendToRoom(Encoding.UTF8.GetBytes("8," + networkId), true, true); } /// True if successful, False if failed to transfer ownership @@ -175,7 +181,7 @@ namespace VelNet 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); + VelNetManager.SendToRoom(Encoding.UTF8.GetBytes("6," + networkId),true,true); return true; } diff --git a/TestVelGameServer/ProjectSettings/EditorBuildSettings.asset b/TestVelGameServer/ProjectSettings/EditorBuildSettings.asset index b07974f..ba9b4aa 100644 --- a/TestVelGameServer/ProjectSettings/EditorBuildSettings.asset +++ b/TestVelGameServer/ProjectSettings/EditorBuildSettings.asset @@ -6,6 +6,6 @@ EditorBuildSettings: serializedVersion: 2 m_Scenes: - enabled: 1 - path: Assets/Samples/VelNet/1.0.4/Example/test_binary.unity - guid: 2e6e0ddeb76e51b46afc0f0a43386ff2 + path: Assets/Samples/VelNet/1.0.4/Example/test.unity + guid: e4e43899246c941c78acfc59ce2f664a m_configObjects: {} From 1be285ce0999195e75920c92de2222bd726a680b Mon Sep 17 00:00:00 2001 From: Kyle Johnsen Date: Wed, 19 Jan 2022 00:54:12 -0500 Subject: [PATCH 06/14] no longer muted and deafened to start --- .../Assets/Samples/VelNet/1.0.4/Example/PlayerPrefab.prefab | 2 +- .../Assets/Samples/VelNet/1.0.4/Example/test.unity | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) 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 2d9733f..843b5b6 100644 --- a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/PlayerPrefab.prefab +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/PlayerPrefab.prefab @@ -149,7 +149,7 @@ MonoBehaviour: networkObject: {fileID: 9102273340480352682} dissonanceID: closePlayers: - maxDistance: 0 + maxDistance: 2 --- !u!114 &7564913803199044469 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 34763ce..a0e4d36 100644 --- a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test.unity +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test.unity @@ -2809,8 +2809,8 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: _lastPrefabError: - _isMuted: 1 - _isDeafened: 1 + _isMuted: 0 + _isDeafened: 0 _oneMinusBaseRemoteVoiceVolume: 0 _playbackPrefab: {fileID: 0} _playbackPrefab2: {fileID: 1041743830464418, guid: 7b8de751a39894b0c8e1cfc9ef961a5b, type: 3} From 9adb458b0fbbbd86b0125cf30235341627f15256 Mon Sep 17 00:00:00 2001 From: Kyle Johnsen Date: Thu, 20 Jan 2022 00:14:30 -0500 Subject: [PATCH 07/14] added a test for the rooms message --- .../VelNet/1.0.4/Example/NetworkGUI.cs | 7 + .../Samples/VelNet/1.0.4/Example/test.unity | 229 +++++++++++++++++- .../VelNetUnity/Runtime/VelNetManager.cs | 22 +- 3 files changed, 245 insertions(+), 13 deletions(-) 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 53f4d1e..be10c99 100644 --- a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/NetworkGUI.cs +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/NetworkGUI.cs @@ -34,6 +34,13 @@ namespace VelNet } } + public void HandleGetRooms() + { + if (VelNetManager.instance.connected) + { + VelNetManager.GetRooms(); + } + } public void HandleJoin() { if (roomInput.text != "") 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 a0e4d36..2c11908 100644 --- a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test.unity +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test.unity @@ -174,7 +174,7 @@ MonoBehaviour: m_HorizontalOverflow: 0 m_VerticalOverflow: 0 m_LineSpacing: 1 - m_Text: User Name + m_Text: Username --- !u!222 &2034438 CanvasRenderer: m_ObjectHideFlags: 0 @@ -305,8 +305,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: 98, y: 138} - m_SizeDelta: {x: 160, y: 38.7538} + m_AnchoredPosition: {x: 227.83, y: 138} + m_SizeDelta: {x: 445.67, y: 38.7538} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &117638566 MonoBehaviour: @@ -422,7 +422,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: -7.5, y: -0.5} + m_AnchoredPosition: {x: -7.4999695, y: -0.5} m_SizeDelta: {x: -35, y: -13} m_Pivot: {x: 0.5, y: 0.5} --- !u!1 &162005663 @@ -606,6 +606,7 @@ RectTransform: - {fileID: 945446556} - {fileID: 1843597586} - {fileID: 948755938} + - {fileID: 545137760} m_Father: {fileID: 0} m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -778,6 +779,139 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 5 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &545137759 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 545137760} + - component: {fileID: 545137763} + - component: {fileID: 545137762} + - component: {fileID: 545137761} + m_Layer: 5 + m_Name: GetRooms + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &545137760 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 545137759} + 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: 1081889596} + m_Father: {fileID: 244561620} + m_RootOrder: 10 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -382, y: -321} + m_SizeDelta: {x: 160, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &545137761 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 545137759} + 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: 545137762} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 244561621} + m_TargetAssemblyTypeName: VelNet.NetworkGUI, Assembly-CSharp + m_MethodName: HandleGetRooms + 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 &545137762 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 545137759} + 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 &545137763 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 545137759} + m_CullTransparentMesh: 1 --- !u!1 &615558651 GameObject: m_ObjectHideFlags: 0 @@ -1842,8 +1976,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: 112.91498, y: 88} - m_SizeDelta: {x: 215.83, y: 30} + m_AnchoredPosition: {x: 181.94519, y: 88} + m_SizeDelta: {x: 353.8904, y: 30} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &945446557 MonoBehaviour: @@ -2184,6 +2318,85 @@ RectTransform: m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 0, y: 28} m_Pivot: {x: 0.5, y: 1} +--- !u!1 &1081889595 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1081889596} + - component: {fileID: 1081889598} + - component: {fileID: 1081889597} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1081889596 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1081889595} + 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: 545137760} + 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 &1081889597 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1081889595} + 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: Get Rooms +--- !u!222 &1081889598 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1081889595} + m_CullTransparentMesh: 1 --- !u!1 &1099803612 GameObject: m_ObjectHideFlags: 0 @@ -3387,7 +3600,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: 273.05, y: 88} + m_AnchoredPosition: {x: 416.95, y: 88} m_SizeDelta: {x: 94.1, y: 30} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &1843597587 @@ -3866,7 +4079,7 @@ MonoBehaviour: m_HorizontalOverflow: 0 m_VerticalOverflow: 0 m_LineSpacing: 1 - m_Text: Join Server + m_Text: Login --- !u!222 &2118429761 CanvasRenderer: m_ObjectHideFlags: 0 diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs index 546fe36..db95c0b 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs @@ -466,19 +466,25 @@ namespace VelNet } else if(type == 1) //rooms { + RoomsMessage m = new RoomsMessage(); m.rooms = new List(); int N = GetIntFromBytes(ReadExact(stream, 4)); //the size of the payload byte[] utf8data = ReadExact(stream, N); string roomMessage = Encoding.UTF8.GetString(utf8data); + + + string[] sections = roomMessage.Split(','); - foreach(string s in sections) + foreach (string s in sections) { string[] pieces = s.Split(':'); - ListedRoom lr = new ListedRoom(); - lr.name = pieces[0]; - lr.numUsers = int.Parse(pieces[1]); - m.rooms.Add(lr); + if (pieces.Length == 2) { + ListedRoom lr = new ListedRoom(); + lr.name = pieces[0]; + lr.numUsers = int.Parse(pieces[1]); + m.rooms.Add(lr); + } } AddMessage(m); } @@ -640,6 +646,12 @@ namespace VelNet } + public static void GetRooms() + { + + SendTcpMessage(new byte[1] { 1 }); //very simple message + } + /// /// Joins a room by name /// From 35f999f77baa10b08c445db2d58f7dae4c2ca34a Mon Sep 17 00:00:00 2001 From: Kyle Johnsen Date: Fri, 21 Jan 2022 08:59:02 -0500 Subject: [PATCH 08/14] fixed connected event, added ordered tcp messages (not group), automatically running login/connect --- .../VelNet/1.0.4/Example/NetworkGUI.cs | 12 +++++ .../VelNetUnity/Runtime/VelNetManager.cs | 46 +++++++++++++------ 2 files changed, 43 insertions(+), 15 deletions(-) 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 be10c99..0a2b7cc 100644 --- a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/NetworkGUI.cs +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/NetworkGUI.cs @@ -1,3 +1,4 @@ +using System.Collections; using System.Collections.Generic; using System.Text; using Dissonance; @@ -79,6 +80,17 @@ namespace VelNet } }; */ + StartCoroutine(testes()); + + + } + IEnumerator testes() + { + yield return new WaitForSeconds(1.0f); + HandleLogin(); + yield return new WaitForSeconds(1.0f); + HandleJoin(); + yield return null; } public void handleMicrophoneSelection() diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs index db95c0b..0e9ae32 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs @@ -19,6 +19,8 @@ namespace VelNet { public enum MessageSendType { + MESSAGE_OTHERS_ORDERED = 7, + MESSAGE_ALL_ORDERED = 8, MESSAGE_LOGIN = 0, MESSAGE_GETROOMS = 1, MESSAGE_JOINROOM = 2, @@ -128,6 +130,11 @@ namespace VelNet public int masterId; } + public class ConnectedMessage: Message + { + + } + public readonly List receivedMessages = new List(); private void Awake() @@ -146,20 +153,9 @@ namespace VelNet }; } - private IEnumerator Start() + private void Start() { ConnectToTcpServer(); - yield return null; - - try - { - OnConnectedToServer?.Invoke(); - } - // prevent errors in subscribers from breaking our code - catch (Exception e) - { - Debug.LogError(e); - } } @@ -181,6 +177,19 @@ namespace VelNet { switch (m) { + case ConnectedMessage connected: + { + try + { + OnConnectedToServer?.Invoke(); + } + // prevent errors in subscribers from breaking our code + catch (Exception e) + { + Debug.LogError(e); + } + break; + } case LoginMessage lm: { userid = lm.userId; @@ -445,6 +454,8 @@ namespace VelNet socketConnection = new TcpClient(host, port); socketConnection.NoDelay = true; NetworkStream stream = socketConnection.GetStream(); + //now we are connected, so add a message to the queue + AddMessage(new ConnectedMessage()); //Join("MyRoom"); //SendTo(MessageSendType.MESSAGE_OTHERS, Encoding.UTF8.GetBytes("Hello")); //FormGroup("close", new List { 1 }); @@ -632,7 +643,7 @@ namespace VelNet MemoryStream stream = new MemoryStream(); BinaryWriter writer = new BinaryWriter(stream); - + byte[] uB = Encoding.UTF8.GetBytes(username); byte[] pB = Encoding.UTF8.GetBytes(password); writer.Write((byte)0); @@ -685,9 +696,14 @@ namespace VelNet } } - public static void SendToRoom(byte[] message, bool include_self = false, bool reliable = true) + public static void SendToRoom(byte[] message, bool include_self = false, bool reliable = true, bool ordered = false) { - byte sendType = (byte)(include_self ? MessageSendType.MESSAGE_ALL : MessageSendType.MESSAGE_OTHERS); + byte sendType = (byte) MessageSendType.MESSAGE_OTHERS; + if (include_self && ordered) sendType = (byte)MessageSendType.MESSAGE_ALL_ORDERED; + if (include_self && !ordered) sendType = (byte)MessageSendType.MESSAGE_ALL; + if (!include_self && ordered) sendType = (byte)MessageSendType.MESSAGE_OTHERS_ORDERED; + + if (reliable) { MemoryStream stream = new MemoryStream(); From e42b4994908a953988cbb521fdd22503de1da20d Mon Sep 17 00:00:00 2001 From: Anton Franzluebbers Date: Mon, 24 Jan 2022 19:18:38 -0500 Subject: [PATCH 09/14] pulled changes from main branch --- .../VelNet/1.0.4/Example/MouseDragger.cs | 18 +-- .../VelNet/1.0.4/Example/PlayerController.cs | 11 +- .../Example/TestNetworkedGameObject.prefab | 7 +- .../VelNetUnity/Runtime/NetworkObject.cs | 39 ++++- .../Runtime/Util/BinaryWriterExtensions.cs | 57 ++++++- .../Util/NetworkSerializedObjectStream.cs | 20 ++- .../VelNetUnity/Runtime/Util/SyncRigidbody.cs | 143 ++++++++++++++++++ .../Runtime/Util/SyncRigidbody.cs.meta | 3 + .../VelNetUnity/Runtime/Util/SyncTransform.cs | 37 +++-- .../VelNetUnity/Runtime/VelNetManager.cs | 44 ++++-- .../VelNetUnity/Runtime/VelNetPlayer.cs | 6 +- .../Packages/VelNetUnity/package.json | 4 +- 12 files changed, 330 insertions(+), 59 deletions(-) create mode 100644 TestVelGameServer/Packages/VelNetUnity/Runtime/Util/SyncRigidbody.cs create mode 100644 TestVelGameServer/Packages/VelNetUnity/Runtime/Util/SyncRigidbody.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 index 6802b65..55cf69a 100644 --- a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/MouseDragger.cs +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/MouseDragger.cs @@ -1,5 +1,3 @@ -using System.Collections; -using System.Collections.Generic; using UnityEngine; using VelNet; @@ -22,13 +20,15 @@ public class MouseDragger : MonoBehaviour { 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; + if (hit.transform.CompareTag(draggableTag) || hit.transform.parent == null || hit.transform.parent.CompareTag(draggableTag)) + { + NetworkObject netObj = hit.transform.GetComponent(); + netObj ??= hit.transform.GetComponentInParent(); + if (netObj == null) break; + netObj.TakeOwnership(); + draggingObject = netObj; + break; + } } } } 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 3420680..e0fda99 100644 --- a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/PlayerController.cs +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/PlayerController.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.IO; +using System.Linq; using UnityEngine; namespace VelNet @@ -36,19 +37,15 @@ namespace VelNet { foreach (KeyValuePair kvp in VelNetManager.instance.objects) { - VelNetManager.TakeOwnership(kvp.Key); + kvp.Value.TakeOwnership(); } } if (Input.GetKeyDown(KeyCode.Backspace)) { - foreach (KeyValuePair kvp in VelNetManager.instance.objects) + foreach (KeyValuePair kvp in VelNetManager.instance.objects.Where(kvp => !kvp.Value.ownershipLocked)) { - // don't destroy player objects - if (!kvp.Value.ownershipLocked) - { - VelNetManager.NetworkDestroy(kvp.Key); - } + VelNetManager.NetworkDestroy(kvp.Key); } } } diff --git a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/TestNetworkedGameObject.prefab b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/TestNetworkedGameObject.prefab index e08d947..f94ea79 100644 --- a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/TestNetworkedGameObject.prefab +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/TestNetworkedGameObject.prefab @@ -47,6 +47,7 @@ MonoBehaviour: m_EditorClassIdentifier: ownershipLocked: 0 networkId: + sceneNetworkId: 0 prefabName: isSceneObject: 0 syncedComponents: @@ -64,10 +65,8 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: networkObject: {fileID: 3951900052977689805} - serializationRateHz: 30 - targetPosition: {x: 0, y: 0, z: 0} - targetRotation: {x: 0, y: 0, z: 0, w: 0} - smoothness: 0.1 + serializationRateHz: 60 + useLocalTransform: 0 --- !u!1 &8565720276181857625 GameObject: m_ObjectHideFlags: 0 diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/NetworkObject.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/NetworkObject.cs index b08e041..5c605ac 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/NetworkObject.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/NetworkObject.cs @@ -18,13 +18,19 @@ namespace VelNet [Tooltip("Whether this object's ownership is transferrable. Should be true for player objects.")] public bool ownershipLocked; - public bool IsMine => owner != null && owner.isLocal; - + public bool IsMine => owner?.isLocal ?? false; + /// /// This is forged from the combination of the creator's id (-1 in the case of a scene object) and an object id, so it's always unique for a room /// public string networkId; + /// + /// This is generated at editor time and used to generated the network id at runtime. + /// This is needed because finding all objects of type at runtime doesn't have a guaranteed order. + /// + public int sceneNetworkId; + /// /// This may be empty if it's not a prefab (scene object) /// @@ -50,7 +56,14 @@ namespace VelNet } int index = syncedComponents.IndexOf(component); - owner.SendMessage(this, index.ToString(), message, reliable); + if (index < 0) + { + Debug.LogError("WAAAAAAAH. NetworkObject doesn't have a reference to this component.", component); + } + else + { + owner.SendMessage(this, index.ToString(), message, reliable); + } } public void SendBytesToGroup(NetworkComponent component, string group, byte[] message, bool reliable = true) @@ -116,6 +129,26 @@ namespace VelNet { c.networkObject = t; } + PrefabUtility.RecordPrefabInstancePropertyModifications(t); + } + + // make the sceneNetworkId a new unique value + if (Application.isEditor && !Application.isPlaying && t.isSceneObject && t.sceneNetworkId == 0) + { + // find the first unused value + int[] used = FindObjectsOfType().Select(o => o.sceneNetworkId).ToArray(); + int available = -1; + for (int i = 1; i <= used.Max()+1; i++) + { + if (!used.Contains(i)) + { + available = i; + break; + } + } + + t.sceneNetworkId = available; + PrefabUtility.RecordPrefabInstancePropertyModifications(t); } EditorGUILayout.Space(); diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/BinaryWriterExtensions.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/BinaryWriterExtensions.cs index f122745..f43524d 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/BinaryWriterExtensions.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/BinaryWriterExtensions.cs @@ -1,4 +1,7 @@ -using System.IO; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; using UnityEngine; namespace VelNet @@ -34,5 +37,57 @@ namespace VelNet reader.ReadSingle() ); } + + /// + /// Compresses the list of bools into bytes using a bitmask + /// + public static byte[] GetBitmasks(this IEnumerable bools) + { + List values = bools.ToList(); + List bytes = new List(); + for (int b = 0; b < Mathf.Ceil(values.Count / 8f); b++) + { + byte currentByte = 0; + for (int bit = 0; bit < 8; bit++) + { + if (values.Count > b * 8 + bit) + { + currentByte |= (byte)((values[b * 8 + bit] ? 1 : 0) << bit); + } + } + + bytes.Add(currentByte); + } + + return bytes.ToArray(); + } + + public static List GetBitmaskValues(this IEnumerable bytes) + { + List l = new List(); + foreach (byte b in bytes) + { + l.AddRange(b.GetBitmaskValues()); + } + + return l; + } + + public static List GetBitmaskValues(this byte b) + { + List l = new List(); + for (int i = 0; i < 8; i++) + { + l.Add(b.GetBitmaskValue(i)); + } + + return l; + } + + public static bool GetBitmaskValue(this byte b, int index) + { + return (b & (1 << index)) != 0; + } + } } \ No newline at end of file diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObjectStream.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObjectStream.cs index a6929f8..161791f 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObjectStream.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObjectStream.cs @@ -1,4 +1,5 @@ -using System.Collections; +using System; +using System.Collections; using System.IO; using UnityEngine; using UnityEngine.Serialization; @@ -19,12 +20,19 @@ namespace VelNet { while (true) { - if (IsMine) + try { - using MemoryStream mem = new MemoryStream(); - using BinaryWriter writer = new BinaryWriter(mem); - SendState(writer); - SendBytes(mem.ToArray()); + if (IsMine) + { + using MemoryStream mem = new MemoryStream(); + using BinaryWriter writer = new BinaryWriter(mem); + SendState(writer); + SendBytes(mem.ToArray()); + } + } + catch (Exception e) + { + Debug.LogError(e); } yield return new WaitForSeconds(1f / serializationRateHz); diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/SyncRigidbody.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/SyncRigidbody.cs new file mode 100644 index 0000000..5937ff4 --- /dev/null +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/SyncRigidbody.cs @@ -0,0 +1,143 @@ +using System.IO; +using UnityEngine; + +namespace VelNet +{ + /// + /// A simple class that will sync the position and rotation of a network object with a rigidbody + /// + [AddComponentMenu("VelNet/VelNet Sync Rigidbody")] + [RequireComponent(typeof(Rigidbody))] + public class SyncRigidbody : NetworkSerializedObjectStream + { + public bool useLocalTransform; + [Tooltip("0 to disable.")] + public float teleportDistance; + [Tooltip("0 to disable.")] + public float teleportAngle; + + public bool syncKinematic = true; + public bool syncGravity = true; + public bool syncVelocity = true; + public bool syncAngularVelocity = true; + + private Vector3 targetPosition; + private Quaternion targetRotation; + private float distanceAtReceiveTime; + private float angleAtReceiveTime; + private Rigidbody rb; + + private void Start() + { + rb = GetComponent(); + 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 + /// + protected override void SendState(BinaryWriter writer) + { + if (useLocalTransform) + { + writer.Write(transform.localPosition); + writer.Write(transform.localRotation); + } + else + { + writer.Write(transform.position); + writer.Write(transform.rotation); + } + + // writer.Write((new bool[] {rb.isKinematic, rb.useGravity}).GetBitmasks()); + if (syncKinematic) writer.Write(rb.isKinematic); + if (syncGravity) writer.Write(rb.useGravity); + if (syncVelocity) writer.Write(rb.velocity); + if (syncAngularVelocity) writer.Write(rb.angularVelocity); + } + + /// + /// This gets called whenever a message about the state of this object is received. + /// Usually at serializationRateHz. + /// + protected override void ReceiveState(BinaryReader reader) + { + targetPosition = reader.ReadVector3(); + targetRotation = reader.ReadQuaternion(); + + if (syncKinematic) rb.isKinematic = reader.ReadBoolean(); + if (syncGravity) rb.useGravity = reader.ReadBoolean(); + if (syncVelocity) rb.velocity = reader.ReadVector3(); + if (syncAngularVelocity) rb.angularVelocity = reader.ReadVector3(); + + // record the distance from the target for interpolation + if (useLocalTransform) + { + distanceAtReceiveTime = Vector3.Distance(targetPosition, transform.localPosition); + angleAtReceiveTime = Quaternion.Angle(targetRotation, transform.localRotation); + if (teleportDistance != 0 && teleportDistance < distanceAtReceiveTime) + { + transform.localPosition = targetPosition; + } + if (teleportAngle != 0 && teleportAngle < angleAtReceiveTime) + { + transform.localRotation = targetRotation; + } + } + else + { + distanceAtReceiveTime = Vector3.Distance(targetPosition, transform.position); + angleAtReceiveTime = Quaternion.Angle(targetRotation, transform.rotation); + if (teleportDistance != 0 && teleportDistance < distanceAtReceiveTime) + { + transform.position = targetPosition; + } + if (teleportAngle != 0 && teleportAngle < angleAtReceiveTime) + { + transform.rotation = targetRotation; + } + } + } + + private void Update() + { + if (IsMine) return; + + 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/Util/SyncRigidbody.cs.meta b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/SyncRigidbody.cs.meta new file mode 100644 index 0000000..e516561 --- /dev/null +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/SyncRigidbody.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 951f5c5e2245481d8f969b94f998c78b +timeCreated: 1642738174 \ No newline at end of file diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/SyncTransform.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/SyncTransform.cs index 162a9c9..dddd19f 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/SyncTransform.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/SyncTransform.cs @@ -1,16 +1,19 @@ using System.IO; using UnityEngine; - namespace VelNet { /// /// A simple class that will sync the position and rotation of a network object /// [AddComponentMenu("VelNet/VelNet Sync Transform")] - public class SyncTransform : NetworkSerializedObject + public class SyncTransform : NetworkSerializedObjectStream { public bool useLocalTransform; + [Tooltip("0 to disable.")] + public float teleportDistance; + [Tooltip("0 to disable.")] + public float teleportAngle; private Vector3 targetPosition; private Quaternion targetRotation; @@ -34,28 +37,18 @@ namespace VelNet /// /// 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() + protected override void SendState(BinaryWriter writer) { - using MemoryStream mem = new MemoryStream(); - using BinaryWriter writer = new BinaryWriter(mem); - 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) + protected override void ReceiveState(BinaryReader reader) { - using MemoryStream mem = new MemoryStream(message); - using BinaryReader reader = new BinaryReader(mem); - targetPosition = reader.ReadVector3(); targetRotation = reader.ReadQuaternion(); @@ -64,11 +57,27 @@ namespace VelNet { distanceAtReceiveTime = Vector3.Distance(targetPosition, transform.localPosition); angleAtReceiveTime = Quaternion.Angle(targetRotation, transform.localRotation); + if (teleportDistance != 0 && teleportDistance < distanceAtReceiveTime) + { + transform.localPosition = targetPosition; + } + if (teleportAngle != 0 && teleportAngle < angleAtReceiveTime) + { + transform.localRotation = targetRotation; + } } else { distanceAtReceiveTime = Vector3.Distance(targetPosition, transform.position); angleAtReceiveTime = Quaternion.Angle(targetRotation, transform.rotation); + if (teleportDistance != 0 && teleportDistance < distanceAtReceiveTime) + { + transform.position = targetPosition; + } + if (teleportAngle != 0 && teleportAngle < angleAtReceiveTime) + { + transform.rotation = targetRotation; + } } } diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs index 0e9ae32..31714f7 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs @@ -42,7 +42,6 @@ namespace VelNet private Thread clientReceiveThread; private Thread clientReceiveThreadUDP; public int userid = -1; - public string room; private int messagesReceived = 0; public readonly Dictionary players = new Dictionary(); @@ -90,8 +89,23 @@ namespace VelNet public readonly Dictionary> groups = new Dictionary>(); private VelNetPlayer masterPlayer; - public static VelNetPlayer LocalPlayer => instance.players.Where(p => p.Value.isLocal).Select(p => p.Value).FirstOrDefault(); + public static VelNetPlayer LocalPlayer => instance != null ? instance.players.Where(p => p.Value.isLocal).Select(p => p.Value).FirstOrDefault() : null; public static bool InRoom => LocalPlayer != null && LocalPlayer.room != "-1" && LocalPlayer.room != ""; + public static string Room => LocalPlayer?.room; + + /// + /// The player count in this room. + /// -1 if not in a room. + /// + public static int PlayerCount => instance.players.Count; + + /// + /// The player count in all rooms. + /// Will include players connected to the server but not in a room? + /// + public static int PlayerCountInAllRooms => PlayerCount; // TODO hook up to actual player count + + public static bool IsConnected => instance != null && instance.connected && instance.udpConnected; //this is for sending udp packets @@ -396,7 +410,7 @@ namespace VelNet private void OnApplicationQuit() { - socketConnection.Close(); + socketConnection?.Close(); } /// @@ -845,14 +859,26 @@ namespace VelNet public static bool TakeOwnership(string networkId) { // local player must exist - if (LocalPlayer == null) return false; - + if (LocalPlayer == null) + { + Debug.LogError("Can't take ownership. No local player."); + return false; + } + // obj must exist - if (!instance.objects.ContainsKey(networkId)) return false; + if (!instance.objects.ContainsKey(networkId)) + { + Debug.LogError("Can't take ownership. Object with that network id doesn't exist."); + return false; + } // if the ownership is locked, fail - if (instance.objects[networkId].ownershipLocked) return false; - + if (instance.objects[networkId].ownershipLocked) + { + Debug.LogError("Can't take ownership. Ownership for this object is locked."); + return false; + } + // immediately successful instance.objects[networkId].owner = LocalPlayer; @@ -862,4 +888,4 @@ namespace VelNet 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 c31ab89..56bb8ff 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetPlayer.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetPlayer.cs @@ -10,8 +10,6 @@ namespace VelNet public class VelNetPlayer { public int userid; - public string username; - public string room; public bool isLocal; @@ -72,7 +70,7 @@ namespace VelNet switch (sections[0]) { - case "5": //sync update for an object I may own + case "5": // sync update for an object I may own { string objectKey = sections[1]; string identifier = sections[2]; @@ -88,7 +86,7 @@ namespace VelNet break; } - case "6": //I'm trying to take ownership of an object + case "6": // I'm trying to take ownership of an object { string networkId = sections[1]; diff --git a/TestVelGameServer/Packages/VelNetUnity/package.json b/TestVelGameServer/Packages/VelNetUnity/package.json index b846be2..956001f 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.6", + "version": "1.0.7", "unity": "2019.1", "description": "A custom networking library for Unity.", "keywords": [ @@ -23,4 +23,4 @@ "dependencies": { } } - \ No newline at end of file + From 80a16c4ce29fa8d245878526f58f38eea057516d Mon Sep 17 00:00:00 2001 From: Anton Franzluebbers Date: Mon, 24 Jan 2022 21:12:13 -0500 Subject: [PATCH 10/14] fixes for mouse dragger, visualization for audio range, added some more callbacks to velnetmanager, added color syncing extension, take ownership of synced textbox, fix for deleting all scene objects --- .../VelNet/1.0.4/Example/MouseDragger.cs | 2 +- .../VelNet/1.0.4/Example/NetworkGUI.cs | 35 +- .../VelNet/1.0.4/Example/PlayerController.cs | 64 +-- .../VelNet/1.0.4/Example/PlayerPrefab.prefab | 94 ++- .../VelNet/1.0.4/Example/SyncedTextbox.cs | 5 + .../Example/TestNetworkedGameObject.prefab | 196 +++---- .../VelNet/1.0.4/Example/TransparentMat.mat | 79 +++ .../1.0.4/Example/TransparentMat.mat.meta | 8 + .../Samples/VelNet/1.0.4/Example/test.meta | 8 + .../Samples/VelNet/1.0.4/Example/test.unity | 259 ++++++++- .../1.0.4/Example/test/LightingData.asset | Bin 0 -> 18168 bytes .../Example/test/LightingData.asset.meta | 8 + .../Runtime/Util/BinaryWriterExtensions.cs | 42 +- .../VelNetUnity/Runtime/VelNetManager.cs | 543 ++++++++++-------- .../Packages/VelNetUnity/package.json | 2 +- TestVelGameServer/Packages/manifest.json | 4 +- TestVelGameServer/Packages/packages-lock.json | 9 +- .../ProjectSettings/ProjectVersion.txt | 4 +- 18 files changed, 907 insertions(+), 455 deletions(-) create mode 100644 TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/TransparentMat.mat create mode 100644 TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/TransparentMat.mat.meta create mode 100644 TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test.meta create mode 100644 TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test/LightingData.asset create mode 100644 TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test/LightingData.asset.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 index 55cf69a..e77cd8f 100644 --- a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/MouseDragger.cs +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/MouseDragger.cs @@ -20,7 +20,7 @@ public class MouseDragger : MonoBehaviour { foreach (string draggableTag in draggableTags) { - if (hit.transform.CompareTag(draggableTag) || hit.transform.parent == null || hit.transform.parent.CompareTag(draggableTag)) + if (hit.transform.CompareTag(draggableTag) || (hit.transform.parent != null && hit.transform.parent.CompareTag(draggableTag))) { NetworkObject netObj = hit.transform.GetComponent(); netObj ??= hit.transform.GetComponentInParent(); 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 0a2b7cc..180392a 100644 --- a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/NetworkGUI.cs +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/NetworkGUI.cs @@ -10,14 +10,16 @@ namespace VelNet { public class NetworkGUI : MonoBehaviour { - [FormerlySerializedAs("networkManager")] public VelNetManager velNetManager; + [FormerlySerializedAs("networkManager")] + public VelNetManager velNetManager; + public InputField userInput; public InputField sendInput; public InputField roomInput; public Text messages; public List messageBuffer; public Dropdown microphones; - DissonanceComms comms; + private DissonanceComms comms; public void HandleSend() { @@ -42,6 +44,7 @@ namespace VelNet VelNetManager.GetRooms(); } } + public void HandleJoin() { if (roomInput.text != "") @@ -61,34 +64,14 @@ namespace VelNet comms = FindObjectOfType(); microphones.AddOptions(new List(Microphone.devices)); - /* todo - VelNetManager.MessageReceived += (m) => - { - string s = m.type + ":" + m.sender + ":" + m.text; - messageBuffer.Add(s); - messages.text = ""; - - - if (messageBuffer.Count > 10) - { - messageBuffer.RemoveAt(0); - } - - foreach (string msg in messageBuffer) - { - messages.text = messages.text + msg + "\n"; - } - }; - */ StartCoroutine(testes()); - - } + IEnumerator testes() { - yield return new WaitForSeconds(1.0f); - HandleLogin(); - yield return new WaitForSeconds(1.0f); + yield return new WaitForSeconds(1.0f); + HandleLogin(); + yield return new WaitForSeconds(1.0f); HandleJoin(); yield return null; } 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 e0fda99..6cad912 100644 --- a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/PlayerController.cs +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/PlayerController.cs @@ -1,25 +1,30 @@ +using System; using System.Collections.Generic; using System.IO; using System.Linq; using UnityEngine; +using Random = UnityEngine.Random; namespace VelNet { - public class PlayerController : NetworkComponent + public class PlayerController : NetworkSerializedObjectStream { - public Vector3 targetPosition; - public Quaternion targetRotation; + private Renderer rend; + public Color color; + private void Start() + { + rend = GetComponent(); + if (IsMine) + { + color = new Color(Random.Range(0, 1f), Random.Range(0, 1f), Random.Range(0, 1f)); + rend.material.color = color; + } + } // Update is called once per frame private void Update() { - // if (!IsMine) - // { - // transform.position = Vector3.Lerp(transform.position, targetPosition, .1f); - // transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, .1f); - // } - // else if (IsMine) { Vector3 movement = new Vector3(); @@ -43,37 +48,30 @@ namespace VelNet if (Input.GetKeyDown(KeyCode.Backspace)) { - foreach (KeyValuePair kvp in VelNetManager.instance.objects.Where(kvp => !kvp.Value.ownershipLocked)) + foreach (string key in VelNetManager.instance.objects + .Where(kvp => !kvp.Value.ownershipLocked) + .Select(kvp => kvp.Key).ToArray()) { - VelNetManager.NetworkDestroy(kvp.Key); + VelNetManager.NetworkDestroy(key); } } } } - // - // protected override byte[] SendState() - // { - // using MemoryStream mem = new MemoryStream(); - // using BinaryWriter writer = new BinaryWriter(mem); - // - // writer.Write(transform.position); - // writer.Write(transform.rotation); - // - // return mem.ToArray(); - // } - // - // protected override void ReceiveState(byte[] message) - // { - // using MemoryStream mem = new MemoryStream(message); - // using BinaryReader reader = new BinaryReader(mem); - // - // targetPosition = reader.ReadVector3(); - // targetRotation = reader.ReadQuaternion(); - // } - public override void ReceiveBytes(byte[] message) + protected override void SendState(BinaryWriter binaryWriter) { - throw new System.NotImplementedException(); + binaryWriter.Write(color); + } + + protected override void ReceiveState(BinaryReader binaryReader) + { + Color newColor = binaryReader.ReadColor(); + if (newColor != color) + { + rend.material.color = newColor; + } + + color = newColor; } } } \ No newline at end of file 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 843b5b6..6ab0ec1 100644 --- a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/PlayerPrefab.prefab +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/PlayerPrefab.prefab @@ -1,5 +1,86 @@ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: +--- !u!1 &2802320351940726854 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6602982999811082154} + - component: {fileID: 6433756913090684124} + - component: {fileID: 6919422133110223353} + m_Layer: 0 + m_Name: Dissonance Range + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6602982999811082154 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2802320351940726854} + m_LocalRotation: {x: -0.70710635, y: -0, z: -0, w: 0.7071073} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 8, y: 0.1, z: 8} + m_Children: [] + m_Father: {fileID: 3076416102083120807} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: -90, y: 0, z: 0} +--- !u!33 &6433756913090684124 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2802320351940726854} + m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &6919422133110223353 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2802320351940726854} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2100000, guid: 6fad1ca32acea73489c2c4b898cdb9d4, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} --- !u!1 &6139051692386484099 GameObject: m_ObjectHideFlags: 0 @@ -33,7 +114,8 @@ Transform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 0.5, y: 0.5, z: 0.5} - m_Children: [] + m_Children: + - {fileID: 6602982999811082154} m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -113,6 +195,7 @@ MonoBehaviour: m_EditorClassIdentifier: ownershipLocked: 1 networkId: + sceneNetworkId: 0 prefabName: isSceneObject: 0 syncedComponents: @@ -132,8 +215,8 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: networkObject: {fileID: 9102273340480352682} - targetPosition: {x: 0, y: 0, z: 0} - targetRotation: {x: 0, y: 0, z: 0, w: 0} + serializationRateHz: 30 + color: {r: 0, g: 0, b: 0, a: 0} --- !u!114 &1181612843795795320 MonoBehaviour: m_ObjectHideFlags: 0 @@ -147,6 +230,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: networkObject: {fileID: 9102273340480352682} + useTcp: 0 dissonanceID: closePlayers: maxDistance: 2 @@ -163,5 +247,7 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: networkObject: {fileID: 9102273340480352682} - serializationRateHz: 1 + serializationRateHz: 60 useLocalTransform: 0 + teleportDistance: 0 + teleportAngle: 0 diff --git a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/SyncedTextbox.cs b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/SyncedTextbox.cs index 73c526b..af83c6d 100644 --- a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/SyncedTextbox.cs +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/SyncedTextbox.cs @@ -16,4 +16,9 @@ public class SyncedTextbox : NetworkSerializedObjectStream { text.text = binaryReader.ReadString(); } + + public void TakeOwnership() + { + networkObject.TakeOwnership(); + } } \ No newline at end of file diff --git a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/TestNetworkedGameObject.prefab b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/TestNetworkedGameObject.prefab index f94ea79..096eb0d 100644 --- a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/TestNetworkedGameObject.prefab +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/TestNetworkedGameObject.prefab @@ -1,5 +1,100 @@ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: +--- !u!1 &6003361529827848619 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7099230484513283147} + - component: {fileID: 8811139817265458480} + - component: {fileID: 3776025769317911085} + - component: {fileID: 1426238303320144522} + m_Layer: 0 + m_Name: Cube + m_TagString: TestSphere + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &7099230484513283147 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6003361529827848619} + 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: 8565720275311462455} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &8811139817265458480 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6003361529827848619} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &3776025769317911085 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6003361529827848619} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!65 &1426238303320144522 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6003361529827848619} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} --- !u!1 &8565720275311462453 GameObject: m_ObjectHideFlags: 0 @@ -13,7 +108,7 @@ GameObject: - component: {fileID: 8565720275311462452} m_Layer: 0 m_Name: TestNetworkedGameObject - m_TagString: TestSphere + m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 @@ -29,7 +124,7 @@ Transform: m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: - - {fileID: 8565720276181857624} + - {fileID: 7099230484513283147} m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -67,98 +162,5 @@ MonoBehaviour: networkObject: {fileID: 3951900052977689805} serializationRateHz: 60 useLocalTransform: 0 ---- !u!1 &8565720276181857625 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 8565720276181857624} - - component: {fileID: 8565720276181857605} - - component: {fileID: 8565720276181857626} - - component: {fileID: 8565720276181857627} - m_Layer: 0 - m_Name: Sphere - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &8565720276181857624 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 8565720276181857625} - 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: 8565720275311462455} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!33 &8565720276181857605 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 8565720276181857625} - m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} ---- !u!23 &8565720276181857626 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 8565720276181857625} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RayTracingMode: 2 - m_RayTraceProcedural: 0 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_ReceiveGI: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 1 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} ---- !u!135 &8565720276181857627 -SphereCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 8565720276181857625} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Radius: 0.5 - m_Center: {x: 0, y: 0, z: 0} + teleportDistance: 0 + teleportAngle: 0 diff --git a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/TransparentMat.mat b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/TransparentMat.mat new file mode 100644 index 0000000..194ed0a --- /dev/null +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/TransparentMat.mat @@ -0,0 +1,79 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: TransparentMat + m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0} + m_ShaderKeywords: _ALPHAPREMULTIPLY_ON _GLOSSYREFLECTIONS_OFF _SPECULARHIGHLIGHTS_OFF + m_LightmapFlags: 4 + m_EnableInstancingVariants: 0 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: 3000 + stringTagMap: + RenderType: Transparent + disabledShaderPasses: [] + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Floats: + - _BumpScale: 1 + - _Cutoff: 0.5 + - _DetailNormalMapScale: 1 + - _DstBlend: 10 + - _GlossMapScale: 1 + - _Glossiness: 0.5 + - _GlossyReflections: 0 + - _Metallic: 0 + - _Mode: 3 + - _OcclusionStrength: 1 + - _Parallax: 0.02 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 0 + - _SrcBlend: 1 + - _UVSec: 0 + - _ZWrite: 0 + m_Colors: + - _Color: {r: 1, g: 1, b: 1, a: 0.03137255} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/TransparentMat.mat.meta b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/TransparentMat.mat.meta new file mode 100644 index 0000000..ab60bc1 --- /dev/null +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/TransparentMat.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6fad1ca32acea73489c2c4b898cdb9d4 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test.meta b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test.meta new file mode 100644 index 0000000..d6e9138 --- /dev/null +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 009dc4ba29f14b649beb8c3eaad89f15 +folderAsset: yes +DefaultImporter: + externalObjects: {} + 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 2c11908..4688170 100644 --- a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test.unity +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test.unity @@ -20,13 +20,13 @@ RenderSettings: m_FogDensity: 0.01 m_LinearFogStart: 0 m_LinearFogEnd: 300 - m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientSkyColor: {r: 0.5137255, g: 0.53333336, b: 0.5647059, a: 1} m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} m_AmbientIntensity: 1 - m_AmbientMode: 0 + m_AmbientMode: 3 m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} - m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_SkyboxMaterial: {fileID: 0} m_HaloStrength: 0.5 m_FlareStrength: 1 m_FlareFadeSpeed: 3 @@ -37,8 +37,8 @@ RenderSettings: m_ReflectionBounces: 1 m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} - m_Sun: {fileID: 0} - m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1} + m_Sun: {fileID: 652307110} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: @@ -97,7 +97,7 @@ LightmapSettings: m_ExportTrainingData: 0 m_TrainingDataDestination: TrainingData m_LightProbeSampleCountMultiplier: 4 - m_LightingDataAsset: {fileID: 0} + m_LightingDataAsset: {fileID: 112000000, guid: d1b34f106c04378428823df374b0e07c, type: 2} m_LightingSettings: {fileID: 0} --- !u!196 &4 NavMeshSettings: @@ -608,7 +608,7 @@ RectTransform: - {fileID: 948755938} - {fileID: 545137760} m_Father: {fileID: 0} - m_RootOrder: 4 + m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} @@ -779,6 +779,85 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 5 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &498776799 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 498776800} + - component: {fileID: 498776802} + - component: {fileID: 498776801} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &498776800 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 498776799} + 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: 1992361063} + 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 &498776801 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 498776799} + 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: Take Ownership +--- !u!222 &498776802 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 498776799} + m_CullTransparentMesh: 1 --- !u!1 &545137759 GameObject: m_ObjectHideFlags: 0 @@ -813,11 +892,11 @@ RectTransform: m_Father: {fileID: 244561620} m_RootOrder: 10 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0.5, y: 0.5} - m_AnchorMax: {x: 0.5, y: 0.5} - m_AnchoredPosition: {x: -382, y: -321} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 5, y: 165.7} m_SizeDelta: {x: 160, y: 30} - m_Pivot: {x: 0.5, y: 0.5} + m_Pivot: {x: 0, y: 0} --- !u!114 &545137761 MonoBehaviour: m_ObjectHideFlags: 0 @@ -1221,7 +1300,7 @@ Transform: m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 0} - m_RootOrder: 1 + m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} --- !u!1 &711524766 GameObject: @@ -1629,7 +1708,7 @@ Camera: m_Enabled: 1 serializedVersion: 2 m_ClearFlags: 1 - m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_BackGroundColor: {r: 0.2735849, g: 0.2735849, b: 0.2735849, a: 0} m_projectionMatrixMode: 1 m_GateFitMode: 2 m_FOVAxisMode: 0 @@ -1644,7 +1723,7 @@ Camera: height: 1 near clip plane: 0.3 far clip plane: 1000 - field of view: 60 + field of view: 40 orthographic: 0 orthographic size: 5 m_Depth: -1 @@ -1670,11 +1749,11 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 903768653} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalPosition: {x: 0, y: 1, z: -20} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 0} - m_RootOrder: 0 + m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &912887455 GameObject: @@ -2051,6 +2130,7 @@ RectTransform: m_Children: - {fileID: 359309141} - {fileID: 1840952814} + - {fileID: 1992361063} m_Father: {fileID: 244561620} m_RootOrder: 9 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -2088,6 +2168,7 @@ MonoBehaviour: m_EditorClassIdentifier: ownershipLocked: 0 networkId: + sceneNetworkId: 2 prefabName: isSceneObject: 1 syncedComponents: @@ -2440,7 +2521,7 @@ Transform: m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 0} - m_RootOrder: 3 + m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!114 &1099803616 MonoBehaviour: @@ -2454,11 +2535,10 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 233344de094f11341bdb834d564708dc, type: 3} m_Name: m_EditorClassIdentifier: - host: 127.0.0.1 + host: 129.159.107.234 port: 80 udpConnected: 0 userid: -1 - room: connected: 0 prefabs: - {fileID: 9102273340480352682, guid: d4158ab9c4a204cdbba28d3273fc1fb3, type: 3} @@ -3007,7 +3087,7 @@ Transform: m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 0} - m_RootOrder: 2 + m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!114 &1434745021 MonoBehaviour: @@ -3793,7 +3873,7 @@ GameObject: m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 - m_IsActive: 1 + m_IsActive: 0 --- !u!224 &1894247853 RectTransform: m_ObjectHideFlags: 0 @@ -3934,6 +4014,139 @@ RectTransform: m_AnchoredPosition: {x: 0, y: -0.5} m_SizeDelta: {x: -20, y: -13} m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &1992361062 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1992361063} + - component: {fileID: 1992361066} + - component: {fileID: 1992361065} + - component: {fileID: 1992361064} + m_Layer: 5 + m_Name: Button + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1992361063 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1992361062} + 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: 498776800} + m_Father: {fileID: 948755938} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 31.6} + m_SizeDelta: {x: 160, y: 30} + m_Pivot: {x: 1, y: 1} +--- !u!114 &1992361064 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1992361062} + 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: 1992361065} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 948755939} + m_TargetAssemblyTypeName: SyncedTextbox, Assembly-CSharp + m_MethodName: TakeOwnership + 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 &1992361065 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1992361062} + 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 &1992361066 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1992361062} + m_CullTransparentMesh: 1 --- !u!1 &2033163676 GameObject: m_ObjectHideFlags: 0 @@ -4174,8 +4387,8 @@ PrefabInstance: propertyPath: isSceneObject value: 1 objectReference: {fileID: 0} - - target: {fileID: 8565720275311462452, guid: 6e4a023f70e01405e8b249a4488fe319, type: 3} - propertyPath: serializationRateHz + - target: {fileID: 3951900052977689805, guid: 6e4a023f70e01405e8b249a4488fe319, type: 3} + propertyPath: sceneNetworkId value: 1 objectReference: {fileID: 0} - target: {fileID: 8565720275311462453, guid: 6e4a023f70e01405e8b249a4488fe319, type: 3} diff --git a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test/LightingData.asset b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test/LightingData.asset new file mode 100644 index 0000000000000000000000000000000000000000..38f5004fcd1aaed792fcc49c0841024cf07eb9b6 GIT binary patch literal 18168 zcmdU%eVklXdB@LWHwgqJ@*dtd;VlVd$;>7p5QvjkvLSC|HzDE0WOnCncF6ARGBZnd zBQFC85eWzqYz0b*RlpZ2SQVv85tO!oFIBOXDwVdV^@XBUijdTwl*W%x3BXHn`e%k|CwDkT=4ppZ%n>7wIF58=O!3K%5Vep^OP(Vsg_;*3dpauEz6l#dA$N(q74p+K+z*@U zqv{}X%0Ce|*3~d*C?7)_Q~tyRPnjFXnQF<)rw(K3zki~AsQ;t{Pni`M-^Vd% z&hG)_RrcZ%^iN^z9KYq9!&ElTo9z4@0~wr~w~^bKlJ-sJ0<^sh8}&XY!Bb`}>b7E| z?8(^Tsd4_^4mj5JIXJ;n=6UGWi+YZawvehK^Qm!shoU}}70SNC@f}89$GEyprh;RR z?AU+`MXh1`A1of%%?{A zN25M$AIhimhTO@&3-y$LtmVjjYLtH*>cjS-{NoecU7rU~&+Bsnc@>#Yjn}6I^_DXZ$$Ba%4U+zP^F-WGLN-{cLQZ{^QJEv_B1% zY>zlKD$jVHQTSP&w<$d9`5c9x=lNWPukn1I!Z&!1``oDdU*h?Eg?D>?mclRdocAge zYl+uqFXr!Z&lf0s*zt2&w0K=;otJSUEwcyzEa^Yd47I^yZH8FaK@iiHaBDbI-wu_%%zqi^NIIY@-ENciTd#R zx$*7rclcSu{5$@b=i3$jl;^w$hu6=wf6nuMg+K3k zQQ-k86yZC(`IOF$D@+vZ)8sqo7P@l>Q zx{!YjvN^sis^6X9M%YyF7fBR3YYkEv%)3*>`riZ|2+sdN8TTAu^gFCj6aM| zM*>p+Td{@qGa-mi?^C$Mr`r@R@#%JjOMH62!X-Z4p>T;$dlWA5=}v`9eENXGB|iO; z!X-ZavBD)jeNf>NpYBq)#HYIzF7fFeg-d+;6NO8Bx;Md{eVpX&<4-NGB6o@Q9lw9w zhw9Kj92fh5FO15?K0c&yv5!AfxY);s6)yJi5rvC=+^=x4j|UVk_VJ*?#Xdf&aIue% zDO~L1;|dr1_=Lj6J|0rI*vFqMTR%R6)yhs1%-?Md{N=zKaVS1{O7L}F8=d`!o`2Sq;T<{ClxOK z^OVBHf4;16@t?0KT>R&0g^U0EwZg@J{zl>AKYyFxF23IH?c9KEA7Pv5yxL+{M?&U>}UH|43d%=2K&Q{T}Maim%@%m&Ug2-cK1{8J`df8+iDB z`cDcM`}={y#r|GWxY*x6D_rdFUlcC(_pb^U`+Hg8Vt+qWxY*y16fXAnV}*@xT3K#qPxx&T%UP*9ge@}b+`*-pxGM^gl?^V=~Wq-dQm&Uf-Y`z28 zw7)4h{$+x@_m|gj4*tx4jKX<;#cPbczy2!0!}$4Yg^T^Zrf{*}|5Uix@9PQ|`~8i= z#eUyVxY+N1DO~LLO@)j7{}8f3e?`!o_~aDO~KgN#SC@ z%?a-8XAEFCo9#OowdR_kn1(e}ael zO;Y$uum1rGztHmo6WpyY<-s|=w~<%l`iH+CIEXwO=i&Mizw_a*mM}jizP|MK1P|Aj z4pz9VFCCKLPXAqA|3k^EweF!ysQ+Q)**FjNKRh8n)c=SC5A{D%;iCVP1b6!1=Jh{{ zd<^}MCVxWL|Ck2({C&emAe;7eFq$2kknimCQJh2jKdzy@*zY$yKYkScGT3X__Cxy< z65QGE#0gG*i^8XPJ~hFc%_`_V6CB7)BhRAX6TdG%kM+Y0IPLdD@~Tj_39tW2PZ%uVa*(?C)zhf0TbpLVo!D{#5d8T>#h5`2HyClhYIO!|(Sq65NgNB0s*FiT=a! z@jH6he>lF=6Y`tP!?E92%t~-)AJZ`;+DEJ9)!G1QAMxJ@oRQ#8{}HeMZ1Q^Z#Pvy& zXKUi^{Kw~yzXQNuEj7lMwgeCTbB@BrKj$X6)Bkp_|2*<)t^0)jXOd^*Je>de3HeQS zeT?=6WcWJ|nQw=K<8a*N94sAATwtCY@JmM>HWO3Q{T zQL$VYC@wVpTb394qV}aItjkq;QLyK&D@8rIuJ&TNk}Gyc3teSLcT|k5Ft)Qt*xR1^ zbAx3gCH5HuC@w9O1hQpsE3p&7b@ zdsB%@rCg!7bflQ;FLZC%*wJZ*&4}4)b_iP1J5<~r=Y6y(%yT<>88*R@Kdn{?X~H`? z1+K`Id()ZuCK?{>D|8p!W$1`1tT$aFm8g6%#_kFjy(?h+u7DYE1+=J%y-bD!J0O zsN$;qf%7J_tZ3&XD%ystbAy9$P;{Zy%M~owTS`@Xv1g#vpR2%!P03$%lXus0mA_0K zo$bYrk#Z&KH)XqP&zpkxXglTGqJjRXQW~)ba7%kqtTR_JT35~jq~ngl&dB5{eYvu$ zx5c$RJ%~D+T)jKkjP3`ADo(8Jw3N#i2FiuXNURQl$ohFyVMK6X5rrcb)Mv`-YOCY= z*`Dj_*gkp+rLyl66VSh<(;2?C?wG`&Ixe#~)bGx1FK#ligU#BNt6d|Qh_|0w0Z|Co zeC<#L^WXz!yvhu6=xe*X`-T{v?Ui(MIv{lnn@f6g#bVS~3%HDJHuj0njatz;G8mcu z!f=$ga-oN9Qz-Ln&Wzo!k9zuG(CFP>h9yH?5nMhNkHuVR!-yeeGjZujs zwzoIF%i*DI+gCRpviRzI9=dwg$xr?Kg?%sb6Wk+B_1oZ?xc%|b%eJZ7+-AHrzSU31 z`AYRxKOLWjb9ie-mylRR?h-#u^U>xs9P-hY=Y%|E_{kyXf7*>FVDNfkd)~T5KJMTR z?L+w!6a0Vo({Yi%f1-UTe^P?~?tePo4xKh(4xQI6p~|AEEHaJwH<6 z{3O8kT>gqDep;n{aY>u}s5nGf_)DH2t#B^svHdX$=aLfnv7>MD=f4su^N=bf#!uiTa-lA~6l95kUIA58_=_m1&GEP6f(vY7RhbRk|pB|s2aJ~|- z{mBaFBRlyi3Sa2?sS020IbXrzN%ULp`HVP3nb)7M&MU$3XJ%SnwK+4sI`P$cJs|y$ zan4kkxrA4{;M45stj;>dywQJV)sZcczYO{GAI9NUTiarDX4G#l*rn*7^K*tJEjDK+ ze2eF_F=JY6&P;gD^Ry)`HfP58!SV5@)f``jl~ragVf?}P+E|@+jJYg*$g4YJeLRs5 zKsLum-<%tVD0BQ*f!~0Qv1?v}yQR)ARWOWgExu_53V_Kj8V< z3g=Iw@n;q&{PUilqwps^KUd+;dcIKM-}d|+3je<6S%v@5^F<1O)$_#)f5Y=73U40g z=4YwG5AuAO!l!t?Ji*=4&@^z`|9J{O&GQur?(91QPW$G)bS(Q`NuFiqQlovJFCfO_ z{)QT%tcB`r2*CS3e?jU_EMXC_?ycdaEYHfKiv{RQMN^y6DsBd*Zs zzr07sQ{(v7$05q(C-|i=-rGA8-1+a_(1HHjnc$)SZcw=R??#1-|6ZtY@n1eC#gq8I z`0wU8L|M4_??nn1|Gik@;=h+DT>SS^g^T~bQ{m#jeAbI6(O>*`YaF61T>LkuaPi+R zg^T}oD_s0HpWyz}3}Q6>H%f4~blC0fw}-r1KMD37+<&$aW#c?tI_#|@TjKqjKfCAs zrw=uS1aG$fxf|zDKb#jN+CTmG4$rp-)cFVbU7oX#c#`&eJ@1c0l!ZU&xqIoWpCtT~ zo)6TKEeZdu=YtCWqUV<@{L7w~6#lH|Wrcs!^NPa1>-mtvf8hBQ3g@R=UY{Kbf5r1* zh5y>~5rx0$Ip3q=N#?f+FTU*mU2%xA@JXIusqlk6ze?d#Jil7u{PfHIuTl6Zo>vt< z%kyg$KF9Ox6u!Xo>lMD(^LHn>^Y3l9)p!?6iqaHHnudj47N5CrE#3baT>>I9A|Kx z!Epx1nKn}>Z^YoZG`V7^uWx;Br0l;@_%&k80=^G%$rPn_`&EKVzWm03Ccn>L72JY2 zw6u%W7!Fs#vHr<*(lrCc+GXOkjq9m?D;SP&;KPIh(=a(|J|0dTc%D6`WCsOYfKeE zzjynU&}c&uUwM|>SE-3}TZdbRP5gh2@hbDgN!Yk*@|0WHPq$`T=gb-`9gmro7d?64 X+ut{PtKCGLFnvkiKrxyz=BfV!OflI4 literal 0 HcmV?d00001 diff --git a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test/LightingData.asset.meta b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test/LightingData.asset.meta new file mode 100644 index 0000000..59c9c51 --- /dev/null +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test/LightingData.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d1b34f106c04378428823df374b0e07c +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 112000000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/BinaryWriterExtensions.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/BinaryWriterExtensions.cs index f43524d..2b39a98 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/BinaryWriterExtensions.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/BinaryWriterExtensions.cs @@ -8,6 +8,8 @@ namespace VelNet { public static class BinaryWriterExtensions { + #region Writers + public static void Write(this BinaryWriter writer, Vector3 v) { writer.Write(v.x); @@ -23,6 +25,18 @@ namespace VelNet writer.Write(q.w); } + public static void Write(this BinaryWriter writer, Color c) + { + writer.Write(c.r); + writer.Write(c.g); + writer.Write(c.b); + writer.Write(c.a); + } + + #endregion + + #region Readers + public static Vector3 ReadVector3(this BinaryReader reader) { return new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); @@ -31,19 +45,32 @@ namespace VelNet public static Quaternion ReadQuaternion(this BinaryReader reader) { return new Quaternion( - reader.ReadSingle(), - reader.ReadSingle(), - reader.ReadSingle(), + reader.ReadSingle(), + reader.ReadSingle(), + reader.ReadSingle(), reader.ReadSingle() ); } + public static Color ReadColor(this BinaryReader reader) + { + return new Color( + reader.ReadSingle(), + reader.ReadSingle(), + reader.ReadSingle(), + reader.ReadSingle() + ); + } + + #endregion + + /// /// Compresses the list of bools into bytes using a bitmask /// public static byte[] GetBitmasks(this IEnumerable bools) { - List values = bools.ToList(); + List values = bools.ToList(); List bytes = new List(); for (int b = 0; b < Mathf.Ceil(values.Count / 8f); b++) { @@ -61,7 +88,7 @@ namespace VelNet return bytes.ToArray(); } - + public static List GetBitmaskValues(this IEnumerable bytes) { List l = new List(); @@ -72,7 +99,7 @@ namespace VelNet return l; } - + public static List GetBitmaskValues(this byte b) { List l = new List(); @@ -83,11 +110,10 @@ namespace VelNet return l; } - + public static bool GetBitmaskValue(this byte b, int index) { return (b & (1 << index)) != 0; } - } } \ No newline at end of file diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs index 31714f7..c166404 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs @@ -1,5 +1,4 @@ using System; -using System.Collections; using System.Collections.Generic; using System.Linq; using System.Net.Sockets; @@ -8,8 +7,6 @@ using System.Threading; using UnityEngine; using System.Net; using UnityEngine.SceneManagement; -using System.Runtime.Serialization.Formatters.Binary; -using System.Runtime.Serialization; using System.IO; namespace VelNet @@ -42,10 +39,11 @@ namespace VelNet private Thread clientReceiveThread; private Thread clientReceiveThreadUDP; public int userid = -1; - private int messagesReceived = 0; public readonly Dictionary players = new Dictionary(); + #region Callbacks + /// /// We just joined a room /// string - the room name @@ -69,8 +67,12 @@ namespace VelNet public static Action OnPlayerLeft; public static Action OnConnectedToServer; - public static Action LoggedIn; - public static Action RoomsReceived; + public static Action OnLoggedIn; + public static Action RoomsReceived; + + public static Action MessageReceived; + + #endregion public bool connected; @@ -92,7 +94,7 @@ namespace VelNet public static VelNetPlayer LocalPlayer => instance != null ? instance.players.Where(p => p.Value.isLocal).Select(p => p.Value).FirstOrDefault() : null; public static bool InRoom => LocalPlayer != null && LocalPlayer.room != "-1" && LocalPlayer.room != ""; public static string Room => LocalPlayer?.room; - + /// /// The player count in this room. /// -1 if not in a room. @@ -107,46 +109,59 @@ namespace VelNet public static bool IsConnected => instance != null && instance.connected && instance.udpConnected; - //this is for sending udp packets - static byte[] toSend = new byte[1024]; + private static readonly byte[] toSend = new byte[1024]; // Use this for initialization public abstract class Message { - } + public class ListedRoom { public string name; public int numUsers; + + public override string ToString() + { + return "Room Name: " + name + "\tUsers: " + numUsers; + } } - public class LoginMessage: Message + + public class LoginMessage : Message { public int userId; } - public class RoomsMessage: Message + + public class RoomsMessage : Message { public List rooms; + + public override string ToString() + { + return string.Join("\n", rooms); + } } - public class JoinMessage: Message + + public class JoinMessage : Message { public int userId; public string room; } - public class DataMessage: Message + + public class DataMessage : Message { public int senderId; public byte[] data; } - public class ChangeMasterMessage: Message + + public class ChangeMasterMessage : Message { public int masterId; } - public class ConnectedMessage: Message + public class ConnectedMessage : Message { - } public readonly List receivedMessages = new List(); @@ -180,6 +195,15 @@ namespace VelNet //Debug.Log(messagesReceived++); receivedMessages.Add(m); } + + try + { + MessageReceived?.Invoke(m); + } + catch (Exception e) + { + Debug.LogError(e); + } } private void Update() @@ -191,216 +215,236 @@ namespace VelNet { switch (m) { - case ConnectedMessage connected: + case ConnectedMessage msg: + { + try { - try - { - OnConnectedToServer?.Invoke(); - } - // prevent errors in subscribers from breaking our code - catch (Exception e) - { - Debug.LogError(e); - } - break; + OnConnectedToServer?.Invoke(); } + // prevent errors in subscribers from breaking our code + catch (Exception e) + { + Debug.LogError(e); + } + + break; + } case LoginMessage lm: + { + userid = lm.userId; + Debug.Log("Joined server " + userid); + + try { - userid = lm.userId; - Debug.Log("joined server " + userid); - - try - { - LoggedIn?.Invoke(); - } - // prevent errors in subscribers from breaking our code - catch (Exception e) - { - Debug.LogError(e); - } - - //start the udp thread - clientReceiveThreadUDP = new Thread(ListenForDataUDP); - clientReceiveThreadUDP.IsBackground = true; - clientReceiveThreadUDP.Start(); - - break; + OnLoggedIn?.Invoke(); } - case RoomsMessage rm: { - Debug.Log("Got Rooms Message"); - - break; + // prevent errors in subscribers from breaking our code + catch (Exception e) + { + Debug.LogError(e); } - case JoinMessage jm: { - if(userid == jm.userId) //this is us + + //start the udp thread + clientReceiveThreadUDP = new Thread(ListenForDataUDP); + clientReceiveThreadUDP.Start(); + + break; + } + case RoomsMessage rm: + { + Debug.Log("Got Rooms Message:\n" + rm); + + try + { + RoomsReceived?.Invoke(rm); + } + // prevent errors in subscribers from breaking our code + catch (Exception e) + { + Debug.LogError(e); + } + + break; + } + case JoinMessage jm: + { + if (userid == jm.userId) //this is us + { + string oldRoom = LocalPlayer?.room; + + // we clear the list, but will recreate as we get messages from people in our room + players.Clear(); + masterPlayer = null; + + if (jm.room != "") { - string oldRoom = LocalPlayer?.room; - - // we clear the list, but will recreate as we get messages from people in our room - players.Clear(); - masterPlayer = null; - - if (jm.room != "") + VelNetPlayer player = new VelNetPlayer { - VelNetPlayer player = new VelNetPlayer - { - isLocal = true, - userid = jm.userId, - room = jm.room - }; + isLocal = true, + userid = jm.userId, + room = jm.room + }; - players.Add(userid, player); - - try - { - OnJoinedRoom?.Invoke(jm.room); - } - // prevent errors in subscribers from breaking our code - catch (Exception e) - { - Debug.LogError(e); - } - + players.Add(userid, player); + + try + { + OnJoinedRoom?.Invoke(jm.room); } - // we just left a room - else + // prevent errors in subscribers from breaking our code + catch (Exception e) { - // delete all networkobjects that aren't sceneobjects or are null now - objects - .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) - { - SetupMessageGroup(group, new List()); - } - - instance.groups.Clear(); - - try - { - OnLeftRoom?.Invoke(oldRoom); - } - // prevent errors in subscribers from breaking our code - catch (Exception e) - { - Debug.LogError(e); - } + Debug.LogError(e); } } + // we just left a room else { - VelNetPlayer me = players[userid]; + // delete all networkobjects that aren't sceneobjects or are null now + objects + .Where(kvp => kvp.Value == null || !kvp.Value.isSceneObject) + .Select(o => o.Key) + .ToList().ForEach(NetworkDestroy); - if (me.room != jm.room) + // then remove references to the ones that are left + objects.Clear(); + + // empty all the groups + foreach (string group in instance.groups.Keys) { - // we got a left message, kill it - // change ownership of all objects to master - List deleteObjects = new List(); - foreach (KeyValuePair kvp in objects) + SetupMessageGroup(group, new List()); + } + + instance.groups.Clear(); + + try + { + OnLeftRoom?.Invoke(oldRoom); + } + // prevent errors in subscribers from breaking our code + catch (Exception e) + { + Debug.LogError(e); + } + } + } + else + { + VelNetPlayer me = players[userid]; + + if (me.room != jm.room) + { + // we got a left message, kill it + // change ownership of all objects to master + List deleteObjects = new List(); + foreach (KeyValuePair kvp in objects) + { + if (kvp.Value.owner == players[jm.userId]) // the owner is the player that left { - if (kvp.Value.owner == players[jm.userId]) // the owner is the player that left + // if this object has locked ownership, delete it + if (kvp.Value.ownershipLocked) { - // if this object has locked ownership, delete it - if (kvp.Value.ownershipLocked) - { - deleteObjects.Add(kvp.Value.networkId); - } - // I'm the local master player, so can take ownership immediately - else if (me.isLocal && me == masterPlayer) - { - TakeOwnership(kvp.Key); - } - // the master player left, so everyone should set the owner null (we should get a new master shortly) - else if (players[jm.userId] == masterPlayer) - { - kvp.Value.owner = null; - } + deleteObjects.Add(kvp.Value.networkId); + } + // I'm the local master player, so can take ownership immediately + else if (me.isLocal && me == masterPlayer) + { + TakeOwnership(kvp.Key); + } + // the master player left, so everyone should set the owner null (we should get a new master shortly) + else if (players[jm.userId] == masterPlayer) + { + kvp.Value.owner = null; } } - - // TODO this may check for ownership in the future. We don't need ownership here - deleteObjects.ForEach(NetworkDestroy); - - players.Remove(jm.userId); } - else + + // TODO this may check for ownership in the future. We don't need ownership here + deleteObjects.ForEach(NetworkDestroy); + + VelNetPlayer leftPlayer = players[jm.userId]; + players.Remove(jm.userId); + + try { - // we got a join message, create it - VelNetPlayer player = new VelNetPlayer - { - isLocal = false, - room = jm.room, - userid = jm.userId - }; - players.Add(jm.userId, player); - try - { - OnPlayerJoined?.Invoke(player); - } - // prevent errors in subscribers from breaking our code - catch (Exception e) - { - Debug.LogError(e); - } + OnPlayerLeft?.Invoke(leftPlayer); } - } - break; - - } - case DataMessage dm: { - if (players.ContainsKey(dm.senderId)) - { - players[dm.senderId]?.HandleMessage(dm); //todo - } - else - { - Debug.LogError("Received message from player that doesn't exist "); - } - - break; - - - } - case ChangeMasterMessage cm: { - - if (masterPlayer == null) - { - masterPlayer = players[cm.masterId]; - - // no master player yet, add the scene objects - - for (int i = 0; i < sceneObjects.Length; i++) + // prevent errors in subscribers from breaking our code + catch (Exception e) { - sceneObjects[i].networkId = -1 + "-" + i; - sceneObjects[i].owner = masterPlayer; - sceneObjects[i].isSceneObject = true; // needed for special handling when deleted - objects.Add(sceneObjects[i].networkId, sceneObjects[i]); + Debug.LogError(e); } } else { - masterPlayer = players[cm.masterId]; + // we got a join message, create it + VelNetPlayer player = new VelNetPlayer + { + isLocal = false, + room = jm.room, + userid = jm.userId + }; + players.Add(jm.userId, player); + try + { + OnPlayerJoined?.Invoke(player); + } + // prevent errors in subscribers from breaking our code + catch (Exception e) + { + Debug.LogError(e); + } } - - masterPlayer.SetAsMasterPlayer(); - - // master player should take over any objects that do not have an owner - foreach (KeyValuePair kvp in objects) - { - kvp.Value.owner ??= masterPlayer; - } - - break; - } + + break; + } + case DataMessage dm: + { + if (players.ContainsKey(dm.senderId)) + { + players[dm.senderId]?.HandleMessage(dm); //todo + } + else + { + Debug.LogError("Received message from player that doesn't exist "); + } + + break; + } + case ChangeMasterMessage cm: + { + if (masterPlayer == null) + { + masterPlayer = players[cm.masterId]; + + // no master player yet, add the scene objects + + for (int i = 0; i < sceneObjects.Length; i++) + { + sceneObjects[i].networkId = -1 + "-" + i; + sceneObjects[i].owner = masterPlayer; + sceneObjects[i].isSceneObject = true; // needed for special handling when deleted + objects.Add(sceneObjects[i].networkId, sceneObjects[i]); + } + } + else + { + masterPlayer = players[cm.masterId]; + } + + masterPlayer.SetAsMasterPlayer(); + + // master player should take over any objects that do not have an owner + foreach (KeyValuePair kvp in objects) + { + kvp.Value.owner ??= masterPlayer; + } + + break; + } } - + //MessageReceived?.Invoke(m); } @@ -421,7 +465,6 @@ namespace VelNet try { clientReceiveThread = new Thread(ListenForData); - clientReceiveThread.IsBackground = true; clientReceiveThread.Start(); } catch (Exception e) @@ -432,10 +475,9 @@ namespace VelNet /// - /// Runs in background clientReceiveThread; Listens for incomming data. - /// - /// - private byte[] ReadExact(NetworkStream stream, int N) + /// Runs in background clientReceiveThread; Listens for incoming data. + /// + private static byte[] ReadExact(Stream stream, int N) { byte[] toReturn = new byte[N]; @@ -446,20 +488,15 @@ namespace VelNet numRead += stream.Read(toReturn, numRead, numLeft); numLeft = N - numRead; } + return toReturn; } - private int GetIntFromBytes(byte[] bytes) + private static int GetIntFromBytes(byte[] bytes) { - if (BitConverter.IsLittleEndian) - { - return BitConverter.ToInt32(bytes.Reverse().ToArray(),0); - } - else - { - return BitConverter.ToInt32(bytes, 0); - } + return BitConverter.ToInt32(BitConverter.IsLittleEndian ? bytes.Reverse().ToArray() : bytes, 0); } + private void ListenForData() { connected = true; @@ -476,44 +513,43 @@ namespace VelNet //SendToGroup("close", Encoding.UTF8.GetBytes("HelloGroup")); while (true) { - // Get a stream object for reading - + //read a byte byte type = (byte)stream.ReadByte(); - + if (type == 0) //login { LoginMessage m = new LoginMessage(); m.userId = GetIntFromBytes(ReadExact(stream, 4)); //not really the sender... AddMessage(m); } - else if(type == 1) //rooms + else if (type == 1) //rooms { - RoomsMessage m = new RoomsMessage(); m.rooms = new List(); int N = GetIntFromBytes(ReadExact(stream, 4)); //the size of the payload byte[] utf8data = ReadExact(stream, N); string roomMessage = Encoding.UTF8.GetString(utf8data); - string[] sections = roomMessage.Split(','); foreach (string s in sections) { string[] pieces = s.Split(':'); - if (pieces.Length == 2) { + if (pieces.Length == 2) + { ListedRoom lr = new ListedRoom(); lr.name = pieces[0]; lr.numUsers = int.Parse(pieces[1]); m.rooms.Add(lr); } } + AddMessage(m); } - else if(type == 2) //joined + else if (type == 2) //joined { JoinMessage m = new JoinMessage(); m.userId = GetIntFromBytes(ReadExact(stream, 4)); @@ -521,7 +557,8 @@ namespace VelNet byte[] utf8data = ReadExact(stream, N); //the room name, encoded as utf-8 m.room = Encoding.UTF8.GetString(utf8data); AddMessage(m); - }else if(type == 3) //data + } + else if (type == 3) //data { DataMessage m = new DataMessage(); m.senderId = GetIntFromBytes(ReadExact(stream, 4)); @@ -529,10 +566,10 @@ namespace VelNet m.data = ReadExact(stream, N); //the message AddMessage(m); } - else if(type == 4) //new master + else if (type == 4) //new master { ChangeMasterMessage m = new ChangeMasterMessage(); - m.masterId = (int)GetIntFromBytes(ReadExact(stream, 4)); //sender is the new master + m.masterId = GetIntFromBytes(ReadExact(stream, 4)); //sender is the new master AddMessage(m); } } @@ -584,20 +621,24 @@ namespace VelNet while (true) { int numReceived = udpSocket.Receive(buffer); - if (buffer[0] == 0) + switch (buffer[0]) { - Debug.Log("UDP connected"); - }else if (buffer[0] == 3) - { - DataMessage m = new DataMessage(); - //we should get the sender address - byte[] senderBytes = new byte[4]; - Array.Copy(buffer, 1, senderBytes, 0, 4); - m.senderId = GetIntFromBytes(senderBytes); - byte[] messageBytes = new byte[numReceived - 5]; - Array.Copy(buffer, 5, messageBytes, 0, messageBytes.Length); - m.data = messageBytes; - AddMessage(m); + case 0: + Debug.Log("UDP connected"); + break; + case 3: + { + DataMessage m = new DataMessage(); + //we should get the sender address + byte[] senderBytes = new byte[4]; + Array.Copy(buffer, 1, senderBytes, 0, 4); + m.senderId = GetIntFromBytes(senderBytes); + byte[] messageBytes = new byte[numReceived - 5]; + Array.Copy(buffer, 5, messageBytes, 0, messageBytes.Length); + m.data = messageBytes; + AddMessage(m); + break; + } } } } @@ -634,8 +675,7 @@ namespace VelNet NetworkStream stream = instance.socketConnection.GetStream(); if (stream.CanWrite) { - - stream.Write(message,0,message.Length); + stream.Write(message, 0, message.Length); } } catch (SocketException socketException) @@ -652,9 +692,9 @@ namespace VelNet { return BitConverter.GetBytes(n).Reverse().ToArray(); } + public static void Login(string username, string password) { - MemoryStream stream = new MemoryStream(); BinaryWriter writer = new BinaryWriter(stream); @@ -667,14 +707,11 @@ namespace VelNet writer.Write(pB); SendTcpMessage(stream.ToArray()); - - } public static void GetRooms() { - - SendTcpMessage(new byte[1] { 1 }); //very simple message + SendTcpMessage(new byte[] { 1 }); //very simple message } /// @@ -691,13 +728,8 @@ namespace VelNet writer.Write((byte)R.Length); writer.Write(R); SendTcpMessage(stream.ToArray()); - - - - } - /// /// Leaves a room if we're in one @@ -712,12 +744,12 @@ namespace VelNet public static void SendToRoom(byte[] message, bool include_self = false, bool reliable = true, bool ordered = false) { - byte sendType = (byte) MessageSendType.MESSAGE_OTHERS; + byte sendType = (byte)MessageSendType.MESSAGE_OTHERS; if (include_self && ordered) sendType = (byte)MessageSendType.MESSAGE_ALL_ORDERED; if (include_self && !ordered) sendType = (byte)MessageSendType.MESSAGE_ALL; if (!include_self && ordered) sendType = (byte)MessageSendType.MESSAGE_OTHERS_ORDERED; - + if (reliable) { MemoryStream stream = new MemoryStream(); @@ -730,10 +762,10 @@ namespace VelNet else { //udp message needs the type - toSend[0] = sendType; //we don't + toSend[0] = sendType; //we don't Array.Copy(get_be_bytes(instance.userid), 0, toSend, 1, 4); Array.Copy(message, 0, toSend, 5, message.Length); - SendUdpMessage(toSend,message.Length+5); //shouldn't be over 1024... + SendUdpMessage(toSend, message.Length + 5); //shouldn't be over 1024... } } @@ -759,7 +791,7 @@ namespace VelNet //also need to send the group toSend[5] = (byte)utf8bytes.Length; Array.Copy(utf8bytes, 0, toSend, 6, utf8bytes.Length); - Array.Copy(message, 0, toSend, 6+utf8bytes.Length, message.Length); + Array.Copy(message, 0, toSend, 6 + utf8bytes.Length, message.Length); SendUdpMessage(toSend, 6 + utf8bytes.Length + message.Length); } } @@ -785,6 +817,7 @@ namespace VelNet { writer.Write(get_be_bytes(client_ids[i])); } + SendTcpMessage(stream.ToArray()); } @@ -805,6 +838,7 @@ namespace VelNet 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 = networkId; newObject.prefabName = prefabName; @@ -812,7 +846,7 @@ namespace VelNet instance.objects.Add(newObject.networkId, newObject); // only sent to others, as I already instantiated this. Nice that it happens immediately. - SendToRoom(Encoding.UTF8.GetBytes("7," + newObject.networkId + "," + prefabName),false,true); + SendToRoom(Encoding.UTF8.GetBytes("7," + newObject.networkId + "," + prefabName), false, true); return newObject; } @@ -842,6 +876,7 @@ namespace VelNet instance.objects.Remove(networkId); return; } + if (obj.isSceneObject) { instance.deletedSceneObjects.Add(networkId); @@ -864,7 +899,7 @@ namespace VelNet Debug.LogError("Can't take ownership. No local player."); return false; } - + // obj must exist if (!instance.objects.ContainsKey(networkId)) { @@ -878,7 +913,7 @@ namespace VelNet Debug.LogError("Can't take ownership. Ownership for this object is locked."); return false; } - + // immediately successful instance.objects[networkId].owner = LocalPlayer; @@ -888,4 +923,4 @@ namespace VelNet return true; } } -} +} \ No newline at end of file diff --git a/TestVelGameServer/Packages/VelNetUnity/package.json b/TestVelGameServer/Packages/VelNetUnity/package.json index 956001f..c278bc1 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.7", + "version": "1.0.8", "unity": "2019.1", "description": "A custom networking library for Unity.", "keywords": [ diff --git a/TestVelGameServer/Packages/manifest.json b/TestVelGameServer/Packages/manifest.json index 9dde81b..ce7db77 100644 --- a/TestVelGameServer/Packages/manifest.json +++ b/TestVelGameServer/Packages/manifest.json @@ -2,13 +2,13 @@ "dependencies": { "com.unity.collab-proxy": "1.15.7", "com.unity.ide.rider": "2.0.7", - "com.unity.ide.visualstudio": "2.0.12", + "com.unity.ide.visualstudio": "2.0.14", "com.unity.ide.vscode": "1.2.4", "com.unity.test-framework": "1.1.30", "com.unity.textmeshpro": "3.0.6", "com.unity.timeline": "1.4.8", "com.unity.ugui": "1.0.0", - "edu.uga.engr.vel.velnet.dissonance": "file:c:/git_repo/VelNetDissonanceIntegration", + "edu.uga.engr.vel.velnet.dissonance": "https://github.com/velaboratory/VelNetDissonanceIntegration.git", "com.unity.modules.ai": "1.0.0", "com.unity.modules.androidjni": "1.0.0", "com.unity.modules.animation": "1.0.0", diff --git a/TestVelGameServer/Packages/packages-lock.json b/TestVelGameServer/Packages/packages-lock.json index 0a48dcc..012ff4f 100644 --- a/TestVelGameServer/Packages/packages-lock.json +++ b/TestVelGameServer/Packages/packages-lock.json @@ -27,7 +27,7 @@ "url": "https://packages.unity.com" }, "com.unity.ide.visualstudio": { - "version": "2.0.12", + "version": "2.0.14", "depth": 0, "source": "registry", "dependencies": { @@ -106,12 +106,13 @@ "dependencies": {} }, "edu.uga.engr.vel.velnet.dissonance": { - "version": "file:c:/git_repo/VelNetDissonanceIntegration", + "version": "https://github.com/velaboratory/VelNetDissonanceIntegration.git", "depth": 0, - "source": "local", + "source": "git", "dependencies": { "edu.uga.engr.vel.velnet": "1.0.4" - } + }, + "hash": "2767cf12e6f1b5c568c44cd6f1753866ae2e6fca" }, "com.unity.modules.ai": { "version": "1.0.0", diff --git a/TestVelGameServer/ProjectSettings/ProjectVersion.txt b/TestVelGameServer/ProjectSettings/ProjectVersion.txt index e610e28..24993f7 100644 --- a/TestVelGameServer/ProjectSettings/ProjectVersion.txt +++ b/TestVelGameServer/ProjectSettings/ProjectVersion.txt @@ -1,2 +1,2 @@ -m_EditorVersion: 2020.3.11f1 -m_EditorVersionWithRevision: 2020.3.11f1 (99c7afb366b3) +m_EditorVersion: 2020.3.23f1 +m_EditorVersionWithRevision: 2020.3.23f1 (c5d91304a876) From 7d110bb8ad5d3df48b109fc82968444f4157da68 Mon Sep 17 00:00:00 2001 From: Anton Franzluebbers Date: Mon, 24 Jan 2022 21:32:09 -0500 Subject: [PATCH 11/14] added hybrid onchange compression to serializedobject helpers --- .../Example/TestNetworkedGameObject.prefab | 1 + .../Runtime/Util/BinaryWriterExtensions.cs | 10 +++++ .../Runtime/Util/NetworkSerializedObject.cs | 38 +++++++++++++++++-- .../Util/NetworkSerializedObjectStream.cs | 30 +++++++++++++-- 4 files changed, 72 insertions(+), 7 deletions(-) diff --git a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/TestNetworkedGameObject.prefab b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/TestNetworkedGameObject.prefab index 096eb0d..3be87ea 100644 --- a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/TestNetworkedGameObject.prefab +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/TestNetworkedGameObject.prefab @@ -161,6 +161,7 @@ MonoBehaviour: m_EditorClassIdentifier: networkObject: {fileID: 3951900052977689805} serializationRateHz: 60 + hybridOnChangeCompression: 1 useLocalTransform: 0 teleportDistance: 0 teleportAngle: 0 diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/BinaryWriterExtensions.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/BinaryWriterExtensions.cs index 2b39a98..a605837 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/BinaryWriterExtensions.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/BinaryWriterExtensions.cs @@ -65,6 +65,16 @@ namespace VelNet #endregion + public static bool SameAs(this byte[] bytes, byte[] otherBytes) + { + if (bytes.Length != otherBytes.Length) + { + return false; + } + + return !bytes.Where((t, i) => t != otherBytes[i]).Any(); + } + /// /// Compresses the list of bools into bytes using a bitmask /// diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObject.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObject.cs index 0569eed..f6fc434 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObject.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObject.cs @@ -1,6 +1,6 @@ -using System.Collections; +using System; +using System.Collections; using UnityEngine; -using UnityEngine.Serialization; namespace VelNet { @@ -9,6 +9,15 @@ namespace VelNet [Tooltip("Send rate of this object. This caps out at the framerate of the game.")] public float serializationRateHz = 30; + /// + /// If the data hasn't changed, only sends updates across the network at 1Hz + /// + public bool hybridOnChangeCompression = true; + + private byte[] lastSentBytes; + private double lastSendTime; + private const double slowSendInterval = 2; + protected virtual void Awake() { StartCoroutine(SendMessageUpdate()); @@ -18,9 +27,30 @@ namespace VelNet { while (true) { - if (IsMine) + try { - SendBytes(SendState()); + if (IsMine) + { + byte[] newBytes = SendState(); + if (hybridOnChangeCompression) + { + if (Time.timeAsDouble - lastSendTime > slowSendInterval || !lastSentBytes.SameAs(newBytes)) + { + SendBytes(newBytes); + } + } + else + { + SendBytes(newBytes); + } + + lastSendTime = Time.timeAsDouble; + lastSentBytes = newBytes; + } + } + catch (Exception e) + { + Debug.LogError(e); } yield return new WaitForSeconds(1f / serializationRateHz); diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObjectStream.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObjectStream.cs index 161791f..d3ac592 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObjectStream.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObjectStream.cs @@ -2,7 +2,6 @@ using System.Collections; using System.IO; using UnityEngine; -using UnityEngine.Serialization; namespace VelNet { @@ -11,6 +10,16 @@ namespace VelNet [Tooltip("Send rate of this object. This caps out at the framerate of the game.")] public float serializationRateHz = 30; + /// + /// If the data hasn't changed, only sends updates across the network at 1Hz + /// + public bool hybridOnChangeCompression = true; + + private byte[] lastSentBytes; + private double lastSendTime; + private const double slowSendInterval = 2; + + protected virtual void Awake() { StartCoroutine(SendMessageUpdate()); @@ -27,7 +36,22 @@ namespace VelNet using MemoryStream mem = new MemoryStream(); using BinaryWriter writer = new BinaryWriter(mem); SendState(writer); - SendBytes(mem.ToArray()); + + byte[] newBytes = mem.ToArray(); + if (hybridOnChangeCompression) + { + if (Time.timeAsDouble - lastSendTime > slowSendInterval || !lastSentBytes.SameAs(newBytes)) + { + SendBytes(newBytes); + } + } + else + { + SendBytes(newBytes); + } + + lastSendTime = Time.timeAsDouble; + lastSentBytes = newBytes; } } catch (Exception e) @@ -44,7 +68,7 @@ namespace VelNet { using MemoryStream mem = new MemoryStream(message); using BinaryReader reader = new BinaryReader(mem); - + ReceiveState(reader); } From 94333a389d5cbbb4d0c7851858fed879f3e038fd Mon Sep 17 00:00:00 2001 From: Anton Franzluebbers Date: Tue, 25 Jan 2022 21:28:35 -0500 Subject: [PATCH 12/14] moved message encoding to binary instead of string --- .../VelNet/1.0.4/Example/NetworkGUI.cs | 8 - .../VelNetUnity/Runtime/NetworkObject.cs | 5 +- .../Runtime/Util/BinaryWriterExtensions.cs | 12 +- .../Runtime/Util/NetworkSerializedObject.cs | 2 +- .../Util/NetworkSerializedObjectStream.cs | 2 +- .../VelNetUnity/Runtime/VelNetManager.cs | 170 +++++++++++------- .../VelNetUnity/Runtime/VelNetPlayer.cs | 116 ++++++++---- 7 files changed, 199 insertions(+), 116 deletions(-) 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 180392a..fbd763f 100644 --- a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/NetworkGUI.cs +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/NetworkGUI.cs @@ -21,14 +21,6 @@ namespace VelNet public Dropdown microphones; private DissonanceComms comms; - public void HandleSend() - { - if (sendInput.text != "") - { - VelNetManager.SendToRoom(Encoding.UTF8.GetBytes(sendInput.text)); - } - } - public void HandleLogin() { if (userInput.text != "") diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/NetworkObject.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/NetworkObject.cs index 5c605ac..9c09aef 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/NetworkObject.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/NetworkObject.cs @@ -62,7 +62,7 @@ namespace VelNet } else { - owner.SendMessage(this, index.ToString(), message, reliable); + VelNetPlayer.SendMessage(this, (byte)index, message, reliable); } } @@ -76,7 +76,7 @@ namespace VelNet // send the message and an identifier for which component it belongs to int index = syncedComponents.IndexOf(component); - owner.SendGroupMessage(this, group, index.ToString(), message, reliable); + VelNetPlayer.SendGroupMessage(this, group, (byte)index, message, reliable); } public void ReceiveBytes(string identifier, byte[] message) @@ -128,6 +128,7 @@ namespace VelNet foreach (NetworkComponent c in comps) { c.networkObject = t; + PrefabUtility.RecordPrefabInstancePropertyModifications(c); } PrefabUtility.RecordPrefabInstancePropertyModifications(t); } diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/BinaryWriterExtensions.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/BinaryWriterExtensions.cs index a605837..309a239 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/BinaryWriterExtensions.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/BinaryWriterExtensions.cs @@ -65,14 +65,20 @@ namespace VelNet #endregion - public static bool SameAs(this byte[] bytes, byte[] otherBytes) + public static bool BytesSame(byte[] b1, byte[] b2) { - if (bytes.Length != otherBytes.Length) + if (b1 == null && b2 != null) return false; // only one null + if (b1 != null && b2 == null) return false; // only one null + if (b1 == null) return true; // both null + + // length doesn't match + if (b1.Length != b2.Length) { return false; } - return !bytes.Where((t, i) => t != otherBytes[i]).Any(); + // check if any bytes are different + return !b1.Where((t, i) => t != b2[i]).Any(); } /// diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObject.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObject.cs index f6fc434..a645854 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObject.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObject.cs @@ -34,7 +34,7 @@ namespace VelNet byte[] newBytes = SendState(); if (hybridOnChangeCompression) { - if (Time.timeAsDouble - lastSendTime > slowSendInterval || !lastSentBytes.SameAs(newBytes)) + if (Time.timeAsDouble - lastSendTime > slowSendInterval || !BinaryWriterExtensions.BytesSame(lastSentBytes, newBytes)) { SendBytes(newBytes); } diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObjectStream.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObjectStream.cs index d3ac592..7623122 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObjectStream.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObjectStream.cs @@ -40,7 +40,7 @@ namespace VelNet byte[] newBytes = mem.ToArray(); if (hybridOnChangeCompression) { - if (Time.timeAsDouble - lastSendTime > slowSendInterval || !lastSentBytes.SameAs(newBytes)) + if (Time.timeAsDouble - lastSendTime > slowSendInterval || !BinaryWriterExtensions.BytesSame(lastSentBytes, newBytes)) { SendBytes(newBytes); } diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs index c166404..670e2c3 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs @@ -27,6 +27,15 @@ namespace VelNet MESSAGE_SETGROUP = 6 }; + public enum MessageType + { + ObjectSync, + TakeOwnership, + Instantiate, + Destroy, + DeleteSceneObjects + } + public string host; public int port; @@ -455,6 +464,8 @@ namespace VelNet private void OnApplicationQuit() { socketConnection?.Close(); + clientReceiveThreadUDP?.Abort(); + clientReceiveThread?.Abort(); } /// @@ -472,11 +483,13 @@ namespace VelNet Debug.Log("On client connect exception " + e); } } - - - /// - /// Runs in background clientReceiveThread; Listens for incoming data. + + /// + /// Reads N bytes /// + /// + /// + /// private static byte[] ReadExact(Stream stream, int N) { byte[] toReturn = new byte[N]; @@ -505,6 +518,7 @@ namespace VelNet socketConnection = new TcpClient(host, port); socketConnection.NoDelay = true; NetworkStream stream = socketConnection.GetStream(); + using BinaryReader reader = new BinaryReader(stream); //now we are connected, so add a message to the queue AddMessage(new ConnectedMessage()); //Join("MyRoom"); @@ -515,62 +529,74 @@ namespace VelNet { // Get a stream object for reading - //read a byte - byte type = (byte)stream.ReadByte(); + byte type = reader.ReadByte(); - if (type == 0) //login + switch (type) { - LoginMessage m = new LoginMessage(); - m.userId = GetIntFromBytes(ReadExact(stream, 4)); //not really the sender... - AddMessage(m); - } - else if (type == 1) //rooms - { - RoomsMessage m = new RoomsMessage(); - m.rooms = new List(); - int N = GetIntFromBytes(ReadExact(stream, 4)); //the size of the payload - byte[] utf8data = ReadExact(stream, N); - string roomMessage = Encoding.UTF8.GetString(utf8data); - - - string[] sections = roomMessage.Split(','); - foreach (string s in sections) + //login + case 0: { - string[] pieces = s.Split(':'); - if (pieces.Length == 2) - { - ListedRoom lr = new ListedRoom(); - lr.name = pieces[0]; - lr.numUsers = int.Parse(pieces[1]); - m.rooms.Add(lr); - } + LoginMessage m = new LoginMessage(); + m.userId = reader.ReadInt32(); //not really the sender... + AddMessage(m); + break; } + //rooms + case 1: + { + RoomsMessage m = new RoomsMessage(); + m.rooms = new List(); + int N = reader.ReadInt32(); //the size of the payload + byte[] utf8data = reader.ReadBytes(N); + string roomMessage = Encoding.UTF8.GetString(utf8data); - AddMessage(m); - } - else if (type == 2) //joined - { - JoinMessage m = new JoinMessage(); - m.userId = GetIntFromBytes(ReadExact(stream, 4)); - int N = stream.ReadByte(); - byte[] utf8data = ReadExact(stream, N); //the room name, encoded as utf-8 - m.room = Encoding.UTF8.GetString(utf8data); - AddMessage(m); - } - else if (type == 3) //data - { - DataMessage m = new DataMessage(); - m.senderId = GetIntFromBytes(ReadExact(stream, 4)); - int N = GetIntFromBytes(ReadExact(stream, 4)); //the size of the payload - m.data = ReadExact(stream, N); //the message - AddMessage(m); - } - else if (type == 4) //new master - { - ChangeMasterMessage m = new ChangeMasterMessage(); - m.masterId = GetIntFromBytes(ReadExact(stream, 4)); //sender is the new master - AddMessage(m); + + string[] sections = roomMessage.Split(','); + foreach (string s in sections) + { + string[] pieces = s.Split(':'); + if (pieces.Length == 2) + { + ListedRoom lr = new ListedRoom(); + lr.name = pieces[0]; + lr.numUsers = int.Parse(pieces[1]); + m.rooms.Add(lr); + } + } + + AddMessage(m); + break; + } + //joined + case 2: + { + JoinMessage m = new JoinMessage(); + m.userId = reader.ReadInt32(); + int N = reader.ReadByte(); + byte[] utf8data = reader.ReadBytes(N); //the room name, encoded as utf-8 + m.room = Encoding.UTF8.GetString(utf8data); + AddMessage(m); + break; + } + //data + case 3: + { + DataMessage m = new DataMessage(); + m.senderId = reader.ReadInt32(); + int N = reader.ReadInt32(); //the size of the payload + m.data = reader.ReadBytes(N); //the message + AddMessage(m); + break; + } + //new master + case 4: + { + ChangeMasterMessage m = new ChangeMasterMessage(); + m.masterId = reader.ReadInt32(); //sender is the new master + AddMessage(m); + break; + } } } } @@ -659,7 +685,7 @@ namespace VelNet } /// - /// Send message to server using socket connection. + /// Send message to server using socket connection. /// private static void SendTcpMessage(byte[] message) //we can assume that this message is already formatted, so we just send it { @@ -684,15 +710,14 @@ namespace VelNet } } - /// - /// Connects to the server with a username - /// - /// public static byte[] get_be_bytes(int n) { return BitConverter.GetBytes(n).Reverse().ToArray(); } + /// + /// Connects to the server with a username + /// public static void Login(string username, string password) { MemoryStream stream = new MemoryStream(); @@ -742,7 +767,7 @@ namespace VelNet } } - public static void SendToRoom(byte[] message, bool include_self = false, bool reliable = true, bool ordered = false) + internal static void SendToRoom(byte[] message, bool include_self = false, bool reliable = true, bool ordered = false) { byte sendType = (byte)MessageSendType.MESSAGE_OTHERS; if (include_self && ordered) sendType = (byte)MessageSendType.MESSAGE_ALL_ORDERED; @@ -752,12 +777,12 @@ namespace VelNet if (reliable) { - MemoryStream stream = new MemoryStream(); - BinaryWriter writer = new BinaryWriter(stream); + MemoryStream mem = new MemoryStream(); + BinaryWriter writer = new BinaryWriter(mem); writer.Write(sendType); writer.Write(get_be_bytes(message.Length)); writer.Write(message); - SendTcpMessage(stream.ToArray()); + SendTcpMessage(mem.ToArray()); } else { @@ -770,7 +795,7 @@ namespace VelNet } - public static void SendToGroup(string group, byte[] message, bool reliable = true) + internal static void SendToGroup(string group, byte[] message, bool reliable = true) { byte[] utf8bytes = Encoding.UTF8.GetBytes(group); if (reliable) @@ -845,8 +870,14 @@ namespace VelNet newObject.owner = localPlayer; instance.objects.Add(newObject.networkId, newObject); + // only sent to others, as I already instantiated this. Nice that it happens immediately. - SendToRoom(Encoding.UTF8.GetBytes("7," + newObject.networkId + "," + prefabName), false, true); + using MemoryStream mem = new MemoryStream(); + using BinaryWriter writer = new BinaryWriter(mem); + writer.Write((byte)MessageType.Instantiate); + writer.Write(newObject.networkId); + writer.Write(prefabName); + SendToRoom(mem.ToArray(), include_self:false, reliable:true); return newObject; } @@ -917,8 +948,13 @@ namespace VelNet // 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. - SendToRoom(Encoding.UTF8.GetBytes("6," + networkId)); + // 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. + using MemoryStream mem = new MemoryStream(); + using BinaryWriter writer = new BinaryWriter(mem); + writer.Write((byte)MessageType.TakeOwnership); + writer.Write(networkId); + SendToRoom(mem.ToArray(), false, true); return true; } diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetPlayer.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetPlayer.cs index 56bb8ff..f4fb524 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetPlayer.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetPlayer.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System; +using System.IO; using System.Text; namespace VelNet @@ -40,7 +41,12 @@ namespace VelNet { if (kvp.Value.owner == this && kvp.Value.prefabName != "") { - VelNetManager.SendToRoom(Encoding.UTF8.GetBytes("7," + kvp.Value.networkId + "," + kvp.Value.prefabName),false,true); + using MemoryStream mem = new MemoryStream(); + using BinaryWriter writer = new BinaryWriter(mem); + writer.Write((byte)VelNetManager.MessageType.Instantiate); + writer.Write(kvp.Value.networkId); + writer.Write(kvp.Value.prefabName); + VelNetManager.SendToRoom(mem.ToArray(), false, true); } } @@ -54,27 +60,39 @@ namespace VelNet /// /// These are generally things that come from the "owner" and should be enacted locally, where appropriate + /// + /// Overall message encoding: + /// uint16: numMessages + /// for m in numMessages + /// int32: message size (including message type) + /// byte: message type + /// byte[]: message /// public void HandleMessage(VelNetManager.DataMessage m) { - //for now, we can just convert to text...because + using MemoryStream mem = new MemoryStream(m.data); + using BinaryReader reader = new BinaryReader(mem); - string text = Encoding.UTF8.GetString(m.data); - - //types of messages - string[] messages = text.Split(';'); //messages are split by ; - foreach (string s in messages) + ushort numMessages = reader.ReadUInt16(); + + for (int i = 0; i < numMessages; i++) { //individual message parameters separated by comma - string[] sections = s.Split(','); + int messageLength = reader.ReadInt32(); + VelNetManager.MessageType messageType = (VelNetManager.MessageType)reader.ReadByte(); + byte[] message = reader.ReadBytes(messageLength-1); + + // make a separate reader to prevent malformed messages from messing us up + using MemoryStream messageMem = new MemoryStream(message); + using BinaryReader messageReader = new BinaryReader(messageMem); - switch (sections[0]) + switch (messageType) { - case "5": // sync update for an object I may own + case VelNetManager.MessageType.ObjectSync: // sync update for an object I may own { - string objectKey = sections[1]; - string identifier = sections[2]; - string syncMessage = sections[3]; + string objectKey = messageReader.ReadString(); + string identifier = messageReader.ReadString(); + string syncMessage = messageReader.ReadString(); byte[] messageBytes = Convert.FromBase64String(syncMessage); if (manager.objects.ContainsKey(objectKey)) { @@ -86,9 +104,9 @@ namespace VelNet break; } - case "6": // I'm trying to take ownership of an object + case VelNetManager.MessageType.TakeOwnership: // I'm trying to take ownership of an object { - string networkId = sections[1]; + string networkId = messageReader.ReadString(); if (manager.objects.ContainsKey(networkId)) { @@ -97,10 +115,10 @@ namespace VelNet break; } - case "7": // I'm trying to instantiate an object + case VelNetManager.MessageType.Instantiate: // I'm trying to instantiate an object { - string networkId = sections[1]; - string prefabName = sections[2]; + string networkId = messageReader.ReadString(); + string prefabName = messageReader.ReadString(); if (manager.objects.ContainsKey(networkId)) { break; //we already have this one, ignore @@ -110,22 +128,25 @@ namespace VelNet break; } - case "8": // I'm trying to destroy a gameobject I own + case VelNetManager.MessageType.Destroy: // I'm trying to destroy a gameobject I own { - string networkId = sections[1]; + string networkId = messageReader.ReadString(); VelNetManager.NetworkDestroy(networkId); break; } - case "9": //deleted scene objects + case VelNetManager.MessageType.DeleteSceneObjects: //deleted scene objects { - for (int k = 1; k < sections.Length; k++) + int len = messageReader.ReadInt32(); + for (int k = 1; k < len; k++) { - VelNetManager.NetworkDestroy(sections[k]); + VelNetManager.NetworkDestroy(messageReader.ReadString()); } break; } + default: + throw new ArgumentOutOfRangeException(); } } } @@ -137,22 +158,39 @@ namespace VelNet //FindObjectsOfType(); } - public void SendGroupMessage(NetworkObject obj, string group, string identifier, byte[] data, bool reliable = true) + public static void SendGroupMessage(NetworkObject obj, string group, byte componentIdx, byte[] data, bool reliable = true) { - string message = "5," + obj.networkId + "," + identifier + "," + Convert.ToBase64String(data); - VelNetManager.SendToGroup(group, Encoding.UTF8.GetBytes(message), reliable); + using MemoryStream mem = new MemoryStream(); + using BinaryWriter writer = new BinaryWriter(mem); + writer.Write((byte)VelNetManager.MessageType.ObjectSync); + writer.Write(obj.networkId); + writer.Write(componentIdx); + writer.Write(data); + VelNetManager.SendToGroup(group, mem.ToArray(), reliable); } - public void SendMessage(NetworkObject obj, string identifier, byte[] data, bool reliable = true) + public static void SendMessage(NetworkObject obj, byte componentIdx, byte[] data, bool reliable = true) { - string message = "5," + obj.networkId + "," + identifier + "," + Convert.ToBase64String(data); - VelNetManager.SendToRoom(Encoding.UTF8.GetBytes(message), false, reliable); + using MemoryStream mem = new MemoryStream(); + using BinaryWriter writer = new BinaryWriter(mem); + writer.Write((byte)VelNetManager.MessageType.ObjectSync); + writer.Write(obj.networkId); + writer.Write(componentIdx); + writer.Write(data); + VelNetManager.SendToRoom(mem.ToArray(), false, reliable); } public void SendSceneUpdate() { - string message = "9," + string.Join(",", manager.deletedSceneObjects); - VelNetManager.SendToRoom( Encoding.UTF8.GetBytes(message)); + using MemoryStream mem = new MemoryStream(); + using BinaryWriter writer = new BinaryWriter(mem); + writer.Write((byte)VelNetManager.MessageType.DeleteSceneObjects); + writer.Write(manager.deletedSceneObjects.Count); + foreach (string o in manager.deletedSceneObjects) + { + writer.Write(o); + } + VelNetManager.SendToRoom(mem.ToArray()); } [Obsolete("Use VelNetManager.NetworkDestroy() instead.")] @@ -162,7 +200,12 @@ namespace VelNet if (!manager.objects.ContainsKey(networkId) || manager.objects[networkId].owner != this || !isLocal) return; // send to all, which will make me delete as well - VelNetManager.SendToRoom(Encoding.UTF8.GetBytes("8," + networkId), true, true); + + using MemoryStream mem = new MemoryStream(); + using BinaryWriter writer = new BinaryWriter(mem); + writer.Write((byte)VelNetManager.MessageType.Destroy); + writer.Write(networkId); + VelNetManager.SendToRoom(mem.ToArray(), true, true); } /// True if successful, False if failed to transfer ownership @@ -178,8 +221,13 @@ namespace VelNet // 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.SendToRoom(Encoding.UTF8.GetBytes("6," + networkId),true,true); + // 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. + using MemoryStream mem = new MemoryStream(); + using BinaryWriter writer = new BinaryWriter(mem); + writer.Write((byte)VelNetManager.MessageType.TakeOwnership); + writer.Write(networkId); + VelNetManager.SendToRoom(mem.ToArray(), true, true, ordered: true); return true; } From e837b624cc43b6f4239ecfe0618837d14cb6b57e Mon Sep 17 00:00:00 2001 From: Anton Franzluebbers Date: Tue, 25 Jan 2022 22:50:30 -0500 Subject: [PATCH 13/14] correct conversion of messages to binary (maybe) --- .../VelNet/1.0.4/Example/PlayerController.cs | 7 +- .../VelNet/1.0.4/Example/PlayerPrefab.prefab | 4 +- .../Samples/VelNet/1.0.4/Example/test.unity | 528 +----------------- .../VelNetUnity/Runtime/NetworkObject.cs | 4 +- .../Runtime/Util/NetworkSerializedObject.cs | 5 +- .../Util/NetworkSerializedObjectStream.cs | 5 +- .../VelNetUnity/Runtime/VelNetManager.cs | 46 +- .../VelNetUnity/Runtime/VelNetPlayer.cs | 135 +++-- 8 files changed, 111 insertions(+), 623 deletions(-) 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 6cad912..c9ab2f9 100644 --- a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/PlayerController.cs +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/PlayerController.cs @@ -65,7 +65,12 @@ namespace VelNet protected override void ReceiveState(BinaryReader binaryReader) { - Color newColor = binaryReader.ReadColor(); + // Color newColor = binaryReader.ReadColor(); + Color newColor; + newColor.r = binaryReader.ReadSingle(); + newColor.g = binaryReader.ReadSingle(); + newColor.b = binaryReader.ReadSingle(); + newColor.a = binaryReader.ReadSingle(); if (newColor != color) { rend.material.color = newColor; 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 6ab0ec1..94ec1b1 100644 --- a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/PlayerPrefab.prefab +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/PlayerPrefab.prefab @@ -200,8 +200,8 @@ MonoBehaviour: isSceneObject: 0 syncedComponents: - {fileID: -4404668399269848200} - - {fileID: 7564913803199044469} - {fileID: 1181612843795795320} + - {fileID: 7564913803199044469} --- !u!114 &-4404668399269848200 MonoBehaviour: m_ObjectHideFlags: 0 @@ -216,6 +216,7 @@ MonoBehaviour: m_EditorClassIdentifier: networkObject: {fileID: 9102273340480352682} serializationRateHz: 30 + hybridOnChangeCompression: 1 color: {r: 0, g: 0, b: 0, a: 0} --- !u!114 &1181612843795795320 MonoBehaviour: @@ -248,6 +249,7 @@ MonoBehaviour: m_EditorClassIdentifier: networkObject: {fileID: 9102273340480352682} serializationRateHz: 60 + hybridOnChangeCompression: 1 useLocalTransform: 0 teleportDistance: 0 teleportAngle: 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 4688170..97ccff3 100644 --- a/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test.unity +++ b/TestVelGameServer/Assets/Samples/VelNet/1.0.4/Example/test.unity @@ -603,8 +603,6 @@ RectTransform: - {fileID: 626742070} - {fileID: 711524767} - {fileID: 864104176} - - {fileID: 945446556} - - {fileID: 1843597586} - {fileID: 948755938} - {fileID: 545137760} m_Father: {fileID: 0} @@ -629,7 +627,7 @@ MonoBehaviour: m_EditorClassIdentifier: velNetManager: {fileID: 1099803616} userInput: {fileID: 626742069} - sendInput: {fileID: 945446555} + sendInput: {fileID: 0} roomInput: {fileID: 711524768} messages: {fileID: 1894247854} messageBuffer: [] @@ -890,11 +888,11 @@ RectTransform: m_Children: - {fileID: 1081889596} m_Father: {fileID: 244561620} - m_RootOrder: 10 + m_RootOrder: 8 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} - m_AnchoredPosition: {x: 5, y: 165.7} + m_AnchoredPosition: {x: 5, y: 76.8} m_SizeDelta: {x: 160, y: 30} m_Pivot: {x: 0, y: 0} --- !u!114 &545137761 @@ -1953,149 +1951,6 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 927188572} m_CullTransparentMesh: 1 ---- !u!1 &945446554 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 945446556} - - component: {fileID: 945446558} - - component: {fileID: 945446557} - - component: {fileID: 945446555} - m_Layer: 5 - m_Name: Message - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &945446555 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 945446554} - 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: 945446557} - m_TextComponent: {fileID: 1235343403} - m_Placeholder: {fileID: 1954037270} - m_ContentType: 0 - m_InputType: 0 - m_AsteriskChar: 42 - m_KeyboardType: 0 - m_LineType: 0 - 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!224 &945446556 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 945446554} - 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: 1954037272} - - {fileID: 1235343401} - m_Father: {fileID: 244561620} - m_RootOrder: 7 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 0, y: 0} - m_AnchoredPosition: {x: 181.94519, y: 88} - m_SizeDelta: {x: 353.8904, y: 30} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &945446557 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 945446554} - 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 &945446558 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 945446554} - m_CullTransparentMesh: 1 --- !u!1 &948755937 GameObject: m_ObjectHideFlags: 0 @@ -2132,7 +1987,7 @@ RectTransform: - {fileID: 1840952814} - {fileID: 1992361063} m_Father: {fileID: 244561620} - m_RootOrder: 9 + m_RootOrder: 7 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 1, y: 0} m_AnchorMax: {x: 1, y: 0} @@ -2153,6 +2008,7 @@ MonoBehaviour: m_EditorClassIdentifier: networkObject: {fileID: 948755940} serializationRateHz: 30 + hybridOnChangeCompression: 1 text: {fileID: 948755941} --- !u!114 &948755940 MonoBehaviour: @@ -2671,85 +2527,6 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1154194181} m_CullTransparentMesh: 1 ---- !u!1 &1235343400 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1235343401} - - component: {fileID: 1235343402} - - component: {fileID: 1235343403} - m_Layer: 5 - m_Name: Text - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &1235343401 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1235343400} - 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: 945446556} - 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.5} - m_SizeDelta: {x: -20, y: -13} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!222 &1235343402 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1235343400} - m_CullTransparentMesh: 1 ---- !u!114 &1235343403 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1235343400} - 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: 1 - m_VerticalOverflow: 0 - m_LineSpacing: 1 - m_Text: --- !u!1 &1278634766 GameObject: m_ObjectHideFlags: 0 @@ -3644,218 +3421,6 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1840952813} m_CullTransparentMesh: 1 ---- !u!1 &1843597585 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1843597586} - - component: {fileID: 1843597589} - - component: {fileID: 1843597588} - - component: {fileID: 1843597587} - m_Layer: 5 - m_Name: Send - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &1843597586 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1843597585} - 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: 1852007163} - m_Father: {fileID: 244561620} - m_RootOrder: 8 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 0, y: 0} - m_AnchoredPosition: {x: 416.95, y: 88} - m_SizeDelta: {x: 94.1, y: 30} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!114 &1843597587 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1843597585} - 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: 1843597588} - m_OnClick: - m_PersistentCalls: - m_Calls: - - m_Target: {fileID: 244561621} - m_TargetAssemblyTypeName: NetworkGUI, Assembly-CSharp - m_MethodName: HandleSend - 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 &1843597588 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1843597585} - 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 &1843597589 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1843597585} - m_CullTransparentMesh: 1 ---- !u!1 &1852007162 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1852007163} - - component: {fileID: 1852007165} - - component: {fileID: 1852007164} - m_Layer: 5 - m_Name: Text - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &1852007163 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1852007162} - 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: 1843597586} - 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 &1852007164 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1852007162} - 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: Send ---- !u!222 &1852007165 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1852007162} - m_CullTransparentMesh: 1 --- !u!1 &1894247852 GameObject: m_ObjectHideFlags: 0 @@ -3935,85 +3500,6 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1894247852} m_CullTransparentMesh: 1 ---- !u!1 &1954037269 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 1954037272} - - component: {fileID: 1954037271} - - component: {fileID: 1954037270} - m_Layer: 5 - m_Name: Placeholder - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!114 &1954037270 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1954037269} - 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 &1954037271 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1954037269} - m_CullTransparentMesh: 1 ---- !u!224 &1954037272 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1954037269} - 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: 945446556} - 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.5} - m_SizeDelta: {x: -20, y: -13} - m_Pivot: {x: 0.5, y: 0.5} --- !u!1 &1992361062 GameObject: m_ObjectHideFlags: 0 @@ -4395,6 +3881,10 @@ PrefabInstance: propertyPath: m_Name value: TestNetworkedGameObject objectReference: {fileID: 0} + - target: {fileID: 8565720275311462453, guid: 6e4a023f70e01405e8b249a4488fe319, type: 3} + propertyPath: m_IsActive + value: 1 + objectReference: {fileID: 0} - target: {fileID: 8565720275311462455, guid: 6e4a023f70e01405e8b249a4488fe319, type: 3} propertyPath: m_RootOrder value: 6 diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/NetworkObject.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/NetworkObject.cs index 9c09aef..0dd136a 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/NetworkObject.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/NetworkObject.cs @@ -79,12 +79,12 @@ namespace VelNet VelNetPlayer.SendGroupMessage(this, group, (byte)index, message, reliable); } - public void ReceiveBytes(string identifier, byte[] message) + public void ReceiveBytes(byte componentIdx, byte[] message) { // send the message to the right component try { - syncedComponents[int.Parse(identifier)].ReceiveBytes(message); + syncedComponents[componentIdx].ReceiveBytes(message); } catch (Exception e) { diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObject.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObject.cs index a645854..7836f2b 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObject.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObject.cs @@ -29,7 +29,7 @@ namespace VelNet { try { - if (IsMine) + if (IsMine && enabled) { byte[] newBytes = SendState(); if (hybridOnChangeCompression) @@ -37,14 +37,15 @@ namespace VelNet if (Time.timeAsDouble - lastSendTime > slowSendInterval || !BinaryWriterExtensions.BytesSame(lastSentBytes, newBytes)) { SendBytes(newBytes); + lastSendTime = Time.timeAsDouble; } } else { SendBytes(newBytes); + lastSendTime = Time.timeAsDouble; } - lastSendTime = Time.timeAsDouble; lastSentBytes = newBytes; } } diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObjectStream.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObjectStream.cs index 7623122..5808afd 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObjectStream.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/Util/NetworkSerializedObjectStream.cs @@ -31,7 +31,7 @@ namespace VelNet { try { - if (IsMine) + if (IsMine && enabled) { using MemoryStream mem = new MemoryStream(); using BinaryWriter writer = new BinaryWriter(mem); @@ -43,14 +43,15 @@ namespace VelNet if (Time.timeAsDouble - lastSendTime > slowSendInterval || !BinaryWriterExtensions.BytesSame(lastSentBytes, newBytes)) { SendBytes(newBytes); + lastSendTime = Time.timeAsDouble; } } else { SendBytes(newBytes); + lastSendTime = Time.timeAsDouble; } - lastSendTime = Time.timeAsDouble; lastSentBytes = newBytes; } } diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs index 670e2c3..9234857 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs @@ -412,7 +412,7 @@ namespace VelNet { if (players.ContainsKey(dm.senderId)) { - players[dm.senderId]?.HandleMessage(dm); //todo + players[dm.senderId]?.HandleMessage(dm); } else { @@ -431,7 +431,11 @@ namespace VelNet for (int i = 0; i < sceneObjects.Length; i++) { - sceneObjects[i].networkId = -1 + "-" + i; + if (sceneObjects[i].sceneNetworkId == 0) + { + Debug.LogError("Scene Network ID is 0. Make sure to assign one first.", sceneObjects[i]); + } + sceneObjects[i].networkId = -1 + "-" + sceneObjects[i].sceneNetworkId; sceneObjects[i].owner = masterPlayer; sceneObjects[i].isSceneObject = true; // needed for special handling when deleted objects.Add(sceneObjects[i].networkId, sceneObjects[i]); @@ -483,13 +487,11 @@ namespace VelNet Debug.Log("On client connect exception " + e); } } - - /// - /// Reads N bytes + + + /// + /// Runs in background clientReceiveThread; Listens for incoming data. /// - /// - /// - /// private static byte[] ReadExact(Stream stream, int N) { byte[] toReturn = new byte[N]; @@ -517,20 +519,16 @@ namespace VelNet { socketConnection = new TcpClient(host, port); socketConnection.NoDelay = true; + // Get a stream object for reading NetworkStream stream = socketConnection.GetStream(); using BinaryReader reader = new BinaryReader(stream); //now we are connected, so add a message to the queue AddMessage(new ConnectedMessage()); - //Join("MyRoom"); - //SendTo(MessageSendType.MESSAGE_OTHERS, Encoding.UTF8.GetBytes("Hello")); - //FormGroup("close", new List { 1 }); - //SendToGroup("close", Encoding.UTF8.GetBytes("HelloGroup")); while (true) { - // Get a stream object for reading //read a byte - byte type = reader.ReadByte(); + byte type = (byte)stream.ReadByte(); switch (type) { @@ -538,7 +536,7 @@ namespace VelNet case 0: { LoginMessage m = new LoginMessage(); - m.userId = reader.ReadInt32(); //not really the sender... + m.userId = GetIntFromBytes(ReadExact(stream, 4)); //not really the sender... AddMessage(m); break; } @@ -547,8 +545,8 @@ namespace VelNet { RoomsMessage m = new RoomsMessage(); m.rooms = new List(); - int N = reader.ReadInt32(); //the size of the payload - byte[] utf8data = reader.ReadBytes(N); + int N = GetIntFromBytes(ReadExact(stream, 4)); //the size of the payload + byte[] utf8data = ReadExact(stream, N); string roomMessage = Encoding.UTF8.GetString(utf8data); @@ -572,9 +570,9 @@ namespace VelNet case 2: { JoinMessage m = new JoinMessage(); - m.userId = reader.ReadInt32(); - int N = reader.ReadByte(); - byte[] utf8data = reader.ReadBytes(N); //the room name, encoded as utf-8 + m.userId = GetIntFromBytes(ReadExact(stream, 4)); + int N = stream.ReadByte(); + byte[] utf8data = ReadExact(stream, N); //the room name, encoded as utf-8 m.room = Encoding.UTF8.GetString(utf8data); AddMessage(m); break; @@ -583,9 +581,9 @@ namespace VelNet case 3: { DataMessage m = new DataMessage(); - m.senderId = reader.ReadInt32(); - int N = reader.ReadInt32(); //the size of the payload - m.data = reader.ReadBytes(N); //the message + m.senderId = GetIntFromBytes(ReadExact(stream, 4)); + int N = GetIntFromBytes(ReadExact(stream, 4)); //the size of the payload + m.data = ReadExact(stream, N); //the message AddMessage(m); break; } @@ -593,7 +591,7 @@ namespace VelNet case 4: { ChangeMasterMessage m = new ChangeMasterMessage(); - m.masterId = reader.ReadInt32(); //sender is the new master + m.masterId = GetIntFromBytes(ReadExact(stream, 4)); //sender is the new master AddMessage(m); break; } diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetPlayer.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetPlayer.cs index f4fb524..7369dfd 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetPlayer.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetPlayer.cs @@ -61,93 +61,81 @@ namespace VelNet /// /// These are generally things that come from the "owner" and should be enacted locally, where appropriate /// - /// Overall message encoding: - /// uint16: numMessages - /// for m in numMessages - /// int32: message size (including message type) + /// Message encoding: /// byte: message type /// byte[]: message + /// + /// The length of the byte[] for message is fixed according to the message type /// public void HandleMessage(VelNetManager.DataMessage m) { using MemoryStream mem = new MemoryStream(m.data); using BinaryReader reader = new BinaryReader(mem); - - ushort numMessages = reader.ReadUInt16(); - for (int i = 0; i < numMessages; i++) + //individual message parameters separated by comma + VelNetManager.MessageType messageType = (VelNetManager.MessageType)reader.ReadByte(); + + switch (messageType) { - //individual message parameters separated by comma - int messageLength = reader.ReadInt32(); - VelNetManager.MessageType messageType = (VelNetManager.MessageType)reader.ReadByte(); - byte[] message = reader.ReadBytes(messageLength-1); - - // make a separate reader to prevent malformed messages from messing us up - using MemoryStream messageMem = new MemoryStream(message); - using BinaryReader messageReader = new BinaryReader(messageMem); - - switch (messageType) + case VelNetManager.MessageType.ObjectSync: // sync update for an object I may own { - case VelNetManager.MessageType.ObjectSync: // sync update for an object I may own + string objectKey = reader.ReadString(); + byte componentIdx = reader.ReadByte(); + int messageLength = reader.ReadInt32(); + byte[] syncMessage = reader.ReadBytes(messageLength); + if (manager.objects.ContainsKey(objectKey)) { - string objectKey = messageReader.ReadString(); - string identifier = messageReader.ReadString(); - string syncMessage = messageReader.ReadString(); - byte[] messageBytes = Convert.FromBase64String(syncMessage); - if (manager.objects.ContainsKey(objectKey)) + if (manager.objects[objectKey].owner == this) { - if (manager.objects[objectKey].owner == this) - { - manager.objects[objectKey].ReceiveBytes(identifier, messageBytes); - } + manager.objects[objectKey].ReceiveBytes(componentIdx, syncMessage); } - - break; } - case VelNetManager.MessageType.TakeOwnership: // I'm trying to take ownership of an object - { - string networkId = messageReader.ReadString(); - if (manager.objects.ContainsKey(networkId)) - { - manager.objects[networkId].owner = this; - } - - break; - } - case VelNetManager.MessageType.Instantiate: // I'm trying to instantiate an object - { - string networkId = messageReader.ReadString(); - string prefabName = messageReader.ReadString(); - if (manager.objects.ContainsKey(networkId)) - { - break; //we already have this one, ignore - } - - VelNetManager.SomebodyInstantiatedNetworkObject(networkId, prefabName, this); - - break; - } - case VelNetManager.MessageType.Destroy: // I'm trying to destroy a gameobject I own - { - string networkId = messageReader.ReadString(); - - VelNetManager.NetworkDestroy(networkId); - break; - } - case VelNetManager.MessageType.DeleteSceneObjects: //deleted scene objects - { - int len = messageReader.ReadInt32(); - for (int k = 1; k < len; k++) - { - VelNetManager.NetworkDestroy(messageReader.ReadString()); - } - - break; - } - default: - throw new ArgumentOutOfRangeException(); + break; } + case VelNetManager.MessageType.TakeOwnership: // I'm trying to take ownership of an object + { + string networkId = reader.ReadString(); + + if (manager.objects.ContainsKey(networkId)) + { + manager.objects[networkId].owner = this; + } + + break; + } + case VelNetManager.MessageType.Instantiate: // I'm trying to instantiate an object + { + string networkId = reader.ReadString(); + string prefabName = reader.ReadString(); + if (manager.objects.ContainsKey(networkId)) + { + break; //we already have this one, ignore + } + + VelNetManager.SomebodyInstantiatedNetworkObject(networkId, prefabName, this); + + break; + } + case VelNetManager.MessageType.Destroy: // I'm trying to destroy a gameobject I own + { + string networkId = reader.ReadString(); + + VelNetManager.NetworkDestroy(networkId); + break; + } + case VelNetManager.MessageType.DeleteSceneObjects: //deleted scene objects + { + int len = reader.ReadInt32(); + for (int k = 1; k < len; k++) + { + VelNetManager.NetworkDestroy(reader.ReadString()); + } + + break; + } + default: + throw new ArgumentOutOfRangeException(); } } @@ -165,6 +153,7 @@ namespace VelNet writer.Write((byte)VelNetManager.MessageType.ObjectSync); writer.Write(obj.networkId); writer.Write(componentIdx); + writer.Write(data.Length); writer.Write(data); VelNetManager.SendToGroup(group, mem.ToArray(), reliable); } @@ -176,6 +165,7 @@ namespace VelNet writer.Write((byte)VelNetManager.MessageType.ObjectSync); writer.Write(obj.networkId); writer.Write(componentIdx); + writer.Write(data.Length); writer.Write(data); VelNetManager.SendToRoom(mem.ToArray(), false, reliable); } @@ -190,6 +180,7 @@ namespace VelNet { writer.Write(o); } + VelNetManager.SendToRoom(mem.ToArray()); } @@ -200,7 +191,7 @@ namespace VelNet if (!manager.objects.ContainsKey(networkId) || manager.objects[networkId].owner != this || !isLocal) return; // send to all, which will make me delete as well - + using MemoryStream mem = new MemoryStream(); using BinaryWriter writer = new BinaryWriter(mem); writer.Write((byte)VelNetManager.MessageType.Destroy); From d0849774027c5f73014cb12869a6bdcdf80f0ecd Mon Sep 17 00:00:00 2001 From: Anton Franzluebbers Date: Sun, 30 Jan 2022 17:04:37 -0500 Subject: [PATCH 14/14] converted some magic numbers to message types, added a custom message type, added editor button for scene ids --- .../VelNetUnity/Editor/EditorUtils.cs | 48 ++++++++++++++++ .../VelNetUnity/Editor/EditorUtils.cs.meta | 11 ++++ .../VelNetUnity/Editor/VelNet.Editor.asmdef | 18 ++++++ .../Editor/VelNet.Editor.asmdef.meta | 7 +++ .../VelNetUnity/Runtime/VelNetManager.cs | 55 +++++++++++++++---- .../VelNetUnity/Runtime/VelNetPlayer.cs | 8 ++- 6 files changed, 135 insertions(+), 12 deletions(-) create mode 100644 TestVelGameServer/Packages/VelNetUnity/Editor/EditorUtils.cs create mode 100644 TestVelGameServer/Packages/VelNetUnity/Editor/EditorUtils.cs.meta create mode 100644 TestVelGameServer/Packages/VelNetUnity/Editor/VelNet.Editor.asmdef create mode 100644 TestVelGameServer/Packages/VelNetUnity/Editor/VelNet.Editor.asmdef.meta diff --git a/TestVelGameServer/Packages/VelNetUnity/Editor/EditorUtils.cs b/TestVelGameServer/Packages/VelNetUnity/Editor/EditorUtils.cs new file mode 100644 index 0000000..ab66d21 --- /dev/null +++ b/TestVelGameServer/Packages/VelNetUnity/Editor/EditorUtils.cs @@ -0,0 +1,48 @@ +#if UNITY_EDITOR + +using System.Collections.Generic; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace VelNet.Editor +{ + public class EditorUtils : MonoBehaviour + { + [MenuItem("VelNet/Check For Duplicate NetworkIds", false, 10)] + private static void CheckDuplicateNetworkIds() + { + NetworkObject[] objs = FindObjectsOfType(); + Dictionary ids = new Dictionary(); + foreach (NetworkObject o in objs) + { + if (!o.isSceneObject) continue; + + if (ids.ContainsKey(o.sceneNetworkId) || o.sceneNetworkId < 100) + { + if (ids.ContainsKey(o.sceneNetworkId)) + { + Debug.Log($"Found duplicated id: {o.name} {ids[o.sceneNetworkId].name}", o); + } + else + { + Debug.Log($"Found duplicated id: {o.name} {o.sceneNetworkId}", o); + } + + o.sceneNetworkId = 100; + while (ids.ContainsKey(o.sceneNetworkId)) + { + o.sceneNetworkId += 1; + } + + PrefabUtility.RecordPrefabInstancePropertyModifications(o); + EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene()); + } + + ids.Add(o.sceneNetworkId, o); + } + } + } +} +#endif \ No newline at end of file diff --git a/TestVelGameServer/Packages/VelNetUnity/Editor/EditorUtils.cs.meta b/TestVelGameServer/Packages/VelNetUnity/Editor/EditorUtils.cs.meta new file mode 100644 index 0000000..a0118c0 --- /dev/null +++ b/TestVelGameServer/Packages/VelNetUnity/Editor/EditorUtils.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8f2f5f489d44f614c96bcf8f493c787d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestVelGameServer/Packages/VelNetUnity/Editor/VelNet.Editor.asmdef b/TestVelGameServer/Packages/VelNetUnity/Editor/VelNet.Editor.asmdef new file mode 100644 index 0000000..044643a --- /dev/null +++ b/TestVelGameServer/Packages/VelNetUnity/Editor/VelNet.Editor.asmdef @@ -0,0 +1,18 @@ +{ + "name": "VelNet.Editor", + "rootNamespace": "VelNet.Editor", + "references": [ + "GUID:1e55e2c4387020247a1ae212bbcbd381" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/TestVelGameServer/Packages/VelNetUnity/Editor/VelNet.Editor.asmdef.meta b/TestVelGameServer/Packages/VelNetUnity/Editor/VelNet.Editor.asmdef.meta new file mode 100644 index 0000000..4389fa2 --- /dev/null +++ b/TestVelGameServer/Packages/VelNetUnity/Editor/VelNet.Editor.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ae0703a992a8fe347978b1cd2dd2d7a9 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs index 9234857..0b5174b 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetManager.cs @@ -27,13 +27,14 @@ namespace VelNet MESSAGE_SETGROUP = 6 }; - public enum MessageType + public enum MessageType : byte { ObjectSync, TakeOwnership, Instantiate, Destroy, - DeleteSceneObjects + DeleteSceneObjects, + Custom } public string host; @@ -80,6 +81,7 @@ namespace VelNet public static Action RoomsReceived; public static Action MessageReceived; + public static Action CustomMessageReceived; #endregion @@ -438,7 +440,15 @@ namespace VelNet sceneObjects[i].networkId = -1 + "-" + sceneObjects[i].sceneNetworkId; sceneObjects[i].owner = masterPlayer; sceneObjects[i].isSceneObject = true; // needed for special handling when deleted - objects.Add(sceneObjects[i].networkId, sceneObjects[i]); + + if (objects.ContainsKey(sceneObjects[i].networkId)) + { + Debug.LogError($"Duplicate NetworkID: {sceneObjects[i].networkId} {sceneObjects[i].name} {objects[sceneObjects[i].networkId]}"); + } + else + { + objects.Add(sceneObjects[i].networkId, sceneObjects[i]); + } } } else @@ -528,12 +538,12 @@ namespace VelNet { //read a byte - byte type = (byte)stream.ReadByte(); + MessageSendType type = (MessageSendType)stream.ReadByte(); switch (type) { //login - case 0: + case MessageSendType.MESSAGE_LOGIN: { LoginMessage m = new LoginMessage(); m.userId = GetIntFromBytes(ReadExact(stream, 4)); //not really the sender... @@ -541,7 +551,7 @@ namespace VelNet break; } //rooms - case 1: + case MessageSendType.MESSAGE_GETROOMS: { RoomsMessage m = new RoomsMessage(); m.rooms = new List(); @@ -567,7 +577,7 @@ namespace VelNet break; } //joined - case 2: + case MessageSendType.MESSAGE_JOINROOM: { JoinMessage m = new JoinMessage(); m.userId = GetIntFromBytes(ReadExact(stream, 4)); @@ -578,7 +588,10 @@ namespace VelNet break; } //data - case 3: + case MessageSendType.MESSAGE_OTHERS: + // case MessageSendType.MESSAGE_OTHERS_ORDERED: + // case MessageSendType.MESSAGE_ALL: + // case MessageSendType.MESSAGE_ALL_ORDERED: { DataMessage m = new DataMessage(); m.senderId = GetIntFromBytes(ReadExact(stream, 4)); @@ -588,7 +601,7 @@ namespace VelNet break; } //new master - case 4: + case MessageSendType.MESSAGE_ALL: { ChangeMasterMessage m = new ChangeMasterMessage(); m.masterId = GetIntFromBytes(ReadExact(stream, 4)); //sender is the new master @@ -723,7 +736,7 @@ namespace VelNet byte[] uB = Encoding.UTF8.GetBytes(username); byte[] pB = Encoding.UTF8.GetBytes(password); - writer.Write((byte)0); + writer.Write((byte)MessageSendType.MESSAGE_LOGIN); writer.Write((byte)uB.Length); writer.Write(uB); writer.Write((byte)pB.Length); @@ -747,7 +760,7 @@ namespace VelNet BinaryWriter writer = new BinaryWriter(stream); byte[] R = Encoding.UTF8.GetBytes(roomname); - writer.Write((byte)2); + writer.Write((byte)MessageSendType.MESSAGE_JOINROOM); writer.Write((byte)R.Length); writer.Write(R); SendTcpMessage(stream.ToArray()); @@ -765,6 +778,26 @@ namespace VelNet } } + public static void SendCustomMessage(byte[] message, bool include_self = false, bool reliable = true, bool ordered = false) + { + using MemoryStream mem = new MemoryStream(); + using BinaryWriter writer = new BinaryWriter(mem); + writer.Write((byte)MessageType.Custom); + writer.Write(message.Length); + writer.Write(message); + SendToRoom(mem.ToArray(), include_self, reliable, ordered); + } + + public static void SendCustomMessageToGroup(string group, byte[] message,bool reliable = true) + { + using MemoryStream mem = new MemoryStream(); + using BinaryWriter writer = new BinaryWriter(mem); + writer.Write((byte)MessageType.Custom); + writer.Write(message.Length); + writer.Write(message); + SendToGroup(group, mem.ToArray(), reliable); + } + internal static void SendToRoom(byte[] message, bool include_self = false, bool reliable = true, bool ordered = false) { byte sendType = (byte)MessageSendType.MESSAGE_OTHERS; diff --git a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetPlayer.cs b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetPlayer.cs index 7369dfd..1b8a3c0 100644 --- a/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetPlayer.cs +++ b/TestVelGameServer/Packages/VelNetUnity/Runtime/VelNetPlayer.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System; using System.IO; using System.Text; +using UnityEngine; namespace VelNet { @@ -131,7 +132,12 @@ namespace VelNet { VelNetManager.NetworkDestroy(reader.ReadString()); } - + break; + } + case VelNetManager.MessageType.Custom: // custom packets + { + int len = reader.ReadInt32(); + VelNetManager.CustomMessageReceived?.Invoke(reader.ReadBytes(len)); break; } default: