feat: Implement multiplayer functionality.
- Server can handle multiple clients simultaneously. - Client can see other players in the game. - Server broadcasts the game state to all clients. - Client receives the game state and renders the other players. - Server assigns a unique ID to each player. - Client receives its player ID form the server. - Server handles client disconnections.. Kinda... Server is ignoring SIGPIPE signal. - Server and client signals are non-blocking. - Moved player objects off the stack and onto the heap.
This commit is contained in:
parent
39a06147c8
commit
5944663017
@ -7,6 +7,7 @@ enum class MessageType : unsigned char {
|
|||||||
PlayerPosition,
|
PlayerPosition,
|
||||||
PlayerState,
|
PlayerState,
|
||||||
GameState,
|
GameState,
|
||||||
|
PlayerId,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MessageHeader {
|
struct MessageHeader {
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <cerrno>
|
||||||
|
|
||||||
#include "bettola/network/socket.h"
|
#include "bettola/network/socket.h"
|
||||||
#include "bettola/network/net_common.h"
|
#include "bettola/network/net_common.h"
|
||||||
@ -34,11 +35,6 @@ bool Socket::create(void) {
|
|||||||
perror("fcntl F_GETFL failed.");
|
perror("fcntl F_GETFL failed.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(fcntl(_sockfd, F_SETFL, flags & ~O_NONBLOCK) == -1) {
|
|
||||||
perror("fcntl F_SETFL O_NONBLOCK failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,7 +70,8 @@ Socket* Socket::accept(void) {
|
|||||||
socklen_t client_len = sizeof(client_addr);
|
socklen_t client_len = sizeof(client_addr);
|
||||||
int client_sockfd = ::accept(_sockfd, (struct sockaddr*)&client_addr, &client_len);
|
int client_sockfd = ::accept(_sockfd, (struct sockaddr*)&client_addr, &client_len);
|
||||||
if(client_sockfd == -1) {
|
if(client_sockfd == -1) {
|
||||||
perror("Socket accept failed.");
|
if(errno != EWOULDBLOCK && errno != EAGAIN)
|
||||||
|
perror("Socket accept failed.");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,7 +94,7 @@ bool Socket::connect(const std::string& ip_address, unsigned short port) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(::connect(_sockfd, (struct sockaddr*)&_address, sizeof(_address)) == -1) {
|
if(::connect(_sockfd, (struct sockaddr*)&_address, sizeof(_address)) < 0) {
|
||||||
fprintf(stderr, "Socket::connect() failed for sockfd %d with errno %d: %s\n", _sockfd,
|
fprintf(stderr, "Socket::connect() failed for sockfd %d with errno %d: %s\n", _sockfd,
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
perror("Connection failed.");
|
perror("Connection failed.");
|
||||||
@ -117,7 +114,7 @@ ssize_t Socket::send(const void* buffer, size_t length) {
|
|||||||
|
|
||||||
ssize_t Socket::recv(void* buffer, size_t length) {
|
ssize_t Socket::recv(void* buffer, size_t length) {
|
||||||
ssize_t bytes_received = ::recv(_sockfd, buffer, length, 0);
|
ssize_t bytes_received = ::recv(_sockfd, buffer, length, 0);
|
||||||
if(bytes_received == -1) {
|
if(bytes_received == -1 && errno != EWOULDBLOCK && errno != EAGAIN) {
|
||||||
perror("Receive failed.");
|
perror("Receive failed.");
|
||||||
}
|
}
|
||||||
return bytes_received;
|
return bytes_received;
|
||||||
|
|||||||
@ -1,17 +1,22 @@
|
|||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
#include <SDL3/SDL_error.h>
|
#include <SDL3/SDL_error.h>
|
||||||
|
#include <algorithm>
|
||||||
/* FINE LSP!! I'll play your games!!!! */
|
/* FINE LSP!! I'll play your games!!!! */
|
||||||
#include <SDL3/SDL_events.h> /* ~HJAPPY?!?!?! */
|
#include <SDL3/SDL_events.h> /* ~HJAPPY?!?!?! */
|
||||||
#include <SDL3/SDL_stdinc.h>
|
#include <SDL3/SDL_stdinc.h>
|
||||||
#include <SDL3/SDL_timer.h>
|
#include <SDL3/SDL_timer.h>
|
||||||
#include <SDL3/SDL_video.h>
|
#include <SDL3/SDL_video.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <cstddef>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "bettola.h"
|
#include "bettola.h"
|
||||||
#include "bettola/network/socket.h"
|
#include "bettola/network/socket.h"
|
||||||
#include "bettola/network/net_common.h"
|
#include "bettola/network/net_common.h"
|
||||||
|
#include "math/mat4.h"
|
||||||
#include "network/message.h"
|
#include "network/message.h"
|
||||||
|
#include "network/game_state_message.h"
|
||||||
#include "network/player_pos_message.h"
|
#include "network/player_pos_message.h"
|
||||||
|
|
||||||
/* Dacav's resolution ;) */
|
/* Dacav's resolution ;) */
|
||||||
@ -23,7 +28,8 @@ Bettola::Bettola(void) :
|
|||||||
_window(nullptr),
|
_window(nullptr),
|
||||||
_gl_context(nullptr),
|
_gl_context(nullptr),
|
||||||
_vao(0),
|
_vao(0),
|
||||||
_vbo(0) {}
|
_vbo(0),
|
||||||
|
_our_player_id(0) {}
|
||||||
|
|
||||||
Bettola::~Bettola(void) {
|
Bettola::~Bettola(void) {
|
||||||
if(_gl_context) {
|
if(_gl_context) {
|
||||||
@ -97,6 +103,28 @@ int Bettola::run(void) {
|
|||||||
network_time = 0.0;
|
network_time = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(_our_player_id == 0) {
|
||||||
|
BettolaLib::Network::MessageHeader id_header;
|
||||||
|
ssize_t id_bytes_received = _client_socket.recv(&id_header, sizeof(id_header));
|
||||||
|
if(id_bytes_received > 0 && id_header.type == BettolaLib::Network::MessageType::PlayerId) {
|
||||||
|
_client_socket.recv(&_our_player_id, sizeof(_our_player_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
BettolaLib::Network::MessageHeader header;
|
||||||
|
ssize_t bytes_received = _client_socket.recv(&header, sizeof(header));
|
||||||
|
if(bytes_received <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(header.type == BettolaLib::Network::MessageType::GameState) {
|
||||||
|
BettolaLib::Network::GameStateMessage msg;
|
||||||
|
if(_client_socket.recv(&msg, sizeof(msg)) > 0) {
|
||||||
|
update_remote_players(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
process_events();
|
process_events();
|
||||||
update(delta_time);
|
update(delta_time);
|
||||||
render();
|
render();
|
||||||
@ -171,9 +199,50 @@ void Bettola::render(void) {
|
|||||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
|
|
||||||
|
/* Render remote players. */
|
||||||
|
for(const auto& remote_player : _remote_players) {
|
||||||
|
BettolaMath::Mat4 remote_trans_matrix =
|
||||||
|
BettolaMath::Mat4::translation(remote_player.get_x(),
|
||||||
|
remote_player.get_y(),
|
||||||
|
0.0f);
|
||||||
|
|
||||||
|
BettolaMath::Mat4 remote_scale_matrix =
|
||||||
|
/* Assuming remote players have same size as local player. */
|
||||||
|
BettolaMath::Mat4::scale(50.0f, 50.0f, 1.0f);
|
||||||
|
|
||||||
|
BettolaMath::Mat4 remote_model = remote_trans_matrix.multiply(remote_scale_matrix);
|
||||||
|
|
||||||
|
glUniformMatrix4fv(model_loc, 1, GL_FALSE, remote_model.get_ptr());
|
||||||
|
|
||||||
|
glBindVertexArray(_vao);
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
|
glBindVertexArray(0);
|
||||||
|
}
|
||||||
|
|
||||||
SDL_GL_SwapWindow(_window);
|
SDL_GL_SwapWindow(_window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Bettola::update_remote_players(const BettolaLib::Network::GameStateMessage& msg) {
|
||||||
|
for(unsigned int i = 0; i < msg.num_players; ++i) {
|
||||||
|
const auto& player_state = msg.players[i];
|
||||||
|
|
||||||
|
auto it = std::find_if(_remote_players.begin(), _remote_players.end(),
|
||||||
|
[player_state](const RemotePlayer& remote_player) {
|
||||||
|
return remote_player.get_id() == player_state.player_id;
|
||||||
|
});
|
||||||
|
|
||||||
|
if(it != _remote_players.end()) {
|
||||||
|
it->set_position(player_state.x, player_state.y);
|
||||||
|
} else {
|
||||||
|
/* We don't want to add ourselves as a remote player! */
|
||||||
|
if(player_state.player_id != _our_player_id) {
|
||||||
|
_remote_players.emplace_back(player_state.player_id, player_state.x,
|
||||||
|
player_state.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Bettola::init_sdl(void) {
|
bool Bettola::init_sdl(void) {
|
||||||
if(!SDL_Init(SDL_INIT_VIDEO)) {
|
if(!SDL_Init(SDL_INIT_VIDEO)) {
|
||||||
fprintf(stderr, "Failed to iniit SDL! SDL ERROR: %s\n", SDL_GetError());
|
fprintf(stderr, "Failed to iniit SDL! SDL ERROR: %s\n", SDL_GetError());
|
||||||
@ -257,6 +326,14 @@ bool Bettola::init_client_connection(void) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set the socket to non-blocking. */
|
||||||
|
int flags = fcntl(_client_socket.get_sockfd(), F_GETFL, 0);
|
||||||
|
if(flags == -1) {
|
||||||
|
perror("fcntl F_GETFL failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fcntl(_client_socket.get_sockfd(), F_SETFL, flags | O_NONBLOCK);
|
||||||
|
|
||||||
printf("Bettola Client: Connected to server at 127.0.01.:%hu\n", BettolaLib::Network::DEFAULT_PORT);
|
printf("Bettola Client: Connected to server at 127.0.01.:%hu\n", BettolaLib::Network::DEFAULT_PORT);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "graphics/shader.h"
|
#include "graphics/shader.h"
|
||||||
#include "game/player.h"
|
#include "game/player.h"
|
||||||
|
#include "game/remote_player.h"
|
||||||
#include "math/mat4.h"
|
#include "math/mat4.h"
|
||||||
#include "bettola/network/socket.h"
|
#include "bettola/network/socket.h"
|
||||||
|
#include "network/game_state_message.h"
|
||||||
|
|
||||||
class Bettola {
|
class Bettola {
|
||||||
public:
|
public:
|
||||||
@ -18,6 +21,7 @@ private:
|
|||||||
void process_events(void);
|
void process_events(void);
|
||||||
void update(double dt);
|
void update(double dt);
|
||||||
void render(void);
|
void render(void);
|
||||||
|
void update_remote_players(const BettolaLib::Network::GameStateMessage& msg);
|
||||||
|
|
||||||
bool init_sdl(void);
|
bool init_sdl(void);
|
||||||
bool init_glew(void);
|
bool init_glew(void);
|
||||||
@ -37,6 +41,7 @@ private:
|
|||||||
|
|
||||||
bool _is_running;
|
bool _is_running;
|
||||||
|
|
||||||
|
unsigned int _our_player_id;
|
||||||
SDL_Window* _window;
|
SDL_Window* _window;
|
||||||
SDL_GLContext _gl_context;
|
SDL_GLContext _gl_context;
|
||||||
|
|
||||||
@ -47,5 +52,6 @@ private:
|
|||||||
BettolaMath::Mat4 _projection;
|
BettolaMath::Mat4 _projection;
|
||||||
Player _player;
|
Player _player;
|
||||||
InputState _input;
|
InputState _input;
|
||||||
|
std::vector<RemotePlayer> _remote_players;
|
||||||
BettolaLib::Network::Socket _client_socket;
|
BettolaLib::Network::Socket _client_socket;
|
||||||
};
|
};
|
||||||
|
|||||||
8
src/game/remote_player.cpp
Normal file
8
src/game/remote_player.cpp
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#include "remote_player.h"
|
||||||
|
|
||||||
|
RemotePlayer::RemotePlayer(unsigned int id, float x, float y) :
|
||||||
|
_id(id), _x(x), _y(y) {}
|
||||||
|
|
||||||
|
void RemotePlayer::set_position(float x, float y) {
|
||||||
|
_x = x; _y = y;
|
||||||
|
}
|
||||||
17
src/game/remote_player.h
Normal file
17
src/game/remote_player.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
class RemotePlayer {
|
||||||
|
public:
|
||||||
|
RemotePlayer(unsigned int id, float x, float y);
|
||||||
|
|
||||||
|
void set_position(float x, float y);
|
||||||
|
|
||||||
|
unsigned int get_id(void) const { return _id; }
|
||||||
|
float get_x(void) const { return _x; }
|
||||||
|
float get_y(void) const { return _y; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned int _id;
|
||||||
|
float _x;
|
||||||
|
float _y;
|
||||||
|
};
|
||||||
@ -6,27 +6,26 @@
|
|||||||
#include "network/message.h"
|
#include "network/message.h"
|
||||||
|
|
||||||
Player* Game::add_player(BettolaLib::Network::Socket* socket) {
|
Player* Game::add_player(BettolaLib::Network::Socket* socket) {
|
||||||
_players.emplace_back(socket);
|
_players.push_back(new Player(socket));
|
||||||
return &_players.back();
|
return _players.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::remove_player(unsigned int player_id) {
|
void Game::remove_player(unsigned int player_id) {
|
||||||
_players.erase(
|
_players.erase(
|
||||||
std::remove_if(_players.begin(), _players.end(),
|
std::remove_if(_players.begin(), _players.end(),
|
||||||
[player_id](const Player& player) {
|
[player_id](const Player* player) {
|
||||||
/* this is a sh.t way to compare players. */
|
return player->get_id() == player_id;
|
||||||
return player.get_id() == player_id;
|
|
||||||
}),
|
}),
|
||||||
_players.end());
|
_players.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::update_player_pos(unsigned int player_id, 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(),
|
||||||
[player_id](const Player& player) {
|
[player_id](const Player* player) {
|
||||||
return player.get_id() == player_id;
|
return player->get_id() == player_id;
|
||||||
});
|
});
|
||||||
if(it != _players.end()) {
|
if(it != _players.end()) {
|
||||||
it->set_position(x, y);
|
(*it)->set_position(x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,9 +34,9 @@ void Game::broadcast_game_state(void) {
|
|||||||
msg.num_players = _players.size();
|
msg.num_players = _players.size();
|
||||||
|
|
||||||
for(size_t i = 0; i < _players.size(); ++i) {
|
for(size_t i = 0; i < _players.size(); ++i) {
|
||||||
msg.players[i].player_id = _players[i].get_id();
|
msg.players[i].player_id = _players[i]->get_id();
|
||||||
msg.players[i].x = _players[i].get_x();
|
msg.players[i].x = _players[i]->get_x();
|
||||||
msg.players[i].y = _players[i].get_y();
|
msg.players[i].y = _players[i]->get_y();
|
||||||
}
|
}
|
||||||
|
|
||||||
BettolaLib::Network::MessageHeader header;
|
BettolaLib::Network::MessageHeader header;
|
||||||
@ -45,9 +44,23 @@ void Game::broadcast_game_state(void) {
|
|||||||
header.size = sizeof(msg);
|
header.size = sizeof(msg);
|
||||||
|
|
||||||
for(const auto& player : _players) {
|
for(const auto& player : _players) {
|
||||||
BettolaLib::Network::Socket& socket = player.get_socket();
|
BettolaLib::Network::Socket& socket = player->get_socket();
|
||||||
socket.send(&header, sizeof(header));
|
/* Just quick fix the server crash for now. */
|
||||||
socket.send(&msg, sizeof(msg));
|
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.. */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Player* Game::get_player_by_socket(BettolaLib::Network::Socket* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,8 @@ public:
|
|||||||
void remove_player(unsigned int player_id);
|
void remove_player(unsigned int player_id);
|
||||||
void update_player_pos(unsigned int player_id, float x, float y);
|
void update_player_pos(unsigned int player_id, float x, float y);
|
||||||
void broadcast_game_state(void);
|
void broadcast_game_state(void);
|
||||||
|
Player* get_player_by_socket(BettolaLib::Network::Socket* socket);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<Player> _players;
|
std::vector<Player*> _players;
|
||||||
};
|
};
|
||||||
|
|||||||
77
srv/main.cpp
77
srv/main.cpp
@ -2,6 +2,9 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
#include "bettola/network/socket.h"
|
#include "bettola/network/socket.h"
|
||||||
#include "bettola/network/net_common.h"
|
#include "bettola/network/net_common.h"
|
||||||
@ -11,6 +14,9 @@
|
|||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
Game game;
|
Game game;
|
||||||
|
std::vector<BettolaLib::Network::Socket*> client_sockets;
|
||||||
|
|
||||||
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
|
||||||
printf("=== Bettola Server: Starting ===\n");
|
printf("=== Bettola Server: Starting ===\n");
|
||||||
|
|
||||||
@ -36,46 +42,81 @@ 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);
|
||||||
|
|
||||||
|
/* Set the server socket to non-blocking. */
|
||||||
|
int flags = fcntl(server_socket.get_sockfd(), F_GETFL, 0);
|
||||||
|
if(flags == -1) {
|
||||||
|
perror("fcntl F_GETFL, failed.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
fcntl(server_socket.get_sockfd(), F_SETFL, flags | O_NONBLOCK);
|
||||||
|
|
||||||
auto last_time = std::chrono::high_resolution_clock::now();
|
auto last_time = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
/* Main server loop. */
|
/* Main server loop. */
|
||||||
while(true) {
|
while(true) {
|
||||||
auto current_time = std::chrono::high_resolution_clock::now();
|
/* Accept new connections. */
|
||||||
auto delta_time = std::chrono::duration_cast<std::chrono::duration<double>>
|
|
||||||
(current_time-last_time).count();
|
|
||||||
|
|
||||||
/* TODO:
|
|
||||||
* Accept new connections.
|
|
||||||
* This is blocking.. Will fix later.
|
|
||||||
*/
|
|
||||||
BettolaLib::Network::Socket* client_socket = server_socket.accept();
|
BettolaLib::Network::Socket* client_socket = server_socket.accept();
|
||||||
if(client_socket != nullptr) {
|
if(client_socket != nullptr) {
|
||||||
Player* new_player = game.add_player(client_socket);
|
Player* new_player = game.add_player(client_socket);
|
||||||
printf("Bettola Server: Client connected! Player ID: %u\n", new_player->get_id());
|
printf("Bettola Server: Client connected! Player ID: %u\n", new_player->get_id());
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
fcntl(client_socket->get_sockfd(), F_SETFL, client_flags | O_NONBLOCK);
|
||||||
|
|
||||||
|
client_sockets.push_back(client_socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO:
|
/* Process messages from clients. */
|
||||||
* Process messages from clients.
|
for(auto it = client_sockets.begin(); it != client_sockets.end();) {
|
||||||
* this is also blocking and only handles one client at a time. fix later
|
BettolaLib::Network::Socket* client = *it;
|
||||||
*/
|
bool client_disconnected = false;
|
||||||
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));
|
/* Non-blocking. */
|
||||||
|
ssize_t bytes_received = client->recv(&header, sizeof(header));
|
||||||
|
|
||||||
if(bytes_received <= 0) {
|
if(bytes_received == 0) {
|
||||||
//game.remove_player(new_player->get_id());
|
client_disconnected = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(bytes_received < 0) {
|
||||||
|
/* No data to read.. */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(header.type == BettolaLib::Network::MessageType::PlayerPosition) {
|
if(header.type == BettolaLib::Network::MessageType::PlayerPosition) {
|
||||||
BettolaLib::Network::PlayerPosMessage msg;
|
BettolaLib::Network::PlayerPosMessage msg;
|
||||||
bytes_received = client_socket->recv(&msg, sizeof(msg));
|
bytes_received = client->recv(&msg, sizeof(msg));
|
||||||
if(bytes_received > 0) {
|
if(bytes_received > 0) {
|
||||||
//game.update_player_pos(new_player->get_id(), msg.x, msg.y);
|
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);
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Broadcase game state. */
|
/* Broadcase game state. */
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user