diff --git a/Client/Client.cs b/Client/Client.cs index 1cb4822..fda6892 100644 --- a/Client/Client.cs +++ b/Client/Client.cs @@ -1,158 +1,170 @@ -using SharedClientServer; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Net.Sockets; -using System.Text; -using static SharedClientServer.JSONConvert; - -namespace Client -{ - public delegate void OnLobbyCreated(int id); - - public delegate void CanvasDataReceived(double[] coordinates); - class Client : ObservableObject - { - - private ClientData clientData = ClientData.Instance; - - private TcpClient tcpClient; - private NetworkStream stream; - private byte[] buffer = new byte[2048]; - private byte[] totalBuffer = new byte[2048]; - private int totalBufferReceived = 0; - public int Port = 5555; - public bool Connected = false; - private string username; - public Callback OnSuccessfullConnect; - public Callback OnLobbiesListReceived; - public Callback OnLobbyJoinSuccess; - public Callback OnLobbiesReceivedAndWaitingForHost; - public OnLobbyCreated OnLobbyCreated; - - public CanvasDataReceived CanvasDataReceived; - public Lobby[] Lobbies { get; set; } - - public Client(string username) - { - this.username = username; - this.tcpClient = new TcpClient(); - Debug.WriteLine("Starting connect to server"); - tcpClient.BeginConnect("localhost", Port, new AsyncCallback(OnConnect), null); - } - - private void OnConnect(IAsyncResult ar) - { - Debug.Write("finished connecting to server"); - this.tcpClient.EndConnect(ar); - this.stream = tcpClient.GetStream(); - OnSuccessfullConnect?.Invoke(); - SendMessage(JSONConvert.ConstructUsernameMessage(username)); - this.stream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(OnReadComplete),null); - } - - private void OnReadComplete(IAsyncResult ar) - { - int amountReceived = stream.EndRead(ar); - - if (totalBufferReceived > 2048) - { - throw new OutOfMemoryException("buffer too small"); - } - - Array.Copy(buffer, 0, totalBuffer, totalBufferReceived, amountReceived); - totalBufferReceived += amountReceived; - - int expectedMessageLength = BitConverter.ToInt32(totalBuffer, 0); - - while (totalBufferReceived >= expectedMessageLength) - { - // we have received the complete packet - byte[] message = new byte[expectedMessageLength]; - // put the message received into the message array - Array.Copy(totalBuffer, 0, message, 0, expectedMessageLength); - - handleData(message); - - totalBufferReceived -= expectedMessageLength; - Debug.WriteLine($"reduced buffer: {expectedMessageLength}"); - expectedMessageLength = BitConverter.ToInt32(totalBuffer, 0); - } - - stream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(OnReadComplete), null); - } - - private void handleData(byte[] message) - { - byte id = message[4]; - - byte[] payload = new byte[message.Length - 5]; - Array.Copy(message, 5, payload, 0, message.Length - 5); - - switch (id) - { - case JSONConvert.LOGIN: - // json log in username data - break; - case JSONConvert.MESSAGE: - // json message data - (string, string) combo = JSONConvert.GetUsernameAndMessage(payload); - string textUsername = combo.Item1; - string textMsg = combo.Item2; - - //TODO display username and message in chat window - Debug.WriteLine("[CLIENT] INCOMING MESSAGE!"); - Debug.WriteLine("[CLIENT] User name: {0}\t User message: {1}", textUsername, textMsg); - break; - - case JSONConvert.LOBBY: - // lobby data - LobbyIdentifier lobbyIdentifier = JSONConvert.GetLobbyIdentifier(payload); - switch (lobbyIdentifier) - { - case LobbyIdentifier.LIST: - Debug.WriteLine("got lobbies list"); - Lobbies = JSONConvert.GetLobbiesFromMessage(payload); - OnLobbiesListReceived?.Invoke(); - OnLobbiesReceivedAndWaitingForHost?.Invoke(); - break; - case LobbyIdentifier.HOST: - // we receive this when the server has made us a host of a new lobby - // TODO get lobby id - Debug.WriteLine("[CLIENT] got lobby object"); - int lobbyCreatedID = JSONConvert.GetLobbyID(payload); - OnLobbyCreated?.Invoke(lobbyCreatedID); - break; - case LobbyIdentifier.JOIN_SUCCESS: - OnLobbyJoinSuccess?.Invoke(); - break; - } - //TODO fill lobby with the data received - break; - - case JSONConvert.CANVAS: - // canvas data - //clientData.CanvasData = JSONConvert.getCoordinates(payload); - CanvasDataReceived?.Invoke(JSONConvert.getCoordinates(payload)); - break; - - default: - Debug.WriteLine("[CLIENT] Received weird identifier: " + id); - break; - } - - } - - public void SendMessage(byte[] message) - { - Debug.WriteLine("[CLIENT] sending message " + Encoding.ASCII.GetString(message)); - stream.BeginWrite(message, 0, message.Length, new AsyncCallback(OnWriteComplete), null); - } - - private void OnWriteComplete(IAsyncResult ar) - { - Debug.WriteLine("[CLIENT] finished writing"); - stream.EndWrite(ar); - } - } -} +using SharedClientServer; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Net.Sockets; +using System.Text; +using static SharedClientServer.JSONConvert; + +namespace Client +{ + public delegate void LobbyJoinCallback(bool isHost); + public delegate void CanvasDataReceived(double[] coordinates); + public delegate void LobbyCallback(int id); + class Client : ObservableObject + { + + private ClientData clientData = ClientData.Instance; + + private TcpClient tcpClient; + private NetworkStream stream; + private byte[] buffer = new byte[2048]; + private byte[] totalBuffer = new byte[2048]; + private int totalBufferReceived = 0; + public int Port = 5555; + public bool Connected = false; + private string username; + public Callback OnSuccessfullConnect; + public Callback OnLobbiesListReceived; + public LobbyJoinCallback OnLobbyJoinSuccess; + public Callback OnLobbiesReceivedAndWaitingForHost; + public LobbyCallback OnLobbyCreated; + public LobbyCallback OnLobbyLeave; + private ClientData data = ClientData.Instance; + public CanvasDataReceived CanvasDataReceived; + public Lobby[] Lobbies { get; set; } + + public Client(string username) + { + this.username = username; + this.tcpClient = new TcpClient(); + Debug.WriteLine("Starting connect to server"); + tcpClient.BeginConnect("localhost", Port, new AsyncCallback(OnConnect), null); + } + + private void OnConnect(IAsyncResult ar) + { + Debug.Write("finished connecting to server"); + this.tcpClient.EndConnect(ar); + this.stream = tcpClient.GetStream(); + OnSuccessfullConnect?.Invoke(); + SendMessage(JSONConvert.ConstructUsernameMessage(username)); + this.stream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(OnReadComplete),null); + } + + private void OnReadComplete(IAsyncResult ar) + { + int amountReceived = stream.EndRead(ar); + + if (totalBufferReceived > 2048) + { + throw new OutOfMemoryException("buffer too small"); + } + + Array.Copy(buffer, 0, totalBuffer, totalBufferReceived, amountReceived); + totalBufferReceived += amountReceived; + + int expectedMessageLength = BitConverter.ToInt32(totalBuffer, 0); + + while (totalBufferReceived >= expectedMessageLength) + { + // we have received the complete packet + byte[] message = new byte[expectedMessageLength]; + // put the message received into the message array + Array.Copy(totalBuffer, 0, message, 0, expectedMessageLength); + + handleData(message); + + totalBufferReceived -= expectedMessageLength; + Debug.WriteLine($"reduced buffer: {expectedMessageLength}"); + expectedMessageLength = BitConverter.ToInt32(totalBuffer, 0); + } + + stream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(OnReadComplete), null); + } + + private void handleData(byte[] message) + { + byte id = message[4]; + + byte[] payload = new byte[message.Length - 5]; + Array.Copy(message, 5, payload, 0, message.Length - 5); + + Debug.WriteLine("[CLIENT] GOT STRING" + Encoding.ASCII.GetString(payload)); + switch (id) + { + case JSONConvert.LOGIN: + // json log in username data + break; + case JSONConvert.MESSAGE: + // json message data + (string, string) combo = JSONConvert.GetUsernameAndMessage(payload); + string textUsername = combo.Item1; + string textMsg = combo.Item2; + + if(textUsername != data.User.Username) + { + ViewModels.ViewModelGame.HandleIncomingMsg(textUsername, textMsg); + } + + //TODO display username and message in chat window + Debug.WriteLine("[CLIENT] INCOMING MESSAGE!"); + Debug.WriteLine("[CLIENT] User name: {0}\t User message: {1}", textUsername, textMsg); + break; + + case JSONConvert.LOBBY: + // lobby data + LobbyIdentifier lobbyIdentifier = JSONConvert.GetLobbyIdentifier(payload); + switch (lobbyIdentifier) + { + case LobbyIdentifier.LIST: + Debug.WriteLine("got lobbies list"); + Lobbies = JSONConvert.GetLobbiesFromMessage(payload); + OnLobbiesListReceived?.Invoke(); + OnLobbiesReceivedAndWaitingForHost?.Invoke(); + break; + case LobbyIdentifier.HOST: + // we receive this when the server has made us a host of a new lobby + // TODO get lobby id + Debug.WriteLine("[CLIENT] got lobby object"); + int lobbyCreatedID = JSONConvert.GetLobbyID(payload); + OnLobbyCreated?.Invoke(lobbyCreatedID); + break; + case LobbyIdentifier.JOIN_SUCCESS: + + OnLobbyJoinSuccess?.Invoke(JSONConvert.GetLobbyJoinIsHost(payload)); + break; + case LobbyIdentifier.LEAVE: + int lobbyLeaveID = JSONConvert.GetLobbyID(payload); + OnLobbyLeave?.Invoke(lobbyLeaveID); + break; + } + //TODO fill lobby with the data received + break; + + case JSONConvert.CANVAS: + // canvas data + //clientData.CanvasData = JSONConvert.getCoordinates(payload); + CanvasDataReceived?.Invoke(JSONConvert.getCoordinates(payload)); + break; + + default: + Debug.WriteLine("[CLIENT] Received weird identifier: " + id); + break; + } + + } + + public void SendMessage(byte[] message) + { + Debug.WriteLine("[CLIENT] sending message " + Encoding.ASCII.GetString(message)); + stream.BeginWrite(message, 0, message.Length, new AsyncCallback(OnWriteComplete), null); + } + + private void OnWriteComplete(IAsyncResult ar) + { + Debug.WriteLine("[CLIENT] finished writing"); + stream.EndWrite(ar); + } + } +} diff --git a/Client/ViewModels/ViewModel.cs b/Client/ViewModels/ViewModel.cs index f90c1fe..829efda 100644 --- a/Client/ViewModels/ViewModel.cs +++ b/Client/ViewModels/ViewModel.cs @@ -37,6 +37,7 @@ namespace Client _lobbies = new ObservableCollection(); client = ClientData.Instance.Client; client.OnLobbiesListReceived = updateLobbies; + client.OnLobbyLeave = leaveLobby; OnHostButtonClick = new RelayCommand(hostGame); @@ -44,6 +45,13 @@ namespace Client JoinSelectedLobby = new RelayCommand(joinLobby, true); } + private void leaveLobby(int id) + { + _model.CanStartGame = true; + ClientData.Instance.Lobby = null; + SelectedLobby = null; + } + private void hostGame() { Debug.WriteLine("attempting to host game for " + ClientData.Instance.User.Username); @@ -94,8 +102,9 @@ namespace Client } - private void OnLobbyJoinSuccess() + private void OnLobbyJoinSuccess(bool isHost) { + ClientData.Instance.User.Host = isHost; startGameInLobby(); } @@ -107,19 +116,6 @@ namespace Client Lobby[] lobbiesArr = client.Lobbies; Application.Current.Dispatcher.Invoke(delegate { - - //for (int i = 0; i < lobbiesArr.Length; i++) - //{ - // Lobby lobby = lobbiesArr[i]; - // Debug.WriteLine(lobby.PlayersIn); - // if (i < _lobbies.Count && _lobbies[i].ID == lobby.ID) - // { - // _lobbies[i].Set(lobby); - // } else - // { - // _lobbies.Add(lobbiesArr[i]); - // } - //} _lobbies.Clear(); diff --git a/Client/ViewModels/ViewModelGame.cs b/Client/ViewModels/ViewModelGame.cs index 406845f..d9b8eaf 100644 --- a/Client/ViewModels/ViewModelGame.cs +++ b/Client/ViewModels/ViewModelGame.cs @@ -4,6 +4,7 @@ using GalaSoft.MvvmLight.Command; using SharedClientServer; using System.Collections.ObjectModel; using System.ComponentModel; +using System.Diagnostics; using System.Windows; using System.Windows.Input; using System.Windows.Media; @@ -18,10 +19,14 @@ namespace Client.ViewModels private GameWindow window; private Point currentPoint = new Point(); private Color color; - private dynamic _payload; - private string _username; - private string _message; + public static ObservableCollection Messages { get; } = new ObservableCollection(); + + private dynamic _payload; + + public string _username; + + public string _message; public string Message { get @@ -150,6 +155,19 @@ namespace Client.ViewModels data.Client.SendMessage(JSONConvert.GetMessageToSend(JSONConvert.MESSAGE, _payload)); } + public static void HandleIncomingMsg(string username, string message) + { + Application.Current.Dispatcher.Invoke(delegate + { + Messages.Add($"{username}: {message}"); + }); + } + public void LeaveGame(object sender, System.ComponentModel.CancelEventArgs e) + { + Debug.WriteLine("Leaving..."); + data.Client.SendMessage(JSONConvert.ConstructLobbyLeaveMessage(data.Lobby.ID)); + } + } } diff --git a/Client/Views/GameWindow.xaml b/Client/Views/GameWindow.xaml index a69a641..dbd544d 100644 --- a/Client/Views/GameWindow.xaml +++ b/Client/Views/GameWindow.xaml @@ -3,7 +3,6 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:local="clr-namespace:Client.Views" xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" mc:Ignorable="d" Title="Scrubl.io" Height="600" Width="1200"> diff --git a/Client/Views/GameWindow.xaml.cs b/Client/Views/GameWindow.xaml.cs index d59926f..b5e2683 100644 --- a/Client/Views/GameWindow.xaml.cs +++ b/Client/Views/GameWindow.xaml.cs @@ -1,15 +1,8 @@ using Client.ViewModels; -using System; -using System.Collections.Generic; -using System.Text; using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows.Shapes; + namespace Client.Views { @@ -24,6 +17,7 @@ namespace Client.Views { this.viewModel = new ViewModelGame(this); DataContext = this.viewModel; + Closing += this.viewModel.LeaveGame; InitializeComponent(); } @@ -58,5 +52,6 @@ namespace Client.Views { viewModel.Color_Picker(e, this); } + } } diff --git a/Server/Models/ServerClient.cs b/Server/Models/ServerClient.cs index dd746c9..5d960f4 100644 --- a/Server/Models/ServerClient.cs +++ b/Server/Models/ServerClient.cs @@ -6,6 +6,7 @@ using SharedClientServer; using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Net.Sockets; using System.Text; using static SharedClientServer.JSONConvert; @@ -45,48 +46,56 @@ namespace Server.Models if (ar == null || (!ar.IsCompleted) || (!this.stream.CanRead) || !this.tcpClient.Client.Connected) return; - - int bytesReceived = this.stream.EndRead(ar); - - if (totalBufferReceived > 2048) + try { - throw new OutOfMemoryException("buffer is too small!"); - } + int bytesReceived = this.stream.EndRead(ar); - // copy the received bytes into the buffer - Array.Copy(buffer, 0, totalBuffer, totalBufferReceived, bytesReceived); - // add the bytes we received to the total amount - totalBufferReceived += bytesReceived; - - // calculate the expected length of the message - int expectedMessageLength = BitConverter.ToInt32(totalBuffer, 0); - - while (totalBufferReceived >= expectedMessageLength) - { - // we have received the full packet - byte[] message = new byte[expectedMessageLength]; - // copy the total buffer contents into the message array so we can pass it to the handleIncomingMessage method - Array.Copy(totalBuffer, 0, message, 0, expectedMessageLength); - HandleIncomingMessage(message); - - // move the contents of the totalbuffer to the start of the array - Array.Copy(totalBuffer, expectedMessageLength, totalBuffer, 0, (totalBufferReceived - expectedMessageLength)); - - // remove the length of the expected message from the total buffer - totalBufferReceived -= expectedMessageLength; - // and set the new expected length to the rest that is still in the buffer - expectedMessageLength = BitConverter.ToInt32(totalBuffer, 0); - - if (expectedMessageLength == 0) + if (totalBufferReceived + bytesReceived > 1024) { - break; - } + throw new OutOfMemoryException("buffer is too small!"); + } + // copy the received bytes into the buffer + Array.Copy(buffer, 0, totalBuffer, totalBufferReceived, bytesReceived); + // add the bytes we received to the total amount + totalBufferReceived += bytesReceived; + + // calculate the expected length of the message + int expectedMessageLength = BitConverter.ToInt32(totalBuffer, 0); + + while (totalBufferReceived >= expectedMessageLength) + { + // we have received the full packet + byte[] message = new byte[expectedMessageLength]; + // copy the total buffer contents into the message array so we can pass it to the handleIncomingMessage method + Array.Copy(totalBuffer, 0, message, 0, expectedMessageLength); + HandleIncomingMessage(message); + + // move the contents of the totalbuffer to the start of the array + Array.Copy(totalBuffer, expectedMessageLength, totalBuffer, 0, (totalBufferReceived - expectedMessageLength)); + + // remove the length of the expected message from the total buffer + totalBufferReceived -= expectedMessageLength; + // and set the new expected length to the rest that is still in the buffer + expectedMessageLength = BitConverter.ToInt32(totalBuffer, 0); + + if (expectedMessageLength == 0) + { + break; + } + + + } + // start reading for a new message + stream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(OnRead), null); } - // start reading for a new message - stream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(OnRead), null); - + catch (IOException e) + { + tcpClient.Close(); + ServerCommunication.INSTANCE.ServerClientDisconnect(this); + } + } @@ -122,11 +131,15 @@ namespace Server.Models string textUsername = combo.Item1; string textMsg = combo.Item2; - Debug.WriteLine("[SERVERCLIENT] User name: {0}\t User message: {1}", textUsername, textMsg); + //Takes the data sent from the client, and then sets it in a data packet to be sent. + dynamic packet = new + { + username = textUsername, + message = textMsg + }; - // todo handle sending to all except this user the username and message to display in chat - serverCom.SendToLobby(ServerCommunication.INSTANCE.GetLobbyForUser(User),payload); - Debug.WriteLine("Payload has been sent!"); + //Sends the incomming message to be broadcast to all of the clients inside the current lobby. + serverCom.SendToLobby(serverCom.GetLobbyForUser(User), JSONConvert.GetMessageToSend(JSONConvert.MESSAGE, packet)); break; case JSONConvert.LOBBY: @@ -183,8 +196,15 @@ namespace Server.Models break; case LobbyIdentifier.JOIN: int id = JSONConvert.GetLobbyID(payload); - ServerCommunication.INSTANCE.JoinLobby(this.User,id); - sendMessage(JSONConvert.ConstructLobbyJoinSuccessMessage()); + bool isHost; + ServerCommunication.INSTANCE.JoinLobby(this.User,id, out isHost); + sendMessage(JSONConvert.ConstructLobbyJoinSuccessMessage(isHost)); + ServerCommunication.INSTANCE.sendToAll(JSONConvert.ConstructLobbyListMessage(ServerCommunication.INSTANCE.lobbies.ToArray())); + break; + case LobbyIdentifier.LEAVE: + id = JSONConvert.GetLobbyID(payload); + ServerCommunication.INSTANCE.LeaveLobby(User, id); + sendMessage(JSONConvert.ConstructLobbyLeaveMessage(id)); ServerCommunication.INSTANCE.sendToAll(JSONConvert.ConstructLobbyListMessage(ServerCommunication.INSTANCE.lobbies.ToArray())); break; } diff --git a/Server/Models/ServerCommunication.cs b/Server/Models/ServerCommunication.cs index 5b668f3..24da86b 100644 --- a/Server/Models/ServerCommunication.cs +++ b/Server/Models/ServerCommunication.cs @@ -16,6 +16,7 @@ namespace Server.Models public bool Started = false; public List lobbies; private Dictionary> serverClientsInlobbies; + internal Action DisconnectClientAction; public Action newClientAction; @@ -97,6 +98,26 @@ namespace Server.Models } } + public void ServerClientDisconnect(ServerClient serverClient) + { + Debug.WriteLine("[SERVERCOMM] handling disconnect"); + DisconnectClientAction?.Invoke(); + int id = -1; + foreach (Lobby l in serverClientsInlobbies.Keys) + { + if (serverClientsInlobbies[l].Contains(serverClient)) + { + id = l.ID; + }break; + } + + if (id != -1) + { + LeaveLobby(serverClient.User, id); + SendToAllExcept(serverClient, JSONConvert.ConstructLobbyLeaveMessage(id)); + } + } + public void SendToAllExcept(string username, byte[] message) { foreach (ServerClient sc in serverClients) @@ -105,6 +126,14 @@ namespace Server.Models } } + public void SendToAllExcept(ServerClient sc, byte[] message) + { + foreach (ServerClient s in serverClients) + { + if (s != sc) s.sendMessage(message); + } + } + public void SendToLobby(Lobby lobby, byte[] message) { foreach (Lobby l in lobbies) @@ -161,6 +190,7 @@ namespace Server.Models } } + public int HostForLobby(User user) { Lobby lobby = new Lobby( lobbies.Count + 1,0, 8); @@ -171,12 +201,18 @@ namespace Server.Models return lobby.ID; } - public void JoinLobby(User user, int id) + public void JoinLobby(User user, int id, out bool isHost) { + isHost = false; foreach (Lobby l in lobbies) { if (l.ID == id) { + if (l.Users.Count == 0) + { + user.Host = true; + isHost = true; + } AddToLobby(l, user); Debug.WriteLine($"{user.Username} joined lobby with id {id}"); break; @@ -184,6 +220,41 @@ namespace Server.Models } } + public void LeaveLobby(User user, int id) + { + Debug.WriteLine("[SERVERCOMM] removing user from lobby"); + foreach (Lobby l in lobbies) + { + if (l.ID == id) + { + Debug.WriteLine($"[SERVERCOMM] checking for lobby with id {l.ID}"); + + foreach (User u in l.Users) + { + Debug.WriteLine($"[SERVERCOMM] checking if {u.Username} is {user.Username} "); + // contains doesn't work, so we'll do it like this... + if (u.Username == user.Username) + { + Debug.WriteLine("[SERVERCOMM] removed user from lobby!"); + l.Users.Remove(user); + foreach (ServerClient sc in serverClients) + { + if (sc.User.Username == user.Username) + { + serverClientsInlobbies[l].Remove(sc); + break; + } + } + break; + } + } + + + + } + } + } + public void CloseALobby(int lobbyID) { foreach (Lobby lobby in lobbies) diff --git a/Server/ViewModels/MainViewModel.cs b/Server/ViewModels/MainViewModel.cs index ad06638..5d153b8 100644 --- a/Server/ViewModels/MainViewModel.cs +++ b/Server/ViewModels/MainViewModel.cs @@ -33,6 +33,10 @@ namespace Server.ViewModels { InformationModel.ClientsConnected++; }; + serverCommunication.DisconnectClientAction = () => + { + InformationModel.ClientsConnected--; + }; //BitmapImage onlineImg = new BitmapImage(new Uri(@"/img/online.png",UriKind.Relative)); //BitmapImage offlineImg = new BitmapImage(new Uri(@"/img/offline.png", UriKind.Relative)); diff --git a/SharedClientServer/JSONConvert.cs b/SharedClientServer/JSONConvert.cs index 77bb80f..1154f2f 100644 --- a/SharedClientServer/JSONConvert.cs +++ b/SharedClientServer/JSONConvert.cs @@ -1,208 +1,215 @@ -using Client; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; - -namespace SharedClientServer -{ - class JSONConvert - { - public const byte LOGIN = 0x01; - public const byte MESSAGE = 0x02; - public const byte LOBBY = 0x03; - public const byte CANVAS = 0x04; - public const byte GAME = 0x05; - - public enum LobbyIdentifier - { - HOST, - JOIN, - JOIN_SUCCESS, - LEAVE, - LIST, - REQUEST - } - public static (string,string) GetUsernameAndMessage(byte[] json) - { - string msg = Encoding.ASCII.GetString(json); - dynamic payload = JsonConvert.DeserializeObject(msg); - - return (payload.username, payload.message); - } - - public static string GetUsernameLogin(byte[] json) - { - dynamic payload = JsonConvert.DeserializeObject(Encoding.ASCII.GetString(json)); - return payload.username; - } - - public static byte[] ConstructUsernameMessage(string uName) - { - return GetMessageToSend(LOGIN, new - { - username = uName - }); - } - - #region lobby messages - - public static byte[] ConstructLobbyHostMessage() - { - return GetMessageToSend(LOBBY, new - { - identifier = LobbyIdentifier.HOST - }); - } - - public static byte[] ConstructLobbyHostCreatedMessage(int lobbyID) - { - return GetMessageToSend(LOBBY, new - { - identifier = LobbyIdentifier.HOST, - id = lobbyID - }) ; - } - - public static byte[] ConstructLobbyRequestMessage() - { - return GetMessageToSend(LOBBY, new - { - identifier = LobbyIdentifier.REQUEST - }); - } - - public static byte[] ConstructLobbyListMessage(Lobby[] lobbiesList) - { - return GetMessageToSend(LOBBY, new - { - identifier = LobbyIdentifier.LIST, - lobbies = lobbiesList - }); - } - - - public static byte[] ConstructLobbyJoinMessage(int lobbyID) - { - return GetMessageToSend(LOBBY, new - { - identifier = LobbyIdentifier.JOIN, - id = lobbyID - }); - } - - public static byte[] ConstructLobbyLeaveMessage(int lobbyID) - { - return GetMessageToSend(LOBBY, new - { - identifier = LobbyIdentifier.LEAVE, - id = lobbyID - }); - } - public static LobbyIdentifier GetLobbyIdentifier(byte[] json) - { - dynamic payload = JsonConvert.DeserializeObject(Encoding.ASCII.GetString(json)); - return payload.identifier; - } - - public static Lobby[] GetLobbiesFromMessage(byte[] json) - { - dynamic payload = JsonConvert.DeserializeObject(Encoding.ASCII.GetString(json)); - JArray lobbiesArray = payload.lobbies; - Debug.WriteLine("[JSONCONVERT] got lobbies from message" + lobbiesArray.ToString()); - Lobby[] lobbiesTemp = lobbiesArray.ToObject(); - Debug.WriteLine("lobbies in array: "); - foreach (Lobby l in lobbiesTemp) - { - Debug.WriteLine("players: " + l.PlayersIn); - } - return lobbiesTemp; - } - - public static int GetLobbyID(byte[] json) - { - dynamic payload = JsonConvert.DeserializeObject(Encoding.ASCII.GetString(json)); - return payload.id; - } - - public static Lobby GetLobby(byte[] json) - { - dynamic payload = JsonConvert.DeserializeObject(Encoding.ASCII.GetString(json)); - JObject dynamicAsObject = payload.lobby; - return dynamicAsObject.ToObject(); - } - - public static byte[] ConstructLobbyJoinSuccessMessage() - { - return GetMessageToSend(LOBBY, new { identifier = LobbyIdentifier.JOIN_SUCCESS}); - } - - #endregion - - public static byte[] ConstructCanvasDataSend(double[] coordinates) - { - return GetMessageToSend(CANVAS, new - { - coordinatesLine = coordinates - }); - } - - public static double[] getCoordinates(byte[] payload) - { - dynamic payloadD = JsonConvert.DeserializeObject(Encoding.ASCII.GetString(payload)); - JArray coordinatesArray = payloadD.coordinatesLine; - - double[] coordinates = coordinatesArray.ToObject(); - - return coordinates; - } - - public static byte[] ConstructGameStartData(int lobbyID) - { - string startGame = "startGame"; - return GetMessageToSend(GAME, new - { - command = startGame, - lobbyToStart = lobbyID - }); ; - } - - public static string GetGameCommand(byte[] payload) - { - dynamic json = JsonConvert.DeserializeObject(Encoding.ASCII.GetString(payload)); - return json.command; - } - - public static int GetStartGameLobbyID(byte[] payload) - { - dynamic json = JsonConvert.DeserializeObject(Encoding.ASCII.GetString(payload)); - return json.lobbyToStart; - } - - /// - /// constructs a message that can be sent to the clients or server - /// - /// the identifier for what kind of message it is - /// the json payload - /// a byte array containing a message that can be sent to clients or server - public static byte[] GetMessageToSend(byte identifier, dynamic payload) - { - // convert the dynamic to bytes - byte[] payloadBytes = Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(payload)); - // make the array that holds the message and copy the payload into it with the first spot containing the identifier - byte[] res = new byte[payloadBytes.Length + 5]; - // put the payload in the res array - Array.Copy(payloadBytes, 0, res, 5, payloadBytes.Length); - // put the identifier at the start of the payload part - res[4] = identifier; - // put the length of the payload at the start of the res array - Array.Copy(BitConverter.GetBytes(payloadBytes.Length+5),0,res,0,4); - return res; - } - - - } -} +using Client; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; + +namespace SharedClientServer +{ + class JSONConvert + { + public const byte LOGIN = 0x01; + public const byte MESSAGE = 0x02; + public const byte LOBBY = 0x03; + public const byte CANVAS = 0x04; + public const byte GAME = 0x05; + + public enum LobbyIdentifier + { + HOST, + JOIN, + JOIN_SUCCESS, + LEAVE, + LIST, + REQUEST + } + public static (string,string) GetUsernameAndMessage(byte[] json) + { + string msg = Encoding.ASCII.GetString(json); + dynamic payload = JsonConvert.DeserializeObject(msg); + + return (payload.username, payload.message); + } + + public static string GetUsernameLogin(byte[] json) + { + dynamic payload = JsonConvert.DeserializeObject(Encoding.ASCII.GetString(json)); + return payload.username; + } + + public static byte[] ConstructUsernameMessage(string uName) + { + return GetMessageToSend(LOGIN, new + { + username = uName + }); + } + + #region lobby messages + + public static byte[] ConstructLobbyHostMessage() + { + return GetMessageToSend(LOBBY, new + { + identifier = LobbyIdentifier.HOST + }); + } + + public static byte[] ConstructLobbyHostCreatedMessage(int lobbyID) + { + return GetMessageToSend(LOBBY, new + { + identifier = LobbyIdentifier.HOST, + id = lobbyID + }) ; + } + + public static byte[] ConstructLobbyRequestMessage() + { + return GetMessageToSend(LOBBY, new + { + identifier = LobbyIdentifier.REQUEST + }); + } + + public static byte[] ConstructLobbyListMessage(Lobby[] lobbiesList) + { + return GetMessageToSend(LOBBY, new + { + identifier = LobbyIdentifier.LIST, + lobbies = lobbiesList + }); + } + + + public static byte[] ConstructLobbyJoinMessage(int lobbyID) + { + return GetMessageToSend(LOBBY, new + { + identifier = LobbyIdentifier.JOIN, + id = lobbyID + }); + } + + public static byte[] ConstructLobbyLeaveMessage(int lobbyID) + { + return GetMessageToSend(LOBBY, new + { + identifier = LobbyIdentifier.LEAVE, + id = lobbyID + }); + } + public static LobbyIdentifier GetLobbyIdentifier(byte[] json) + { + dynamic payload = JsonConvert.DeserializeObject(Encoding.ASCII.GetString(json)); + return payload.identifier; + } + + public static Lobby[] GetLobbiesFromMessage(byte[] json) + { + dynamic payload = JsonConvert.DeserializeObject(Encoding.ASCII.GetString(json)); + JArray lobbiesArray = payload.lobbies; + Debug.WriteLine("[JSONCONVERT] got lobbies from message" + lobbiesArray.ToString()); + Lobby[] lobbiesTemp = lobbiesArray.ToObject(); + Debug.WriteLine("lobbies in array: "); + foreach (Lobby l in lobbiesTemp) + { + Debug.WriteLine("players: " + l.PlayersIn); + } + return lobbiesTemp; + } + + public static int GetLobbyID(byte[] json) + { + dynamic payload = JsonConvert.DeserializeObject(Encoding.ASCII.GetString(json)); + return payload.id; + } + + public static Lobby GetLobby(byte[] json) + { + dynamic payload = JsonConvert.DeserializeObject(Encoding.ASCII.GetString(json)); + JObject dynamicAsObject = payload.lobby; + return dynamicAsObject.ToObject(); + } + + public static byte[] ConstructLobbyJoinSuccessMessage(bool isHost) + { + return GetMessageToSend(LOBBY, new { identifier = LobbyIdentifier.JOIN_SUCCESS, + host = isHost}); + } + + public static bool GetLobbyJoinIsHost(byte[] json) + { + dynamic payload = JsonConvert.DeserializeObject(Encoding.ASCII.GetString(json)); + return payload.host; + } + + #endregion + + public static byte[] ConstructCanvasDataSend(double[] coordinates) + { + return GetMessageToSend(CANVAS, new + { + coordinatesLine = coordinates + }); + } + + public static double[] getCoordinates(byte[] payload) + { + dynamic payloadD = JsonConvert.DeserializeObject(Encoding.ASCII.GetString(payload)); + JArray coordinatesArray = payloadD.coordinatesLine; + + double[] coordinates = coordinatesArray.ToObject(); + + return coordinates; + } + + public static byte[] ConstructGameStartData(int lobbyID) + { + string startGame = "startGame"; + return GetMessageToSend(GAME, new + { + command = startGame, + lobbyToStart = lobbyID + }); ; + } + + public static string GetGameCommand(byte[] payload) + { + dynamic json = JsonConvert.DeserializeObject(Encoding.ASCII.GetString(payload)); + return json.command; + } + + public static int GetStartGameLobbyID(byte[] payload) + { + dynamic json = JsonConvert.DeserializeObject(Encoding.ASCII.GetString(payload)); + return json.lobbyToStart; + } + + /// + /// constructs a message that can be sent to the clients or server + /// + /// the identifier for what kind of message it is + /// the json payload + /// a byte array containing a message that can be sent to clients or server + public static byte[] GetMessageToSend(byte identifier, dynamic payload) + { + // convert the dynamic to bytes + byte[] payloadBytes = Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(payload)); + // make the array that holds the message and copy the payload into it with the first spot containing the identifier + byte[] res = new byte[payloadBytes.Length + 5]; + // put the payload in the res array + Array.Copy(payloadBytes, 0, res, 5, payloadBytes.Length); + // put the identifier at the start of the payload part + res[4] = identifier; + // put the length of the payload at the start of the res array + Array.Copy(BitConverter.GetBytes(payloadBytes.Length+5),0,res,0,4); + return res; + } + + + } +} diff --git a/SharedClientServer/User.cs b/SharedClientServer/User.cs index 4676904..500a481 100644 --- a/SharedClientServer/User.cs +++ b/SharedClientServer/User.cs @@ -1,11 +1,12 @@ using Newtonsoft.Json; using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Text; namespace SharedClientServer { - class User + class User : IEquatable { private string _username; private int _score; @@ -30,6 +31,42 @@ namespace SharedClientServer _turnToDraw = false; } + public static bool operator ==(User u1, User u2) + { + if (object.ReferenceEquals(u1, null)) + { + return object.ReferenceEquals(u2, null); + } + return u1.Equals(u2 as object); + } + + public static bool operator !=(User u1, User u2) + { + if (object.ReferenceEquals(u1, null)) + { + return object.ReferenceEquals(u2, null); + } + return u1.Equals(u2 as object); + } + + public override bool Equals(object obj) + { + if ((obj == null) || !this.GetType().Equals(obj.GetType())) + { + return false; + } + else + { + return this.Equals(obj as User); + + } + } + + public bool Equals([AllowNull] User other) + { + return other.Username == this.Username; + } + public string Username { get { return _username; }