feat(world): add player-based chunk loading and UUID support

Restructure world generation to trigger chunk loading based on player
movement. Replace player name with UUID for identification. Implement
chunk request/response protocol. Improve thread management for gen
thread.
This commit is contained in:
2026-06-24 14:51:48 +08:00
parent 6f39ff771d
commit 9d33b240c6
11 changed files with 222 additions and 83 deletions

View File

@@ -55,4 +55,10 @@ inline ChunkPos get_chunk_pos(int world_x, int world_z) {
return {chunk_x, chunk_z}; return {chunk_x, chunk_z};
} }
inline float distance2(const ChunkPos& a, const ChunkPos& b) {
float dx = static_cast<float>(a.x) - b.x;
float dz = static_cast<float>(a.z) - b.z;
return dx * dx + dz * dz;
}
} // namespace Cubed } // namespace Cubed

View File

@@ -1,30 +1,48 @@
#pragma once #pragma once
#include "packet.pb.h" #include "packet.pb.h" // IWYU pragma: keep
#include <netinet/in.h> #include <netinet/in.h>
#include <type_traits> #include <type_traits>
#include <utility>
namespace Cubed { namespace Cubed {
constexpr int HEADER_LEN = 8; constexpr int HEADER_LEN = 8;
using Packet = std::shared_ptr<std::vector<uint8_t>>; using Packet = std::shared_ptr<std::vector<uint8_t>>;
enum class PacketEnum {
LOGIN_REQ = 1001,
LOGIN_RSP = 1002,
PLAYER_INFO = 2001,
PLAYER_POS = 2002,
CHUNK_DATA_REQ = 3001,
CHUNK_DATA_RSP = 3002,
PING = 9001,
PONG = 9002
};
template <typename> struct always_false : std::false_type {}; // NOLINT template <typename> struct always_false : std::false_type {}; // NOLINT
template <typename T> constexpr uint16_t get_packet_id() { template <typename T> constexpr uint16_t get_packet_id() {
using enum PacketEnum;
using std::is_same_v; using std::is_same_v;
using U = std::decay_t<T>; using U = std::decay_t<T>;
constexpr auto& to_num = std::to_underlying<PacketEnum>;
if constexpr (is_same_v<U, LoginReq>) { if constexpr (is_same_v<U, LoginReq>) {
return 1001; return to_num(LOGIN_REQ);
} else if constexpr (is_same_v<U, LoginRsp>) { } else if constexpr (is_same_v<U, LoginRsp>) {
return 1002; return to_num(LOGIN_RSP);
} else if constexpr (is_same_v<U, PlayerInfo>) { } else if constexpr (is_same_v<U, PlayerInfo>) {
return 2001; return to_num(PLAYER_INFO);
} else if constexpr (is_same_v<U, PlayerPos>) { } else if constexpr (is_same_v<U, PlayerPos>) {
return 2002; return to_num(PLAYER_POS);
} else if constexpr (is_same_v<U, ChunkData>) { } else if constexpr (is_same_v<U, ChunkDataReq>) {
return 3001; return to_num(CHUNK_DATA_REQ);
} else if constexpr (is_same_v<U, ChunkDataRsp>) {
return to_num(CHUNK_DATA_RSP);
} else if constexpr (is_same_v<U, Ping>) { } else if constexpr (is_same_v<U, Ping>) {
return 9001; return to_num(PING);
} else if (is_same_v<U, Pong>) { } else if (is_same_v<U, Pong>) {
return 9002; return to_num(PONG);
} else { } else {
static_assert(always_false<U>::value, "Unkonw Type"); static_assert(always_false<U>::value, "Unkonw Type");
} }

View File

@@ -48,7 +48,7 @@ public:
unsigned seed() const; unsigned seed() const;
BiomeConditions& conditions(); BiomeConditions& conditions();
bool& has_cave(); bool& has_cave();
const OptionalBlockVectorArray& get_neightbor_blocks() const;
static int index(int x, int y, int z); static int index(int x, int y, int z);
static int index(const glm::vec3& pos); static int index(const glm::vec3& pos);
@@ -69,7 +69,7 @@ private:
HeightMapArray m_heightmap; HeightMapArray m_heightmap;
// the index is a array of block id // the index is a array of block id
std::vector<BlockType> m_blocks; std::vector<BlockType> m_blocks;
OptionalBlockVectorArray m_neightbor_blocks;
float frequency = 0.01f; float frequency = 0.01f;
float height = 80; float height = 80;
unsigned m_seed = 0; unsigned m_seed = 0;

View File

@@ -1,17 +1,24 @@
#pragma once #pragma once
#include "Cubed/gameplay/chunk_pos.hpp"
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <string> #include <string>
#include <string_view> #include <string_view>
namespace Cubed { namespace Cubed {
class ServerWorld;
class ServerPlayer { class ServerPlayer {
public: public:
explicit ServerPlayer(std::string_view); ServerPlayer(std::string_view name, std::string_view uuid,
ServerWorld& m_world);
const glm::vec3& get_pos() const; const glm::vec3& get_pos() const;
const std::string& get_name() const; const std::string& get_name() const;
void update_pos(float x, float y, float z); void update_pos(float x, float y, float z);
private: private:
std::string m_name; std::string m_name;
std::string m_uuid;
glm::vec3 m_pos{0.0f}; glm::vec3 m_pos{0.0f};
ServerWorld& m_world;
ChunkPos m_last_chunk_pos{0, 0};
}; };
} // namespace Cubed } // namespace Cubed

View File

@@ -11,6 +11,7 @@
#include <future> #include <future>
#include <shared_mutex> #include <shared_mutex>
#include <tbb/concurrent_hash_map.h> #include <tbb/concurrent_hash_map.h>
#include <tbb/concurrent_unordered_map.h>
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
#include <utility> #include <utility>
@@ -21,10 +22,10 @@ class ServerWorld {
public: public:
ServerWorld(); ServerWorld();
~ServerWorld(); ~ServerWorld();
void player_join(const std::string& name); void player_join(std::string_view name, std::string_view uuid);
void player_exit(const std::string& name); void player_exit(const std::string& name);
void init_world(); void init_world();
void need_gen(); void need_gen(std::optional<std::string> uuid);
void update(); void update();
void hot_reload(); void hot_reload();
@@ -64,10 +65,12 @@ public:
void set_block(const glm::ivec3& block_pos, unsigned id); void set_block(const glm::ivec3& block_pos, unsigned id);
void sync_player_pos(const std::string& name, float x, float y, float z); void sync_player_pos(const std::string& uuid, float x, float y, float z);
void handle_player_login(const std::string& player_name, void handle_player_login(const std::string& player_name,
std::shared_ptr<Session> session); std::shared_ptr<Session> session);
glm::vec3 get_player_pos(const std::string& name) const; glm::vec3 get_player_pos(const std::string& uuid) const;
void handle_chunk_req(const std::string& uuid, ChunkPos pos);
private: private:
enum class ChunkLoadStyle { RANDOM, CENTER }; enum class ChunkLoadStyle { RANDOM, CENTER };
@@ -77,10 +80,15 @@ private:
}; };
using ChunkHashMap = using ChunkHashMap =
std::unordered_map<ChunkPos, ServerChunk, ChunkPos::Hash>; std::unordered_map<ChunkPos, ServerChunk, ChunkPos::Hash>;
using PlayerHashMap = std::unordered_map<std::string, ServerPlayer>; using PlayerHashMap =
tbb::concurrent_unordered_map<std::string, ServerPlayer>;
using PendingChunkHashMap = using PendingChunkHashMap =
std::unordered_map<ChunkPos, PendingChunk, ChunkPos::Hash>; std::unordered_map<ChunkPos, PendingChunk, ChunkPos::Hash>;
using ChunkPosSet = std::unordered_set<ChunkPos, ChunkPos::Hash>; using ChunkPosSet = std::unordered_set<ChunkPos, ChunkPos::Hash>;
using PlayerSessionMap =
tbb::concurrent_hash_map<std::string, std::shared_ptr<Session>>;
using session_acc = PlayerSessionMap::accessor;
using session_cacc = PlayerSessionMap::const_accessor;
PlayerHashMap m_players; PlayerHashMap m_players;
ChunkHashMap m_chunks; ChunkHashMap m_chunks;
// Can only be used in the gen thread // Can only be used in the gen thread
@@ -90,10 +98,8 @@ private:
CaveCarver m_cave_carcer; CaveCarver m_cave_carcer;
RiverWorm m_river_worm; RiverWorm m_river_worm;
std::thread m_gen_thread; std::jthread m_gen_thread;
std::thread m_server_thread; std::jthread m_server_thread;
std::stop_source m_server_stop_source;
std::atomic<bool> m_chunk_gen_finished{false}; std::atomic<bool> m_chunk_gen_finished{false};
std::atomic<bool> m_could_gen{true}; std::atomic<bool> m_could_gen{true};
@@ -101,7 +107,6 @@ private:
std::atomic<bool> m_need_gen_chunk{false}; std::atomic<bool> m_need_gen_chunk{false};
std::atomic<bool> m_is_rebuilding{false}; std::atomic<bool> m_is_rebuilding{false};
std::atomic<int> m_rendering_distance{24}; std::atomic<int> m_rendering_distance{24};
std::atomic<int> m_pool_threads{0}; std::atomic<int> m_pool_threads{0};
std::atomic<int> m_max_threads{1}; std::atomic<int> m_max_threads{1};
@@ -112,26 +117,27 @@ private:
std::shared_mutex m_chunks_mutex; std::shared_mutex m_chunks_mutex;
std::shared_mutex m_new_chunk_mutex; std::shared_mutex m_new_chunk_mutex;
std::mutex m_gen_signal_mutex; std::mutex m_need_gen_queue_mutex;
std::condition_variable m_gen_cv; std::condition_variable m_gen_cv;
std::deque<std::string> m_need_gen_queue;
std::atomic<std::shared_ptr<ThreadPool>> m_gen_thread_pool; std::atomic<std::shared_ptr<ThreadPool>> m_gen_thread_pool;
std::atomic<ChunkLoadStyle> m_chunk_load_style{ChunkLoadStyle::RANDOM}; std::atomic<ChunkLoadStyle> m_chunk_load_style{ChunkLoadStyle::RANDOM};
std::optional<std::string> m_request_gen_name = std::nullopt; // key = uuid
PlayerSessionMap m_player_session;
tbb::concurrent_hash_map<std::string, std::shared_ptr<Session>> tbb::concurrent_hash_map<std::string, std::string> m_uuid_to_name;
m_player_session;
void init_chunks(); void init_chunks();
void gen_chunks_internal(); void gen_chunks_internal(std::optional<std::string> uuid);
void compute_required_chunks(ChunkPosSet& required_chunks); void compute_required_chunks(ChunkPosSet& required_chunks,
const std::optional<std::string>& uuid);
void sync_and_collect_missing_chunks(std::vector<ChunkPos>&, void sync_and_collect_missing_chunks(std::vector<ChunkPos>&,
const ChunkPosSet&); const ChunkPosSet&);
void submit_new_chunks(); void submit_new_chunks(const std::optional<std::string>& uuid);
void poll_finished_chunks(); void poll_finished_chunks();
void wait_all_chunk_tasks(); void wait_all_chunk_tasks();
}; };

View File

@@ -156,11 +156,10 @@ void ServerChunk::gen_chunk() {
gen_phase_two(); gen_phase_two();
gen_phase_three(); gen_phase_three();
OptionalBlockVectorArray neightbor_blocks;
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
neightbor_blocks[i] = neighbor[i].get_chunk_blocks(); m_neightbor_blocks[i] = neighbor[i].get_chunk_blocks();
} }
gen_phase_four(neightbor_blocks); gen_phase_four(m_neightbor_blocks);
gen_phase_five(); gen_phase_five();
} }
// Logger::info("Cross Sum {}", m_cross_vertices_sum.load()); // Logger::info("Cross Sum {}", m_cross_vertices_sum.load());
@@ -169,6 +168,10 @@ bool ServerChunk::is_temp_chunk() const { return m_temp_chunk.load(); }
bool& ServerChunk::has_cave() { return m_has_cave; } bool& ServerChunk::has_cave() { return m_has_cave; }
const OptionalBlockVectorArray& ServerChunk::get_neightbor_blocks() const {
return m_neightbor_blocks;
}
void ServerChunk::set_chunk_block(int index, unsigned id) { void ServerChunk::set_chunk_block(int index, unsigned id) {
m_blocks[index] = id; m_blocks[index] = id;
} }

