diff --git a/Runtime/VelNetManager.cs b/Runtime/VelNetManager.cs index 04a0dd2..21a49ec 100644 --- a/Runtime/VelNetManager.cs +++ b/Runtime/VelNetManager.cs @@ -1,5 +1,4 @@ using System; -using System.Collections; using System.Collections.Generic; using System.Linq; using System.Net.Sockets; @@ -27,6 +26,7 @@ namespace VelNet YOU_LEFT = 7, ROOM_DATA = 8 } + public enum MessageSendType { MESSAGE_OTHERS_ORDERED = 7, @@ -131,7 +131,7 @@ namespace VelNet public static bool IsConnected => instance != null && instance.connected && instance.udpConnected; - //this is for sending udp packets + // this is for sending udp packets private static readonly byte[] toSend = new byte[1024]; // Use this for initialization @@ -168,7 +168,7 @@ namespace VelNet public class RoomDataMessage : Message { public string room; - public List> members = new List>(); + public readonly List> members = new List>(); } public class JoinMessage : Message @@ -188,18 +188,19 @@ namespace VelNet public int masterId; } - public class YouJoinedMessage: Message + public class YouJoinedMessage : Message { public List ids; public string room; } - public class PlayerLeftMessage: Message + public class PlayerLeftMessage : Message { public int userId; public string room; } - public class YouLeftMessage: Message + + public class YouLeftMessage : Message { public string room; } @@ -296,8 +297,6 @@ namespace VelNet } case RoomsMessage rm: { - Debug.Log("Got Rooms Message:\n" + rm); - try { RoomsReceived?.Invoke(rm); @@ -311,51 +310,51 @@ namespace VelNet break; } case RoomDataMessage rdm: + { + try { - Debug.Log("Got room data message:" + rdm.room); - try - { - RoomDataReceived?.Invoke(rdm); - } - // prevent errors in subscribers from breaking our code - catch (Exception e) - { - Debug.LogError(e); - } - break; + RoomDataReceived?.Invoke(rdm); } - case YouJoinedMessage jm: + // prevent errors in subscribers from breaking our code + catch (Exception e) { - // we clear the list, but will recreate as we get messages from people in our room - players.Clear(); - masterPlayer = null; + Debug.LogError(e); + } + + break; + } + case YouJoinedMessage jm: + { + // we clear the list, but will recreate as we get messages from people in our room + players.Clear(); + masterPlayer = null; - foreach(int playerId in jm.ids) + foreach (int playerId in jm.ids) + { + VelNetPlayer player = new VelNetPlayer { + room = jm.room, + userid = playerId, + isLocal = playerId == userid, + }; + players.Add(player.userid, player); + } - VelNetPlayer player = new VelNetPlayer - { - isLocal = playerId == userid, - room = jm.room, - userid = playerId - }; - players.Add(player.userid, player); + try + { + Debug.Log(jm.room); + OnJoinedRoom?.Invoke(jm.room); + } + // prevent errors in subscribers from breaking our code + catch (Exception e) + { + Debug.LogError(e); + } - } - - try - { - Debug.Log(jm.room); - OnJoinedRoom?.Invoke(jm.room); - } - // prevent errors in subscribers from breaking our code - catch (Exception e) - { - Debug.LogError(e); - } - - foreach(KeyValuePair kvp in players) + foreach (KeyValuePair kvp in players) + { + if (kvp.Key != userid) { try { @@ -367,90 +366,91 @@ namespace VelNet Debug.LogError(e); } } - - - - break; } - case YouLeftMessage lm: + + + break; + } + case YouLeftMessage msg: + { + string oldRoom = LocalPlayer?.room; + // 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) { - string oldRoom = LocalPlayer?.room; - // 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; + 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; + } case PlayerLeftMessage lm: + { + VelNetPlayer me = players[userid]; + // we got a left message, kill it + // change ownership of all objects to master + List deleteObjects = new List(); + foreach (KeyValuePair kvp in objects) { - VelNetPlayer me = players[userid]; - // 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[lm.userId]) // the owner is the player that left { - if (kvp.Value.owner == players[lm.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[lm.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[lm.userId] == masterPlayer) + { + kvp.Value.owner = null; } } - - // TODO this may check for ownership in the future. We don't need ownership here - deleteObjects.ForEach(NetworkDestroy); - - VelNetPlayer leftPlayer = players[lm.userId]; - players.Remove(lm.userId); - - try - { - OnPlayerLeft?.Invoke(leftPlayer); - } - // prevent errors in subscribers from breaking our code - catch (Exception e) - { - Debug.LogError(e); - } - break; } + + // TODO this may check for ownership in the future. We don't need ownership here + deleteObjects.ForEach(NetworkDestroy); + + VelNetPlayer leftPlayer = players[lm.userId]; + players.Remove(lm.userId); + + try + { + OnPlayerLeft?.Invoke(leftPlayer); + } + // prevent errors in subscribers from breaking our code + catch (Exception e) + { + Debug.LogError(e); + } + + break; + } case JoinMessage jm: { - // we got a join message, create it VelNetPlayer player = new VelNetPlayer { @@ -468,8 +468,7 @@ namespace VelNet { Debug.LogError(e); } - - + break; } @@ -500,6 +499,7 @@ namespace VelNet { 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 @@ -599,7 +599,6 @@ namespace VelNet AddMessage(new ConnectedMessage()); while (true) { - //read a byte MessageReceivedType type = (MessageReceivedType)stream.ReadByte(); @@ -658,6 +657,7 @@ namespace VelNet rdm.members.Add(new Tuple(client_id, username)); Debug.Log(username); } + AddMessage(rdm); break; } @@ -696,10 +696,11 @@ namespace VelNet YouJoinedMessage m = new YouJoinedMessage(); int N = GetIntFromBytes(ReadExact(stream, 4)); m.ids = new List(); - for(int i = 0; i < N; i++) + for (int i = 0; i < N; i++) { m.ids.Add(GetIntFromBytes(ReadExact(stream, 4))); } + N = stream.ReadByte(); byte[] utf8data = ReadExact(stream, N); //the room name, encoded as utf-8 m.room = Encoding.UTF8.GetString(utf8data); @@ -707,25 +708,24 @@ namespace VelNet break; } case MessageReceivedType.PLAYER_LEFT: - { - PlayerLeftMessage m = new PlayerLeftMessage(); - 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; - } + { + PlayerLeftMessage m = new PlayerLeftMessage(); + 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; + } case MessageReceivedType.YOU_LEFT: - { - YouLeftMessage m = new YouLeftMessage(); - 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; - } - + { + YouLeftMessage m = new YouLeftMessage(); + 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; + } } } } @@ -845,20 +845,22 @@ namespace VelNet } /// - /// Connects to the server with a username + /// Connects to the server for a particular app /// - public static void Login(string username, string password) + /// A unique name for your app. Communication can only happen between clients with the same app name. + /// Should be unique per device that connects. e.g. md5(deviceUniqueIdentifier) + public static void Login(string appName, string deviceId) { MemoryStream stream = new MemoryStream(); BinaryWriter writer = new BinaryWriter(stream); - byte[] uB = Encoding.UTF8.GetBytes(username); - byte[] pB = Encoding.UTF8.GetBytes(password); + byte[] id = Encoding.UTF8.GetBytes(deviceId); + byte[] app = Encoding.UTF8.GetBytes(appName); writer.Write((byte)MessageSendType.MESSAGE_LOGIN); - writer.Write((byte)uB.Length); - writer.Write(uB); - writer.Write((byte)pB.Length); - writer.Write(pB); + writer.Write((byte)id.Length); + writer.Write(id); + writer.Write((byte)app.Length); + writer.Write(app); SendTcpMessage(stream.ToArray()); } @@ -929,7 +931,7 @@ namespace VelNet SendToRoom(mem.ToArray(), include_self, reliable, ordered); } - public static void SendCustomMessageToGroup(string group, byte[] message,bool reliable = true) + public static void SendCustomMessageToGroup(string group, byte[] message, bool reliable = true) { using MemoryStream mem = new MemoryStream(); using BinaryWriter writer = new BinaryWriter(mem); @@ -1042,14 +1044,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. 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); + SendToRoom(mem.ToArray(), include_self: false, reliable: true); return newObject; } @@ -1131,4 +1133,4 @@ namespace VelNet return true; } } -} +} \ No newline at end of file