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();
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user