bettola/srv/game/game.cpp
Ritchie Cunningham f653c34baf [Change] Switched to an input-based reconcilation
Replaced the previous correction models with a full "Reconciliation by
Replaying Inputs system".
2025-09-14 04:25:10 +01:00

102 lines
3.4 KiB
C++

#include <algorithm>
#include <netinet/in.h>
#include <string.h>
#include "game.h"
#include "network/game_state_message.h"
#include "network/player_input_message.h"
#include "network/tcpsocket.h"
#include "network/message.h"
#include "network/udpsocket.h"
Player* Game::add_player(BettolaLib::Network::TCPSocket* socket) {
_players.push_back(new Player(socket));
return _players.back();
}
void Game::remove_player(unsigned int player_id) {
_players.erase(
std::remove_if(_players.begin(), _players.end(),
[player_id](Player* player) {
if(player->get_id() == player_id) {
delete player;
return true;
}
return false;
}),
_players.end());
}
void Game::process_udp_message(const char* buffer, size_t size, const sockaddr_in& from_addr) {
if(size < sizeof(BettolaLib::Network::MessageHeader)) return;
BettolaLib::Network::MessageHeader header;
memcpy(&header, buffer, sizeof(header));
if(header.type == BettolaLib::Network::MessageType::PlayerInput) {
if(size < sizeof(BettolaLib::Network::MessageHeader)
+ sizeof(BettolaLib::Network::PlayerInputMessage)) return;
BettolaLib::Network::PlayerInputMessage msg;
memcpy(&msg, buffer + sizeof(header), sizeof(msg));
Player* player = get_player_by_id(msg.player_id);
if(player) {
if(!player->has_udp_addr()) {
printf("Bettola Server: Associated UDP address for player %u\n", msg.player_id);
player->set_udp_addr(from_addr);
}
player->set_last_processed_sequence(msg.sequence_number);
float dir_x = (msg.right ? 1.0f : 0.0f) - (msg.left ? 1.0f : 0.0f);
float dir_y = (msg.down ? 1.0f : 0.0f) - (msg.up ? 1.0f : 0.0f);
player->set_velocity_direction(dir_x, dir_y);
player->update(msg.dt);
}
}
}
void Game::broadcast_game_state(BettolaLib::Network::UDPSocket& udp_socket) {
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();
msg.players[i].x = _players[i]->get_x();
msg.players[i].y = _players[i]->get_y();
msg.players[i].last_processed_sequence = _players[i]->get_last_processed_sequence();
}
BettolaLib::Network::MessageHeader header;
header.type = BettolaLib::Network::MessageType::GameState;
header.size = sizeof(msg);
for(const auto& player : _players) {
if(player->has_udp_addr()) {
char buffer[sizeof(header) + sizeof(msg)];
memcpy(buffer, &header, sizeof(header));
memcpy(buffer + sizeof(header), &msg, sizeof(msg));
udp_socket.send_to(buffer, sizeof(buffer), player->get_udp_addr());
}
}
}
Player* Game::get_player_by_socket(const BettolaLib::Network::TCPSocket* socket) {
auto it = std::find_if(_players.begin(), _players.end(),
[socket](const Player* player) {
return &player->get_socket() == socket;
});
return(it != _players.end() ? *it : nullptr);
}
Player* Game::get_player_by_id(unsigned int id) {
auto it = std::find_if(_players.begin(), _players.end(),
[id](const Player* player) {
return player->get_id() == id;
});
return(it != _players.end() ? *it : nullptr);
}