mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-09 02:07:04 +08:00
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:
@@ -55,4 +55,10 @@ inline ChunkPos get_chunk_pos(int world_x, int world_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
|
||||
@@ -1,30 +1,48 @@
|
||||
#pragma once
|
||||
#include "packet.pb.h"
|
||||
#include "packet.pb.h" // IWYU pragma: keep
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
namespace Cubed {
|
||||
constexpr int HEADER_LEN = 8;
|
||||
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 T> constexpr uint16_t get_packet_id() {
|
||||
|
||||
using enum PacketEnum;
|
||||
using std::is_same_v;
|
||||
|
||||
using U = std::decay_t<T>;
|
||||
constexpr auto& to_num = std::to_underlying<PacketEnum>;
|
||||
if constexpr (is_same_v<U, LoginReq>) {
|
||||
return 1001;
|
||||
return to_num(LOGIN_REQ);
|
||||
} else if constexpr (is_same_v<U, LoginRsp>) {
|
||||
return 1002;
|
||||
return to_num(LOGIN_RSP);
|
||||
} else if constexpr (is_same_v<U, PlayerInfo>) {
|
||||
return 2001;
|
||||
return to_num(PLAYER_INFO);
|
||||
} else if constexpr (is_same_v<U, PlayerPos>) {
|
||||
return 2002;
|
||||
} else if constexpr (is_same_v<U, ChunkData>) {
|
||||
return 3001;
|
||||
return to_num(PLAYER_POS);
|
||||
} else if constexpr (is_same_v<U, ChunkDataReq>) {
|
||||
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>) {
|
||||
return 9001;
|
||||
return to_num(PING);
|
||||
} else if (is_same_v<U, Pong>) {
|
||||
return 9002;
|
||||
return to_num(PONG);
|
||||
} else {
|
||||
static_assert(always_false<U>::value, "Unkonw Type");
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
unsigned seed() const;
|
||||
BiomeConditions& conditions();
|
||||
bool& has_cave();
|
||||
|
||||
const OptionalBlockVectorArray& get_neightbor_blocks() const;
|
||||
static int index(int x, int y, int z);
|
||||
static int index(const glm::vec3& pos);
|
||||
|
||||
@@ -69,7 +69,7 @@ private:
|
||||
HeightMapArray m_heightmap;
|
||||
// the index is a array of block id
|
||||
std::vector<BlockType> m_blocks;
|
||||
|
||||
OptionalBlockVectorArray m_neightbor_blocks;
|
||||
float frequency = 0.01f;
|
||||
float height = 80;
|
||||
unsigned m_seed = 0;
|
||||
|
||||
@@ -1,17 +1,24 @@
|
||||
#pragma once
|
||||
#include "Cubed/gameplay/chunk_pos.hpp"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
namespace Cubed {
|
||||
class ServerWorld;
|
||||
class ServerPlayer {
|
||||
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 std::string& get_name() const;
|
||||
void update_pos(float x, float y, float z);
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
std::string m_uuid;
|
||||
glm::vec3 m_pos{0.0f};
|
||||
ServerWorld& m_world;
|
||||
ChunkPos m_last_chunk_pos{0, 0};
|
||||
};
|
||||
} // namespace Cubed
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <future>
|
||||
#include <shared_mutex>
|
||||
#include <tbb/concurrent_hash_map.h>
|
||||
#include <tbb/concurrent_unordered_map.h>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
@@ -21,10 +22,10 @@ class ServerWorld {
|
||||
public:
|
||||
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 init_world();
|
||||
void need_gen();
|
||||
void need_gen(std::optional<std::string> uuid);
|
||||
void update();
|
||||
void hot_reload();
|
||||
|
||||
@@ -64,10 +65,12 @@ public:
|
||||
|
||||
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,
|
||||
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:
|
||||
enum class ChunkLoadStyle { RANDOM, CENTER };
|
||||
@@ -77,10 +80,15 @@ private:
|
||||
};
|
||||
using ChunkHashMap =
|
||||
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 =
|
||||
std::unordered_map<ChunkPos, PendingChunk, 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;
|
||||
ChunkHashMap m_chunks;
|
||||
// Can only be used in the gen thread
|
||||
@@ -90,10 +98,8 @@ private:
|
||||
CaveCarver m_cave_carcer;
|
||||
RiverWorm m_river_worm;
|
||||
|
||||
std::thread m_gen_thread;
|
||||
std::thread m_server_thread;
|
||||
|
||||
std::stop_source m_server_stop_source;
|
||||
std::jthread m_gen_thread;
|
||||
std::jthread m_server_thread;
|
||||
|
||||
std::atomic<bool> m_chunk_gen_finished{false};
|
||||
std::atomic<bool> m_could_gen{true};
|
||||
@@ -101,7 +107,6 @@ private:
|
||||
std::atomic<bool> m_need_gen_chunk{false};
|
||||
std::atomic<bool> m_is_rebuilding{false};
|
||||
std::atomic<int> m_rendering_distance{24};
|
||||
|
||||
std::atomic<int> m_pool_threads{0};
|
||||
std::atomic<int> m_max_threads{1};
|
||||
|
||||
@@ -112,26 +117,27 @@ private:
|
||||
|
||||
std::shared_mutex m_chunks_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::deque<std::string> m_need_gen_queue;
|
||||
|
||||
std::atomic<std::shared_ptr<ThreadPool>> m_gen_thread_pool;
|
||||
|
||||
std::atomic<ChunkLoadStyle> m_chunk_load_style{ChunkLoadStyle::RANDOM};
|
||||
|
||||
std::optional<std::string> m_request_gen_name = std::nullopt;
|
||||
|
||||
tbb::concurrent_hash_map<std::string, std::shared_ptr<Session>>
|
||||
m_player_session;
|
||||
|
||||
// key = uuid
|
||||
PlayerSessionMap m_player_session;
|
||||
tbb::concurrent_hash_map<std::string, std::string> m_uuid_to_name;
|
||||
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>&,
|
||||
const ChunkPosSet&);
|
||||
void submit_new_chunks();
|
||||
void submit_new_chunks(const std::optional<std::string>& uuid);
|
||||
void poll_finished_chunks();
|
||||
void wait_all_chunk_tasks();
|
||||
};
|
||||
|
||||
@@ -156,11 +156,10 @@ void ServerChunk::gen_chunk() {
|
||||
gen_phase_two();
|
||||
gen_phase_three();
|
||||
|
||||
OptionalBlockVectorArray neightbor_blocks;
|
||||
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();
|
||||
}
|
||||
// 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; }
|
||||
|
||||
const OptionalBlockVectorArray& ServerChunk::get_neightbor_blocks() const {
|
||||
return m_neightbor_blocks;
|
||||
}
|
||||
|
||||
void ServerChunk::set_chunk_block(int index, unsigned id) {
|
||||
m_blocks[index] = id;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
#include "Cubed/gameplay/server_player.hpp"
|
||||
|
||||
#include "Cubed/gameplay/server_world.hpp"
|
||||
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 std::string& ServerPlayer::get_name() const { return m_name; }
|
||||
void ServerPlayer::update_pos(float x, float y, float 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
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Cubed/gameplay/session.hpp"
|
||||
#include "Cubed/tools/cubed_assert.hpp"
|
||||
#include "Cubed/tools/log.hpp"
|
||||
#include "Cubed/tools/uuid.hpp"
|
||||
|
||||
#include <utility>
|
||||
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");
|
||||
m_chunk_gen_finished = false;
|
||||
|
||||
ChunkPosSet required_chunks;
|
||||
compute_required_chunks(required_chunks);
|
||||
compute_required_chunks(required_chunks, uuid);
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
submit_new_chunks();
|
||||
submit_new_chunks(uuid);
|
||||
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;
|
||||
if (m_request_gen_name == std::nullopt) {
|
||||
if (uuid == std::nullopt) {
|
||||
player_pos = glm::vec3{0.0f};
|
||||
} 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 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;
|
||||
std::lock_guard lock(m_new_chunk_mutex);
|
||||
auto pool_ptr = m_gen_thread_pool.load();
|
||||
@@ -153,10 +154,10 @@ void ServerWorld::submit_new_chunks() {
|
||||
}
|
||||
}
|
||||
glm::vec3 player_pos;
|
||||
if (m_request_gen_name == std::nullopt) {
|
||||
if (uuid == std::nullopt) {
|
||||
player_pos = glm::vec3{0.0f};
|
||||
} 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) {
|
||||
ChunkPos player_chunk_pos =
|
||||
@@ -203,27 +204,35 @@ void ServerWorld::poll_finished_chunks() {
|
||||
void ServerWorld::start_gen_thread() {
|
||||
m_gen_running = true;
|
||||
Logger::info("Gen Thread Started");
|
||||
m_gen_thread = std::thread([this]() {
|
||||
while (m_gen_running) {
|
||||
std::unique_lock<std::mutex> lk(m_gen_signal_mutex);
|
||||
m_gen_thread = std::jthread([this](std::stop_token token) {
|
||||
while (!token.stop_requested()) {
|
||||
std::unique_lock<std::mutex> lk(m_need_gen_queue_mutex);
|
||||
|
||||
m_gen_cv.wait(lk, [this]() {
|
||||
return m_need_gen_chunk.load() || !m_gen_running;
|
||||
m_gen_cv.wait(lk, [this](std::stop_token token) {
|
||||
return m_need_gen_chunk.load() || !m_gen_running ||
|
||||
!m_need_gen_queue.empty() || token.stop_requested();
|
||||
});
|
||||
if (!m_gen_running) {
|
||||
break;
|
||||
}
|
||||
if (token.stop_requested()) {
|
||||
break;
|
||||
}
|
||||
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();
|
||||
|
||||
gen_chunks_internal();
|
||||
gen_chunks_internal(uuid);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ServerWorld::start_server_thread() {
|
||||
m_server_thread = std::thread(
|
||||
[this]() { serever_run(m_server_stop_source.get_token()); });
|
||||
m_server_thread =
|
||||
std::jthread([this](std::stop_token token) { serever_run(token); });
|
||||
}
|
||||
|
||||
void ServerWorld::start_thread_pool() {
|
||||
@@ -238,6 +247,7 @@ void ServerWorld::start_thread_pool() {
|
||||
void ServerWorld::stop_gen_thread() {
|
||||
m_gen_running = false;
|
||||
m_gen_cv.notify_all();
|
||||
m_gen_thread.request_stop();
|
||||
if (m_gen_thread.joinable()) {
|
||||
m_gen_thread.join();
|
||||
}
|
||||
@@ -245,7 +255,7 @@ void ServerWorld::stop_gen_thread() {
|
||||
}
|
||||
|
||||
void ServerWorld::stop_server_thread() {
|
||||
m_server_stop_source.request_stop();
|
||||
m_server_thread.request_stop();
|
||||
if (m_server_thread.joinable()) {
|
||||
m_server_thread.join();
|
||||
}
|
||||
@@ -273,20 +283,22 @@ void ServerWorld::serever_run(std::stop_token stoken) {
|
||||
Logger::info("Server Thread Stopped!");
|
||||
}
|
||||
|
||||
void ServerWorld::need_gen() {
|
||||
void ServerWorld::need_gen(std::optional<std::string> uuid) {
|
||||
|
||||
if (!m_could_gen) {
|
||||
Logger::warn("It is generating or consuming new chunks");
|
||||
return;
|
||||
}
|
||||
// if (!m_could_gen) {
|
||||
// Logger::warn("It is generating or consuming new chunks");
|
||||
// return;
|
||||
// }
|
||||
|
||||
m_could_gen = false;
|
||||
{
|
||||
// std::lock_guard lk(m_gen_player_pos_mutex);
|
||||
// m_gen_player_pos = get_player("TestPlayer").get_player_pos();
|
||||
ASSERT_MSG(false, "Player Pos Handle");
|
||||
|
||||
if (uuid) {
|
||||
std::lock_guard lock(m_need_gen_queue_mutex);
|
||||
m_need_gen_queue.push_back(*uuid);
|
||||
}
|
||||
|
||||
// m_gen_player_pos = get_player("TestPlayer").get_player_pos();
|
||||
|
||||
m_need_gen_chunk = true;
|
||||
|
||||
m_gen_cv.notify_one();
|
||||
@@ -321,7 +333,7 @@ void ServerWorld::hot_reload() {
|
||||
auto& config = Config::get();
|
||||
int dist = config.get<int>("world.rendering_distance");
|
||||
m_rendering_distance = dist <= MAX_DISTANCE ? dist : MAX_DISTANCE;
|
||||
need_gen();
|
||||
need_gen(std::nullopt);
|
||||
}
|
||||
|
||||
void ServerWorld::rebuild_world() {
|
||||
@@ -342,16 +354,16 @@ void ServerWorld::rebuild_world() {
|
||||
ChunkGenerator::reload();
|
||||
start_thread_pool();
|
||||
start_gen_thread();
|
||||
need_gen();
|
||||
need_gen(std::nullopt);
|
||||
|
||||
m_is_rebuilding = false;
|
||||
}
|
||||
|
||||
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) {
|
||||
auto it = m_players.find(name);
|
||||
auto it = m_players.find(uuid);
|
||||
if (it == m_players.end()) {
|
||||
Logger::warn("Player {} is not in this Server", it->first);
|
||||
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,
|
||||
std::shared_ptr<Session> session) {
|
||||
player_join(name);
|
||||
m_player_session.emplace(name, session);
|
||||
std::string uuid = generate_uuid();
|
||||
player_join(name, uuid);
|
||||
m_player_session.emplace(uuid, session);
|
||||
m_uuid_to_name.emplace(uuid, name);
|
||||
LoginRsp rsp;
|
||||
rsp.set_success(true);
|
||||
rsp.set_uuid(name);
|
||||
rsp.set_uuid(uuid);
|
||||
session->send(make_packet(name));
|
||||
}
|
||||
|
||||
void ServerWorld::player_join(const std::string& name) {
|
||||
m_players.emplace(name, name);
|
||||
void ServerWorld::player_join(std::string_view name, std::string_view uuid) {
|
||||
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) {
|
||||
auto it = m_players.find(name);
|
||||
if (it == m_players.end()) {
|
||||
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 {
|
||||
auto it = m_players.find(name);
|
||||
glm::vec3 ServerWorld::get_player_pos(const std::string& uuid) const {
|
||||
auto it = m_players.find(uuid);
|
||||
if (it == m_players.end()) {
|
||||
Logger::error("Can't find player uuid {}", uuid);
|
||||
return glm::vec3{0.0f};
|
||||
}
|
||||
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 {
|
||||
return m_rendering_distance.load();
|
||||
}
|
||||
|
||||
@@ -52,15 +52,33 @@ asio::awaitable<void> Session::read_loop() {
|
||||
throw std::runtime_error("invalid packet length");
|
||||
}
|
||||
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) {
|
||||
co_await asio::async_read(m_socket, asio::buffer(body_data),
|
||||
asio::use_awaitable);
|
||||
}
|
||||
|
||||
if (cmd_id == 1001) {
|
||||
constexpr auto& to_num = std::to_underlying<PacketEnum>;
|
||||
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) {
|
||||
|
||||
@@ -2,5 +2,5 @@ syntax = "proto3";
|
||||
|
||||
message ChunkPos {
|
||||
int32 x = 1;
|
||||
int32 y = 2;
|
||||
int32 z = 2;
|
||||
}
|
||||
@@ -2,7 +2,12 @@ syntax = "proto3";
|
||||
|
||||
import "common/chunk_pos.proto";
|
||||
|
||||
message ChunkData {
|
||||
message ChunkDataReq {
|
||||
string uuid = 1;
|
||||
ChunkPos pos = 2;
|
||||
}
|
||||
|
||||
message ChunkDataRsp {
|
||||
ChunkPos pos = 1;
|
||||
uint32 chunk_seed = 2;
|
||||
repeated uint32 chunk_blocks = 3 [packed=true];
|
||||
|
||||
Reference in New Issue
Block a user