From 5e37d936f659ee968f6fcd2abe3a36f042af1b57 Mon Sep 17 00:00:00 2001 From: Joonatan Korpela <joonatan.korpela@paivola.fi> Date: Mon, 1 Mar 2021 16:14:52 +0200 Subject: [PATCH] WIP Protocol: Server doesn't crash when opening and closing connections --- src/cpp/game/game.cpp | 19 ++++++++---- src/cpp/game/game.hpp | 16 +++++----- src/cpp/game/world.cpp | 30 ------------------ src/cpp/{game => logic}/player.cpp | 4 +++ src/cpp/{game => logic}/player.hpp | 1 + src/cpp/{game => logic}/sprite.hpp | 0 src/cpp/{game => logic}/stage.cpp | 0 src/cpp/{game => logic}/stage.hpp | 0 src/cpp/logic/world.cpp | 47 +++++++++++++++++++++++++++++ src/cpp/{game => logic}/world.hpp | 5 +-- src/cpp/protocol/clientHandler.cpp | 10 +++++- src/cpp/protocol/clientHandler.hpp | 8 +++-- src/cpp/websocket-server/server.cpp | 37 +++++++++++++---------- src/cpp/websocket-server/server.hpp | 3 +- 14 files changed, 112 insertions(+), 68 deletions(-) delete mode 100644 src/cpp/game/world.cpp rename src/cpp/{game => logic}/player.cpp (80%) rename src/cpp/{game => logic}/player.hpp (93%) rename src/cpp/{game => logic}/sprite.hpp (100%) rename src/cpp/{game => logic}/stage.cpp (100%) rename src/cpp/{game => logic}/stage.hpp (100%) create mode 100644 src/cpp/logic/world.cpp rename src/cpp/{game => logic}/world.hpp (85%) diff --git a/src/cpp/game/game.cpp b/src/cpp/game/game.cpp index 77e480d66..6837a2339 100644 --- a/src/cpp/game/game.cpp +++ b/src/cpp/game/game.cpp @@ -35,33 +35,40 @@ void Game::init(Engine & engine) { // Called by the engine at regular intervals which are determined by the TPS (ticks per second) void Game::update() { // Update the game + world.update(); } // Called by the engine at regular intervals which are determined by the FPS (frames per second) // The name frames per second can be a bit misleading as the server doesn't do any of the visualization void Game::render() { // Send game state to connected clients + server.sendAll("TEST"); } // Called by the server every time a new connection is established -ClientHandler & Game::clientConnected(ConnectionHandle connectionHandle) { +ClientHandler* Game::clientConnected(ConnectionHandle connectionHandle) { // Get a playerId for the new client int playerId = playerIdCounter++; // Create a new player object - Player & player = world.createNewPlayer(playerId); + Player* player = world.createNewPlayer(playerId); // Add player to the player map - playerMap.insert(pair<int, Player*>(playerId, &player)); + playerMap.insert(pair<int, Player*>(playerId, player)); // Create a new client handler - ClientHandler clientHandler = ClientHandler(connectionHandle, player, playerId, *this); + ClientHandler* clientHandler = new ClientHandler(connectionHandle, player, playerId, *this); // Add client handler to the client map - clientMap.insert(pair<int, ClientHandler*>(playerId, &clientHandler)); + clientMap.insert(pair<int, ClientHandler*>(playerId, clientHandler)); // Return the client handler for the use of the server return clientHandler; } -void Game::clientDisconnected(ConnectionHandle connectionHandle) { +void Game::clientDisconnected(int playerId) { + // Remove player + playerMap.erase(playerId); // Remove client + clientMap.erase(playerId); + + world.removePlayer(playerId); } diff --git a/src/cpp/game/game.hpp b/src/cpp/game/game.hpp index 98cff86ec..b6a8a6c25 100644 --- a/src/cpp/game/game.hpp +++ b/src/cpp/game/game.hpp @@ -5,26 +5,26 @@ #include "../engine/engine.hpp" #include "../protocol/clientHandler.hpp" #include "../websocket-server/server.hpp" -#include "world.hpp" -#include "player.hpp" +#include "../logic/world.hpp" +#include "../logic/player.hpp" typedef websocketpp::connection_hdl ConnectionHandle; // The game class orchestrates everything in the game; it is pretty much the core of the program class Game { public: - Game(Engine &, Server &); + Game(Engine&, Server&); void start(); - void init(Engine &); + void init(Engine&); void update(); void render(); - ClientHandler& clientConnected(ConnectionHandle connection); - void clientDisconnected(ConnectionHandle connection); + ClientHandler* clientConnected(ConnectionHandle connection); + void clientDisconnected(int playerId); private: - Server & server; - Engine & engine; + Server& server; + Engine& engine; World world; map<int, ClientHandler*> clientMap; map<int, Player*> playerMap; diff --git a/src/cpp/game/world.cpp b/src/cpp/game/world.cpp deleted file mode 100644 index 021a9ea31..000000000 --- a/src/cpp/game/world.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "world.hpp" - -using namespace std; - -World::World() { - worlds.insert( pair<Stage*, vector<Sprite*>>(&mainStage, {}) ); -} - -void World::tick() { - for(auto const & world : worlds) { - Stage * stage = world.first; - vector<Sprite*> sprites = world.second; - for(Sprite * sprite : sprites) { - sprite->tick(); - } - } -} - -Player & World::createNewPlayer(int id) { - vector<int> spawnPoint = mainStage.getSpawnPoint(); - Player player = Player(spawnPoint[0], spawnPoint[1], id); - vector<Sprite*> worldSprites = worlds[&mainStage]; - worldSprites.push_back(&player); - return player; -} - -string World::toString() { - // TODO - return ""; -} \ No newline at end of file diff --git a/src/cpp/game/player.cpp b/src/cpp/logic/player.cpp similarity index 80% rename from src/cpp/game/player.cpp rename to src/cpp/logic/player.cpp index 8cdd9e4d2..27158e170 100644 --- a/src/cpp/game/player.cpp +++ b/src/cpp/logic/player.cpp @@ -11,6 +11,10 @@ void Player::tick() { } +int Player::getId() { + return id; +} + string Player::toString() { } \ No newline at end of file diff --git a/src/cpp/game/player.hpp b/src/cpp/logic/player.hpp similarity index 93% rename from src/cpp/game/player.hpp rename to src/cpp/logic/player.hpp index 5d12670b7..b084a046c 100644 --- a/src/cpp/game/player.hpp +++ b/src/cpp/logic/player.hpp @@ -7,6 +7,7 @@ class Player : public Sprite { Player(double, double, int); void tick(); string toString(); + int getId(); private: double xPos; diff --git a/src/cpp/game/sprite.hpp b/src/cpp/logic/sprite.hpp similarity index 100% rename from src/cpp/game/sprite.hpp rename to src/cpp/logic/sprite.hpp diff --git a/src/cpp/game/stage.cpp b/src/cpp/logic/stage.cpp similarity index 100% rename from src/cpp/game/stage.cpp rename to src/cpp/logic/stage.cpp diff --git a/src/cpp/game/stage.hpp b/src/cpp/logic/stage.hpp similarity index 100% rename from src/cpp/game/stage.hpp rename to src/cpp/logic/stage.hpp diff --git a/src/cpp/logic/world.cpp b/src/cpp/logic/world.cpp new file mode 100644 index 000000000..573e05dca --- /dev/null +++ b/src/cpp/logic/world.cpp @@ -0,0 +1,47 @@ +#include "world.hpp" + +using namespace std; + +World::World() { + worlds.insert( pair<Stage*, vector<Sprite*>>(&mainStage, {}) ); +} + +void World::update() { + for(auto const & world : worlds) { + Stage * stage = world.first; + vector<Sprite*> sprites = world.second; + for(Sprite * sprite : sprites) { + sprite->tick(); + } + } +} + +Player* World::createNewPlayer(int id) { + vector<int> spawnPoint = mainStage.getSpawnPoint(); + Player* player = new Player(spawnPoint[0], spawnPoint[1], id); + vector<Sprite*> worldSprites = worlds[&mainStage]; + worldSprites.push_back(player); + return player; +} + +void World::removePlayer(int id) { + for(auto const & world : worlds) { + Stage * stage = world.first; + vector<Sprite*> sprites = world.second; + for(int i = 0; i < sprites.size(); i++) { + Sprite* sprite = sprites[i]; + if(Player* player = dynamic_cast<Player*>(sprite)) { + if(player->getId() == id) { + sprites.erase(sprites.begin()+i); + delete player; + return; + } + } + } + } +} + +string World::toString() { + // TODO + return ""; +} \ No newline at end of file diff --git a/src/cpp/game/world.hpp b/src/cpp/logic/world.hpp similarity index 85% rename from src/cpp/game/world.hpp rename to src/cpp/logic/world.hpp index 8c60ad8d2..81af818c5 100644 --- a/src/cpp/game/world.hpp +++ b/src/cpp/logic/world.hpp @@ -18,8 +18,9 @@ will update each sprite's and its own state. class World { public: World(); - void tick(); - Player & createNewPlayer(int); + void update(); + Player* createNewPlayer(int); + void removePlayer(int); string toString(); private: diff --git a/src/cpp/protocol/clientHandler.cpp b/src/cpp/protocol/clientHandler.cpp index 11b9e617d..eb8b2cf5a 100644 --- a/src/cpp/protocol/clientHandler.cpp +++ b/src/cpp/protocol/clientHandler.cpp @@ -1,7 +1,7 @@ #include "clientHandler.hpp" #include "../game/game.hpp" -ClientHandler::ClientHandler(ConnectionHandle _connectionHandle, Player& _player, int id, Game& _game) : player(_player), game(_game) { +ClientHandler::ClientHandler(ConnectionHandle _connectionHandle, Player* _player, int id, Game& _game) : player(_player), game(_game) { connectionHandle = _connectionHandle; playerId = id; @@ -11,6 +11,10 @@ void ClientHandler::onMessage(ConnectionHandle connectionHandle, MessagePtr msg) // Parse the message } +void ClientHandler::onClose(ConnectionHandle connectionHandle) { + server->disconnectClient(this); +} + ConnectionHandle ClientHandler::getConnectionHandle() { return connectionHandle; } @@ -18,3 +22,7 @@ ConnectionHandle ClientHandler::getConnectionHandle() { void ClientHandler::setServer(Server* _server) { server = _server; } + +int ClientHandler::getPlayerId() { + return playerId; +} \ No newline at end of file diff --git a/src/cpp/protocol/clientHandler.hpp b/src/cpp/protocol/clientHandler.hpp index 795dc826a..583d59a0a 100644 --- a/src/cpp/protocol/clientHandler.hpp +++ b/src/cpp/protocol/clientHandler.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../game/player.hpp" +#include "../logic/player.hpp" #include <websocketpp/config/asio_no_tls.hpp> #include <websocketpp/server.hpp> @@ -17,15 +17,17 @@ using namespace std; class ClientHandler { public: - ClientHandler(ConnectionHandle, Player&, int, Game&); + ClientHandler(ConnectionHandle, Player*, int, Game&); ConnectionHandle getConnectionHandle(); void onMessage(ConnectionHandle connectionHandle, MessagePtr msg); + void onClose(ConnectionHandle connectionHandle); void setServer(Server*); + int getPlayerId(); private: int playerId; ConnectionHandle connectionHandle; - Player& player; + Player* player; Game& game; Server* server; }; \ No newline at end of file diff --git a/src/cpp/websocket-server/server.cpp b/src/cpp/websocket-server/server.cpp index 36e971898..665af9215 100644 --- a/src/cpp/websocket-server/server.cpp +++ b/src/cpp/websocket-server/server.cpp @@ -11,33 +11,40 @@ using namespace std; Server::Server() { // Set logging settings - endpoint.set_access_channels(websocketpp::log::alevel::all); + endpoint.set_access_channels(websocketpp::log::alevel::none); endpoint.clear_error_channels(websocketpp::log::alevel::frame_payload); // Initialize Asio endpoint.init_asio(); // Set message handler - endpoint.set_message_handler(bind(&Server::onMessage, this, placeholders::_1, placeholders::_2)); endpoint.set_open_handler(bind(&Server::onOpen, this, placeholders::_1)); - endpoint.set_close_handler(bind(&Server::onClose, this, placeholders::_1)); } void Server::onOpen(ConnectionHandle connectionHandle) { printf("Connection opened\n"); + const Connection& connection = endpoint.get_con_from_hdl(connectionHandle); - ClientHandler& client = game->clientConnected(connectionHandle); - connection->set_message_handler(bind(&ClientHandler::onMessage, &client, placeholders::_1, placeholders::_2)); - clients.push_back(&client); -} + ClientHandler* client = game->clientConnected(connectionHandle); + client->setServer(this); -void Server::onClose(ConnectionHandle connectionHandle) { - printf("Connection closed\n"); + connection->set_message_handler(bind(&ClientHandler::onMessage, client, placeholders::_1, placeholders::_2)); + connection->set_close_handler(bind(&ClientHandler::onClose, client, placeholders::_1)); + + clients.push_back(client); } -void Server::onMessage(ConnectionHandle connectionHandle, MessagePtr msg) { - - //endpoint.send(connection, msg->get_payload(), msg->get_opcode()); +void Server::disconnectClient(ClientHandler* clientHandler) { + for(int i = 0; i < clients.size(); i++) { + ClientHandler* handler = clients[i]; + if(clientHandler == handler) { + clients.erase(clients.begin()+i); + break; + } + } + game->clientDisconnected(clientHandler->getPlayerId()); + delete clientHandler; + printf("Connection closed\n"); } thread Server::start(int port) { @@ -64,17 +71,15 @@ void Server::setGame(Game & _game) { game = &_game; } -void Server::send(Connection & connection, string message) { +void Server::send(Connection& connection, string message) { } void Server::sendAll(string message) { - /* for(ClientHandler * client : clients) { - const Connection & connection = client->getConnection(); + const Connection & connection = endpoint.get_con_from_hdl(client->getConnectionHandle()); endpoint.send(connection, message, websocketpp::frame::opcode::text); } - */ } const Connection& Server::getConnectionFromHandle(ConnectionHandle& handle) { diff --git a/src/cpp/websocket-server/server.hpp b/src/cpp/websocket-server/server.hpp index f2d48d4f5..fb3f04f36 100644 --- a/src/cpp/websocket-server/server.hpp +++ b/src/cpp/websocket-server/server.hpp @@ -26,15 +26,14 @@ class Server { void setGame(Game&); void send(Connection&, string); void sendAll(string); + void disconnectClient(ClientHandler* handler); const Connection& getConnectionFromHandle(ConnectionHandle& handle); private: Game * game; WebsocketServer endpoint; vector<ClientHandler*> clients; - void onMessage(ConnectionHandle hdl, MessagePtr msg); void onOpen(ConnectionHandle hdl); - void onClose(ConnectionHandle hdl); void sendMessage(Connection connection); void startRunLoop(); }; -- GitLab