Physics and collision system to make players interact with the generated terraine without falling through the world like lemmings. It uses a shared bilinear interpolation function for terrain height for smooth and consistant height queries on the client and server.
111 lines
3.9 KiB
C++
111 lines
3.9 KiB
C++
#include <algorithm>
|
|
#include <netinet/in.h>
|
|
#include <string.h>
|
|
|
|
#include "game.h"
|
|
#include "bettola/math/vec3.h"
|
|
#include "bettola/network/game_state_message.h"
|
|
#include "bettola/network/player_input_message.h"
|
|
#include "bettola/network/tcpsocket.h"
|
|
#include "bettola/network/message.h"
|
|
#include "bettola/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);
|
|
player->set_yaw(msg.yaw);
|
|
Player::InputState input = { msg.up, msg.down, msg.left, msg.right };
|
|
BettolaMath::Vec3 cam_front = { msg.cam_front_x, msg.cam_front_y, msg.cam_front_z };
|
|
player->set_velocity_direction(input, cam_front);
|
|
player->update(msg.dt);
|
|
|
|
float terrain_height = _world.get_height(player->get_position().x,
|
|
player->get_position().z);
|
|
player->apply_gravity_and_collision(terrain_height);
|
|
}
|
|
}
|
|
}
|
|
|
|
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();
|
|
const auto& pos = _players[i]->get_position();
|
|
msg.players[i].x = pos.x;
|
|
msg.players[i].y = pos.y;
|
|
msg.players[i].z = pos.z;
|
|
msg.players[i].yaw = _players[i]->get_yaw();
|
|
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);
|
|
}
|
|
|