Server: Implement support for chunk requests

This commit is contained in:
mrkubax10 2023-08-14 11:56:21 +02:00
parent cfa99d24a0
commit 84d93d21ea
8 changed files with 95 additions and 13 deletions

View File

@ -72,6 +72,15 @@ void NetworkPacket::write(uint32_t val) {
m_data.push_back(temp[3]);
}
void NetworkPacket::write(int32_t val) {
char temp[4];
utils::int32_to_bytes(val, temp);
m_data.push_back(temp[0]);
m_data.push_back(temp[1]);
m_data.push_back(temp[2]);
m_data.push_back(temp[3]);
}
void NetworkPacket::write(float val) {
char temp[4];
utils::float_to_bytes(val, temp);
@ -146,6 +155,14 @@ bool NetworkPacket::read(uint32_t& output) {
return true;
}
bool NetworkPacket::read(int32_t& output) {
if(m_reading_offset+4>m_data.size())
return false;
output = utils::bytes_to_int32((const char*)&m_data[m_reading_offset]);
m_reading_offset+=4;
return true;
}
bool NetworkPacket::read(float& output) {
if(m_reading_offset+4>m_data.size())
return false;

View File

@ -47,7 +47,7 @@ namespace polygun::network {
// gameplay packets
PACKET_ACTION,
PACKET_MESSAGE,
PACKET_TO_SERVER_CHUNK_REQUEST,
PACKET_CHUNK,
// node definition packets
PACKET_NODE_DEFINITION,
// resource packets
@ -69,6 +69,7 @@ namespace polygun::network {
void write(uint8_t val);
void write(uint16_t val);
void write(uint32_t val);
void write(int32_t val);
void write(float val);
void write(const std::vector<uint8_t>& val);
void write(const std::string& val);
@ -78,6 +79,7 @@ namespace polygun::network {
bool read(uint8_t& output); // unsigned 8-bit number
bool read(uint16_t& output); // unsigned 16-bit number
bool read(uint32_t& output); // unsigned 32-bit number
bool read(int32_t& output); // signed 32-bit number
bool read(float& output); // float
bool read(std::vector<uint8_t>& output); // unsigned 8-bit number array
bool read(std::string& output); // string

View File

@ -25,6 +25,7 @@ SOFTWARE.
#include <cstring>
#include "common/network/network_packet.hpp"
#include "common/binary_utils.hpp"
#include "common/logger.hpp"
@ -48,7 +49,7 @@ namespace polygun::world {
memset(m_chunk_data, 0, sizeof(m_chunk_data));
}
uint8_t Chunk::to_compressed_data(std::vector<uint8_t>& output) {
uint8_t Chunk::to_compressed_data(std::vector<uint8_t>& output) const {
// Try CHUNK_COMPRESSION_MODE_FILL
const uint16_t match = get_node(glm::vec3ub(0, 0, 0));
bool fill_success = true;
@ -89,7 +90,7 @@ namespace polygun::world {
// If none succeeded use CHUNK_COMPRESSION_MODE_NONE
if(utils::is_little_endian())
output.assign(reinterpret_cast<uint8_t*>(m_chunk_data), reinterpret_cast<uint8_t*>(m_chunk_data)+sizeof(m_chunk_data));
output.assign(reinterpret_cast<const uint8_t*>(m_chunk_data), reinterpret_cast<const uint8_t*>(m_chunk_data)+sizeof(m_chunk_data));
else {
output.resize(sizeof(m_chunk_data));
for(uint16_t i = 0; i<sizeof(m_chunk_data)/2; i++)
@ -140,15 +141,15 @@ namespace polygun::world {
m_chunk_data[pos.z*CHUNK_SIZE*CHUNK_SIZE+pos.y*CHUNK_SIZE+pos.x] = node_to_add;
}
bool Chunk::is_air(const glm::vec3ub& pos) {
bool Chunk::is_air(const glm::vec3ub& pos) const {
return get_node(pos) == 0;
}
uint16_t Chunk::get_node(const glm::vec3ub& pos) {
uint16_t Chunk::get_node(const glm::vec3ub& pos) const {
return m_chunk_data[pos.z*CHUNK_SIZE*CHUNK_SIZE+pos.y*CHUNK_SIZE+pos.x];
}
bool Chunk::is_neighbour_air(const glm::vec3ub& pos) {
bool Chunk::is_neighbour_air(const glm::vec3ub& pos) const {
if (pos.x+1 == CHUNK_SIZE) {
return true;
}
@ -189,4 +190,22 @@ namespace polygun::world {
return false;
}
void Chunk::serialize(network::NetworkPacket& packet) const {
std::vector<uint8_t> compressed_data;
const uint8_t compression_mode = to_compressed_data(compressed_data);
packet.write(compression_mode);
packet.write(compressed_data);
}
bool Chunk::deserialize(network::NetworkPacket& packet) {
uint8_t compression_mode;
std::vector<uint8_t> compressed_data;
if(!packet.read(compression_mode))
return false;
if(!packet.read(compressed_data))
return false;
load_from_compressed_data(reinterpret_cast<char*>(compressed_data.data()), compressed_data.size(), compression_mode);
return true;
}
}

View File

@ -24,6 +24,8 @@ SOFTWARE.
#ifndef POLYGUN_WORLD_CHUNK_HPP
#define POLYGUN_WORLD_CHUNK_HPP
#include "common/network/network_serializable.hpp"
#include <vector>
#include "common/glm_ext.hpp"
@ -35,17 +37,20 @@ namespace polygun::world {
CHUNK_COMPRESSION_MODE_FILL
};
class Chunk final {
class Chunk final : public network::NetworkSerializable {
public:
Chunk();
~Chunk() = default;
uint8_t to_compressed_data(std::vector<uint8_t>& output);
uint8_t to_compressed_data(std::vector<uint8_t>& output) const;
void load_from_compressed_data(const char* data, uint16_t data_size, uint8_t compression_mode);
void add_node(uint16_t node_to_add, const glm::vec3ub& pos);
bool is_air(const glm::vec3ub& pos);
uint16_t get_node(const glm::vec3ub& pos);
bool is_neighbour_air(const glm::vec3ub& pos);
bool is_air(const glm::vec3ub& pos) const;
uint16_t get_node(const glm::vec3ub& pos) const;
bool is_neighbour_air(const glm::vec3ub& pos) const;
virtual void serialize(network::NetworkPacket& packet) const override;
virtual bool deserialize(network::NetworkPacket& packet) override;
static const int CHUNK_SIZE = 32;

View File

@ -34,7 +34,8 @@ Client::Client(std::unique_ptr<polygun::network::NetworkManager> network_manager
m_uuid(0),
m_pos(),
m_join_completed(false),
m_last_activity(time(0))
m_last_activity(time(0)),
m_editmode(false)
{
m_network_manager = std::move(network_manager);
}

View File

@ -47,6 +47,7 @@ namespace polygun::server {
uint32_t get_uuid() const { return m_uuid; }
bool get_join_completed() const { return m_join_completed; }
time_t get_last_activity() const { return m_last_activity; }
bool has_editmode() const { return m_editmode; }
private:
std::unique_ptr<polygun::network::NetworkManager> m_network_manager;
@ -55,6 +56,7 @@ namespace polygun::server {
glm::vec3 m_pos;
bool m_join_completed;
time_t m_last_activity;
bool m_editmode;
};
}

View File

@ -33,6 +33,7 @@ SOFTWARE.
#include <sys/ioctl.h>
#endif
#include "common/math/rect3d.hpp"
#include "common/logger.hpp"
#include "server/command_parser.hpp"
@ -48,7 +49,8 @@ Server::Server(std::atomic<bool>* running_atomic, std::optional<unsigned short>
m_latest_client(),
m_server_socket(new polygun::network::UDPSocket),
m_command_thread(),
m_mod_manager(*this)
m_mod_manager(*this),
m_chunk_manager(*this)
{
LOG_INFO("Starting server");
m_server_socket->bind(port_override.value_or(m_config.m_port));
@ -131,6 +133,8 @@ void Server::run() {
m_clients.push_back(std::move(m_latest_client));
}
}
m_chunk_manager.update();
}
}
@ -201,6 +205,9 @@ bool Server::handle_packet(polygun::network::NetworkPacket& packet, Client* clie
switch(packet.get_id()) {
case polygun::network::NetworkPacketID::PACKET_HANDSHAKE:
return handle_new_player(packet);
case polygun::network::NetworkPacketID::PACKET_CHUNK:
handle_chunk_request(packet, client);
return true;
case polygun::network::NetworkPacketID::PACKET_NODE_DEFINITION:
handle_node_definition(packet, client);
return true;
@ -243,6 +250,32 @@ bool Server::handle_new_player(polygun::network::NetworkPacket& packet) {
return true;
}
void Server::handle_chunk_request(polygun::network::NetworkPacket& packet, Client* client) {
int32_t chunk_x, chunk_y, chunk_z;
packet.read(chunk_x);
packet.read(chunk_y);
packet.read(chunk_z);
network::NetworkPacket out_packet = client->get_connection().create_packet(network::NetworkPacketFlag::FLAG_RELIABLE, network::NetworkPacketID::PACKET_CHUNK);
out_packet.write(chunk_x);
out_packet.write(chunk_y);
out_packet.write(chunk_z);
const math::Rect3D chunk_rect(glm::vec3(chunk_x, chunk_y, chunk_z), glm::vec3(world::Chunk::CHUNK_SIZE));
const math::Rect3D player_view_rect = math::Rect3D::with_center(client->get_position(), glm::vec3(5*world::Chunk::CHUNK_SIZE));
if(player_view_rect.overlaps(chunk_rect)) {
const world::Chunk& chunk = m_chunk_manager.get_chunk(glm::vec3i(chunk_x, chunk_y, chunk_z), client->has_editmode());
out_packet.write(&chunk);
}
else {
// Note: Maybe warn player for possible cheating/ddosing server with chunk requests outside of viewing range
const world::Chunk dummy_chunk;
out_packet.write(&dummy_chunk);
}
client->get_connection().send_packet(out_packet);
}
void Server::handle_node_definition(polygun::network::NetworkPacket& packet, Client* client) {
uint16_t node_id;
if(!packet.read(node_id)) {

View File

@ -31,6 +31,7 @@ SOFTWARE.
#include <optional>
#include "server/client.hpp"
#include "server/chunk_manager.hpp"
#include "server/mod_manager.hpp"
#include "server/server_config.hpp"
#include "common/world/node_def.hpp"
@ -59,12 +60,14 @@ namespace polygun::server {
std::unique_ptr<std::thread> m_command_thread;
ModManager m_mod_manager;
std::map<std::string, world::NodeDef> m_node_defs;
ChunkManager m_chunk_manager;
private:
void command_thread_func();
bool handle_packet(polygun::network::NetworkPacket& packet, Client* client = nullptr);
bool handle_new_player(polygun::network::NetworkPacket& packet);
void handle_chunk_request(polygun::network::NetworkPacket& packet, Client* client);
void handle_node_definition(polygun::network::NetworkPacket& packet, Client* client);
void handle_resource_request(polygun::network::NetworkPacket& packet, Client* client);
void handle_player_disconnected(const Client* client);