feat(server): Implement game state broadcasting.
This commit is contained in:
parent
bd6281c9bc
commit
39a06147c8
15
libbettola/include/bettola/network/game_state_message.h
Normal file
15
libbettola/include/bettola/network/game_state_message.h
Normal file
@ -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. */
|
||||
@ -5,6 +5,8 @@ namespace Network {
|
||||
|
||||
enum class MessageType : unsigned char {
|
||||
PlayerPosition,
|
||||
PlayerState,
|
||||
GameState,
|
||||
};
|
||||
|
||||
struct MessageHeader {
|
||||
|
||||
15
libbettola/include/bettola/network/player_state_message.h
Normal file
15
libbettola/include/bettola/network/player_state_message.h
Normal file
@ -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. */
|
||||
@ -1,33 +1,53 @@
|
||||
#include <algorithm>
|
||||
|
||||
#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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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<Player> _players;
|
||||
|
||||
@ -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) {}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
42
srv/main.cpp
42
srv/main.cpp
@ -1,4 +1,7 @@
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include "bettola/network/socket.h"
|
||||
#include "bettola/network/net_common.h"
|
||||
@ -33,25 +36,35 @@ 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<std::chrono::duration<double>>
|
||||
(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);
|
||||
|
||||
printf("Bettola Server: Client connected!\n");
|
||||
|
||||
/* 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));
|
||||
|
||||
if(bytes_received <= 0) {
|
||||
game.remove_player(client_socket);
|
||||
//game.remove_player(new_player->get_id());
|
||||
break;
|
||||
}
|
||||
|
||||
@ -59,14 +72,19 @@ int main(void) {
|
||||
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);
|
||||
//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. */
|
||||
printf("=== Bettola Server: Shutting Down ===\n");
|
||||
return 0;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user