/// <summary> /// This method parses the commands received and calls a method to deserialize them. /// </summary> /// <param name="ss">Socket state to process the data from</param> private static void ProcessData(SocketState ss) { //Splits the string but keeps the '\n' characters string totalData = ss.GetData(); string[] parts = Regex.Split(totalData, @"(?<=[\n])"); lock (TheWorld) { string lastCommand = null; foreach (string p in parts) { //This is to ignore empty strings if (p.Length == 0) { continue; } //This is so it ignores the last string if it doesn't end in '\n' if (p[p.Length - 1] != '\n') { break; } lastCommand = p; ss.RemoveData(0, p.Length); } if (lastCommand != null) { //Calls a method to deserialize the data and then removes the data from the buffer UpdateObject(lastCommand, (int)ss.ID); } } }
/// <summary> /// Process any buffered messages separated by '\n' /// Then inform the view /// </summary> /// <param name="state"></param> private void ProcessMessages(SocketState state) { string totalData = state.GetData(); string[] parts = Regex.Split(totalData, @"(?<=[\n])"); // Loop until we have processed all messages. foreach (string p in parts) { // Ignore empty strings added by the regex splitter if (p.Length == 0) { continue; } // Ignore incomplete messages if (p[p.Length - 1] != '\n') { break; } // If the string contains text, try to parse it as json ParseMessage(p); // Then remove it from the SocketState's growable buffer state.RemoveData(0, p.Length); } }
/// <summary> /// Process any buffered messages separated by '\n' /// Display them, then remove them from the buffer. /// </summary> /// <param name="state"></param> private void ProcessMessages(SocketState state) { string totalData = state.GetData(); string[] parts = Regex.Split(totalData, @"(?<=[\n])"); // Loop until we have processed all messages. // We may have received more than one. foreach (string p in parts) { // Ignore empty strings added by the regex splitter if (p.Length == 0) { continue; } // The regex splitter will include the last string even if it doesn't end with a '\n', // So we need to ignore it if this happens. if (p[p.Length - 1] != '\n') { break; } // Display the message // "messages" is the big message text box in the form. // We must use a MethodInvoker, because only the thread // that created the GUI can modify it. this.Invoke(new MethodInvoker( () => messages.AppendText(p + Environment.NewLine))); // Then remove it from the SocketState's growable buffer state.RemoveData(0, p.Length); } }
/// <summary> /// Process any buffered messages separated by '\n' /// Display them, then remove them from the buffer. /// </summary> /// <param name="state"></param> private void ProcessMessages(SocketState state) { string totalData = state.GetData(); string[] parts = Regex.Split(totalData, @"(?<=[\n])"); // Loop until we have processed all messages. foreach (string p in parts) { // Ignore empty strings if (p.Length == 0) { continue; } // The regex splitter will include the last string even if it doesn't end with a '\n', // So we need to ignore it if this happens. if (p[p.Length - 1] != '\n') { break; } // Then remove it from the SocketState's growable buffer state.RemoveData(0, p.Length); //checks JSONstring and determines if its a tank, wall, proj, or powerup UpdateArrived(p); } //display the new inputs InputArrived(); }
/// <summary> /// Callback for ReceivePlayerName to handle incoming requests. /// Parses the JSON requests. This method uses the same logic as ClientSide handshake /// of Processing Messages, but instead of loading in objects we use the given information to /// update our tank with the ControlCommand. For incorrect commands that did not parse, we /// ignore the request. /// </summary> /// <param name="state"></param> private void HandleRequests(SocketState state) { if (state.ErrorOccured) { lock (serverWorld) { RemoveClient(state.ID); serverWorld.GetTank(state.ID).disconnected = true; return; } } lock (state) { string totalData = state.GetData(); string[] parts = Regex.Split(totalData, @"(?<=[\n])"); // Loop until we have processed all messages. foreach (string p in parts) { // Ignore empty strings added by the regex splitter if (p.Length == 0) { continue; } // Ignoring strings with no newline if (p[p.Length - 1] != '\n') { break; } // Skipping incomplete JSONS if (p[0] != '{' || !p.EndsWith("\n")) { continue; } // Process the command, update the tank w/ this client ID try { ControlCommand command = JsonConvert.DeserializeObject <ControlCommand>(p); serverWorld.SetMoveTank(command, state.ID); serverWorld.RotateTurret(command, state.ID); serverWorld.FireTurret(command, state.ID); } catch { /*command did not parse correctly; ignore*/ } //Remove data from the SocketState's growable buffer state.RemoveData(0, p.Length); } Networking.GetData(state); } }
/// <summary> /// Callback to receive player name. /// </summary> /// <param name="state"></param> private void ReceivePlayerName(SocketState state) { // If a Socket disconnects, return. if (state.ErrorOccured) { return; } // Add tank to the world if it doesnt exist yet if (!clients.ContainsKey(state.ID)) { lock (serverWorld) { serverWorld.AddTank(state.ID, state.GetData()); } } state.OnNetworkAction = HandleRequests; // Send start-up info; Lock the socket to avoid race conditions lock (state.TheSocket) { if (!clients.ContainsKey(state.ID)) { Networking.Send(state.TheSocket, $"{ state.ID }\n{ WORLD_SIZE }\n"); Networking.Send(state.TheSocket, serverWorld.GetWalls() + "\n"); } } // Add client to clients list lock (clients) { if (!clients.ContainsKey(state.ID)) { clients.Add(state.ID, state); Console.WriteLine($"Player({ state.ID }): { state.GetData().TrimEnd('\n') } Has Joined The Game!"); } } Networking.GetData(state); }
private static void HandleClientRequests(SocketState state) { if (state.ErrorOccurred) { return; } string[] request = state.GetData().Split(' ')[1].Substring(1).Split(':'); string command = request[0]; string[] args = request.Length == 2 ? request[1].Split(',') : new string[0]; Execute(state.Socket, command, args); }
private void HandleIDandWorldSize(SocketState state) { if (state.ErrorOccured) { // inform the view Error("Lost connection to server"); return; } string totalData = state.GetData(); string[] parts = Regex.Split(totalData, @"(?<=[\n])"); // Checks to ensure both the userID and the worldSize have been received if (parts.Length < 3) { Networking.GetData(state); return; } //Removes the used data from the buffer state.RemoveData(0, parts[0].Length + parts[1].Length); // try to parse the first message as the user's ID string id = parts[0]; if (!(Int32.TryParse(id, out userID))) { Error("First message sent be server was not the players ID"); return; } // try to parse the second message as the world size string size = parts[1]; int worldSize = -1; if (!(Int32.TryParse(size, out worldSize))) { worldSize = -1; Error("Failed to receive wallsize"); return; } //creates a new world world = new World(worldSize); world.AddAnimation += HandleAnimation; // prepares to handle the next messages as walls state.OnNetworkAction = HandleWalls; Networking.GetData(state); }
protected void OnNetworkAction(SocketState state) { if (state.ErrorOccurred) { OnDisconnected?.Invoke(this); return; } string data = state.GetData(); OnReceived?.Invoke(this, data); state.RemoveData(0, data.Length); Networking.GetData(state); }
/// <summary> /// This handles the HTTP request and makes the web page depending on the request /// </summary> /// <param name="ss">Socket state for the connection</param> public static void ServeHttpRequest(SocketState ss) { if (ss.ErrorOccured == true) { Console.WriteLine("Error occured while accepting: \"" + ss.ErrorMessage + "\""); return; } string request = ss.GetData(); Console.WriteLine(request); //Player request if (request.Contains("GET /games?player=")) { //Finds the player name with substring int start = request.IndexOf("=") + 1; int length = request.IndexOf(" HTTP/1.1") - start; string name = request.Substring(start, length); //Gets all of the players in the form of a dictionary Dictionary <uint, PlayerModel> playersDictionary = DatabaseController.GetAllPlayerGames(name); //Creates list of sessions that the player has been in by getting the game durations from the database List <SessionModel> SessionList = new List <SessionModel>(); foreach (KeyValuePair <uint, PlayerModel> player in playersDictionary) { SessionList.Add(new SessionModel(player.Key, DatabaseController.GetGameDuration(player.Key), player.Value.Score, player.Value.Accuracy)); } //Sends the list so it can be formatted into a table Networking.SendAndClose(ss.TheSocket, WebViews.GetPlayerGames(name, SessionList)); } //Games request else if (request.Contains("GET /games HTTP/1.1")) { //Creates a table with each of the games and all of their data Networking.SendAndClose(ss.TheSocket, WebViews.GetAllGames(DatabaseController.GetAllGames())); } //If there aren't any slashes it goes to the home page else if (request.Contains("GET / HTTP/1.1")) { Networking.SendAndClose(ss.TheSocket, WebViews.GetHomePage(0)); } //Otherwise it throws a 404 error else { Networking.SendAndClose(ss.TheSocket, WebViews.Get404()); } }
public void TestNoEventLoop(bool clientSide) { SetupTestConnections(clientSide, out testListener, out testLocalSocketState, out testRemoteSocketState, 2115); int calledCount = 0; // This OnNetworkAction will not ask for more data after receiving one message, // so it should only ever receive one message testLocalSocketState.OnNetworkAction = (x) => calledCount++; Networking.Send(testRemoteSocketState.TheSocket, "a"); Networking.GetData(testLocalSocketState); // Note that waiting for data like this is *NOT* how the networking library is // intended to be used. This is only for testing purposes. // Normally, you would provide an OnNetworkAction that handles the data. NetworkTestHelper.WaitForOrTimeout(() => testLocalSocketState.GetData().Length > 0, NetworkTestHelper.timeout); // Send a second message (which should not increment calledCount) Networking.Send(testRemoteSocketState.TheSocket, "a"); NetworkTestHelper.WaitForOrTimeout(() => false, NetworkTestHelper.timeout); Assert.AreEqual(1, calledCount); }
private static void ServeHttpRequest(SocketState state) { StringBuilder sb = new StringBuilder(); string data = state.GetData(); state.ClearData(); if (String.IsNullOrEmpty(data)) { Networking.GetData(state); return; } if (data.Contains("GET")) { Networking.SendAndClose(state.TheSocket, DatabaseModel.GetHomePage(0) + DatabaseModel.GetAllGames(DatabaseModel.GetGamesFromDB())); } }
private void HandleWalls(SocketState state) { if (state.ErrorOccured) { // inform the view Error("Lost connection to server"); return; } string totalData = state.GetData(); string[] parts = Regex.Split(totalData, @"(?<=[\n])"); // Add all wall json foreach (string s in parts) { if (s != "") { if (s[s.Length - 1] != '\n') { break; } JObject obj = JObject.Parse(s); JToken token; // if the json is a valid wall, set it if ((token = obj["wall"]) != null) { lock (world) { world.setWall(JsonConvert.DeserializeObject <Wall>(s)); } } // if all the walls have been sent and now a new object is sent (that is not a wall), the client can now send commands else { commandControl = new CommandControl(); AllowInput(); state.OnNetworkAction = ReceiveMessage; } } } Networking.GetData(state); }
/// <summary> /// Handles all client sent commands and updates their tank accordingly so that it can be processed on the next frame /// </summary> /// <param name="s"></param> private void HandleClientCommands(SocketState s) { // Handle errors if (s.ErrorOccured) { Console.WriteLine("Client: " + s.ID + " disconnected."); lock (world) { world.Players[(int)s.ID].disconnected = true; } return; } string data = s.GetData(); string[] parts = Regex.Split(data, @"(?<=[\n])"); // Try to deserialize messages as valid commands if (parts.Length > 2) { try { CommandControl cc = JsonConvert.DeserializeObject <CommandControl>(parts[parts.Length - 2]); // Remove all processed data for (int i = 0; i < parts.Length - 1; i++) { s.RemoveData(0, parts[i].Length); } // Update the client's command control object clients[s].commandControl = cc; } // Disconnect client if invalid commands are received catch { Console.WriteLine("Client: " + s.ID + " disconnected."); lock (world) { world.Players[(int)s.ID].disconnected = true; } return; } } // loop Networking.GetData(s); }
/// <summary> /// when data arrives from clients update the world /// </summary> /// <param name="state"></param> public void UpdateWorld(SocketState state) { string data = state.GetData(); string[] parts = Regex.Split(data, @"(?<=[\n])"); state.ClearData(); foreach (string p in parts) { if (p.Length == 0) { continue; } if (p[p.Length - 1] != '\n') { break; } UpdateArrived(p, state); } }
/// <summary> /// Callback method for after the server receives the name /// </summary> /// <param name="sock"></param> static void ReceiveName(SocketState sock) { //Create the players tank and assign its name and ID Tank mainPlayer = new Tank(); mainPlayer.name = sock.GetData().Trim(); mainPlayer.ID = (int)sock.ID; //Add the tank to both tank classes lock (tanks) { allTanksEver.Add(mainPlayer.ID, mainPlayer); tanks.Add(mainPlayer.ID, mainPlayer); } //Assign the health of the tank and spawn the tank mainPlayer.hitPoints = StartingHitPoints; tankRespawn(mainPlayer); //Change the callback to CommandRequestHandler and clear the sock's data sock.OnNetworkAction = CommandRequestHandler; sock.ClearData(); //Get the startup data, serialize it, and send it to the client string startupData = mainPlayer.ID + "\n" + serverWorld.worldSize + "\n"; foreach (Wall w in walls.Values) { startupData += JsonConvert.SerializeObject(w) + "\n"; } startupData += GetWorldData(); Networking.Send(sock.TheSocket, startupData); //Add the client to the connectedClients list and ask for more data lock (connectedClients) { connectedClients.Add(sock.ID, sock); } Console.WriteLine(mainPlayer.name + " has Joined the Game"); mainPlayer.joined = true; Networking.GetData(sock); }
// Helper to simualte "processing" a message by looking for a newline separator void ProcessMessage(SocketState state, StringBuilder clientReceived) { string[] objects = Regex.Split(state.GetData(), @"(?<=[\n])"); foreach (string obj in objects) { if (obj.Length == 0) { continue; } if (obj[obj.Length - 1] != '\n') { continue; } clientReceived.Append(obj); state.RemoveData(0, obj.Length); } }
/// <summary> /// Called when server sends all spreadsheet names. /// </summary> /// <param name="state"></param> private void ReceiveSpreadsheets(SocketState state) { if (state.ErrorOccured) { // inform the view Error?.Invoke(state.ErrorMessage, "Error Receiving Spreadsheets"); Disconnect(); return; } string data = state.GetData(); if (!data.EndsWith("\n\n")) { Networking.GetData(state); return; } string[] spreadSheetNames = data.Substring(0, data.Length - 2).Split('\n'); GetSpreadsheets?.Invoke(spreadSheetNames.Where(sheet => !string.IsNullOrEmpty(sheet)).ToArray()); }
public void GetData_SocketIsAlreadyClosedSoBeginReceiveWillFail_ShouldSetErrorSocketStateAndInvokeToCallDelegate(bool clientSide) { bool isCalled = false; int numTimesCalled = 0; void saveClientState(SocketState x) { isCalled = true; numTimesCalled++; testLocalSocketState = x; } testLocalSocketState = new SocketState(saveClientState, null); Networking.GetData(testLocalSocketState); NetworkTestHelper.WaitForOrTimeout(() => isCalled, NetworkTestHelper.timeout); Assert.AreEqual(1, numTimesCalled); Assert.IsTrue(testLocalSocketState.ErrorOccured); Assert.AreEqual("", testLocalSocketState.GetData()); }
/// <summary> /// Gets the player's name and sends startup info /// </summary> /// <param name="s"></param> private void HandlePlayerName(SocketState s) { string data = s.GetData(); string[] parts = Regex.Split(data, @"(?<=[\n])"); // Check if a full message has been received if (parts.Length > 1) { // Generate a new tank for the client Tank t = new Tank((int)s.ID, parts[0].Substring(0, parts[0].Length - 1), new TankWars.Vector2D(50, 50)); spawnTank(t); lock (world) { // Add the tank to the world world.setTankData(t); s.RemoveData(0, parts[0].Length); //Send the player's id Networking.Send(s.TheSocket, s.ID + "\n"); // Send world size Networking.Send(s.TheSocket, world.UniverseSize + "\n"); // Send all the walls foreach (Wall w in world.Walls.Values) { Networking.Send(s.TheSocket, JsonConvert.SerializeObject(w) + '\n'); } } // Add the tank to the dictionary so it can start receiving frames lock (clients) { clients.Add(s, t); } s.OnNetworkAction = HandleClientCommands; } Networking.GetData(s); }
/// <summary> /// Second callback method for after the server has made a connection /// </summary> /// <param name="state"></param> private static void ServeHttpRequest(SocketState state) { string request = state.GetData(); //If the request is for an individual player, create their table if (request.Contains("GET /games?player=")) { String playerNameRequest = request.Substring(21, request.IndexOf("\n") - 34); String dataToSend = mainDataControl.individualTableCreator(playerNameRequest); Networking.SendAndClose(state.TheSocket, dataToSend); } //If the request is for all games, generate all the tables else if (request.Contains("GET /games")) { String dataToSend = mainDataControl.allGamesTableCreator(); Networking.SendAndClose(state.TheSocket, dataToSend); } //If the request is for anything else, send them to the homepage else { Networking.SendAndClose(state.TheSocket, mainDataControl.sendToHomePage()); } }
public void SendAndClose_SendTinyMessage_ShouldPutDataInSocketStateAndCloseSocket(bool clientSide) { // assemble SetupTestConnections(clientSide, out testListener, out testLocalSocketState, out testRemoteSocketState); testLocalSocketState.OnNetworkAction = x => { }; testRemoteSocketState.OnNetworkAction = x => { }; bool sendWasSuccessful; // act sendWasSuccessful = Networking.SendAndClose(testLocalSocketState.TheSocket, "abc"); Networking.GetData(testRemoteSocketState); NetworkTestHelper.WaitForOrTimeout(() => testRemoteSocketState.GetData().Length > 0, NetworkTestHelper.timeout); // assert Assert.IsTrue(sendWasSuccessful); Assert.AreEqual("abc", testRemoteSocketState.GetData()); Assert.IsFalse(testLocalSocketState.TheSocket.Connected); }
public void TestReceiveTinyMessage(bool clientSide) { SetupTestConnections(clientSide); testLocalSocketState.OnNetworkAction = (x) => { }; Networking.Send(testRemoteSocketState.TheSocket, "a"); Networking.GetData(testLocalSocketState); WaitForOrTimeout(() => testLocalSocketState.GetData().Length > 0, timeout); Assert.AreEqual("a", testLocalSocketState.GetData()); }
/// <summary> /// Callback method for any commands the player sends to the controller /// </summary> /// <param name="sock">The socketstate the connection is on</param> static void CommandRequestHandler(SocketState sock) { Tank main; //If the tank is not currently connected, don't listen to any commands from that client if (tanks.ContainsKey((int)sock.ID)) { main = tanks[(int)sock.ID]; } else { return; } // Split the command by its \n's string[] commands = Regex.Split(sock.GetData(), @"(?<=[\n])"); if (commands.Length == 1) { return; } //Deserialize the command ControllerObject command = JsonConvert.DeserializeObject <ControllerObject>(commands[commands.Length - 2]); //If there is nothing in command then ignore it if (command == null) { return; } //If the tank is currently alive and has made it this far, listen to its commands if (main.hitPoints != 0) { //Process the fire status of the tank and either fire a projectile, beam, or do nothing switch (command.getFireStatus()) { case "none": break; case "main": if (main.shotTimer > 0) { break; } Projectile shot = new Projectile(); main.tankTotalShots++; shot.orientation = main.aiming; shot.location = main.location; shot.tankID = main.ID; shot.ID = shotCount; shotCount++; lock (projectiles) { projectiles.Add(shot.ID, shot); } main.shotTimer = FramesPerShot; break; case "alt": if (main.railgunShots > 0) { main.railgunShots--; Beam railBeam = new Beam(); main.tankTotalShots++; railBeam.direction = main.aiming; railBeam.origin = main.location; railBeam.tankID = main.ID; railBeam.ID = shotCount; lock (beams) { beams.Add(railBeam.ID, railBeam); } shotCount++; } break; } //Variables used to track where the tank will be after the command is implemented double tankLocAfterMoveY; double tankLocAfterMoveX; //Process the tank's move command and update it's location based on the button that was pressed switch (command.getMoveDirection()) { case "none": main.tankVelocity = new Vector2D(0, 0); break; case "up": main.tankVelocity = new Vector2D(0, -EngineStrength); tankLocAfterMoveY = main.location.GetY() + main.tankVelocity.GetY(); tankLocAfterMoveX = main.location.GetX() + main.tankVelocity.GetX(); //If the tank will hit a wall with this move, don't move it if (collisionCheck(tankLocAfterMoveX, tankLocAfterMoveY)) { main.tankVelocity = new Vector2D(0, 0); } //If the tank is at the edge of the world after this move, teleport it to the other side else if (tankLocAfterMoveY < -serverWorld.worldSize / 2) { tankLocAfterMoveY = serverWorld.worldSize / 2 - 5; main.location = new Vector2D(main.location.GetX(), tankLocAfterMoveY); main.orientation = new Vector2D(0, -1); } //If the tank won't hit a wall or the edge, move it else { main.location = main.location + main.tankVelocity; main.orientation = new Vector2D(0, -1); } break; case "down": main.tankVelocity = new Vector2D(0, EngineStrength); tankLocAfterMoveY = main.location.GetY() + main.tankVelocity.GetY(); tankLocAfterMoveX = main.location.GetX() + main.tankVelocity.GetX(); //If the tank will hit a wall with this move, don't move it if (collisionCheck(tankLocAfterMoveX, tankLocAfterMoveY)) { main.tankVelocity = new Vector2D(0, 0); } //If the tank is at the edge of the world after this move, teleport it to the other side else if (tankLocAfterMoveY > serverWorld.worldSize / 2) { tankLocAfterMoveY = -serverWorld.worldSize / 2 + 5; main.location = new Vector2D(main.location.GetX(), tankLocAfterMoveY); main.orientation = new Vector2D(0, 1); } //If the tank won't hit a wall or the edge, move it else { main.location = main.location + main.tankVelocity; main.orientation = new Vector2D(0, 1); } break; case "left": main.tankVelocity = new Vector2D(-EngineStrength, 0); tankLocAfterMoveY = main.location.GetY() + main.tankVelocity.GetY(); tankLocAfterMoveX = main.location.GetX() + main.tankVelocity.GetX(); //If the tank will hit a wall with this move, don't move it if (collisionCheck(tankLocAfterMoveX, tankLocAfterMoveY)) { main.tankVelocity = new Vector2D(0, 0); } //If the tank is at the edge of the world after this move, teleport it to the other side else if (tankLocAfterMoveX < -serverWorld.worldSize / 2) { tankLocAfterMoveX = serverWorld.worldSize / 2 - 5; main.location = new Vector2D(tankLocAfterMoveX, main.location.GetY()); main.orientation = new Vector2D(-1, 0); } //If the tank won't hit a wall or the edge, move it else { main.location = main.location + main.tankVelocity; main.orientation = new Vector2D(-1, 0); } break; case "right": main.tankVelocity = new Vector2D(EngineStrength, 0); tankLocAfterMoveY = main.location.GetY() + main.tankVelocity.GetY(); tankLocAfterMoveX = main.location.GetX() + main.tankVelocity.GetX(); //If the tank will hit a wall with this move, don't move it if (collisionCheck(tankLocAfterMoveX, tankLocAfterMoveY)) { main.tankVelocity = new Vector2D(0, 0); } //If the tank is at the edge of the world after this move, teleport it to the other side else if (tankLocAfterMoveX > serverWorld.worldSize / 2) { tankLocAfterMoveX = -serverWorld.worldSize / 2 + 5; main.location = new Vector2D(tankLocAfterMoveX, main.location.GetY()); main.orientation = new Vector2D(1, 0); } //If the tank won't hit a wall or the edge, move it else { main.location = main.location + main.tankVelocity; main.orientation = new Vector2D(1, 0); } break; } //Aim the turret the direction it should be facing main.aiming = command.getTurretDirection(); } //Remove the data that has been processed and ask for more data sock.RemoveData(0, sock.GetData().Length); Networking.GetData(sock); }
/// <summary> /// This part sets up a tank with the player name and sends the startup info to the client including the world size, player ID, /// and walls. /// </summary> /// <param name="ss">Socket state for the connection</param> private static void SendStartupInfo(SocketState ss) { if (ss.ErrorOccured == true) { Console.WriteLine("Error occured while accepting: \"" + ss.ErrorMessage + "\""); return; } //Gets the name and ID from the socket and removes the name from the socket string tankName = ss.GetData(); int tankID = (int)ss.ID; ss.RemoveData(0, tankName.Length); lock (TheWorld) { /*This sets up the tank, sets the cooldown frames so it can fire, adds a filler command to the dictionary, and * spawns the tank at a random location.*/ Tank t = new Tank(tankName.Substring(0, tankName.Length - 1), tankID); TheWorld.UpdateTank(t); TheWorld.TankSetCooldownFrames(t.ID, FramesPerShot); TheWorld.UpdateCommand(tankID, new ControlCommands()); SpawnTank(t); Console.WriteLine("Player(" + tankID + ") " + "\"" + t.Name + "\" joined"); } //Changes the delegate ss.OnNetworkAction = ReceiveCommandData; //Sends the tank ID and the world size string message = tankID + "\n" + UniverseSize.ToString() + "\n"; if (!Networking.Send(ss.TheSocket, message)) { Console.WriteLine("Error occured while sending data"); } //Sends the walls to the client lock (TheWorld) { StringBuilder wallMessage = new StringBuilder(); foreach (Wall w in TheWorld.Walls.Values) { wallMessage.Append(JsonConvert.SerializeObject(w) + "\n"); } if (!Networking.Send(ss.TheSocket, wallMessage.ToString())) { Console.WriteLine("Error occured while sending data"); } } //Adds the socket state to the list of connections SocketConnections.Add(ss); Networking.GetData(ss); }
public void TestMyOwn() { // List to represents connections List <SocketState> server = new List <SocketState>(); void SaveServer(SocketState s) { lock (this) { server.Add(s); } } //Two clients SocketState client_1 = null; void SaveClient_1(SocketState s) { client_1 = s; } SocketState client_2 = null; void SaveClient_2(SocketState s) { client_2 = s; } // Starting a server TcpListener listener = Networking.StartServer(SaveServer, 2112); // Client1 Connect to the server Networking.ConnectToServer(SaveClient_1, "localhost", 2112); // Client2 Connect to the server Networking.ConnectToServer(SaveClient_2, "localhost", 2112); // Make sure this line is what you want to it behave NetworkTestHelper.WaitForOrTimeout(() => (client_2 != null) && (client_1 != null) && (server.Count == 2), NetworkTestHelper.timeout); // Set the action to do nothing foreach (SocketState state in server) { state.OnNetworkAction = x => { }; } client_1.OnNetworkAction = x => { }; client_2.OnNetworkAction = x => { }; foreach (SocketState state in server) { Networking.SendAndClose(state.TheSocket, "a"); } Networking.GetData(client_1); Networking.GetData(client_2); // Note that waiting for data like this is *NOT* how the networking library is // intended to be used. This is only for testing purposes. // Normally, you would provide an OnNetworkAction that handles the data. NetworkTestHelper.WaitForOrTimeout(() => client_1.GetData().Length > 0 && client_2.GetData().Length > 0, NetworkTestHelper.timeout); Assert.AreEqual("a", client_1.GetData()); Assert.AreEqual("a", client_2.GetData()); //Make sure everything close and stop properly listener.Stop(); foreach (SocketState state in server) { state.TheSocket.Close(); } client_1.TheSocket.Close(); client_2.TheSocket.Close(); }
/// <summary> /// Detects the incoming messages of new players when they connect then calls Get Data in order to create an event loop to continue listening for /// new incoming players /// </summary> /// <param name="state">Connection of incoming player.</param> private void ProcessMessage(SocketState state) { string data; long ID = state.ID; string[] movingCommands; if (state.ErrorOccured) { PlayerDisconnect(state); Networking.SendAndClose(state.TheSocket, "error"); //Networking.GetData(state); return; } data = state.GetData(); state.ClearData(); if (String.IsNullOrEmpty(data)) { Networking.GetData(state); return; } //checks to see if user is sending a user command or name if (data.StartsWith("{\"moving\"")) { movingCommands = data.Split(','); foreach (string s in movingCommands) { string[] command = s.Split(':'); foreach (string t in command) { string tempString = t.Replace("\"", String.Empty); string tempString2 = tempString.Replace("{", String.Empty); string stringToCompare = tempString2.Replace("}", String.Empty); switch (stringToCompare) { case "none": break; case "up": MoveTank(new Vector2D(0, playerSpeed * -1), new Vector2D(0, -1), players[ID]); break; case "down": MoveTank(new Vector2D(0, playerSpeed), new Vector2D(0, 1), players[ID]); break; case "left": MoveTank(new Vector2D(playerSpeed * -1, 0), new Vector2D(-1, 0), players[ID]); break; case "right": MoveTank(new Vector2D(playerSpeed, 0), new Vector2D(1, 0), players[ID]); break; case "main": FireProjectile(players[ID]); break; case "alt": FireBeam(players[ID]); break; case "x": if (double.TryParse(command[2], out double anglex)) { turretAimx = anglex; } break; case "y": if (command[1].Length > 4) { if (double.TryParse(command[1].Substring(0, command[1].Length - 5), out double angley)) { turretAimy = angley; } players[ID].SetAim(new Vector2D(turretAimx, turretAimy)); } break; } } } } else if (!players.ContainsKey(ID)) { Console.WriteLine("Player " + state.ID.ToString() + " Connected."); CreateTank(data, ID); Sendwalls(state); Networking.GetData(state); return; } Networking.GetData(state); }
//Method used to process the messages public void ProcessMessages(SocketState sock) { //Get the data and split it around \n string totalData = sock.GetData(); string[] parts = Regex.Split(totalData, @"(?<=[\n])"); int i = 1; // For every string, find out what it is and then deserialize it. foreach (string s in parts) { totalData = totalData.Substring(s.Length, totalData.Length - s.Length); //If it doesn't end with\n, it is incomplete data if (!s.EndsWith("\n")) { break; } //If this is the first frame, then the first thing being sent is the playerID else if (i == 1 && Constants.firstFrame) { Constants.playerID = int.Parse(s); sock.RemoveData(0, sock.GetData().Length - totalData.Length); i++; Constants.firstFrame = false; } //If this is the second bit of data being processed, then this is the worldsize else if (i == 2) { Constants.worldSize = int.Parse(s); sock.RemoveData(0, sock.GetData().Length - totalData.Length); i++; } //If s contains a wall, then deserialize it and add it to the walls dictionary else if (s.Contains("wall")) { Wall newWall = JsonConvert.DeserializeObject <Wall>(s); Constants.walls.Add(newWall.ID, newWall); sock.RemoveData(0, sock.GetData().Length - totalData.Length); Constants.wallsRec = true; } //If s is a beam, then deserialize it and add it to the beams dictionary or update it else if (s.Contains("beam")) { Beam newBeam = JsonConvert.DeserializeObject <Beam>(s); if (Constants.beams.ContainsKey(newBeam.ID)) { Constants.beams.Remove(newBeam.ID); Constants.beams.Add(newBeam.ID, newBeam); } else { Constants.beams.Add(newBeam.ID, newBeam); } sock.RemoveData(0, sock.GetData().Length - totalData.Length); continue; } //If s is a tank, then deserialize it and update all of the tank's data. //If this is a new tank, then determine its color as well else if (s.Contains("tank")) { Tank newTank = JsonConvert.DeserializeObject <Tank>(s); if (Constants.tanks.ContainsKey(newTank.ID)) { Constants.tanks[newTank.ID].hitPoints = newTank.hitPoints; Constants.tanks[newTank.ID].died = newTank.died; Constants.tanks[newTank.ID].location = newTank.location; Constants.tanks[newTank.ID].orientation = newTank.orientation; Constants.tanks[newTank.ID].aiming = newTank.aiming; Constants.tanks[newTank.ID].score = newTank.score; } else { switch ((Constants.tanks.Keys.Count) % 8) { case 0: newTank.color = "blue"; break; case 1: newTank.color = "dark"; break; case 2: newTank.color = "green"; break; case 3: newTank.color = "lightGreen"; break; case 4: newTank.color = "orange"; break; case 5: newTank.color = "purple"; break; case 6: newTank.color = "red"; break; case 7: newTank.color = "yellow"; break; } Constants.tanks.Add(newTank.ID, newTank); } sock.RemoveData(0, sock.GetData().Length - totalData.Length); continue; } //If s is a powerup, then deserialize it and add it to the powerups dictionary else if (s.Contains("power")) { Powerup newPowerup = JsonConvert.DeserializeObject <Powerup>(s); if (Constants.powerups.ContainsKey(newPowerup.ID)) { Constants.powerups[newPowerup.ID].location = newPowerup.location; Constants.powerups[newPowerup.ID].died = newPowerup.died; } else { Constants.powerups.Add(newPowerup.ID, newPowerup); } sock.RemoveData(0, sock.GetData().Length - totalData.Length); continue; } //If s is a projectile, then deserialize it and add it to the projectiles dictionary else if (s.Contains("proj")) { Projectile newProj = JsonConvert.DeserializeObject <Projectile>(s); if (Constants.projectiles.ContainsKey(newProj.ID)) { Constants.projectiles[newProj.ID].location = newProj.location; Constants.projectiles[newProj.ID].died = newProj.died; } else { Constants.projectiles.Add(newProj.ID, newProj); } sock.RemoveData(0, sock.GetData().Length - totalData.Length); continue; } } }
/// <summary> /// Receives messages from server and handles them /// </summary> /// <param name="state"></param> private void ReceiveUpdatesLoop(SocketState state) { if (state.ErrorOccured) { // inform the view Error?.Invoke(state.ErrorMessage, "Error In Event Loop"); Disconnect(); return; } string incomingMessages = state.GetData(); string[] data = Regex.Split(incomingMessages, @"(?<=[\n])"); foreach (string message in data.Where(message => message.Length != 0)) { //Last Step of handshake if message is the id if (int.TryParse(message, out int i)) { IDReceive?.Invoke(i); continue; } // The regex splitter will include the last string even if it doesn't end with a '\n', // So we need to ignore it if this happens. if (message.Last() != '\n' || message[0] != '{') { continue; } Console.WriteLine("Received:" + message); //Parse message as json object var x = JObject.Parse(message); switch (x["messageType"]?.ToString()) { case "cellUpdated": { if (EditCell is null) { continue; } var updated = JsonConvert.DeserializeObject <CellUpdated>(message); EditCell.Invoke(updated); break; } case "cellSelected": { if (SelectCell is null) { continue; } var selected = JsonConvert.DeserializeObject <CellSelected>(message); SelectCell.Invoke(selected); break; } case "serverError": { if (ServerShutdown is null) { continue; } var error = JsonConvert.DeserializeObject <ServerShutdownError>(message); ServerShutdown.Invoke(error); break; } case "requestError": { if (RequestError is null) { continue; } var error = JsonConvert.DeserializeObject <RequestError>(message); RequestError.Invoke(error); break; } case "disconnected": { var d = JsonConvert.DeserializeObject <Disconnected>(message); ClientDisconnected?.Invoke(d); break; } } state.RemoveData(0, message.Length); } Networking.GetData(state); }