diff --git a/Assets/Scripts/Entities/Spawner.cs b/Assets/Scripts/Entities/Spawner.cs index fffa743..c2ddf17 100644 --- a/Assets/Scripts/Entities/Spawner.cs +++ b/Assets/Scripts/Entities/Spawner.cs @@ -1,6 +1,4 @@ -using System.Collections; -using System.Collections.Generic; -using UnityEngine; +using UnityEngine; using Cyber.Console; namespace Cyber.Entities { diff --git a/Assets/Scripts/Networking/Clientside/CConnectedPlayer.cs b/Assets/Scripts/Networking/Clientside/CConnectedPlayer.cs new file mode 100644 index 0000000..37154b4 --- /dev/null +++ b/Assets/Scripts/Networking/Clientside/CConnectedPlayer.cs @@ -0,0 +1,26 @@ +using Cyber.Entities; + +namespace Cyber.Networking.Clientside { + + /// + /// Represents a connected player on the clientside. This class is used by clients. + /// The C stands for "Client". + /// + class CConnectedPlayer { + + /// + /// Connection ID on the global perspective. + /// + public readonly int ConnectionID; + + /// + /// The player's controlled character. + /// + public Character Character; + + public CConnectedPlayer(int connectionID) { + ConnectionID = connectionID; + } + + } +} diff --git a/Assets/Scripts/Networking/Clientside/CConnectedPlayer.cs.meta b/Assets/Scripts/Networking/Clientside/CConnectedPlayer.cs.meta new file mode 100644 index 0000000..89a585b --- /dev/null +++ b/Assets/Scripts/Networking/Clientside/CConnectedPlayer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: f30b47eaf72d54f4099f5690a67965e3 +timeCreated: 1494285679 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Networking/Clientside/Client.cs b/Assets/Scripts/Networking/Clientside/Client.cs index 941a139..954ed80 100644 --- a/Assets/Scripts/Networking/Clientside/Client.cs +++ b/Assets/Scripts/Networking/Clientside/Client.cs @@ -1,5 +1,6 @@ using Cyber.Console; using Cyber.Networking.Messages; +using System.Collections.Generic; using UnityEngine; using UnityEngine.Networking; @@ -9,6 +10,13 @@ namespace Cyber.Networking.Clientside { /// Client-class used to connecting to a server and communicating to it. /// Also handles all events incoming from the server and forwards them where they should be handled. /// + /// + /// The pipeline of requests sent by the client: + /// 1. Player sends command to server (e.g. player presses 'w') and then processes it on the client. + /// 2. Server receives the command and determines weather it's possible + /// 3. Server then sends the results(along with a timestamp) to the clients + /// 4. Clients receive their results and if the action was possible, starts the action and catches up to the server with the timestamp + /// public class Client : MonoBehaviour { private NetworkClient NetClient; @@ -16,6 +24,12 @@ namespace Cyber.Networking.Clientside { private static Client Singleton; + /// + /// The player of this client + /// + private CConnectedPlayer Player; + private List Players = new List(); + /// /// Creates the client and sets it as the signleton. /// @@ -88,6 +102,8 @@ namespace Cyber.Networking.Clientside { Running = true; NetClient.RegisterHandler(PktType.TextMessage, HandlePacket); + NetClient.RegisterHandler(PktType.Identity, HandlePacket); + NetClient.RegisterHandler(PktType.MassIdentity, HandlePacket); NetClient.RegisterHandler(MsgType.Connect, OnConnected); NetClient.RegisterHandler(MsgType.Disconnect, OnDisconnected); @@ -104,10 +120,29 @@ namespace Cyber.Networking.Clientside { private void HandlePacket(NetworkMessage msg) { switch (msg.msgType) { case (PktType.TextMessage): - TextMessage TextMsg = new TextMessage(); + TextMessagePkt TextMsg = new TextMessagePkt(); TextMsg.Deserialize(msg.reader); Term.Println(TextMsg.Message); break; + case (PktType.Identity): + IdentityPkt Identity = new IdentityPkt(); + Identity.Deserialize(msg.reader); + var Conn = new CConnectedPlayer(Identity.ConnectionID); + if (Identity.Owned) { + Player = Conn; + } else { + Debug.Log(Conn.ConnectionID + " connected!"); + Term.Println(Conn.ConnectionID + " connected!"); + } + Players.Add(Conn); + break; + case (PktType.MassIdentity): + MassIdentityPkt Identities = new MassIdentityPkt(); + Identities.Deserialize(msg.reader); + foreach (int currId in Identities.IdList) { + Players.Add(new CConnectedPlayer(currId)); + } + break; default: Debug.LogError("Received an unknown packet, id: " + msg.msgType); Term.Println("Received an unknown packet, id: " + msg.msgType); @@ -123,7 +158,7 @@ namespace Cyber.Networking.Clientside { Term.AddCommand("send (message)", "Send a message across the vastness of space and time!", (args) => { Term.Println("You: " + args[0]); - NetClient.Send(PktType.TextMessage, new TextMessage("A Client: " + args[0])); + NetClient.Send(PktType.TextMessage, new TextMessagePkt("A Client: " + args[0])); }); } diff --git a/Assets/Scripts/Networking/Messages/IdentityPkt.cs b/Assets/Scripts/Networking/Messages/IdentityPkt.cs new file mode 100644 index 0000000..96d6ee8 --- /dev/null +++ b/Assets/Scripts/Networking/Messages/IdentityPkt.cs @@ -0,0 +1,54 @@ +using UnityEngine.Networking; + +namespace Cyber.Networking.Messages { + + /// + /// Contains the Connection ID of the user and weather the ID belongs to the client or not. + /// + public class IdentityPkt : MessageBase { + + /// + /// ID of the Connection + /// + public int ConnectionID; + + /// + /// Weather the recieving client owns this ID or not. + /// + public bool Owned; + + /// + /// Creates a packet containing an ID and the detail weather the recieving client owns this ID. + /// + /// ID of the connection. + /// Weather the recieving client owns this ID. + public IdentityPkt(int connectionID, bool owned) { + ConnectionID = connectionID; + Owned = owned; + } + + /// + /// Parameter-less constructor using when deserializing the message. + /// + public IdentityPkt() { + } + + /// + /// Used to deserialize a message received via networking. + /// + /// + public override void Deserialize(NetworkReader reader) { + ConnectionID = reader.ReadInt32(); + Owned = reader.ReadBoolean(); + } + + /// + /// Used to serialize the message before it is sent. + /// + /// + public override void Serialize(NetworkWriter writer) { + writer.Write(ConnectionID); + writer.Write(Owned); + } + } +} diff --git a/Assets/Scripts/Networking/Messages/IdentityPkt.cs.meta b/Assets/Scripts/Networking/Messages/IdentityPkt.cs.meta new file mode 100644 index 0000000..56c29bd --- /dev/null +++ b/Assets/Scripts/Networking/Messages/IdentityPkt.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: c30897b96fbb288409d685055ea44926 +timeCreated: 1494285679 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Networking/Messages/MassIdentityPkt.cs b/Assets/Scripts/Networking/Messages/MassIdentityPkt.cs new file mode 100644 index 0000000..ceb7e83 --- /dev/null +++ b/Assets/Scripts/Networking/Messages/MassIdentityPkt.cs @@ -0,0 +1,38 @@ + +using UnityEngine.Networking; + +namespace Cyber.Networking.Messages { + + /// + /// Packet containing a list of ID's of players currently connected. + /// + public class MassIdentityPkt : MessageBase { + + public int[] IdList; + + public MassIdentityPkt(int[] idList) { + IdList = idList; + } + + public MassIdentityPkt() { + + } + + public override void Deserialize(NetworkReader reader) { + byte[][] ByteArray = new byte[4][]; + ByteArray[0] = reader.ReadBytesAndSize(); + ByteArray[1] = reader.ReadBytesAndSize(); + ByteArray[2] = reader.ReadBytesAndSize(); + ByteArray[3] = reader.ReadBytesAndSize(); + IdList = NetworkHelper.DeserializeIntArray(ByteArray); + } + + public override void Serialize(NetworkWriter writer) { + byte[][] ByteArray = NetworkHelper.SerializeIntArray(IdList); + writer.WriteBytesFull(ByteArray[0]); + writer.WriteBytesFull(ByteArray[1]); + writer.WriteBytesFull(ByteArray[2]); + writer.WriteBytesFull(ByteArray[3]); + } + } +} diff --git a/Assets/Scripts/Networking/Messages/MassIdentityPkt.cs.meta b/Assets/Scripts/Networking/Messages/MassIdentityPkt.cs.meta new file mode 100644 index 0000000..cc36e0d --- /dev/null +++ b/Assets/Scripts/Networking/Messages/MassIdentityPkt.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 97cd8f5bc9c011e4eb4b6f638b852656 +timeCreated: 1494288982 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Networking/Messages/TextMessage.cs b/Assets/Scripts/Networking/Messages/TextMessagePkt.cs similarity index 90% rename from Assets/Scripts/Networking/Messages/TextMessage.cs rename to Assets/Scripts/Networking/Messages/TextMessagePkt.cs index 90dae19..1ee08ca 100644 --- a/Assets/Scripts/Networking/Messages/TextMessage.cs +++ b/Assets/Scripts/Networking/Messages/TextMessagePkt.cs @@ -6,7 +6,7 @@ namespace Cyber.Networking.Messages { /// Generic Text Message for chat etc. /// To be removed later when no longer necessary. /// - public class TextMessage : MessageBase { + public class TextMessagePkt : MessageBase { /// /// Message inside the Text Message. Does not container sender information. @@ -17,14 +17,14 @@ namespace Cyber.Networking.Messages { /// Create a TextMessage containing the message to be sent. /// /// Message to be sent. - public TextMessage(string message) { + public TextMessagePkt(string message) { this.Message = message; } /// /// Parameter-less constructor using when deserializing the message. /// - public TextMessage() { + public TextMessagePkt() { } /// diff --git a/Assets/Scripts/Networking/Messages/TextMessage.cs.meta b/Assets/Scripts/Networking/Messages/TextMessagePkt.cs.meta similarity index 100% rename from Assets/Scripts/Networking/Messages/TextMessage.cs.meta rename to Assets/Scripts/Networking/Messages/TextMessagePkt.cs.meta diff --git a/Assets/Scripts/Networking/NetworkHelper.cs b/Assets/Scripts/Networking/NetworkHelper.cs new file mode 100644 index 0000000..4f7ab0f --- /dev/null +++ b/Assets/Scripts/Networking/NetworkHelper.cs @@ -0,0 +1,55 @@ + +using System; +using UnityEngine; + +namespace Cyber.Networking { + + /// + /// Class that contains a few functions to help de/serialize some arrays. + /// + public class NetworkHelper { + + /// + /// Divides an int-array into four byte-arrays. + /// + /// Int-array to divide + /// Four byte-arrays + public static byte[][] SerializeIntArray(int[] intArray) { + byte[][] ByteArray = new byte[4][]; + for (int i = 0; i < 4; i++) { + ByteArray[i] = new byte[intArray.Length]; + } + + for (int top = 0; top < 4; top++) { + for (int i = 0; i < intArray.Length; i++) { + byte B = (byte) ((intArray[i] & (0xFF << (top * 8))) >> (top * 8)); + ByteArray[top][i] = B; + } + } + + return ByteArray; + } + + /// + /// Deserializes an int-array from four byte-arrays + /// + /// Four byte arrays + /// An int array + public static int[] DeserializeIntArray(byte[][] byteArray) { + if (byteArray.GetLength(0) != 4) { + throw new ArgumentException("Specified byte-array is invalid (First dimension should be of length 4)."); + } else if (byteArray.Length <= 0 || byteArray[0] == null) { + return new int[0]; + } + int[] IntArray = new int[byteArray[0].Length]; + + for (int i = 0; i < byteArray[0].Length; i++) { + int I = byteArray[0][i] + (byteArray[1][i] << 8) + (byteArray[2][i] << 16) + (byteArray[3][i] << 24); + IntArray[i] = I; + } + + return IntArray; + } + + } +} diff --git a/Assets/Scripts/Networking/NetworkHelper.cs.meta b/Assets/Scripts/Networking/NetworkHelper.cs.meta new file mode 100644 index 0000000..828857c --- /dev/null +++ b/Assets/Scripts/Networking/NetworkHelper.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 914f19b5c62c68c429667403d97f2837 +timeCreated: 1494288981 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Networking/PktType.cs b/Assets/Scripts/Networking/PktType.cs index 90b21a0..aece22c 100644 --- a/Assets/Scripts/Networking/PktType.cs +++ b/Assets/Scripts/Networking/PktType.cs @@ -6,6 +6,19 @@ namespace Cyber.Networking { /// public class PktType { + /// + /// Test Text Message for sending stuff like chat. + /// public const short TextMessage = 200; + + /// + /// Packet containing identification details, server's given ID and if the ID belongs to you or not. + /// + public const short Identity = 201; + + /// + /// Packet containing the identification details about everyone on the server before the client connected. + /// + public const short MassIdentity = 202; } } \ No newline at end of file diff --git a/Assets/Scripts/Networking/Serverside/SConnectedPlayer.cs b/Assets/Scripts/Networking/Serverside/SConnectedPlayer.cs new file mode 100644 index 0000000..25fa9b5 --- /dev/null +++ b/Assets/Scripts/Networking/Serverside/SConnectedPlayer.cs @@ -0,0 +1,31 @@ + +using Cyber.Entities; + +namespace Cyber.Networking.Serverside { + + /// + /// Represents a player on the server. This class is used by the server. + /// The S stands for "Server". + /// + class SConnectedPlayer { + + /// + /// The player's connection ID. + /// + public readonly int ConnectionID; + + /// + /// The player's controlled character + /// + public Character Character; + + /// + /// Create a connected player and give it a connection ID; + /// + /// The player's connection ID + public SConnectedPlayer(int connectionID) { + ConnectionID = connectionID; + } + + } +} diff --git a/Assets/Scripts/Networking/Serverside/SConnectedPlayer.cs.meta b/Assets/Scripts/Networking/Serverside/SConnectedPlayer.cs.meta new file mode 100644 index 0000000..5da3370 --- /dev/null +++ b/Assets/Scripts/Networking/Serverside/SConnectedPlayer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8e1569e7f6fe73a438a3ba0421ac5059 +timeCreated: 1494282762 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Networking/Serverside/Server.cs b/Assets/Scripts/Networking/Serverside/Server.cs index 1366b93..4bfd73e 100644 --- a/Assets/Scripts/Networking/Serverside/Server.cs +++ b/Assets/Scripts/Networking/Serverside/Server.cs @@ -1,5 +1,7 @@ using Cyber.Console; +using Cyber.Entities; using Cyber.Networking.Messages; +using System.Collections.Generic; using UnityEngine; using UnityEngine.Networking; @@ -8,10 +10,14 @@ namespace Cyber.Networking.Serverside { /// /// Server-class used to host a server and communicate to clients. /// + /// \todo Change connection channels to Unreliable to optimize ping. public class Server : MonoBehaviour { + private List Players = new List(); private static Server Singleton; + private Spawner Spawner; + /// /// Creates the server-component, and sets the singleton as itself. /// @@ -81,6 +87,8 @@ namespace Cyber.Networking.Serverside { return false; } + Spawner = GetComponent(); + ConnectionConfig Config = new ConnectionConfig(); Config.AddChannel(QosType.ReliableSequenced); Config.AddChannel(QosType.UnreliableSequenced); @@ -99,7 +107,7 @@ namespace Cyber.Networking.Serverside { Term.AddCommand("send (message)", "Howl at the darkness of space. Does it echo though?", (args) => { Term.Println("You: " + args[0]); - SendToAll(PktType.TextMessage, new TextMessage("Server: " + args[0])); + SendToAll(PktType.TextMessage, new TextMessagePkt("Server: " + args[0])); }); return true; @@ -109,7 +117,7 @@ namespace Cyber.Networking.Serverside { switch (msg.msgType) { case PktType.TextMessage: - TextMessage TextMsg = new TextMessage(); + TextMessagePkt TextMsg = new TextMessagePkt(); TextMsg.Deserialize(msg.reader); Term.Println(TextMsg.Message); break; @@ -122,9 +130,28 @@ namespace Cyber.Networking.Serverside { // Internal built-in event handler - private void OnConnected(NetworkMessage msg) { - Debug.Log("Someone connected!"); - Term.Println("Someone connected!"); + private void OnConnected(NetworkMessage msg) { + int Id = msg.conn.connectionId; + + Debug.Log(Id + " connected!"); + Term.Println(Id + " connected!"); + + int[] IdList = new int[Players.Count]; + for (int i = 0; i < Players.Count; i++) { + SConnectedPlayer P = Players[i]; + IdList[i] = P.ConnectionID; + NetworkServer.SendToClient(P.ConnectionID, PktType.Identity, new IdentityPkt(Id, false)); + } + foreach (int id in IdList) { + Debug.Log("id: " + id); + } + NetworkServer.SendToClient(Id, PktType.MassIdentity, new MassIdentityPkt(IdList)); + + SConnectedPlayer Player = new SConnectedPlayer(msg.conn.connectionId); + Players.Add(Player); + + NetworkServer.SendToClient(msg.conn.connectionId, + PktType.Identity, new IdentityPkt(msg.conn.connectionId, true)); } private void OnDisconnected(NetworkMessage msg) {