diff --git a/srv/game/game.cpp b/srv/game/game.cpp index 5fb17ea..a2f2d9e 100644 --- a/srv/game/game.cpp +++ b/srv/game/game.cpp @@ -1,4 +1,5 @@ #include +#include #include "game.h" #include "network/game_state_message.h" @@ -13,8 +14,12 @@ Player* Game::add_player(BettolaLib::Network::Socket* socket) { void Game::remove_player(unsigned int player_id) { _players.erase( std::remove_if(_players.begin(), _players.end(), - [player_id](const Player* player) { - return player->get_id() == player_id; + [player_id](Player* player) { + if(player->get_id() == player_id) { + delete player; + return true; + } + return false; }), _players.end()); } @@ -32,6 +37,7 @@ void Game::update_player_pos(unsigned int player_id, float x, float y) { void Game::broadcast_game_state(void) { BettolaLib::Network::GameStateMessage msg; msg.num_players = _players.size(); + memset(msg.players, 0, sizeof(msg.players)); for(size_t i = 0; i < _players.size(); ++i) { msg.players[i].player_id = _players[i]->get_id(); @@ -45,13 +51,8 @@ void Game::broadcast_game_state(void) { for(const auto& player : _players) { BettolaLib::Network::Socket& socket = player->get_socket(); - /* Just quick fix the server crash for now. */ - if(socket.send(&header, sizeof(header)) <= 0) { - /* TODO: Probably should handle this error by removing player.. */ - } - if(socket.send(&msg, sizeof(msg)) <= 0) { - /* TODO: Probably should handle this error by removing player.. */ - } + socket.send(&header, sizeof(header)); + socket.send(&msg, sizeof(msg)); } } diff --git a/srv/main.cpp b/srv/main.cpp index 998ecc2..c629356 100644 --- a/srv/main.cpp +++ b/srv/main.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -54,68 +55,85 @@ int main(void) { /* Main server loop. */ while(true) { - /* Accept new connections. */ - BettolaLib::Network::Socket* client_socket = server_socket.accept(); - if(client_socket != nullptr) { - Player* new_player = game.add_player(client_socket); - printf("Bettola Server: Client connected! Player ID: %u\n", new_player->get_id()); + fd_set read_fds; + FD_ZERO(&read_fds); + FD_SET(server_socket.get_sockfd(), &read_fds); + int max_fd = server_socket.get_sockfd(); - BettolaLib::Network::MessageHeader header; - header.type = BettolaLib::Network::MessageType::PlayerId; - header.size = sizeof(unsigned int); - client_socket->send(&header, sizeof(header)); - unsigned int id = new_player->get_id(); - client_socket->send(&id, sizeof(id)); - - /* Set the client socket to non-blocking. */ - int client_flags = fcntl(client_socket->get_sockfd(), F_GETFL, 0); - if(client_flags == -1) { - perror("fcntl F_GETFL failed"); - return 1; + for(const auto& client : client_sockets) { + FD_SET(client->get_sockfd(), &read_fds); + if(client->get_sockfd() > max_fd) { + max_fd = client->get_sockfd(); } - fcntl(client_socket->get_sockfd(), F_SETFL, client_flags | O_NONBLOCK); - - client_sockets.push_back(client_socket); } - /* Process messages from clients. */ - for(auto it = client_sockets.begin(); it != client_sockets.end();) { - BettolaLib::Network::Socket* client = *it; - bool client_disconnected = false; + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 1000; /* 1ms */ - while(true) { - BettolaLib::Network::MessageHeader header; - /* Non-blocking. */ - ssize_t bytes_received = client->recv(&header, sizeof(header)); + int activity = select(max_fd+1, &read_fds, nullptr, nullptr, &tv); - if(bytes_received == 0) { - client_disconnected = true; - break; - } + if(activity > 0) { + if(FD_ISSET(server_socket.get_sockfd(), &read_fds)) { + BettolaLib::Network::Socket* client_socket = server_socket.accept(); + if(client_socket != nullptr) { + Player* new_player = game.add_player(client_socket); + printf("Bettola Server: Client connected! Player ID: %u\n", new_player->get_id()); - if(bytes_received < 0) { - /* No data to read.. */ - break; - } + BettolaLib::Network::MessageHeader header; + header.type = BettolaLib::Network::MessageType::PlayerId; + header.size = sizeof(unsigned int); + client_socket->send(&header, sizeof(header)); + unsigned int id = new_player->get_id(); + client_socket->send(&id, sizeof(id)); - if(header.type == BettolaLib::Network::MessageType::PlayerPosition) { - BettolaLib::Network::PlayerPosMessage msg; - bytes_received = client->recv(&msg, sizeof(msg)); - if(bytes_received > 0) { - Player* player = game.get_player_by_socket(client); - if(player) { - game.update_player_pos(player->get_id(), msg.x, msg.y); - } - } + int client_flags = fcntl(client_socket->get_sockfd(), F_GETFL, 0); + fcntl(client_socket->get_sockfd(), F_SETFL, client_flags | O_NONBLOCK); + + client_sockets.push_back(client_socket); } } - if(client_disconnected) { - Player* player = game.get_player_by_socket(client); - if(player) game.remove_player(player->get_id()); - it = client_sockets.erase(it); - } else { - ++it; + for(auto it = client_sockets.begin(); it != client_sockets.end();) { + BettolaLib::Network::Socket* client = *it; + if(FD_ISSET(client->get_sockfd(), &read_fds)) { + bool client_disconnected = false; + while (true) { + BettolaLib::Network::MessageHeader header; + ssize_t bytes_received = client->recv(&header, sizeof(header)); + + if(bytes_received == 0) { + client_disconnected = true; + break; + } + + if(bytes_received < 0) { + break; + } + + if(header.type == BettolaLib::Network::MessageType::PlayerPosition) { + BettolaLib::Network::PlayerPosMessage msg; + bytes_received = client->recv(&msg, sizeof(msg)); + if(bytes_received > 0) { + Player* player = game.get_player_by_socket(client); + if(player) { + game.update_player_pos(player->get_id(), msg.x, msg.y); + } + } + } + } + + if(client_disconnected) { + Player* player = game.get_player_by_socket(client); + if(player) game.remove_player(player->get_id()); + it = client_sockets.erase(it); + delete client; + } else { + ++it; + } + } else { + ++it; + } } } @@ -123,7 +141,7 @@ int main(void) { game.broadcast_game_state(); /* Sleep for a short time to avoid busy-waiting. */ - std::this_thread::sleep_for(std::chrono::milliseconds(1000/60)); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); } server_socket.close(); /* Shouldn't reach here. */