diff --git a/Client/App.xaml b/Client/App.xaml
new file mode 100644
index 0000000..408569d
--- /dev/null
+++ b/Client/App.xaml
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/Client/App.xaml.cs b/Client/App.xaml.cs
new file mode 100644
index 0000000..9f2324b
--- /dev/null
+++ b/Client/App.xaml.cs
@@ -0,0 +1,30 @@
+using Client.Views;
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace Client
+{
+ ///
+ /// Interaction logic for App.xaml
+ ///
+ public partial class App : Application
+ {
+
+ protected override void OnStartup(StartupEventArgs e)
+ {
+ base.OnStartup(e);
+ LoginScreen startWindow = new LoginScreen();
+ //ViewModel VM = new ViewModel();
+ //startWindow.DataContext = VM;
+ startWindow.Show();
+ }
+
+ }
+
+
+}
diff --git a/Client/AssemblyInfo.cs b/Client/AssemblyInfo.cs
new file mode 100644
index 0000000..8b5504e
--- /dev/null
+++ b/Client/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+using System.Windows;
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
diff --git a/Client/Client.cs b/Client/Client.cs
new file mode 100644
index 0000000..5346d92
--- /dev/null
+++ b/Client/Client.cs
@@ -0,0 +1,148 @@
+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);
+ class Client : ObservableObject
+ {
+ private TcpClient tcpClient;
+ private NetworkStream stream;
+ private byte[] buffer = new byte[1024];
+ private byte[] totalBuffer = new byte[1024];
+ 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 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 + amountReceived > 1024)
+ {
+ 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;
+ 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
+ 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/Client.csproj b/Client/Client.csproj
new file mode 100644
index 0000000..d5b88aa
--- /dev/null
+++ b/Client/Client.csproj
@@ -0,0 +1,22 @@
+
+
+
+ WinExe
+ netcoreapp3.1
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Client/ClientData.cs b/Client/ClientData.cs
new file mode 100644
index 0000000..8a217a0
--- /dev/null
+++ b/Client/ClientData.cs
@@ -0,0 +1,72 @@
+using SharedClientServer;
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Text;
+
+namespace Client
+{
+ class ClientData
+ {
+ private static ClientData _instance;
+ private static readonly object padlock = new object();
+
+ public static ClientData Instance
+ {
+ get
+ {
+ lock (padlock)
+ {
+ if (_instance == null)
+ {
+ _instance = new ClientData();
+ }
+ return _instance;
+ }
+ }
+ }
+
+
+ private User _user;
+ private Client _client;
+ private Lobby _lobby;
+ private string _message;
+
+ private ClientData()
+ {
+
+ }
+
+
+ public User User
+ {
+ get { return _user; }
+ set { _user = value; }
+ }
+
+ public Client Client
+ {
+ get { return _client; }
+ set { _client = value; }
+ }
+
+ public Lobby Lobby
+ {
+ get { return _lobby; }
+ set { _lobby = value; }
+ }
+
+ public String Message
+ {
+ get
+ {
+ return _message;
+ }
+ set
+ {
+ _message = value;
+ }
+ }
+
+ }
+}
diff --git a/Client/FodyWeavers.xml b/Client/FodyWeavers.xml
new file mode 100644
index 0000000..d5abfed
--- /dev/null
+++ b/Client/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/Client/FodyWeavers.xsd b/Client/FodyWeavers.xsd
new file mode 100644
index 0000000..69dbe48
--- /dev/null
+++ b/Client/FodyWeavers.xsd
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+ Used to control if the On_PropertyName_Changed feature is enabled.
+
+
+
+
+ Used to control if the Dependent properties feature is enabled.
+
+
+
+
+ Used to control if the IsChanged property feature is enabled.
+
+
+
+
+ Used to change the name of the method that fires the notify event. This is a string that accepts multiple values in a comma separated form.
+
+
+
+
+ Used to control if equality checks should be inserted. If false, equality checking will be disabled for the project.
+
+
+
+
+ Used to control if equality checks should use the Equals method resolved from the base class.
+
+
+
+
+ Used to control if equality checks should use the static Equals method resolved from the base class.
+
+
+
+
+ Used to turn off build warnings from this weaver.
+
+
+
+
+ Used to turn off build warnings about mismatched On_PropertyName_Changed methods.
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/Client/Models/Model.cs b/Client/Models/Model.cs
new file mode 100644
index 0000000..9e50229
--- /dev/null
+++ b/Client/Models/Model.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Text;
+
+namespace Client
+{
+ class Model : INotifyPropertyChanged
+ {
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ private int _numbers;
+ private bool _status;
+ private bool _canStartGame;
+
+ //Test code
+ public int Numbers
+ {
+ get { return _numbers; }
+
+ set
+ {
+ _numbers = value;
+ }
+ }
+
+
+ public bool Status
+ {
+ get
+ {
+ return _status;
+ }
+
+ set
+ {
+ _status = value;
+ }
+ }
+
+ public bool CanStartGame
+ {
+ get { return _canStartGame; }
+ set { _canStartGame = value; }
+ }
+
+
+ public Model()
+ {
+ _status = false;
+ _numbers = 0;
+ _canStartGame = true;
+ }
+
+ }
+}
diff --git a/Client/ViewModels/ViewModel.cs b/Client/ViewModels/ViewModel.cs
new file mode 100644
index 0000000..bbb9843
--- /dev/null
+++ b/Client/ViewModels/ViewModel.cs
@@ -0,0 +1,172 @@
+using GalaSoft.MvvmLight.Command;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Text;
+using System.Windows.Input;
+using SharedClientServer;
+using System.Diagnostics;
+using System.Windows;
+using System.Collections.ObjectModel;
+using Client.Views;
+using System.Linq;
+using System.Windows.Data;
+
+namespace Client
+{
+ class ViewModel : INotifyPropertyChanged
+ {
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ public ICommand OnHostButtonClick { get; set; }
+ public ICommand JoinSelectedLobby { get; set; }
+
+ public Lobby SelectedLobby { get; set; }
+
+ private Client client;
+
+ private bool wantToBeHost = false;
+ private int wantToBeHostId = 0;
+
+ public ViewModel()
+ {
+ _model = new Model();
+ _lobbies = new ObservableCollection();
+ client = ClientData.Instance.Client;
+ client.OnLobbiesListReceived = updateLobbies;
+
+
+ OnHostButtonClick = new RelayCommand(hostGame);
+
+ JoinSelectedLobby = new RelayCommand(joinLobby, true);
+ }
+
+ private void hostGame()
+ {
+ Debug.WriteLine("attempting to host game for " + ClientData.Instance.User.Username);
+ client.SendMessage(JSONConvert.ConstructLobbyHostMessage());
+ client.OnLobbyCreated = becomeHostForLobby;
+ }
+
+ private void becomeHostForLobby(int id)
+ {
+
+ Debug.WriteLine($"got host succes with data {id} ");
+ wantToBeHost = true;
+ wantToBeHostId = id;
+ client.OnLobbiesReceivedAndWaitingForHost = hostLobbiesReceived;
+
+ }
+
+ private void hostLobbiesReceived()
+ {
+ if (wantToBeHost)
+ foreach (Lobby l in Lobbies)
+ {
+ if (l.ID == wantToBeHostId)
+ {
+ Debug.WriteLine("found lobby that we want to be host of: " + l.ID + ", joining..");
+ SelectedLobby = l;
+ startGameInLobby();
+ wantToBeHost = false;
+ client.OnLobbiesReceivedAndWaitingForHost = null;
+ break;
+ }
+ }
+ }
+
+ private void joinLobby()
+ {
+ // lobby die je wilt joinen verwijderen
+ // nieuwe binnengekregen lobby toevoegen
+ client.OnLobbyJoinSuccess = OnLobbyJoinSuccess;
+ client.SendMessage(JSONConvert.ConstructLobbyJoinMessage(SelectedLobby.ID));
+ }
+
+ private void OnLobbyJoinSuccess()
+ {
+ startGameInLobby();
+ }
+
+
+
+ private void updateLobbies()
+ {
+ Debug.WriteLine("updating lobbies...");
+ 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();
+
+ foreach (Lobby l in lobbiesArr)
+ {
+ _lobbies.Add(l);
+ }
+
+ });
+ }
+
+ private void startGameInLobby()
+ {
+ if (SelectedLobby != null)
+ {
+ ClientData.Instance.Lobby = SelectedLobby;
+ startGameWindow();
+ }
+ }
+
+ private void startGameWindow()
+ {
+ _model.CanStartGame = false;
+ Application.Current.Dispatcher.Invoke(delegate
+ {
+ GameWindow window = new GameWindow();
+ window.Show();
+ });
+ }
+
+ private void ClickCheck()
+ {
+ if(!(_model.Status))
+ _model.Status = true;
+
+ _model.Numbers = _model.Numbers + 5;
+ }
+
+
+ private Model _model;
+ public Model Model
+ {
+ get
+ {
+ return _model;
+ }
+
+ set
+ {
+ _model = value;
+ }
+ }
+
+ private ObservableCollection _lobbies;
+ public ObservableCollection Lobbies
+ {
+ get { return _lobbies; }
+ set { _lobbies = value; }
+ }
+ }
+}
diff --git a/Client/ViewModels/ViewModelGame.cs b/Client/ViewModels/ViewModelGame.cs
new file mode 100644
index 0000000..65fd353
--- /dev/null
+++ b/Client/ViewModels/ViewModelGame.cs
@@ -0,0 +1,126 @@
+
+using Client.Views;
+using GalaSoft.MvvmLight.Command;
+using SharedClientServer;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Windows;
+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();
+
+ private dynamic _payload;
+
+ private string _username;
+
+ private 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()
+ {
+ if (_payload == null)
+ {
+ _message = "";
+
+ }
+ else
+ {
+ //_message = data.Message;
+ //_username = data.User.Username;
+ //Messages.Add($"{data.User.Username}: {Message}");
+ }
+ OnKeyDown = new RelayCommand(ChatBox_KeyDown);
+ }
+
+ 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));
+ }
+
+
+ }
+}
+
diff --git a/Client/Views/GameWindow.xaml b/Client/Views/GameWindow.xaml
new file mode 100644
index 0000000..6614197
--- /dev/null
+++ b/Client/Views/GameWindow.xaml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Client/Views/GameWindow.xaml.cs b/Client/Views/GameWindow.xaml.cs
new file mode 100644
index 0000000..9d90635
--- /dev/null
+++ b/Client/Views/GameWindow.xaml.cs
@@ -0,0 +1,62 @@
+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
+{
+ ///
+ /// Interaction logic for GameWindow.xaml
+ ///
+ public partial class GameWindow : Window
+ {
+ ClientData data = ClientData.Instance;
+ private ViewModelGame viewModel;
+ public GameWindow()
+ {
+ this.viewModel = new ViewModelGame();
+ DataContext = this.viewModel;
+ InitializeComponent();
+
+ }
+
+
+ private void CanvasForPaint_MouseDown(object sender, MouseButtonEventArgs e)
+ {
+ this.viewModel.Canvas_MouseDown(e, this);
+ }
+
+ private void CanvasForPaint_MouseMove(object sender, MouseEventArgs e)
+ {
+ viewModel.Canvas_MouseMove(e, this);
+ }
+
+ private void CanvasReset_Click(object sender, RoutedEventArgs e)
+ {
+ CanvasForPaint.Children.Clear();
+
+ //FOR FUTURE USE, IF NECCESSARY
+ //TEST.Children.Clear();
+
+ //foreach (UIElement child in CanvasForPaint.Children)
+ //{
+ // var xaml = System.Windows.Markup.XamlWriter.Save(child);
+ // var deepCopy = System.Windows.Markup.XamlReader.Parse(xaml) as UIElement;
+ // TEST.Children.Add(deepCopy);
+ //}
+ }
+
+ private void ClrPcker_Background_SelectedColorChanged_1(object sender, RoutedPropertyChangedEventArgs e)
+ {
+ viewModel.Color_Picker(e, this);
+ }
+ }
+}
diff --git a/Client/Views/LoginScreen.xaml b/Client/Views/LoginScreen.xaml
new file mode 100644
index 0000000..e011780
--- /dev/null
+++ b/Client/Views/LoginScreen.xaml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Client/Views/LoginScreen.xaml.cs b/Client/Views/LoginScreen.xaml.cs
new file mode 100644
index 0000000..5b742d2
--- /dev/null
+++ b/Client/Views/LoginScreen.xaml.cs
@@ -0,0 +1,46 @@
+using SharedClientServer;
+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
+{
+ ///
+ /// Interaction logic for LoginScreen.xaml
+ ///
+ public partial class LoginScreen : Window
+ {
+ ClientData data = ClientData.Instance;
+ public LoginScreen()
+ {
+ InitializeComponent();
+ }
+
+ private void Button_EnterUsername(object sender, RoutedEventArgs e)
+ {
+ User user = new User(usernameTextbox.Text);
+ Client client = new Client(user.Username);
+ client.OnSuccessfullConnect = () =>
+ {
+ // because we need to start the main window on a UI thread, we need to let the dispatcher handle it, which will execute the code on the ui thread
+ Application.Current.Dispatcher.Invoke(delegate {
+ data.User = user;
+ data.Client = client;
+ client.SendMessage(JSONConvert.ConstructLobbyRequestMessage());
+ MainWindow startWindow = new MainWindow();
+ startWindow.Show();
+ this.Close();
+ });
+ };
+
+ }
+ }
+}
diff --git a/Client/Views/MainWindow.xaml b/Client/Views/MainWindow.xaml
new file mode 100644
index 0000000..c0db1de
--- /dev/null
+++ b/Client/Views/MainWindow.xaml
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Client/Views/MainWindow.xaml.cs b/Client/Views/MainWindow.xaml.cs
new file mode 100644
index 0000000..fbcf18a
--- /dev/null
+++ b/Client/Views/MainWindow.xaml.cs
@@ -0,0 +1,37 @@
+using Client.Views;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+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.Navigation;
+using System.Windows.Shapes;
+
+namespace Client
+{
+ ///
+ /// Interaction logic for MainWindow.xaml
+ ///
+ public partial class MainWindow : Window
+ {
+ ClientData data = ClientData.Instance;
+ public MainWindow()
+ {
+ this.DataContext = new ViewModel();
+ InitializeComponent();
+
+ usernameLabel.Content = data.User.Username;
+ }
+
+ private void Button_Click(object sender, RoutedEventArgs e)
+ {
+ }
+ }
+}
diff --git a/Eindproject/.idea/.idea.Eindproject/.idea/contentModel.xml b/Eindproject/.idea/.idea.Eindproject/.idea/contentModel.xml
new file mode 100644
index 0000000..c0c1781
--- /dev/null
+++ b/Eindproject/.idea/.idea.Eindproject/.idea/contentModel.xml
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Eindproject/.idea/.idea.Eindproject/.idea/indexLayout.xml b/Eindproject/.idea/.idea.Eindproject/.idea/indexLayout.xml
new file mode 100644
index 0000000..27ba142
--- /dev/null
+++ b/Eindproject/.idea/.idea.Eindproject/.idea/indexLayout.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Eindproject/.idea/.idea.Eindproject/.idea/workspace.xml b/Eindproject/.idea/.idea.Eindproject/.idea/workspace.xml
new file mode 100644
index 0000000..e5f7c09
--- /dev/null
+++ b/Eindproject/.idea/.idea.Eindproject/.idea/workspace.xml
@@ -0,0 +1,41 @@
+
+
+
+ ../Server/Server.csproj
+ ../Client/Client.csproj
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Eindproject/Eindproject.sln b/Eindproject/Eindproject.sln
index a84d6d9..4c7629c 100644
--- a/Eindproject/Eindproject.sln
+++ b/Eindproject/Eindproject.sln
@@ -3,18 +3,31 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30517.126
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Eindproject", "Eindproject.csproj", "{F9D948F4-BD6F-4E5A-B7D1-59C6AA04B308}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "..\Server\Server.csproj", "{67A9BF1A-D317-47CA-9F07-C3480D1360FF}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client", "..\Client\Client.csproj", "{83768EDB-097E-4089-A5DE-208CB252D1A0}"
+EndProject
+Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "SharedClientServer", "..\SharedClientServer\SharedClientServer.shproj", "{6D26F969-9CB1-414F-AC3E-7253D449AC5A}"
EndProject
Global
+ GlobalSection(SharedMSBuildProjectFiles) = preSolution
+ ..\SharedClientServer\SharedClientServer.projitems*{67a9bf1a-d317-47ca-9f07-c3480d1360ff}*SharedItemsImports = 5
+ ..\SharedClientServer\SharedClientServer.projitems*{6d26f969-9cb1-414f-ac3e-7253d449ac5a}*SharedItemsImports = 13
+ ..\SharedClientServer\SharedClientServer.projitems*{83768edb-097e-4089-a5de-208cb252d1a0}*SharedItemsImports = 5
+ EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {F9D948F4-BD6F-4E5A-B7D1-59C6AA04B308}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {F9D948F4-BD6F-4E5A-B7D1-59C6AA04B308}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {F9D948F4-BD6F-4E5A-B7D1-59C6AA04B308}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {F9D948F4-BD6F-4E5A-B7D1-59C6AA04B308}.Release|Any CPU.Build.0 = Release|Any CPU
+ {67A9BF1A-D317-47CA-9F07-C3480D1360FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {67A9BF1A-D317-47CA-9F07-C3480D1360FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {67A9BF1A-D317-47CA-9F07-C3480D1360FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {67A9BF1A-D317-47CA-9F07-C3480D1360FF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {83768EDB-097E-4089-A5DE-208CB252D1A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {83768EDB-097E-4089-A5DE-208CB252D1A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {83768EDB-097E-4089-A5DE-208CB252D1A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {83768EDB-097E-4089-A5DE-208CB252D1A0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Server/App.xaml b/Server/App.xaml
new file mode 100644
index 0000000..8ef660c
--- /dev/null
+++ b/Server/App.xaml
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/Server/App.xaml.cs b/Server/App.xaml.cs
new file mode 100644
index 0000000..008245b
--- /dev/null
+++ b/Server/App.xaml.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace Server
+{
+ ///
+ /// Interaction logic for App.xaml
+ ///
+ public partial class App : Application
+ {
+
+ }
+}
diff --git a/Server/AssemblyInfo.cs b/Server/AssemblyInfo.cs
new file mode 100644
index 0000000..8b5504e
--- /dev/null
+++ b/Server/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+using System.Windows;
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
diff --git a/Server/FodyWeavers.xml b/Server/FodyWeavers.xml
new file mode 100644
index 0000000..d5abfed
--- /dev/null
+++ b/Server/FodyWeavers.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/Server/FodyWeavers.xsd b/Server/FodyWeavers.xsd
new file mode 100644
index 0000000..69dbe48
--- /dev/null
+++ b/Server/FodyWeavers.xsd
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+ Used to control if the On_PropertyName_Changed feature is enabled.
+
+
+
+
+ Used to control if the Dependent properties feature is enabled.
+
+
+
+
+ Used to control if the IsChanged property feature is enabled.
+
+
+
+
+ Used to change the name of the method that fires the notify event. This is a string that accepts multiple values in a comma separated form.
+
+
+
+
+ Used to control if equality checks should be inserted. If false, equality checking will be disabled for the project.
+
+
+
+
+ Used to control if equality checks should use the Equals method resolved from the base class.
+
+
+
+
+ Used to control if equality checks should use the static Equals method resolved from the base class.
+
+
+
+
+ Used to turn off build warnings from this weaver.
+
+
+
+
+ Used to turn off build warnings about mismatched On_PropertyName_Changed methods.
+
+
+
+
+
+
+
+ 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
+
+
+
+
+ A comma-separated list of error codes that can be safely ignored in assembly verification.
+
+
+
+
+ 'false' to turn off automatic generation of the XML Schema file.
+
+
+
+
+
\ No newline at end of file
diff --git a/Server/Models/Information.cs b/Server/Models/Information.cs
new file mode 100644
index 0000000..eb2b690
--- /dev/null
+++ b/Server/Models/Information.cs
@@ -0,0 +1,22 @@
+using SharedClientServer;
+
+namespace Server.Models
+{
+ public class Information : ObservableObject
+ {
+
+ public bool CanStartServer { get; set; }
+ public bool ServerOnline { get; set; }
+
+ public string ServerStatus
+ {
+ get
+ {
+ if (ServerOnline) return "Online";
+ return "Offline";
+ }
+ }
+
+ public int ClientsConnected{ get; set; }
+ }
+}
\ No newline at end of file
diff --git a/Server/Models/ServerClient.cs b/Server/Models/ServerClient.cs
new file mode 100644
index 0000000..90eab73
--- /dev/null
+++ b/Server/Models/ServerClient.cs
@@ -0,0 +1,192 @@
+
+
+using Client;
+using Newtonsoft.Json.Linq;
+using SharedClientServer;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Net.Sockets;
+using System.Text;
+using static SharedClientServer.JSONConvert;
+
+namespace Server.Models
+{
+ class ServerClient : ObservableObject
+ {
+ private TcpClient tcpClient;
+ private NetworkStream stream;
+ private byte[] buffer = new byte[1024];
+ private byte[] totalBuffer = new byte[1024];
+ private int totalBufferReceived = 0;
+ public User User { get; set; }
+ private ServerCommunication serverCom = ServerCommunication.INSTANCE;
+
+
+ ///
+ /// Constructor that creates a new serverclient object with the given tcp client.
+ ///
+ /// the TcpClient object to use
+ public ServerClient(TcpClient client)
+ {
+ Debug.WriteLine("[SERVERCLIENT] making new instance and starting");
+ tcpClient = client;
+ stream = tcpClient.GetStream();
+ Debug.WriteLine("[SERVERCLIENT] starting read");
+ stream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(OnRead), null);
+ }
+
+ ///
+ /// callback method that gets called when the stream has finished reading a message from the stream.
+ ///
+ /// the async result status
+ private void OnRead(IAsyncResult ar)
+ {
+ if (ar == null || (!ar.IsCompleted) || (!this.stream.CanRead) || !this.tcpClient.Client.Connected)
+ return;
+
+
+ int bytesReceived = this.stream.EndRead(ar);
+
+ if (totalBufferReceived + bytesReceived > 1024)
+ {
+ 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);
+
+
+ }
+
+ ///
+ /// Method to handle incoming message data
+ ///
+ /// the incoming message
+ private void HandleIncomingMessage(byte[] message)
+ {
+ 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);
+ Debug.WriteLine("[SERVERCLIENT] GOT STRING" + Encoding.ASCII.GetString(payload));
+ 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:
+ // json message data
+ (string, string) combo = JSONConvert.GetUsernameAndMessage(payload);
+ string textUsername = combo.Item1;
+ string textMsg = combo.Item2;
+
+ Debug.WriteLine("[SERVERCLIENT] User name: {0}\t User message: {1}", textUsername, 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!");
+ break;
+
+ case JSONConvert.LOBBY:
+ // lobby data
+ LobbyIdentifier l = JSONConvert.GetLobbyIdentifier(payload);
+ handleLobbyMessage(payload,l);
+ break;
+ case JSONConvert.CANVAS:
+ Debug.WriteLine("GOT A MESSAGE FROM THE CLIENT ABOUT THE CANVAS!!!");
+ // canvas data
+ // todo send canvas data to all other serverclients in lobby
+ break;
+ default:
+ Debug.WriteLine("[SERVER] Received weird identifier: " + id);
+ break;
+ }
+ }
+
+ private void handleLobbyMessage(byte[] payload, LobbyIdentifier l)
+ {
+ switch (l)
+ {
+ case LobbyIdentifier.REQUEST:
+ Debug.WriteLine("[SERVERCLIENT] got lobby request message, sending lobbies...");
+ sendMessage(JSONConvert.ConstructLobbyListMessage(ServerCommunication.INSTANCE.lobbies.ToArray()));
+ break;
+ case LobbyIdentifier.HOST:
+ // add new lobby and add this serverclient to it
+ int createdLobbyID = ServerCommunication.INSTANCE.HostForLobby(this.User);
+ Debug.WriteLine("[SERVERCLIENT] created lobby");
+ sendMessage(JSONConvert.ConstructLobbyHostCreatedMessage(createdLobbyID));
+ ServerCommunication.INSTANCE.sendToAll(JSONConvert.ConstructLobbyListMessage(ServerCommunication.INSTANCE.lobbies.ToArray()));
+ break;
+ case LobbyIdentifier.JOIN:
+ int id = JSONConvert.GetLobbyID(payload);
+ ServerCommunication.INSTANCE.JoinLobby(this.User,id);
+ sendMessage(JSONConvert.ConstructLobbyJoinSuccessMessage());
+ ServerCommunication.INSTANCE.sendToAll(JSONConvert.ConstructLobbyListMessage(ServerCommunication.INSTANCE.lobbies.ToArray()));
+ break;
+ }
+ }
+
+ ///
+ /// sends a message to the tcp client
+ ///
+ /// message to send
+ public void sendMessage(byte[] message)
+ {
+ // start writing the message from the start and until it is empty. When we are done we want to execute the OnWrite method.
+ stream.BeginWrite(message, 0, message.Length, new AsyncCallback(OnWrite), null);
+ }
+
+ ///
+ /// callback method that gets called when the stream has finished writing the message
+ ///
+ /// the async result status
+ private void OnWrite(IAsyncResult ar)
+ {
+ // end writing
+ stream.EndWrite(ar);
+ }
+ }
+}
diff --git a/Server/Models/ServerCommunication.cs b/Server/Models/ServerCommunication.cs
new file mode 100644
index 0000000..497f901
--- /dev/null
+++ b/Server/Models/ServerCommunication.cs
@@ -0,0 +1,187 @@
+using Client;
+using SharedClientServer;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+
+namespace Server.Models
+{
+ class ServerCommunication : ObservableObject
+ {
+ private TcpListener listener;
+ private List serverClients;
+ public bool Started = false;
+ public List lobbies;
+ private Dictionary> serverClientsInlobbies;
+ public Action newClientAction;
+
+
+ ///
+ /// use a padlock object to make sure the singleton is thread-safe
+ ///
+ private static readonly object padlock = new object();
+
+ private static ServerCommunication instance = null;
+ public int port = 5555;
+
+ private ServerCommunication()
+ {
+ listener = new TcpListener(IPAddress.Any, port);
+ serverClients = new List();
+ lobbies = new List();
+ Lobby temp = new Lobby(1, 7, 8);
+ lobbies.Add(temp);
+ serverClientsInlobbies = new Dictionary>();
+ serverClientsInlobbies.Add(temp, new List());
+ }
+
+ ///
+ /// returns the singleton serverCommunication instance
+ ///
+ public static ServerCommunication INSTANCE
+ {
+ get
+ {
+ lock (padlock)
+ {
+ if (instance == null) {
+ instance = new ServerCommunication();
+ }
+
+ }
+ return instance;
+ }
+ }
+
+ ///
+ /// start the server and start listening on port 5555 and begin acceptinc tcp clients
+ ///
+ public void Start()
+ {
+ listener.Start();
+ Debug.WriteLine($"================================================\nStarted Accepting clients at {DateTime.Now}\n================================================");
+ Started = true;
+ // when we have accepted a tcp client, call the onclientconnected callback method
+
+ listener.BeginAcceptTcpClient(new AsyncCallback(OnClientConnected), null);
+ }
+
+ ///
+ /// callback method that gets called when a client is accepted
+ ///
+ /// the result of the asynchronous connect call
+ private void OnClientConnected(IAsyncResult ar)
+ {
+ // stop the acceptation
+ var tcpClient = listener.EndAcceptTcpClient(ar);
+ Debug.WriteLine($"Got connection from {tcpClient.Client.RemoteEndPoint}");
+ newClientAction.Invoke();
+ // create a new serverclient object and add it to the list
+ serverClients.Add(new ServerClient(tcpClient));
+ //start listening for new tcp clients
+ listener.BeginAcceptTcpClient(new AsyncCallback(OnClientConnected), null);
+ }
+
+ ///
+ /// send a message to all tcp clients in the list
+ ///
+ /// the message to send
+ public void sendToAll(byte[] message)
+ {
+ foreach (ServerClient sc in serverClients)
+ {
+ sc.sendMessage(message);
+ }
+ }
+
+ public void SendToAllExcept(string username, byte[] message)
+ {
+ foreach (ServerClient sc in serverClients)
+ {
+ if (sc.User.Username != username) sc.sendMessage(message);
+ }
+ }
+
+ public void SendToLobby(Lobby lobby, byte[] message)
+ {
+ foreach (Lobby l in lobbies)
+ {
+ if (l == lobby)
+ {
+ foreach (ServerClient sc in serverClientsInlobbies[l])
+ {
+ sc.sendMessage(message);
+ }
+ break;
+ }
+ }
+ }
+
+ public Lobby GetLobbyForUser(User user)
+ {
+ foreach (Lobby l in lobbies)
+ {
+ if (l.Users.Contains(user))
+ {
+ return l;
+ }
+ }
+ return null;
+ }
+
+ public void AddToLobby(Lobby lobby, User user)
+ {
+ foreach (Lobby l in lobbies)
+ {
+ if (l == lobby)
+ {
+ bool succ;
+ l.AddUser(user, out succ);
+ Debug.WriteLine("[SERVERCOMM] added user to lobby, now contains " + l.PlayersIn);
+ if (!succ)
+ {
+ // TODO send lobby full message
+ } else
+ {
+ foreach(ServerClient sc in serverClients)
+ {
+ if (sc.User.Username == user.Username)
+ {
+ serverClientsInlobbies[l].Add(sc);
+ break;
+ }
+ }
+
+ }
+ break;
+ }
+ }
+ }
+
+ public int HostForLobby(User user)
+ {
+ Lobby lobby = new Lobby( lobbies.Count + 1,0, 8);
+ lobbies.Add(lobby);
+ serverClientsInlobbies.Add(lobby, new List());
+ user.Host = true;
+ AddToLobby(lobby, user);
+ return lobby.ID;
+ }
+
+ public void JoinLobby(User user, int id)
+ {
+ foreach (Lobby l in lobbies)
+ {
+ if (l.ID == id)
+ {
+ AddToLobby(l, user);
+ Debug.WriteLine($"{user.Username} joined lobby with id {id}");
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/Server/Server.csproj b/Server/Server.csproj
new file mode 100644
index 0000000..65a6e4e
--- /dev/null
+++ b/Server/Server.csproj
@@ -0,0 +1,19 @@
+
+
+
+ WinExe
+ netcoreapp3.1
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Server/ViewModels/MainViewModel.cs b/Server/ViewModels/MainViewModel.cs
new file mode 100644
index 0000000..ad06638
--- /dev/null
+++ b/Server/ViewModels/MainViewModel.cs
@@ -0,0 +1,53 @@
+using GalaSoft.MvvmLight.Command;
+using Server.Models;
+using SharedClientServer;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+
+namespace Server.ViewModels
+{
+ class MainViewModel : ObservableObject
+ {
+ public ServerCommunication serverCommunication { get; set; }
+ public ICommand ServerStartCommand { get; set; }
+ public Information InformationModel { get; set; }
+ private MainWindow mainWindow;
+
+ public MainViewModel(MainWindow mainWindow)
+ {
+ serverCommunication = ServerCommunication.INSTANCE;
+ this.mainWindow = mainWindow;
+ Debug.WriteLine("init mainviewmodel");
+ InformationModel = new Information();
+ InformationModel.CanStartServer = true;
+ InformationModel.ServerOnline = false;
+ InformationModel.ClientsConnected = 0;
+ serverCommunication.newClientAction = () =>
+ {
+ InformationModel.ClientsConnected++;
+ };
+ //BitmapImage onlineImg = new BitmapImage(new Uri(@"/img/online.png",UriKind.Relative));
+ //BitmapImage offlineImg = new BitmapImage(new Uri(@"/img/offline.png", UriKind.Relative));
+
+ this.ServerStartCommand = new RelayCommand(() =>
+ {
+ Debug.WriteLine("connect button clicked");
+
+ if (!serverCommunication.Started)
+ {
+ serverCommunication.Start();
+ InformationModel.ServerOnline = true;
+ InformationModel.CanStartServer = false;
+ }
+ });
+ }
+ }
+}
+
diff --git a/Server/Views/MainWindow.xaml b/Server/Views/MainWindow.xaml
new file mode 100644
index 0000000..5ff94af
--- /dev/null
+++ b/Server/Views/MainWindow.xaml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Server/Views/MainWindow.xaml.cs b/Server/Views/MainWindow.xaml.cs
new file mode 100644
index 0000000..d9b8ac7
--- /dev/null
+++ b/Server/Views/MainWindow.xaml.cs
@@ -0,0 +1,35 @@
+using Server.ViewModels;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+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.Navigation;
+using System.Windows.Shapes;
+
+namespace Server
+{
+ ///
+ /// Interaction logic for MainWindow.xaml
+ ///
+ public partial class MainWindow : Window
+ {
+
+ public MainWindow()
+ {
+
+ // use mainviewmodel for the bindings of our methods
+ DataContext = new MainViewModel(this);
+ InitializeComponent();
+
+ }
+ }
+}
diff --git a/Server/img/offline.png b/Server/img/offline.png
new file mode 100644
index 0000000..be764b2
Binary files /dev/null and b/Server/img/offline.png differ
diff --git a/Server/img/online.png b/Server/img/online.png
new file mode 100644
index 0000000..63b8395
Binary files /dev/null and b/Server/img/online.png differ
diff --git a/SharedClientServer/ClientServerUtil.cs b/SharedClientServer/ClientServerUtil.cs
new file mode 100644
index 0000000..d9d30fe
--- /dev/null
+++ b/SharedClientServer/ClientServerUtil.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net.Sockets;
+using System.Text;
+
+namespace SharedClientServer
+{
+ public delegate void Callback();
+ class ClientServerUtil
+ {
+ // creates a message array to send to the server or to clients
+ public byte[] createPayload(byte id, string payload)
+ {
+ byte[] stringAsBytes = Encoding.ASCII.GetBytes(payload);
+ byte[] res = new byte[stringAsBytes.Length + 1];
+ res[0] = id;
+ Array.Copy(stringAsBytes, 0, res, 1, stringAsBytes.Length);
+ return res;
+ }
+ }
+}
diff --git a/SharedClientServer/JSONConvert.cs b/SharedClientServer/JSONConvert.cs
new file mode 100644
index 0000000..dd967e8
--- /dev/null
+++ b/SharedClientServer/JSONConvert.cs
@@ -0,0 +1,166 @@
+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 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
+
+ ///
+ /// 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/Lobby.cs b/SharedClientServer/Lobby.cs
new file mode 100644
index 0000000..2ddf501
--- /dev/null
+++ b/SharedClientServer/Lobby.cs
@@ -0,0 +1,92 @@
+using SharedClientServer;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Text;
+
+namespace Client
+{
+ class Lobby : INotifyPropertyChanged
+ {
+ public event PropertyChangedEventHandler PropertyChanged;
+
+
+ private int _id;
+ private int _playersIn;
+ private int _maxPlayers;
+ //private List _usernames;
+ private List _users;
+
+ //public void AddUsername(string username, out bool success)
+ //{
+ // success = false;
+ // if (_usernames.Count < _maxPlayers)
+ // {
+ // _usernames.Add(username);
+ // success = true;
+ // }
+ //}
+
+ public Lobby(int id, int playersIn, int maxPlayers)
+ {
+ _id = id;
+ _playersIn = playersIn;
+ _maxPlayers = maxPlayers;
+ //_usernames = new List();
+ _users = new List();
+ }
+
+ public void AddUser(string username, out bool succes)
+ {
+ succes = false;
+ if (_users.Count < _maxPlayers)
+ {
+ _users.Add(new User(username, 0, false));
+ succes = true;
+ }
+ }
+
+ public void AddUser(User user, out bool succes)
+ {
+ succes = false;
+ if (_users.Count < _maxPlayers)
+ {
+ _users.Add(user);
+ succes = true;
+ }
+ }
+
+ public int ID
+ {
+ get { return _id; }
+ set { _id = value; }
+ }
+
+ public int PlayersIn
+ {
+ get { return _users.Count; }
+ set { _playersIn = value; }
+ }
+
+ public void Set(Lobby lobby)
+ {
+ this._id = lobby._id;
+ this._users = lobby._users;
+ this._maxPlayers = lobby._maxPlayers;
+ }
+
+ public int MaxPlayers
+ {
+ get { return _maxPlayers; }
+ set { _maxPlayers = value; }
+ }
+
+ public List Users
+ {
+ get { return _users; }
+ set { _users = value; }
+ }
+
+
+ }
+}
diff --git a/SharedClientServer/ObservableObject.cs b/SharedClientServer/ObservableObject.cs
new file mode 100644
index 0000000..032dfcd
--- /dev/null
+++ b/SharedClientServer/ObservableObject.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Text;
+
+namespace SharedClientServer
+{
+ public abstract class ObservableObject : INotifyPropertyChanged
+ {
+ public event PropertyChangedEventHandler PropertyChanged;
+ }
+}
diff --git a/SharedClientServer/SharedClientServer.projitems b/SharedClientServer/SharedClientServer.projitems
new file mode 100644
index 0000000..74ca621
--- /dev/null
+++ b/SharedClientServer/SharedClientServer.projitems
@@ -0,0 +1,18 @@
+
+
+
+ $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
+ true
+ 6d26f969-9cb1-414f-ac3e-7253d449ac5a
+
+
+ SharedClientServer
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/SharedClientServer/SharedClientServer.shproj b/SharedClientServer/SharedClientServer.shproj
new file mode 100644
index 0000000..68327bb
--- /dev/null
+++ b/SharedClientServer/SharedClientServer.shproj
@@ -0,0 +1,13 @@
+
+
+
+ 6d26f969-9cb1-414f-ac3e-7253d449ac5a
+ 14.0
+
+
+
+
+
+
+
+
diff --git a/SharedClientServer/User.cs b/SharedClientServer/User.cs
new file mode 100644
index 0000000..e504418
--- /dev/null
+++ b/SharedClientServer/User.cs
@@ -0,0 +1,48 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace SharedClientServer
+{
+ class User
+ {
+ private string _username;
+ private int _score;
+ private bool _host;
+ private string _message;
+
+ [JsonConstructor]
+ public User(string username, int score, bool host)
+ {
+ _username = username;
+ _score = score;
+ _host = host;
+ }
+
+ public User(string username)
+ {
+ _username = username;
+ _score = 0;
+ _host = false;
+ }
+
+ public string Username
+ {
+ get { return _username; }
+ set { _username = value; }
+ }
+
+ public int Score
+ {
+ get { return _score; }
+ set { _score = value; }
+ }
+
+ public bool Host
+ {
+ get { return _host; }
+ set { _host = value; }
+ }
+ }
+}