diff --git a/libbettola/include/bettola/network/game_state_message.h b/libbettola/include/bettola/network/game_state_message.h new file mode 100644 index 0000000..f535b08 --- /dev/null +++ b/libbettola/include/bettola/network/game_state_message.h @@ -0,0 +1,15 @@ +#pragma once + +#include "message.h" +#include "player_state_message.h" + +namespace BettolaLib { +namespace Network { + +struct GameStateMessage { + unsigned int num_players; + PlayerStateMessage players[32]; /* Max 32 players for now. */ +}; + +} /* namespace Network. */ +} /* namespace BettolaLib. */ diff --git a/libbettola/include/bettola/network/message.h b/libbettola/include/bettola/network/message.h index 3c6d051..32787a6 100644 --- a/libbettola/include/bettola/network/message.h +++ b/libbettola/include/bettola/network/message.h @@ -5,6 +5,8 @@ namespace Network { enum class MessageType : unsigned char { PlayerPosition, + PlayerState, + GameState, }; struct MessageHeader { diff --git a/libbettola/include/bettola/network/player_state_message.h b/libbettola/include/bettola/network/player_state_message.h new file mode 100644 index 0000000..02c200c --- /dev/null +++ b/libbettola/include/bettola/network/player_state_message.h @@ -0,0 +1,15 @@ +#pragma once + +#include "message.h" + +namespace BettolaLib { +namespace Network { + +struct PlayerStateMessage { + unsigned int player_id; + float x; + float y; +}; + +} /* namespace Network. */ +} /* namespace BettolaLib. */ diff --git a/srv/game/game.cpp b/srv/game/game.cpp index 3b18625..a0f5f9d 100644 --- a/srv/game/game.cpp +++ b/srv/game/game.cpp @@ -1,33 +1,53 @@ #include #include "game.h" +#include "network/game_state_message.h" #include "network/socket.h" +#include "network/message.h" -void Game::add_player(BettolaLib::Network::Socket* socket) { +Player* Game::add_player(BettolaLib::Network::Socket* socket) { _players.emplace_back(socket); + return &_players.back(); } -void Game::remove_player(BettolaLib::Network::Socket* socket) { - /* - * TODO: We'll need a better way to ident players other than - * their socket. We'll match sockets for now though.. -- Falco - */ +void Game::remove_player(unsigned int player_id) { _players.erase( std::remove_if(_players.begin(), _players.end(), - [socket](const Player& player) { + [player_id](const Player& player) { /* this is a sh.t way to compare players. */ - return &player.get_socket() == socket; + return player.get_id() == player_id; }), _players.end()); } -void Game::update_player_pos(BettolaLib::Network::Socket* socket, float x, float y) { +void Game::update_player_pos(unsigned int player_id, float x, float y) { auto it = std::find_if(_players.begin(), _players.end(), - [socket](const Player& player) { - return &player.get_socket() == socket; + [player_id](const Player& player) { + return player.get_id() == player_id; }); if(it != _players.end()) { it->set_position(x, y); } } +void Game::broadcast_game_state(void) { + BettolaLib::Network::GameStateMessage msg; + msg.num_players = _players.size(); + + for(size_t i = 0; i < _players.size(); ++i) { + msg.players[i].player_id = _players[i].get_id(); + msg.players[i].x = _players[i].get_x(); + msg.players[i].y = _players[i].get_y(); + } + + BettolaLib::Network::MessageHeader header; + header.type = BettolaLib::Network::MessageType::GameState; + header.size = sizeof(msg); + + for(const auto& player : _players) { + BettolaLib::Network::Socket& socket = player.get_socket(); + socket.send(&header, sizeof(header)); + socket.send(&msg, sizeof(msg)); + } +} + diff --git a/srv/game/game.h b/srv/game/game.h index 21bdea5..3c9f820 100644 --- a/srv/game/game.h +++ b/srv/game/game.h @@ -6,9 +6,10 @@ class Game { public: - void add_player(BettolaLib::Network::Socket* socket); - void remove_player(BettolaLib::Network::Socket* socket); - void update_player_pos(BettolaLib::Network::Socket* socket, float x, float y); + Player* add_player(BettolaLib::Network::Socket* socket); + void remove_player(unsigned int player_id); + void update_player_pos(unsigned int player_id, float x, float y); + void broadcast_game_state(void); private: std::vector _players; diff --git a/srv/game/player.cpp b/srv/game/player.cpp index 3d41e8d..ca460c7 100644 --- a/srv/game/player.cpp +++ b/srv/game/player.cpp @@ -1,6 +1,8 @@ #include "player.h" #include "network/socket.h" -Player::Player(BettolaLib::Network::Socket* socket) : - _x(0.0f), _y(0.0f), _socket(socket) {} +unsigned int Player::_next_player_id = 0; + +Player::Player(BettolaLib::Network::Socket* socket) : + _id(_next_player_id++), _x(0.0f), _y(0.0f), _socket(socket) {} diff --git a/srv/game/player.h b/srv/game/player.h index 2a15023..c9190de 100644 --- a/srv/game/player.h +++ b/srv/game/player.h @@ -8,9 +8,15 @@ public: void set_position(float x, float y) { _x = x; _y = y; } + unsigned int get_id(void) const { return _id; } + float get_x(void) const { return _x; } + float get_y(void) const { return _y; } BettolaLib::Network::Socket& get_socket(void) const { return *_socket; } private: + static unsigned int _next_player_id; + + unsigned int _id; float _x; float _y; BettolaLib::Network::Socket* _socket; diff --git a/srv/main.cpp b/srv/main.cpp index 11025f5..10916fd 100644 --- a/srv/main.cpp +++ b/srv/main.cpp @@ -1,4 +1,7 @@ +#include #include +#include +#include #include "bettola/network/socket.h" #include "bettola/network/net_common.h" @@ -33,38 +36,53 @@ int main(void) { printf("Bettola Server: Listening on port %hu...\n", BettolaLib::Network::DEFAULT_PORT); + auto last_time = std::chrono::high_resolution_clock::now(); + /* Main server loop. */ while(true) { - BettolaLib::Network::Socket* client_socket = server_socket.accept(); + auto current_time = std::chrono::high_resolution_clock::now(); + auto delta_time = std::chrono::duration_cast> + (current_time-last_time).count(); - if(client_socket == nullptr) { - printf("Bettola Server: Failed to accept client connection.\n"); - continue; /* try accepting again. */ + /* TODO: + * Accept new connections. + * This is blocking.. Will fix later. + */ + 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()); } - game.add_player(client_socket); + /* TODO: + * Process messages from clients. + * this is also blocking and only handles one client at a time. fix later + */ + if(client_socket != nullptr) { + while(true) { + BettolaLib::Network::MessageHeader header; + ssize_t bytes_received = client_socket->recv(&header, sizeof(header)); - printf("Bettola Server: Client connected!\n"); + if(bytes_received <= 0) { + //game.remove_player(new_player->get_id()); + break; + } - while(true) { - BettolaLib::Network::MessageHeader header; - ssize_t bytes_received = client_socket->recv(&header, sizeof(header)); - - if(bytes_received <= 0) { - game.remove_player(client_socket); - break; - } - - if(header.type == BettolaLib::Network::MessageType::PlayerPosition) { - BettolaLib::Network::PlayerPosMessage msg; - bytes_received = client_socket->recv(&msg, sizeof(msg)); - if(bytes_received > 0) { - printf("Bettola Server: Received PlayerPosition messgae: x=%.2f, y=%.2f\n", - msg.x, msg.y); - game.update_player_pos(client_socket, msg.x, msg.y); + if(header.type == BettolaLib::Network::MessageType::PlayerPosition) { + BettolaLib::Network::PlayerPosMessage msg; + bytes_received = client_socket->recv(&msg, sizeof(msg)); + if(bytes_received > 0) { + //game.update_player_pos(new_player->get_id(), msg.x, msg.y); + } } } } + + /* Broadcase game state. */ + game.broadcast_game_state(); + + /* Sleep for a short time to avoid busy-waiting. */ + std::this_thread::sleep_for(std::chrono::milliseconds(1000/60)); } server_socket.close(); /* Shouldn't reach here. */