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 {
|
enum class MessageType : unsigned char {
|
||||||
PlayerPosition,
|
PlayerPosition,
|
||||||
|
PlayerState,
|
||||||
|
GameState,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MessageHeader {
|
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 <algorithm>
|
||||||
|
|
||||||
#include "game.h"
|
#include "game.h"
|
||||||
|
#include "network/game_state_message.h"
|
||||||
#include "network/socket.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);
|
_players.emplace_back(socket);
|
||||||
|
return &_players.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::remove_player(BettolaLib::Network::Socket* socket) {
|
void Game::remove_player(unsigned int player_id) {
|
||||||
/*
|
|
||||||
* TODO: We'll need a better way to ident players other than
|
|
||||||
* their socket. We'll match sockets for now though.. -- Falco
|
|
||||||
*/
|
|
||||||
_players.erase(
|
_players.erase(
|
||||||
std::remove_if(_players.begin(), _players.end(),
|
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. */
|
/* this is a sh.t way to compare players. */
|
||||||
return &player.get_socket() == socket;
|
return player.get_id() == player_id;
|
||||||
}),
|
}),
|
||||||
_players.end());
|
_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(),
|
auto it = std::find_if(_players.begin(), _players.end(),
|
||||||
[socket](const Player& player) {
|
[player_id](const Player& player) {
|
||||||
return &player.get_socket() == socket;
|
return player.get_id() == player_id;
|
||||||
});
|
});
|
||||||
if(it != _players.end()) {
|
if(it != _players.end()) {
|
||||||
it->set_position(x, y);
|
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 {
|
class Game {
|
||||||
public:
|
public:
|
||||||
void add_player(BettolaLib::Network::Socket* socket);
|
Player* add_player(BettolaLib::Network::Socket* socket);
|
||||||
void remove_player(BettolaLib::Network::Socket* socket);
|
void remove_player(unsigned int player_id);
|
||||||
void update_player_pos(BettolaLib::Network::Socket* socket, float x, float y);
|
void update_player_pos(unsigned int player_id, float x, float y);
|
||||||
|
void broadcast_game_state(void);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<Player> _players;
|
std::vector<Player> _players;
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
#include "player.h"
|
#include "player.h"
|
||||||
#include "network/socket.h"
|
#include "network/socket.h"
|
||||||
|
|
||||||
Player::Player(BettolaLib::Network::Socket* socket) :
|
unsigned int Player::_next_player_id = 0;
|
||||||
_x(0.0f), _y(0.0f), _socket(socket) {}
|
|
||||||
|
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; }
|
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; }
|
BettolaLib::Network::Socket& get_socket(void) const { return *_socket; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static unsigned int _next_player_id;
|
||||||
|
|
||||||
|
unsigned int _id;
|
||||||
float _x;
|
float _x;
|
||||||
float _y;
|
float _y;
|
||||||
BettolaLib::Network::Socket* _socket;
|
BettolaLib::Network::Socket* _socket;
|
||||||
|
|||||||
42
srv/main.cpp
42
srv/main.cpp
@ -1,4 +1,7 @@
|
|||||||
|
#include <cstddef>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include "bettola/network/socket.h"
|
#include "bettola/network/socket.h"
|
||||||
#include "bettola/network/net_common.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);
|
printf("Bettola Server: Listening on port %hu...\n", BettolaLib::Network::DEFAULT_PORT);
|
||||||
|
|
||||||
|
auto last_time = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
/* Main server loop. */
|
/* Main server loop. */
|
||||||
while(true) {
|
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) {
|
/* TODO:
|
||||||
printf("Bettola Server: Failed to accept client connection.\n");
|
* Accept new connections.
|
||||||
continue; /* try accepting again. */
|
* 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.
|
||||||
printf("Bettola Server: Client connected!\n");
|
* this is also blocking and only handles one client at a time. fix later
|
||||||
|
*/
|
||||||
|
if(client_socket != nullptr) {
|
||||||
while(true) {
|
while(true) {
|
||||||
BettolaLib::Network::MessageHeader header;
|
BettolaLib::Network::MessageHeader header;
|
||||||
ssize_t bytes_received = client_socket->recv(&header, sizeof(header));
|
ssize_t bytes_received = client_socket->recv(&header, sizeof(header));
|
||||||
|
|
||||||
if(bytes_received <= 0) {
|
if(bytes_received <= 0) {
|
||||||
game.remove_player(client_socket);
|
//game.remove_player(new_player->get_id());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,14 +72,19 @@ int main(void) {
|
|||||||
BettolaLib::Network::PlayerPosMessage msg;
|
BettolaLib::Network::PlayerPosMessage msg;
|
||||||
bytes_received = client_socket->recv(&msg, sizeof(msg));
|
bytes_received = client_socket->recv(&msg, sizeof(msg));
|
||||||
if(bytes_received > 0) {
|
if(bytes_received > 0) {
|
||||||
printf("Bettola Server: Received PlayerPosition messgae: x=%.2f, y=%.2f\n",
|
//game.update_player_pos(new_player->get_id(), msg.x, msg.y);
|
||||||
msg.x, msg.y);
|
|
||||||
game.update_player_pos(client_socket, 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. */
|
server_socket.close(); /* Shouldn't reach here. */
|
||||||
printf("=== Bettola Server: Shutting Down ===\n");
|
printf("=== Bettola Server: Shutting Down ===\n");
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user