View File

@@ -1,10 +1,18 @@
#include "Cubed/gameplay/server_player.hpp" #include "Cubed/gameplay/server_player.hpp"
#include "Cubed/gameplay/server_world.hpp"
namespace Cubed { namespace Cubed {
ServerPlayer::ServerPlayer(std::string_view name) : m_name(name) {} ServerPlayer::ServerPlayer(std::string_view name, std::string_view uuid,
ServerWorld& world)
: m_name(name), m_uuid(uuid), m_world(world) {}
const glm::vec3& ServerPlayer::get_pos() const { return m_pos; } const glm::vec3& ServerPlayer::get_pos() const { return m_pos; }
const std::string& ServerPlayer::get_name() const { return m_name; } const std::string& ServerPlayer::get_name() const { return m_name; }
void ServerPlayer::update_pos(float x, float y, float z) { void ServerPlayer::update_pos(float x, float y, float z) {
m_pos = glm::vec3{x, y, z}; m_pos = glm::vec3{x, y, z};
ChunkPos chunk_pos = get_chunk_pos(x, z);
float dist = distance2(chunk_pos, m_last_chunk_pos);
if (dist > 2) {
m_world.need_gen(m_uuid);
}
} }
} // namespace Cubed } // namespace Cubed

View File

@@ -5,6 +5,7 @@
#include "Cubed/gameplay/session.hpp" #include "Cubed/gameplay/session.hpp"
#include "Cubed/tools/cubed_assert.hpp" #include "Cubed/tools/cubed_assert.hpp"
#include "Cubed/tools/log.hpp" #include "Cubed/tools/log.hpp"
#include "Cubed/tools/uuid.hpp"
#include <utility> #include <utility>
using namespace std::chrono; using namespace std::chrono;
@@ -58,12 +59,12 @@ void ServerWorld::init_chunks() {
} }
} }
void ServerWorld::gen_chunks_internal() { void ServerWorld::gen_chunks_internal(std::optional<std::string> uuid) {
// Logger::info("gen_chunks_internal"); // Logger::info("gen_chunks_internal");
m_chunk_gen_finished = false; m_chunk_gen_finished = false;
ChunkPosSet required_chunks; ChunkPosSet required_chunks;
compute_required_chunks(required_chunks); compute_required_chunks(required_chunks, uuid);
ASSERT_MSG(!required_chunks.empty(), "required chunks is empty!!"); ASSERT_MSG(!required_chunks.empty(), "required chunks is empty!!");
@@ -83,17 +84,17 @@ void ServerWorld::gen_chunks_internal() {
new_chunks.emplace(pos, ServerChunk(*this, pos)); new_chunks.emplace(pos, ServerChunk(*this, pos));
} }
submit_new_chunks(); submit_new_chunks(uuid);
m_chunk_gen_finished = true; m_chunk_gen_finished = true;
m_request_gen_name = std::nullopt;
} }
void ServerWorld::compute_required_chunks(ChunkPosSet& required_chunks) { void ServerWorld::compute_required_chunks(
ChunkPosSet& required_chunks, const std::optional<std::string>& uuid) {
glm::vec3 player_pos; glm::vec3 player_pos;
if (m_request_gen_name == std::nullopt) { if (uuid == std::nullopt) {
player_pos = glm::vec3{0.0f}; player_pos = glm::vec3{0.0f};
} else { } else {
player_pos = get_player_pos(m_request_gen_name.value()); player_pos = get_player_pos(uuid.value());
} }
int x = std::floor(player_pos.x); int x = std::floor(player_pos.x);
int z = std::floor(player_pos.z); int z = std::floor(player_pos.z);
@@ -129,7 +130,7 @@ void ServerWorld::sync_and_collect_missing_chunks(
} }
} }
} }
void ServerWorld::submit_new_chunks() { void ServerWorld::submit_new_chunks(const std::optional<std::string>& uuid) {
using enum ChunkLoadStyle; using enum ChunkLoadStyle;
std::lock_guard lock(m_new_chunk_mutex); std::lock_guard lock(m_new_chunk_mutex);
auto pool_ptr = m_gen_thread_pool.load(); auto pool_ptr = m_gen_thread_pool.load();
@@ -153,10 +154,10 @@ void ServerWorld::submit_new_chunks() {
} }
} }
glm::vec3 player_pos; glm::vec3 player_pos;
if (m_request_gen_name == std::nullopt) { if (uuid == std::nullopt) {
player_pos = glm::vec3{0.0f}; player_pos = glm::vec3{0.0f};
} else { } else {
player_pos = get_player_pos(m_request_gen_name.value()); player_pos = get_player_pos(uuid.value());
} }
auto dist2 = [player_pos](ChunkPos chunk_pos) { auto dist2 = [player_pos](ChunkPos chunk_pos) {
ChunkPos player_chunk_pos = ChunkPos player_chunk_pos =
@@ -203,27 +204,35 @@ void ServerWorld::poll_finished_chunks() {
void ServerWorld::start_gen_thread() { void ServerWorld::start_gen_thread() {
m_gen_running = true; m_gen_running = true;
Logger::info("Gen Thread Started"); Logger::info("Gen Thread Started");
m_gen_thread = std::thread([this]() { m_gen_thread = std::jthread([this](std::stop_token token) {
while (m_gen_running) { while (!token.stop_requested()) {
std::unique_lock<std::mutex> lk(m_gen_signal_mutex); std::unique_lock<std::mutex> lk(m_need_gen_queue_mutex);
m_gen_cv.wait(lk, [this]() { m_gen_cv.wait(lk, [this](std::stop_token token) {
return m_need_gen_chunk.load() || !m_gen_running; return m_need_gen_chunk.load() || !m_gen_running ||
!m_need_gen_queue.empty() || token.stop_requested();
}); });
if (!m_gen_running) { if (!m_gen_running) {
break; break;
} }
if (token.stop_requested()) {
break;
}
m_need_gen_chunk = false; m_need_gen_chunk = false;
std::optional<std::string> uuid{std::nullopt};
if (!m_need_gen_queue.empty()) {
uuid = m_need_gen_queue.front();
m_need_gen_queue.pop_front();
}
lk.unlock(); lk.unlock();
gen_chunks_internal(uuid);
gen_chunks_internal();
} }
}); });
} }
void ServerWorld::start_server_thread() { void ServerWorld::start_server_thread() {
m_server_thread = std::thread( m_server_thread =
[this]() { serever_run(m_server_stop_source.get_token()); }); std::jthread([this](std::stop_token token) { serever_run(token); });
} }
void ServerWorld::start_thread_pool() { void ServerWorld::start_thread_pool() {
@@ -238,6 +247,7 @@ void ServerWorld::start_thread_pool() {
void ServerWorld::stop_gen_thread() { void ServerWorld::stop_gen_thread() {
m_gen_running = false; m_gen_running = false;
m_gen_cv.notify_all(); m_gen_cv.notify_all();
m_gen_thread.request_stop();
if (m_gen_thread.joinable()) { if (m_gen_thread.joinable()) {
m_gen_thread.join(); m_gen_thread.join();
} }
@@ -245,7 +255,7 @@ void ServerWorld::stop_gen_thread() {
} }
void ServerWorld::stop_server_thread() { void ServerWorld::stop_server_thread() {
m_server_stop_source.request_stop(); m_server_thread.request_stop();
if (m_server_thread.joinable()) { if (m_server_thread.joinable()) {
m_server_thread.join(); m_server_thread.join();
} }
@@ -273,20 +283,22 @@ void ServerWorld::serever_run(std::stop_token stoken) {
Logger::info("Server Thread Stopped!"); Logger::info("Server Thread Stopped!");
} }
void ServerWorld::need_gen() { void ServerWorld::need_gen(std::optional<std::string> uuid) {
if (!m_could_gen) { // if (!m_could_gen) {
Logger::warn("It is generating or consuming new chunks"); // Logger::warn("It is generating or consuming new chunks");
return; // return;
} // }
m_could_gen = false; m_could_gen = false;
{
// std::lock_guard lk(m_gen_player_pos_mutex); if (uuid) {
// m_gen_player_pos = get_player("TestPlayer").get_player_pos(); std::lock_guard lock(m_need_gen_queue_mutex);
ASSERT_MSG(false, "Player Pos Handle"); m_need_gen_queue.push_back(*uuid);
} }
// m_gen_player_pos = get_player("TestPlayer").get_player_pos();
m_need_gen_chunk = true; m_need_gen_chunk = true;
m_gen_cv.notify_one(); m_gen_cv.notify_one();
@@ -321,7 +333,7 @@ void ServerWorld::hot_reload() {
auto& config = Config::get(); auto& config = Config::get();
int dist = config.get<int>("world.rendering_distance"); int dist = config.get<int>("world.rendering_distance");
m_rendering_distance = dist <= MAX_DISTANCE ? dist : MAX_DISTANCE; m_rendering_distance = dist <= MAX_DISTANCE ? dist : MAX_DISTANCE;
need_gen(); need_gen(std::nullopt);
} }
void ServerWorld::rebuild_world() { void ServerWorld::rebuild_world() {
@@ -342,16 +354,16 @@ void ServerWorld::rebuild_world() {
ChunkGenerator::reload(); ChunkGenerator::reload();
start_thread_pool(); start_thread_pool();
start_gen_thread(); start_gen_thread();
need_gen(); need_gen(std::nullopt);
m_is_rebuilding = false; m_is_rebuilding = false;
} }
void ServerWorld::update() { poll_finished_chunks(); } void ServerWorld::update() { poll_finished_chunks(); }
void ServerWorld::sync_player_pos(const std::string& name, float x, float y, void ServerWorld::sync_player_pos(const std::string& uuid, float x, float y,
float z) { float z) {
auto it = m_players.find(name); auto it = m_players.find(uuid);
if (it == m_players.end()) { if (it == m_players.end()) {
Logger::warn("Player {} is not in this Server", it->first); Logger::warn("Player {} is not in this Server", it->first);
return; return;
@@ -361,33 +373,89 @@ void ServerWorld::sync_player_pos(const std::string& name, float x, float y,
void ServerWorld::handle_player_login(const std::string& name, void ServerWorld::handle_player_login(const std::string& name,
std::shared_ptr<Session> session) { std::shared_ptr<Session> session) {
player_join(name); std::string uuid = generate_uuid();
m_player_session.emplace(name, session); player_join(name, uuid);
m_player_session.emplace(uuid, session);
m_uuid_to_name.emplace(uuid, name);
LoginRsp rsp; LoginRsp rsp;
rsp.set_success(true); rsp.set_success(true);
rsp.set_uuid(name); rsp.set_uuid(uuid);
session->send(make_packet(name)); session->send(make_packet(name));
} }
void ServerWorld::player_join(const std::string& name) { void ServerWorld::player_join(std::string_view name, std::string_view uuid) {
m_players.emplace(name, name); Logger::info("Player {} (uuid {}) join the world", name, uuid);
m_players.emplace(std::piecewise_construct,
std::forward_as_tuple(std::string(uuid)),
std::forward_as_tuple(name, uuid, *this));
} }
void ServerWorld::player_exit(const std::string& name) { void ServerWorld::player_exit(const std::string& name) {
auto it = m_players.find(name); auto it = m_players.find(name);
if (it == m_players.end()) { if (it == m_players.end()) {
Logger::error("Player {} isn't in Server", it->first); Logger::error("Player {} isn't in Server", it->first);
} }
m_players.erase(it); m_players.unsafe_erase(it);
} }
glm::vec3 ServerWorld::get_player_pos(const std::string& name) const { glm::vec3 ServerWorld::get_player_pos(const std::string& uuid) const {
auto it = m_players.find(name); auto it = m_players.find(uuid);
if (it == m_players.end()) { if (it == m_players.end()) {
Logger::error("Can't find player uuid {}", uuid);
return glm::vec3{0.0f}; return glm::vec3{0.0f};
} }
return it->second.get_pos(); return it->second.get_pos();
} }
void ServerWorld::handle_chunk_req(const std::string& uuid, ChunkPos pos) {
ChunkDataRsp rsq;
auto* rsq_pos = rsq.mutable_pos();
rsq_pos->set_x(pos.x);
rsq_pos->set_z(pos.z);
{
std::shared_lock lock(m_chunks_mutex);
auto it = m_chunks.find(pos);
if (it == m_chunks.end()) {
return;
}
rsq.set_chunk_seed(it->second.seed());
auto* blocks = rsq.mutable_chunk_blocks();
auto& chunk_blocks = it->second.get_chunk_blocks();
blocks->Assign(chunk_blocks.begin(), chunk_blocks.end());
auto& neighbor_blocks = it->second.get_neightbor_blocks();
auto assign = [](auto* nb,
const std::optional<std::vector<BlockType>>& blocks) {
if (!blocks) {
return;
}
if (!nb) {
return;
}
nb->Assign(blocks->begin(), blocks->end());
};
auto* nb1 = rsq.mutable_neighbor_blocks_1();
auto* nb2 = rsq.mutable_neighbor_blocks_2();
auto* nb3 = rsq.mutable_neighbor_blocks_3();
auto* nb4 = rsq.mutable_neighbor_blocks_4();
assign(nb1, neighbor_blocks[1]);
assign(nb2, neighbor_blocks[2]);
assign(nb3, neighbor_blocks[3]);
assign(nb4, neighbor_blocks[4]);
}
std::shared_ptr<Session> s;
{
session_cacc cacc;
if (m_player_session.find(cacc, uuid)) {
s = cacc->second;
}
}
if (!s) {
Logger::error("Player {} session not exist", uuid);
return;
}
s->send(make_packet(rsq));
}
int ServerWorld::rendering_distance() const { int ServerWorld::rendering_distance() const {
return m_rendering_distance.load(); return m_rendering_distance.load();
} }

View File

@@ -52,15 +52,33 @@ asio::awaitable<void> Session::read_loop() {
throw std::runtime_error("invalid packet length"); throw std::runtime_error("invalid packet length");
} }
uint32_t body_len = total_len - HEADER_LEN; uint32_t body_len = total_len - HEADER_LEN;
std::vector<char> body_data(body_len); std::vector<uint8_t> body_data(body_len);
if (body_len > 0) { if (body_len > 0) {
co_await asio::async_read(m_socket, asio::buffer(body_data), co_await asio::async_read(m_socket, asio::buffer(body_data),
asio::use_awaitable); asio::use_awaitable);
} }
constexpr auto& to_num = std::to_underlying<PacketEnum>;
if (cmd_id == 1001) { if (cmd_id == to_num(PacketEnum::LOGIN_REQ)) {
LoginReq req;
if (req.ParseFromArray(body_data.data(), body_data.size())) {
m_server_world.handle_player_login(req.name(),
shared_from_this());
}
} }
if (cmd_id == 1002) { if (cmd_id == to_num(PacketEnum::PLAYER_POS)) {
PlayerPos pos;
if (pos.ParseFromArray(body_data.data(), body_data.size())) {
m_server_world.sync_player_pos(pos.uuid(), pos.pos().x(),
pos.pos().y(),
pos.pos().z());
}
}
if (cmd_id == to_num(PacketEnum::CHUNK_DATA_REQ)) {
ChunkDataReq req;
if (req.ParseFromArray(body_data.data(), body_data.size())) {
m_server_world.handle_chunk_req(
req.uuid(), ChunkPos(req.pos().x(), req.pos().z()));
}
} }
} }
} catch (const asio::system_error& e) { } catch (const asio::system_error& e) {

View File

@@ -2,5 +2,5 @@ syntax = "proto3";
message ChunkPos { message ChunkPos {
int32 x = 1; int32 x = 1;
int32 y = 2; int32 z = 2;
} }

View File

@@ -2,7 +2,12 @@ syntax = "proto3";
import "common/chunk_pos.proto"; import "common/chunk_pos.proto";
message ChunkData { message ChunkDataReq {
string uuid = 1;
ChunkPos pos = 2;
}
message ChunkDataRsp {
ChunkPos pos = 1; ChunkPos pos = 1;
uint32 chunk_seed = 2; uint32 chunk_seed = 2;
repeated uint32 chunk_blocks = 3 [packed=true]; repeated uint32 chunk_blocks = 3 [packed=true];