diff --git a/Client/Client.cs b/Client/Client.cs index 3dd5f1c..50c60fc 100644 --- a/Client/Client.cs +++ b/Client/Client.cs @@ -2,9 +2,12 @@ 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.Media; +using System.Windows; + using static SharedClientServer.JSONConvert; namespace Client @@ -30,6 +33,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 +52,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 > 2048) + + 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 > 2048) + { + 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(); } - ar.AsyncWaitHandle.WaitOne(); - stream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(OnReadComplete), null); } private void handleData(byte[] message) @@ -150,25 +171,33 @@ namespace Client // canvas data //clientData.CanvasData = JSONConvert.getCoordinates(payload); int type = JSONConvert.GetCanvasMessageType(payload); - switch (type) - { - case JSONConvert.CANVAS_RESET: - CReset?.Invoke(); - break; - - case JSONConvert.CANVAS_WRITING: - CanvasDataReceived?.Invoke(JSONConvert.getCoordinates(payload), JSONConvert.getCanvasDrawingColor(payload)); - // we hebben gedrawed, dus stuur dat we weer kunnen drawen - - break; + switch (type) + { + case JSONConvert.CANVAS_RESET: + CReset?.Invoke(); + break; + + case JSONConvert.CANVAS_WRITING: + CanvasDataReceived?.Invoke(JSONConvert.getCoordinates(payload), JSONConvert.getCanvasDrawingColor(payload)); + // we hebben gedrawed, dus stuur dat we weer kunnen drawen + + break; } 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)); } @@ -176,12 +205,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..3bedfe0 100644 --- a/Client/ViewModels/ViewModel.cs +++ b/Client/ViewModels/ViewModel.cs @@ -11,10 +11,10 @@ using System.Collections.ObjectModel; using Client.Views; using System.Linq; using System.Windows.Data; -using System.Data; -using System.Windows.Controls.Primitives; -using System.Windows.Controls; - +using System.Data; +using System.Windows.Controls.Primitives; +using System.Windows.Controls; + namespace Client { class ViewModel : INotifyPropertyChanged @@ -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() @@ -88,16 +90,14 @@ namespace Client private void joinLobby() { - // lobby die je wilt joinen verwijderen - // nieuwe binnengekregen lobby toevoegen - if (SelectedLobby != null) - { - if (SelectedLobby.PlayersIn == SelectedLobby.MaxPlayers || !SelectedLobby.LobbyJoinable) - { - return; - } - client.OnLobbyJoinSuccess = OnLobbyJoinSuccess; - client.SendMessage(JSONConvert.ConstructLobbyJoinMessage(SelectedLobby.ID)); + if (SelectedLobby != null) + { + if (SelectedLobby.PlayersIn == SelectedLobby.MaxPlayers || !SelectedLobby.LobbyJoinable) + { + return; + } + client.OnLobbyJoinSuccess = OnLobbyJoinSuccess; + client.SendMessage(JSONConvert.ConstructLobbyJoinMessage(SelectedLobby.ID)); } } diff --git a/Client/ViewModels/ViewModelGame.cs b/Client/ViewModels/ViewModelGame.cs index b1b01e3..976e24d 100644 --- a/Client/ViewModels/ViewModelGame.cs +++ b/Client/ViewModels/ViewModelGame.cs @@ -1,225 +1,244 @@ - -using Client.Views; -using GalaSoft.MvvmLight.Command; -using SharedClientServer; -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.ComponentModel; -using System.Diagnostics; -using System.Timers; -using System.Windows; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Shapes; - -namespace Client.ViewModels -{ - class ViewModelGame : INotifyPropertyChanged - { - public event PropertyChangedEventHandler PropertyChanged; - private ClientData data = ClientData.Instance; - private GameWindow window; - private Point currentPoint = new Point(); - public Color color; - public double[][] buffer; - public int pos = 0; - public int maxLines = 50; - public Queue linesQueue; - private Timer queueTimer; - - public static ObservableCollection Messages { get; } = new ObservableCollection(); - - private dynamic _payload; - - public string _username; - - public string _message; - public string Message - { - get - { - return _message; - } - set - { - _message = value; - } - } - - public bool IsHost - { - get { return data.User.Host; } - } - - public ViewModelGame(GameWindow window) - { - this.window = window; - if (_payload == null) - { - _message = ""; - - } - else - { - //_message = data.Message; - //_username = data.User.Username; - //Messages.Add($"{data.User.Username}: {Message}"); - } - - buffer = new double[maxLines][]; - linesQueue = new Queue(); - OnKeyDown = new RelayCommand(ChatBox_KeyDown); - ButtonStartGame = new RelayCommand(BeginGame); - ButtonResetCanvas = new RelayCommand(CanvasResetLocal); - data.Client.CanvasDataReceived = UpdateCanvasWithNewData; - data.Client.CReset = CanvasResetData; - } - - public ICommand OnKeyDown { get; set; } - public ICommand ButtonStartGame { get; set; } - public ICommand ButtonResetCanvas { get; set; } - - public void BeginGame() - { - - queueTimer = new Timer(50); - queueTimer.Start(); - queueTimer.Elapsed += sendArrayFromQueue; - data.Client.SendMessage(JSONConvert.ConstructGameStartData(data.Lobby.ID)); - } - - - private void CanvasResetLocal() - { - this.window.CanvasForPaint.Children.Clear(); - data.Client.SendMessage(JSONConvert.GetMessageToSend(JSONConvert.CANVAS, JSONConvert.CANVAS_RESET)); - } - - - public void Canvas_MouseDown(MouseButtonEventArgs e, GameWindow window) - { - if (e.ButtonState == MouseButtonState.Pressed) - { - currentPoint = e.GetPosition(window.CanvasForPaint); - } - } - - public void Canvas_MouseMove(MouseEventArgs e, GameWindow window) - { - if (e.LeftButton == MouseButtonState.Pressed) - { - double[] coordinates = new double[4]; - Line line = new Line(); - - line.Stroke = new SolidColorBrush(color); - //line.Stroke = SystemColors.WindowFrameBrush; - line.X1 = currentPoint.X; - line.Y1 = currentPoint.Y; - line.X2 = e.GetPosition(window.CanvasForPaint).X; - line.Y2 = e.GetPosition(window.CanvasForPaint).Y; - coordinates[0] = line.X1; - coordinates[1] = line.Y1; - coordinates[2] = line.X2; - coordinates[3] = line.Y2; - currentPoint = e.GetPosition(window.CanvasForPaint); - buffer[pos] = coordinates; - pos++; - - window.CanvasForPaint.Children.Add(line); - if (pos == maxLines) - { - double[][] temp = new double[maxLines][]; - for (int i = 0; i < maxLines; i++) - { - temp[i] = buffer[i]; - } - linesQueue.Enqueue(temp); - Array.Clear(buffer, 0, buffer.Length); - pos = 0; - } - - } - } - - private void sendArrayFromQueue(object sender, ElapsedEventArgs e) - { - - if (linesQueue.Count != 0) - { - Debug.WriteLine("[GAME] sending canvas data..."); - double[][] temp = linesQueue.Dequeue(); - data.Client.SendMessage(JSONConvert.ConstructDrawingCanvasData(temp,color)); - } - } - - public void Color_Picker(RoutedPropertyChangedEventArgs e, GameWindow window) - { - Color colorSelected = new Color(); - colorSelected.A = 255; - colorSelected.R = window.ClrPcker_Background.SelectedColor.Value.R; - colorSelected.G = window.ClrPcker_Background.SelectedColor.Value.G; - colorSelected.B = window.ClrPcker_Background.SelectedColor.Value.B; - color = colorSelected; - } - - private void UpdateCanvasWithNewData(double[][] buffer, Color color) - { - Application.Current.Dispatcher.Invoke(delegate - { - foreach (double[] arr in buffer) - { - Line line = new Line(); - line.Stroke = new SolidColorBrush(color); - line.X1 = arr[0]; - line.Y1 = arr[1]; - line.X2 = arr[2]; - line.Y2 = arr[3]; - this.window.CanvasForPaint.Children.Add(line); - } - }); - } - - private void CanvasResetData() - { - this.window.CanvasForPaint.Children.Clear(); - } - - private void ChatBox_KeyDown() - { - //if enter then clear textbox and send message. - if (Message != string.Empty) AddMessage(Message); - Message = string.Empty; - } - - internal void AddMessage(string message) - { - Messages.Add($"{data.User.Username}: {message}"); - - _payload = new - { - username = data.User.Username, - message = message - }; - - //Broadcast the message after adding it to the list! - 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)); - } - - - } -} - + +using Client.Views; +using GalaSoft.MvvmLight.Command; +using SharedClientServer; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Diagnostics; +using System.Timers; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Shapes; + +namespace Client.ViewModels +{ + class ViewModelGame : INotifyPropertyChanged + { + public event PropertyChangedEventHandler PropertyChanged; + private ClientData data = ClientData.Instance; + private GameWindow window; + private Point currentPoint = new Point(); + public Color color; + public double[][] buffer; + public int pos = 0; + public int maxLines = 50; + public Queue linesQueue; + private Timer queueTimer; + + public static ObservableCollection Messages { get; } = new ObservableCollection(); + + private dynamic _payload; + + public static string Word + { + get; + set; + } + + public string _username; + + public string _message; + public string Message + { + get + { + return _message; + } + set + { + _message = value; + } + } + + public bool IsHost + { + get { return data.User.Host; } + } + + public ViewModelGame(GameWindow window) + { + this.window = window; + if (_payload == null) + { + _message = ""; + + } + else + { + //_message = data.Message; + //_username = data.User.Username; + //Messages.Add($"{data.User.Username}: {Message}"); + } + + buffer = new double[maxLines][]; + linesQueue = new Queue(); + OnKeyDown = new RelayCommand(ChatBox_KeyDown); + ButtonStartGame = new RelayCommand(BeginGame); + ButtonResetCanvas = new RelayCommand(CanvasResetLocal); + data.Client.CanvasDataReceived = UpdateCanvasWithNewData; + data.Client.CReset = CanvasResetData; + } + + public ICommand OnKeyDown { get; set; } + public ICommand ButtonStartGame { get; set; } + public ICommand ButtonResetCanvas { get; set; } + + public void BeginGame() + { + + queueTimer = new Timer(50); + queueTimer.Start(); + queueTimer.Elapsed += sendArrayFromQueue; + data.Client.SendMessage(JSONConvert.ConstructGameStartData(data.Lobby.ID)); + } + + + private void CanvasResetLocal() + { + this.window.CanvasForPaint.Children.Clear(); + data.Client.SendMessage(JSONConvert.GetMessageToSend(JSONConvert.CANVAS, JSONConvert.CANVAS_RESET)); + } + + + public void Canvas_MouseDown(MouseButtonEventArgs e, GameWindow window) + { + if (e.ButtonState == MouseButtonState.Pressed) + { + currentPoint = e.GetPosition(window.CanvasForPaint); + } + } + + public void Canvas_MouseMove(MouseEventArgs e, GameWindow window) + { + if (e.LeftButton == MouseButtonState.Pressed) + { + double[] coordinates = new double[4]; + Line line = new Line(); + + line.Stroke = new SolidColorBrush(color); + //line.Stroke = SystemColors.WindowFrameBrush; + line.X1 = currentPoint.X; + line.Y1 = currentPoint.Y; + line.X2 = e.GetPosition(window.CanvasForPaint).X; + line.Y2 = e.GetPosition(window.CanvasForPaint).Y; + coordinates[0] = line.X1; + coordinates[1] = line.Y1; + coordinates[2] = line.X2; + coordinates[3] = line.Y2; + currentPoint = e.GetPosition(window.CanvasForPaint); + buffer[pos] = coordinates; + pos++; + + window.CanvasForPaint.Children.Add(line); + if (pos == maxLines) + { + double[][] temp = new double[maxLines][]; + for (int i = 0; i < maxLines; i++) + { + temp[i] = buffer[i]; + } + linesQueue.Enqueue(temp); + Array.Clear(buffer, 0, buffer.Length); + pos = 0; + } + + } + } + + private void sendArrayFromQueue(object sender, ElapsedEventArgs e) + { + + if (linesQueue.Count != 0) + { + Debug.WriteLine("[GAME] sending canvas data..."); + double[][] temp = linesQueue.Dequeue(); + data.Client.SendMessage(JSONConvert.ConstructDrawingCanvasData(temp,color)); + } + } + + public void Color_Picker(RoutedPropertyChangedEventArgs e, GameWindow window) + { + Color colorSelected = new Color(); + colorSelected.A = 255; + colorSelected.R = window.ClrPcker_Background.SelectedColor.Value.R; + colorSelected.G = window.ClrPcker_Background.SelectedColor.Value.G; + colorSelected.B = window.ClrPcker_Background.SelectedColor.Value.B; + color = colorSelected; + } + + private void UpdateCanvasWithNewData(double[][] buffer, Color color) + { + Application.Current.Dispatcher.Invoke(delegate + { + foreach (double[] arr in buffer) + { + Line line = new Line(); + line.Stroke = new SolidColorBrush(color); + line.X1 = arr[0]; + line.Y1 = arr[1]; + line.X2 = arr[2]; + line.Y2 = arr[3]; + this.window.CanvasForPaint.Children.Add(line); + } + }); + } + + private void CanvasResetData() + { + this.window.CanvasForPaint.Children.Clear(); + } + + private void ChatBox_KeyDown() + { + //if enter then clear textbox and send message. + if (Message != string.Empty) AddMessage(Message); + Message = string.Empty; + } + + internal void AddMessage(string message) + { + Messages.Add($"{data.User.Username}: {message}"); + + _payload = new + { + username = data.User.Username, + message = message + }; + + //Broadcast the message after adding it to the list! + 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 + { + Messages.Add($"{username}: {message}"); + }); + } + 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/Client/Views/GameWindow.xaml b/Client/Views/GameWindow.xaml index 607b4a1..ab2d3ef 100644 --- a/Client/Views/GameWindow.xaml +++ b/Client/Views/GameWindow.xaml @@ -50,6 +50,9 @@