diff --git a/Client/Client.cs b/Client/Client.cs index 4044ec1..4a409de 100644 --- a/Client/Client.cs +++ b/Client/Client.cs @@ -2,9 +2,11 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Net.Sockets; using System.Text; using System.Windows.Media; +using System.Windows; using static SharedClientServer.JSONConvert; namespace Client @@ -30,6 +32,7 @@ namespace Client public Callback OnLobbiesListReceived; public LobbyJoinCallback OnLobbyJoinSuccess; public Callback OnLobbiesReceivedAndWaitingForHost; + public Callback OnServerDisconnect; public LobbyCallback OnLobbyCreated; public LobbyCallback OnLobbyLeave; private ClientData data = ClientData.Instance; @@ -48,43 +51,60 @@ namespace Client 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); + try + { + 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); + + } catch (Exception e) + { + Debug.WriteLine("Can't connect, retrying..."); + tcpClient.BeginConnect("localhost", Port, new AsyncCallback(OnConnect), null); + } } private void OnReadComplete(IAsyncResult ar) { - int amountReceived = stream.EndRead(ar); - if (totalBufferReceived + amountReceived > 1024) + if (ar == null || (!ar.IsCompleted) || (!this.stream.CanRead) || !this.tcpClient.Client.Connected) + return; + try { - throw new OutOfMemoryException("buffer too small"); - } - - // copy the received bytes into the buffer - Array.Copy(buffer, 0, totalBuffer, totalBufferReceived, amountReceived); - // add the bytes we received to the total amount - totalBufferReceived += amountReceived; + int amountReceived = stream.EndRead(ar); - int expectedMessageLength = BitConverter.ToInt32(totalBuffer, 0); + if (totalBufferReceived + amountReceived > 1024) + { + throw new OutOfMemoryException("buffer too small"); + } - while (totalBufferReceived >= expectedMessageLength) + 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; + expectedMessageLength = BitConverter.ToInt32(totalBuffer, 0); + } + + ar.AsyncWaitHandle.WaitOne(); + stream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(OnReadComplete), null); + } catch (IOException e) { - // 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); + Debug.WriteLine("[CLIENT] server not responding! got error: " + e.Message); + OnServerDisconnect?.Invoke(); } - - stream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(OnReadComplete), null); + } private void handleData(byte[] message) @@ -162,10 +182,18 @@ namespace Client } break; + case JSONConvert.RANDOMWORD: + //Flag byte for receiving the random word. + int lobbyId = JSONConvert.GetLobbyID(payload); + + if(data.Lobby?.ID == lobbyId) + ViewModels.ViewModelGame.HandleRandomWord(JSONConvert.GetRandomWord(payload)); + break; default: Debug.WriteLine("[CLIENT] Received weird identifier: " + id); break; } + SendMessage(JSONConvert.GetMessageToSend(JSONConvert.MESSAGE_RECEIVED,null)); } @@ -173,12 +201,14 @@ namespace Client { 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); + stream.Flush(); } } } diff --git a/Client/ViewModels/ViewModel.cs b/Client/ViewModels/ViewModel.cs index fe9cb35..7ff0778 100644 --- a/Client/ViewModels/ViewModel.cs +++ b/Client/ViewModels/ViewModel.cs @@ -38,6 +38,10 @@ namespace Client client = ClientData.Instance.Client; client.OnLobbiesListReceived = updateLobbies; client.OnLobbyLeave = leaveLobby; + client.OnServerDisconnect = () => + { + Environment.Exit(0); + }; OnHostButtonClick = new RelayCommand(hostGame); @@ -61,12 +65,10 @@ namespace Client private void becomeHostForLobby(int id) { - Debug.WriteLine($"got host succes with data {id} "); wantToBeHost = true; wantToBeHostId = id; client.OnLobbiesReceivedAndWaitingForHost = hostLobbiesReceived; - } private void hostLobbiesReceived() diff --git a/Client/ViewModels/ViewModelGame.cs b/Client/ViewModels/ViewModelGame.cs index 9749198..6ddcf48 100644 --- a/Client/ViewModels/ViewModelGame.cs +++ b/Client/ViewModels/ViewModelGame.cs @@ -1,5 +1,5 @@ -using Client.Views; +using Client.Views; using GalaSoft.MvvmLight.Command; using SharedClientServer; using System; @@ -7,6 +7,7 @@ using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Windows; +using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; using System.Windows.Shapes; @@ -25,6 +26,12 @@ namespace Client.ViewModels private dynamic _payload; + public static string Word + { + get; + set; + } + public string _username; public string _message; @@ -165,6 +172,10 @@ namespace Client.ViewModels data.Client.SendMessage(JSONConvert.GetMessageToSend(JSONConvert.MESSAGE, _payload)); } + /* + * MISC make this a callback + * Handles the incoming chat message from another client. + */ public static void HandleIncomingMsg(string username, string message) { Application.Current.Dispatcher.Invoke(delegate @@ -172,13 +183,21 @@ namespace Client.ViewModels Messages.Add($"{username}: {message}"); }); } - public void LeaveGame(object sender, System.ComponentModel.CancelEventArgs e) + public void LeaveGame(object sender, CancelEventArgs e) { Debug.WriteLine("Leaving..."); data.Client.SendMessage(JSONConvert.ConstructLobbyLeaveMessage(data.Lobby.ID)); } - + /* + * MISC make this a callback + * Handles the random word that has been received from the server. + */ + public static void HandleRandomWord(string randomWord) + { + Debug.WriteLine("[CLIENT] Reached the handle random word method!"); + Word = "NegerPik"; + } } } - + diff --git a/Server/Models/ServerClient.cs b/Server/Models/ServerClient.cs index 3561b3a..216f1ec 100644 --- a/Server/Models/ServerClient.cs +++ b/Server/Models/ServerClient.cs @@ -9,10 +9,13 @@ using System.Diagnostics; using System.IO; using System.Net.Sockets; using System.Text; +using System.Threading; +using System.Threading.Tasks; using static SharedClientServer.JSONConvert; namespace Server.Models { + public delegate void Callback(); class ServerClient : ObservableObject { private TcpClient tcpClient; @@ -22,7 +25,8 @@ namespace Server.Models private int totalBufferReceived = 0; public User User { get; set; } private ServerCommunication serverCom = ServerCommunication.INSTANCE; - + private Callback OnMessageReceivedOk; + /// /// Constructor that creates a new serverclient object with the given tcp client. @@ -86,17 +90,18 @@ namespace Server.Models } + ar.AsyncWaitHandle.WaitOne(); // start reading for a new message stream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(OnRead), null); - } catch (IOException e) { + Debug.WriteLine("[SERVERCLIENT] Client disconnected! exception was " + e.Message); tcpClient.Close(); ServerCommunication.INSTANCE.ServerClientDisconnect(this); } - - + + } /// @@ -108,21 +113,21 @@ namespace Server.Models Debug.WriteLine($"Got message : {Encoding.ASCII.GetString(message)}"); byte id = message[4]; byte[] payload = new byte[message.Length - 5]; - Array.Copy(message,5,payload,0,message.Length-5); + Array.Copy(message, 5, payload, 0, message.Length - 5); Debug.WriteLine("[SERVERCLIENT] GOT STRING" + Encoding.ASCII.GetString(payload)); - switch(id) + switch (id) { - + case JSONConvert.LOGIN: // json log in username data string uName = JSONConvert.GetUsernameLogin(payload); - + if (uName != null) { User = new User(uName); User.Username = uName; Debug.WriteLine("[SERVERCLIENT] set username to " + uName); - + } break; case JSONConvert.MESSAGE: @@ -145,7 +150,7 @@ namespace Server.Models case JSONConvert.LOBBY: // lobby data LobbyIdentifier l = JSONConvert.GetLobbyIdentifier(payload); - handleLobbyMessage(payload,l); + handleLobbyMessage(payload, l); break; case JSONConvert.CANVAS: @@ -191,6 +196,13 @@ namespace Server.Models break; + case JSONConvert.RANDOMWORD: + //Flag byte for receiving the random word. + break; + case JSONConvert.MESSAGE_RECEIVED: + // we now can send a new message + OnMessageReceivedOk?.Invoke(); + break; default: Debug.WriteLine("[SERVER] Received weird identifier: " + id); break; @@ -218,6 +230,15 @@ namespace Server.Models ServerCommunication.INSTANCE.JoinLobby(this.User,id, out isHost); sendMessage(JSONConvert.ConstructLobbyJoinSuccessMessage(isHost)); ServerCommunication.INSTANCE.sendToAll(JSONConvert.ConstructLobbyListMessage(ServerCommunication.INSTANCE.lobbies.ToArray())); + OnMessageReceivedOk = () => + { + serverCom.sendToAll(JSONConvert.GetMessageToSend(JSONConvert.RANDOMWORD, new + { + id = serverCom.GetLobbyForUser(User).ID, + word = JSONConvert.SendRandomWord("WordsForGame.json") + })); + OnMessageReceivedOk = null; + }; break; case LobbyIdentifier.LEAVE: id = JSONConvert.GetLobbyID(payload); @@ -228,6 +249,21 @@ namespace Server.Models } } + private async void SendLobbyData() + { + string result = await WaitForData(); + if(result == "bruh momento") + { + + } + } + + private async Task WaitForData() + { + await Task.Delay(1000); + return "bruh momento"; + } + /// /// sends a message to the tcp client /// diff --git a/Server/Models/ServerCommunication.cs b/Server/Models/ServerCommunication.cs index de833ae..e55c835 100644 --- a/Server/Models/ServerCommunication.cs +++ b/Server/Models/ServerCommunication.cs @@ -90,7 +90,7 @@ namespace Server.Models /// send a message to all tcp clients in the list /// /// the message to send - public void sendToAll(byte[] message) + public async void sendToAll(byte[] message) { foreach (ServerClient sc in serverClients) { @@ -142,6 +142,7 @@ namespace Server.Models { foreach (ServerClient sc in serverClientsInlobbies[l]) { + Debug.WriteLine("[SERVERCLIENT] Sending message"); sc.sendMessage(message); } break; diff --git a/Server/Server.csproj b/Server/Server.csproj index 65a6e4e..0e46462 100644 --- a/Server/Server.csproj +++ b/Server/Server.csproj @@ -6,6 +6,16 @@ true + + + + + + + Always + + + diff --git a/Server/resources/WordsForGame.json b/Server/resources/WordsForGame.json new file mode 100644 index 0000000..71676ba --- /dev/null +++ b/Server/resources/WordsForGame.json @@ -0,0 +1,31 @@ +{ + "filename": "wordsForGame", + "words": [ + "teacher", + "love", + "engineer", + "supermarket", + "disaster", + "studio", + "restaurant", + "music", + "chocolate", + "dirt", + "thought", + "virus", + "lieutenant", + "painter", + "kiwi", + "power ranger", + "computer", + "people", + "candidate", + "security guard", + "Canada", + "teeth", + "army", + "airport", + "president", + "bedroom" + ] +} \ No newline at end of file diff --git a/SharedClientServer/JSONConvert.cs b/SharedClientServer/JSONConvert.cs index 0b92fb7..fc036c6 100644 --- a/SharedClientServer/JSONConvert.cs +++ b/SharedClientServer/JSONConvert.cs @@ -1,9 +1,11 @@ using Client; +using Microsoft.VisualBasic.CompilerServices; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Linq; using System.Text; using System.Windows.Media; @@ -16,6 +18,8 @@ namespace SharedClientServer public const byte MESSAGE = 0x02; public const byte LOBBY = 0x03; public const byte CANVAS = 0x04; + public const byte RANDOMWORD = 0x05; + public const byte MESSAGE_RECEIVED = 0x06; public const byte GAME = 0x05; public enum LobbyIdentifier @@ -233,7 +237,39 @@ namespace SharedClientServer Array.Copy(BitConverter.GetBytes(payloadBytes.Length+5),0,res,0,4); return res; } + + /* + * This method sends a random word from the json file, this happens when the client joins a lobby. + */ + public static string SendRandomWord(string filename) + { + dynamic words; + Random random = new Random(); + string workingDir = Path.GetFullPath(@"..\Server"); + string projDir = Directory.GetParent(workingDir).Parent.Parent.FullName; + string filePath = projDir += $@"\resources\{filename}"; + using(StreamReader reader = new StreamReader(filePath)) + { + string json = reader.ReadToEnd(); + words = JsonConvert.DeserializeObject(json); + } + + + int index = random.Next(0, 24); + + Debug.WriteLine($"[SERVERCLIENT] Sending random words {words}"); + + return words.words[index]; + } + /* + * Client gets the payload and retrieves the word from the payload + */ + public static string GetRandomWord(byte[] json) + { + dynamic payload = JsonConvert.DeserializeObject(Encoding.ASCII.GetString(json)); + return payload.word; + } } }