diff --git a/Client/Client.cs b/Client/Client.cs index 26e1adc..77fc98b 100644 --- a/Client/Client.cs +++ b/Client/Client.cs @@ -5,22 +5,31 @@ 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 { - public delegate void LobbyCallback(int id); public delegate void LobbyJoinCallback(bool isHost); + public delegate void RandomWord(string word); public delegate void HandleIncomingMsg(string username, string msg); internal delegate void HandleIncomingPlayer(Lobby lobby); + public delegate void CanvasDataReceived(double[][] coordinates, Color color); + public delegate void CanvasReset(); + 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[1024]; - private byte[] totalBuffer = new byte[1024]; + private byte[] buffer = new byte[2048]; + private byte[] totalBuffer = new byte[2048]; private int totalBufferReceived = 0; public int Port = 5555; public bool Connected = false; @@ -37,6 +46,8 @@ namespace Client public HandleIncomingMsg IncomingMsg; public HandleIncomingPlayer IncomingPlayer; private ClientData data = ClientData.Instance; + public CanvasDataReceived CanvasDataReceived; + public CanvasReset CReset; public Lobby[] Lobbies { get; set; } public Client(string username) @@ -68,6 +79,7 @@ namespace Client private void OnReadComplete(IAsyncResult ar) { + if (ar == null || (!ar.IsCompleted) || (!this.stream.CanRead) || !this.tcpClient.Client.Connected) return; @@ -75,11 +87,12 @@ namespace Client { int amountReceived = stream.EndRead(ar); - if (totalBufferReceived + amountReceived > 1024) + if (totalBufferReceived + amountReceived > 2048) { throw new OutOfMemoryException("buffer too small"); } + Array.Copy(buffer, 0, totalBuffer, totalBufferReceived, amountReceived); totalBufferReceived += amountReceived; @@ -91,7 +104,6 @@ namespace Client byte[] message = new byte[expectedMessageLength]; // put the message received into the message array Array.Copy(totalBuffer, 0, message, 0, expectedMessageLength); - handleData(message); totalBufferReceived -= expectedMessageLength; @@ -105,7 +117,6 @@ namespace Client Debug.WriteLine("[CLIENT] server not responding! got error: " + e.Message); OnServerDisconnect?.Invoke(); } - } private void handleData(byte[] message) @@ -169,7 +180,22 @@ namespace Client case JSONConvert.CANVAS: // canvas data - break; + //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; + } + break; + case JSONConvert.RANDOMWORD: //Flag byte for receiving the random word. diff --git a/Client/ClientData.cs b/Client/ClientData.cs index 8a217a0..507dbca 100644 --- a/Client/ClientData.cs +++ b/Client/ClientData.cs @@ -31,6 +31,7 @@ namespace Client private Client _client; private Lobby _lobby; private string _message; + private double[] _canvasData = new double[4]; private ClientData() { @@ -68,5 +69,11 @@ namespace Client } } + public double[] CanvasData + { + get { return _canvasData; } + set { _canvasData = value; } + } + } } diff --git a/Client/ViewModels/ViewModel.cs b/Client/ViewModels/ViewModel.cs index d800b9a..3bedfe0 100644 --- a/Client/ViewModels/ViewModel.cs +++ b/Client/ViewModels/ViewModel.cs @@ -11,6 +11,9 @@ 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; namespace Client { @@ -87,10 +90,16 @@ namespace Client private void joinLobby() { - // lobby die je wilt joinen verwijderen - // nieuwe binnengekregen lobby toevoegen - 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)); + } + } private void OnLobbyJoinSuccess(bool isHost) @@ -166,5 +175,7 @@ namespace Client get { return _lobbies; } set { _lobbies = value; } } + + } } diff --git a/Client/ViewModels/ViewModelGame.cs b/Client/ViewModels/ViewModelGame.cs index 0346a7e..212584e 100644 --- a/Client/ViewModels/ViewModelGame.cs +++ b/Client/ViewModels/ViewModelGame.cs @@ -1,169 +1,263 @@ - -using Client.Views; -using GalaSoft.MvvmLight; -using GalaSoft.MvvmLight.Command; -using SharedClientServer; -using System.Collections.Generic; -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; - -namespace Client.ViewModels -{ - class ViewModelGame : INotifyPropertyChanged - { - private ClientData data = ClientData.Instance; - - public event PropertyChangedEventHandler PropertyChanged; - - private Point currentPoint = new Point(); - private Color color; - - public ObservableCollection Messages { get; } = new ObservableCollection(); - public ObservableCollection Players { get; } = new ObservableCollection(); - - private dynamic _payload; - - private string _randomWord; - - public string RandomWord - { - get { return _randomWord; } - set { _randomWord = value; } - } - - public string _message; - public string Message - { - get - { - return _message; - } - set - { - _message = value; - } - } - - public ICommand OnKeyDown { get; set; } - - 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); - - window.CanvasForPaint.Children.Add(line); - data.Client.SendMessage(JSONConvert.GetMessageToSend(0x04, coordinates)); - } - } - - 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; - } - - - public ViewModelGame() - { - OnKeyDown = new RelayCommand(ChatBox_KeyDown); - data.Client.RandomWord = HandleRandomWord; - data.Client.IncomingMsg = HandleIncomingMsg; - data.Client.IncomingPlayer = HandleIncomingPlayer; - } - - 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 incomingMessage) - { - Messages.Add($"{data.User.Username}: {incomingMessage}"); - _payload = new - { - username = data.User.Username, - message = incomingMessage - }; - - //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 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..."); - Application.Current.Dispatcher.Invoke(delegate - { - Players.Remove(data.User.Username); - }); - data.Client.SendMessage(JSONConvert.ConstructLobbyLeaveMessage(data.Lobby.ID)); - } - - /* - * Handles the random word that has been received from the server. - */ - public void HandleRandomWord(string randomWord) - { - RandomWord = randomWord; - Debug.WriteLine($"[CLIENT] The random word is: {_randomWord}"); - } - - public void HandleIncomingPlayer(Lobby lobby) - { - Application.Current.Dispatcher.Invoke(delegate - { - Players.Clear(); - foreach (var item in lobby.Users) - { - Players.Add(item.Username); - } - }); - } - } -} - +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(); + public ObservableCollection Players { get; } = new ObservableCollection(); + + private dynamic _payload; + + public string _username; + + public string _message; + public string Message + { + get + { + return _message; + } + set + { + _message = value; + } + } + + private string _randomWord; + + public string RandomWord + { + get { return _randomWord; } + set { _randomWord = value; } + } + + public static string Word + { + get; + set; + } + + 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; + data.Client.RandomWord = HandleRandomWord; + data.Client.IncomingMsg = HandleIncomingMsg; + data.Client.IncomingPlayer = HandleIncomingPlayer; + } + + 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; + } + + } + } + + public void Canvas_MouseUp(object sender, MouseButtonEventArgs e) + { + sendArrayFromQueue(sender, null); + } + + private void sendArrayFromQueue(object sender, ElapsedEventArgs e) + { + + if (linesQueue.Count != 0) + { + 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)); + } + + public static void HandleRandomWord(string randomWord) + { + Debug.WriteLine("[CLIENT] Reached the handle random word method!"); + Application.Current.Dispatcher.Invoke(delegate + { + Word = randomWord; + }); + } + public void HandleIncomingPlayer(Lobby lobby) + { + Application.Current.Dispatcher.Invoke(delegate + { + Players.Clear(); + foreach (var item in lobby.Users) + { + Players.Add(item.Username); + } + }); + } + } +} diff --git a/Client/Views/GameWindow.xaml b/Client/Views/GameWindow.xaml index 1e8832f..dde8efc 100644 --- a/Client/Views/GameWindow.xaml +++ b/Client/Views/GameWindow.xaml @@ -27,14 +27,29 @@ -