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};
|
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
|
||||||
@@ -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");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -2,5 +2,5 @@ syntax = "proto3";
|
|||||||
|
|
||||||
message ChunkPos {
|
message ChunkPos {
|
||||||
int32 x = 1;
|
int32 x = 1;
|
||||||
int32 y = 2;
|
int32 z = 2;
|
||||||
}
|
}
|
||||||
@@ -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];
|
||||||
|
|||||||
Reference in New Issue
Block a user