From ac2abffa89f3438abc9f24c2d6853f73e6282408 Mon Sep 17 00:00:00 2001 From: sili98 <sili98@sch.bme.hu> Date: Sat, 16 Nov 2019 02:47:31 +0100 Subject: [PATCH] Some networking. More backend stuff. --- zsirozas/Form1.cs | 3 +- zsirozas/Game.cs | 5 +- zsirozas/GameClient.cs | 164 +++++++++++++++++++++++++-- zsirozas/Server.cs | 246 ++++++++++++++++++++++++++++++----------- 4 files changed, 346 insertions(+), 72 deletions(-) diff --git a/zsirozas/Form1.cs b/zsirozas/Form1.cs index 091438b..0a73a6d 100644 --- a/zsirozas/Form1.cs +++ b/zsirozas/Form1.cs @@ -16,6 +16,7 @@ namespace zsirozas { InitializeComponent(); CardButtons = new Button[] { buttonCard0, buttonCard1, buttonCard2, buttonCard3 }; + client = new GameClient(); } private void buttonEndTurn_Click(object sender, EventArgs e) @@ -52,7 +53,7 @@ namespace zsirozas int port_num; if (int.TryParse(textBoxServerPort.Text, out port_num)) { - if (GameClient.pingServer(textBoxServerAddr.Text,port_num)) + if (client.pingServer(textBoxServerAddr.Text,port_num)) { buttonServerTest.BackColor = Color.Green; } diff --git a/zsirozas/Game.cs b/zsirozas/Game.cs index 1bfce69..5b8e746 100644 --- a/zsirozas/Game.cs +++ b/zsirozas/Game.cs @@ -15,7 +15,8 @@ namespace zsirozas public void NotifyPlayers(GameEvent @event) { - string message = @event.ToString(); + string prefix = ServerAction.GameAction.ToString() + "\n"; + string message = prefix + @event.ToString(); switch (@event) { case GameEvent.CardAction: @@ -172,6 +173,8 @@ namespace zsirozas Complain("Objection! It's not a valid request!"); break; } + //TODO: ezt majd vagyük ki... + return null; } public void Complain(string message) { diff --git a/zsirozas/GameClient.cs b/zsirozas/GameClient.cs index cd3adc8..d91baf7 100644 --- a/zsirozas/GameClient.cs +++ b/zsirozas/GameClient.cs @@ -1,4 +1,8 @@ using System; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Threading; using System.Web.Script.Serialization; namespace zsirozas @@ -13,19 +17,53 @@ namespace zsirozas //connectivity stuff // - public static bool pingServer(string IP, int port) + public bool pingServer(string IP, int port) { - throw new NotImplementedException(); + try + { + var tempConn = new TcpClient(); + tempConn.Connect(IPAddress.Parse(IP), port); + using (var sw = new StreamWriter(tempConn.GetStream())) + using (var sr = new StreamReader(tempConn.GetStream())) + { + sw.WriteLine(ServerAction.Ping); + if (sr.ReadLine() != "OK") + { + return false; + } + } + return true; + } + catch (Exception ex) + { + return false; + } } - public static string[] searchLAN() + public IPEndPoint[] searchLAN() { + //this is an extendned feature not yet available throw new NotSupportedException(); } public bool Connect(string server_ip, int server_port) { - //TODO: connect + if (pingServer(server_ip, server_port)) + { + server = new IPEndPoint(IPAddress.Parse(server_ip), server_port); + try + { + incomingListener.Start(); + if (SendRequest(ServerAction.Login, 6501 + "")) + { + messageStream = incomingListener.AcceptTcpClient().GetStream(); + new Thread(ListenForServer).Start(); + return true; + } + } + catch (Exception ex) { } + } + return false; } @@ -35,6 +73,119 @@ namespace zsirozas public event EventHandler<string> handleServerError; + public IPEndPoint server; + public string userID; + public string roomID; + public string gameID; + public int playerIDX; + + TcpListener incomingListener = new TcpListener(IPAddress.Any, 6501); + Stream messageStream = null; + + public bool SendRequest(ServerAction action, string @params = null) + { + var tempConn = new TcpClient(); + tempConn.Connect(server); + using (var sw = new StreamWriter(tempConn.GetStream())) + using (var sr = new StreamReader(tempConn.GetStream())) + { + sw.WriteLine(); + string status = null; + sw.WriteLine(action); + switch (action) + { + case ServerAction.CreateRoom: + sw.WriteLine(userID); + if ((status = sr.ReadLine()) != "OK") + { + handleServerError(this, status); + return false; + } + else + { + roomID = sr.ReadLine(); + } + break; + case ServerAction.JoinRoom: + sw.WriteLine(userID); + sw.WriteLine(@params); + if ((status = sr.ReadLine()) != "OK") + { + handleServerError(this, status); + return false; + } + else + { + roomID = @params; + } + break; + case ServerAction.LeaveRoom: + sw.WriteLine(userID); + if ((status = sr.ReadLine()) != "OK") + { + handleServerError(this, status); + return false; + } + break; + case ServerAction.InviteUser: + break; + case ServerAction.GameAction: + sw.WriteLine(gameID); + sw.WriteLine(userID); + sw.WriteLine(@params); + //TODO: ez a getCards idegesítően fura... + if ((status = sr.ReadLine()) != "OK") + { + handleServerError(this, status); + return false; + } + else if (@params.Contains(PlayerAction.GetCards.ToString())) + { + Cards = new JavaScriptSerializer().Deserialize<Card[]>(sr.ReadLine()); + } + break; + case ServerAction.Logout: + sw.WriteLine(userID); + + break; + case ServerAction.Ping: + case ServerAction.Login: + case ServerAction.ListRooms: + default: + break; + } + } + tempConn.Close(); + return true; + } + + void ListenForServer() + { + + //var utruzr = new TcpClient(); + ////-------stolen code----------- + //// Create a TCP/IP socket. + //Socket listener = new Socket(SocketType.Stream, ProtocolType.Tcp); + + //// Bind the socket to the local endpoint and + //// listen for incoming connections. + //IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 1221); + //listener.Bind(localEndPoint); + //listener.Listen(10); + + //// Start listening for connections. + + //Console.WriteLine("Waiting for a connection..."); + //// Program is suspended while waiting for an incoming connection. + //Socket handler = listener.Accept(); + ////-----stuff happens + //handler.Shutdown(SocketShutdown.Both); + //handler.Close(); + + ////------end stolen code----------- + //ParseNextMessage(utruzr.GetStream()); + + } // @@ -56,13 +207,12 @@ namespace zsirozas public bool UseCard(int card_num) { - throw new NotImplementedException(); - + return SendRequest(ServerAction.GameAction, PlayerAction.Card + "\n" + Cards[card_num].ID); } public bool EndTurn() { - throw new NotImplementedException(); + return SendRequest(ServerAction.GameAction, PlayerAction.EndTurn.ToString()); } public Game.MidGameState gameState; diff --git a/zsirozas/Server.cs b/zsirozas/Server.cs index 8832f58..fc02a39 100644 --- a/zsirozas/Server.cs +++ b/zsirozas/Server.cs @@ -10,6 +10,12 @@ namespace zsirozas { public Server() { + Users = new List<string>(); + Rooms = new List<string>(); + Games = new List<string>(); + UsersByID = new Dictionary<string, User>(); + RoomsByID = new Dictionary<string, Room>(); + GamesByID = new Dictionary<string, Game>(); } public List<string> Users; public Dictionary<string, User> UsersByID; @@ -17,72 +23,115 @@ namespace zsirozas public List<string> Games; public Dictionary<string, Game> GamesByID; + public List<string> Rooms; public Dictionary<string, Room> RoomsByID; + public int ListenPort = 6500; public void Loop() { - var utruzr = new TcpClient(); - //-------stolen code----------- - // Create a TCP/IP socket. - Socket listener = new Socket(SocketType.Stream, ProtocolType.Tcp); - - // Bind the socket to the local endpoint and - // listen for incoming connections. - IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 1221); - listener.Bind(localEndPoint); - listener.Listen(10); - - // Start listening for connections. - - Console.WriteLine("Waiting for a connection..."); - // Program is suspended while waiting for an incoming connection. - Socket handler = listener.Accept(); - //-----stuff happens - handler.Shutdown(SocketShutdown.Both); - handler.Close(); - - //------end stolen code----------- - ParseNextMessage(utruzr.GetStream()); + if (bigRoom) + { + string Room0 = "RoomZero"; + Rooms.Add(Room0); + RoomsByID.Add( + Room0, + new Room() + { + roomID = Room0, + userList = new List<string>() + } + ); + } + var requestQueue = new TcpListener(IPAddress.Any, ListenPort); + while (true) + { + var clientRequest = requestQueue.AcceptTcpClient(); + ParseNextMessage(clientRequest.GetStream(), ((IPEndPoint)clientRequest.Client.RemoteEndPoint).Address); + clientRequest.Close(); + } } - public void ParseNextMessage(Stream s) + public void ParseNextMessage(Stream s, object param) { //TODO: eztet rendesen - var sr = new StreamReader(s); - - string line = ""; - while (line == "") + using (var sr = new StreamReader(s)) + using (var sw = new StreamWriter(s)) { - line = sr.ReadLine(); - } - var action = (ServerAction)Enum.Parse(typeof(ServerAction), line); - - switch (action) - { - case ServerAction.GameAction: - //a k9vetkező sor a gameID + string line = ""; + while (line == "") + { line = sr.ReadLine(); - if (Games.Contains(line)) - { - //TODO: GamesByID[line].Action(... - } - break; - case ServerAction.Ping: - case ServerAction.ListRooms: - case ServerAction.Login: - case ServerAction.Logout: - case ServerAction.CreateRoom: - case ServerAction.LeaveRoom: - case ServerAction.JoinRoom: - case ServerAction.InviteUser: - default: - break; + } + + var action = (ServerAction)Enum.Parse(typeof(ServerAction), line); + + switch (action) + { + case ServerAction.GameAction: + //a következő sor a gameID + line = sr.ReadLine(); + if (Games.Contains(line)) + { + //TODO: validálni? vagy kivételt elkapni? + GamesByID[line].Action( + //playerID + sr.ReadLine(), + //action + (PlayerAction)Enum.Parse(typeof(PlayerAction), sr.ReadLine()), + //cardID, nem hagyható el (de nem mindig értelmes) + int.Parse(sr.ReadLine()) + ); + } + break; + case ServerAction.Ping: + //TODO: egyéb ellenőrzés ping során? + sw.WriteLine("OK"); + break; + case ServerAction.ListRooms: + //TODO: szobákat kilistázni + throw new NotImplementedException(); + case ServerAction.Login: + line = sr.ReadLine(); + //TODO: validálni! + string ID = CreateUser(line, (IPAddress)param, int.Parse(sr.ReadLine())); + sw.WriteLine("OK"); + sw.WriteLine(ID); + break; + case ServerAction.Logout: + line = sr.ReadLine(); + RemoveUser(line); + sw.WriteLine("OK"); + break; + case ServerAction.CreateRoom: + line = sr.ReadLine(); + string newroom = CreateRoom(line); + sw.WriteLine("OK"); + sw.WriteLine(newroom); + break; + case ServerAction.LeaveRoom: + line = sr.ReadLine(); + LeaveRoom(line); + sw.WriteLine("OK"); + break; + case ServerAction.JoinRoom: + line = sr.ReadLine(); + JoinRoom(line, sr.ReadLine()); + sw.WriteLine("OK"); + break; + case ServerAction.InviteUser: + //nem része az alapnak + throw new NotSupportedException(); + default: + break; + } } + + } - public void MessageUser(string userID, ServerAction action, string message) { } + // public void MessageUser(string userID, ServerAction action, string message) { } //different kinds of actions /// <summary> @@ -90,35 +139,106 @@ namespace zsirozas /// </summary> public string CreateRoom(string userID) { + //TODO: validálni! var r = new Room(); r.roomID = userID + "~" + (DateTime.Now.TimeOfDay.TotalSeconds).ToString(); r.userList = new List<string>() { userID }; RoomsByID.Add(r.roomID, r); - //TODO: egyéb teendők + Rooms.Add(r.roomID); + UsersByID[userID].roomID = r.roomID; return r.roomID; } + //TODO: ezt majd vissza hamisra + /// <summary> + /// If this is set, everyone on the server will belong to the same big room. + /// If you cant start a game with that many players, you might need some of them to log out. + /// </summary> + public bool bigRoom = true; + + public string CreateUser(string nickname, IPAddress IP, int port) + { + var U = new User(); + + //making sure the userID is unique + U.userID = nickname + (DateTime.Now.TimeOfDay.Milliseconds).ToString(); + + //filling in the data + U.nickname = nickname; + UsersByID.Add(U.userID, U); + Users.Add(U.userID); + if (bigRoom) + { + JoinRoom(U.userID, Rooms[0]); + } + + //estabilishing server-to-client link + U.msgConn = new TcpClient(); + U.msgConn.Connect(IP, port); + U.messageStreamW = new StreamWriter(U.msgConn.GetStream()); + return U.userID; + } + + public void RemoveUser(string userID) + { + LeaveRoom(userID); + UsersByID[userID].SendMessage("Logout"); + UsersByID[userID].messageStreamW.Close(); + UsersByID[userID].msgConn.Close(); + UsersByID.Remove(userID); + Users.Remove(userID); + } + public void LeaveRoom(string userID) + { + if (UsersByID[userID].roomID != null) + { + //TODO: validálni ezt a mindent + RoomsByID[UsersByID[userID].roomID].userList.Remove(userID); + } + } + public void JoinRoom(string userID, string roomID) + { + if (UsersByID[userID].roomID == null) + { + if (Rooms.Contains(roomID)) + { + UsersByID[userID].roomID = roomID; + RoomsByID[roomID].userList.Add(userID); + //TODO: akarok-e erről üzenni? + } + else throw new NotImplementedException(); + } + else throw new NotImplementedException(); + } + public string NewGame(string roomID) + { + var G = new Game(this, RoomsByID[roomID].userList); + string gameID = "G~" + roomID; + GamesByID.Add(gameID, G); + Games.Add(gameID); + return gameID; + //TODO: üzenetsorrend hogy történik? + } } enum ServerAction { - GameAction, Ping, ListRooms, Login, Logout, CreateRoom, LeaveRoom, JoinRoom, InviteUser + GameAction, StartGame, Ping, ListRooms, Login, Logout, CreateRoom, LeaveRoom, JoinRoom, InviteUser } - struct User + class User { - public string userID; public string nickname; - public bool occupied; - public int failedPings; - public System.Net.Sockets.Socket socket; - public IPEndPoint endPoint; - public void SendMessage(string message) + public string userID; + public string roomID; + public bool occupied = false; + + public TcpClient msgConn; + public StreamWriter messageStreamW; + public void SendMessage(string message) { - var client = new TcpClient(); - client.Connect(endPoint); - new StreamWriter(client.GetStream()).WriteLine(message); + messageStreamW.WriteLine(message); } } -- GitLab