diff --git a/include/Cubed/gameplay/client_world.hpp b/include/Cubed/gameplay/client_world.hpp index 6125abe..e9c1dc1 100644 --- a/include/Cubed/gameplay/client_world.hpp +++ b/include/Cubed/gameplay/client_world.hpp @@ -29,8 +29,7 @@ public: void init(std::string_view player_name, std::shared_ptr client); void update(float delta_time); - const std::optional& - get_look_block_pos(const std::string& name) const; + const std::optional& get_look_block_pos() const; ClientPlayer& get_player(); int get_block(const glm::ivec3& block_pos) const; bool is_solid(const glm::ivec3& block_pos) const; @@ -66,8 +65,9 @@ public: const std::vector& render_player_data() const; glm::vec3 sunlight_dir() const; void receive_chunk(ChunkDataRsp data); - void receive_exit(); void request_exit(); + bool is_receive_exit(); + template void register_timer(std::string_view id, TickType threshold, Fn&& f) { m_timers.emplace(std::piecewise_construct, diff --git a/include/Cubed/gameplay/server_world.hpp b/include/Cubed/gameplay/server_world.hpp index 058d766..0c2c2a6 100644 --- a/include/Cubed/gameplay/server_world.hpp +++ b/include/Cubed/gameplay/server_world.hpp @@ -26,6 +26,7 @@ public: enum class ThreadPoolKind { NET, GEN }; ServerWorld(); ~ServerWorld(); + void stop(); void handle_player_exit(const std::string& uuid); void init_world(); void need_gen(std::string uuid); @@ -78,7 +79,6 @@ public: void handle_block_change(const BlockChangeReq& req); int chunk_size() const; - template void register_timer(std::string_view id, TickType threshold, Fn&& f) { m_timers.emplace(std::piecewise_construct, @@ -100,12 +100,12 @@ private: ChunkPos pos; }; struct PendingChunk { - ServerChunk chunk; + std::unique_ptr chunk; std::future future; }; struct FinishedChunk { ChunkPos pos; - std::shared_ptr chunk; + std::unique_ptr chunk; }; using ChunkHashMap = @@ -136,6 +136,7 @@ private: std::atomic m_need_gen_chunk{false}; std::atomic m_is_rebuilding{false}; std::atomic m_init{false}; + std::atomic m_stopped{false}; std::atomic m_rendering_distance{24}; std::atomic m_gen_pool_threads{0}; std::atomic m_net_pool_threads{0}; @@ -185,5 +186,6 @@ private: int change_pool_threads(std::atomic>& thread_pool, int threads); + void send_server_stop(); }; } // namespace Cubed diff --git a/src/app.cpp b/src/app.cpp index bf61efb..50cb74a 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -301,11 +301,16 @@ void App::run() { last_time = glfwGetTime(); while (!glfwWindowShouldClose(m_window.get_glfw_window())) { - + if (m_client_world.is_receive_exit()) { + break; + } update(); render(); } m_client_world.request_exit(); + if (!m_argument.is_client) { + m_server.server_world().stop(); + } } static Gait player_gait = Gait::WALK; void App::update() { diff --git a/src/gameplay/client_world.cpp b/src/gameplay/client_world.cpp index 44ee13b..d58d408 100644 --- a/src/gameplay/client_world.cpp +++ b/src/gameplay/client_world.cpp @@ -44,8 +44,7 @@ ClientWorld::~ClientWorld() { m_timers.clear(); } -const std::optional& -ClientWorld::get_look_block_pos(const std::string& name) const { +const std::optional& ClientWorld::get_look_block_pos() const { return m_player.get_look_block_pos(); } @@ -231,6 +230,14 @@ void ClientWorld::receive_remote_player(const PlayerInfoRsp& rsp) { } void ClientWorld::receive_player_logout(const LogoutRsp& rsp) { + if (rsp.server_stop()) { + m_receive_exit = true; + return; + } + if (rsp.uuid() == m_player.get_uuid()) { + m_receive_exit = true; + return; + } { std::lock_guard lock(m_other_players_mutex); int sum = m_other_players.erase(rsp.uuid()); @@ -240,9 +247,6 @@ void ClientWorld::receive_player_logout(const LogoutRsp& rsp) { Logger::info("Player {} erase", rsp.uuid()); } } - if (rsp.uuid() == m_player.get_uuid()) { - m_receive_exit = true; - } } void ClientWorld::init(std::string_view player_name, @@ -465,8 +469,7 @@ void ClientWorld::receive_chunk(ChunkDataRsp data) { } }); } -void ClientWorld::receive_exit() { m_receive_exit = true; } - +bool ClientWorld::is_receive_exit() { return m_receive_exit; } void ClientWorld::request_exit() { if (m_receive_exit) { return; diff --git a/src/gameplay/server_world.cpp b/src/gameplay/server_world.cpp index 912a49f..cda2189 100644 --- a/src/gameplay/server_world.cpp +++ b/src/gameplay/server_world.cpp @@ -16,10 +16,16 @@ using namespace google::protobuf; namespace Cubed { ServerWorld::ServerWorld() {} -ServerWorld::~ServerWorld() { +ServerWorld::~ServerWorld() { stop(); } + +void ServerWorld::stop() { if (!m_init) { return; } + if (m_stopped.exchange(true)) { + return; + } + send_server_stop(); stop_gen_thread(); stop_server_thread(); wait_all_chunk_tasks(); @@ -115,12 +121,14 @@ void ServerWorld::send_chunk(int task_id, const std::string& uuid, Logger::error("Chunk {} {} is invaild", pos.x, pos.z); return; } + rsp->set_chunk_seed(it->second.chunk->seed()); rsp->set_biome_type(std::to_underlying(it->second.chunk->biome())); auto* blocks = rsp->mutable_chunk_blocks(); auto& chunk_blocks = it->second.chunk->get_chunk_blocks(); blocks->Assign(chunk_blocks.begin(), chunk_blocks.end()); auto& neighbor_blocks = it->second.chunk->get_neightbor_blocks(); + auto assign = [](auto* nb, const std::optional>& blocks) { if (!blocks) { @@ -231,7 +239,8 @@ void ServerWorld::gen_chunks_internal(const std::string& uuid) { // Create new chunk std::lock_guard lock(m_new_chunk_mutex); for (auto& pos : need_gen_chunks_pos) { - m_new_chunks.emplace(pos, ServerChunk(*this, pos)); + m_new_chunks.emplace( + pos, std::make_unique(ServerChunk(*this, pos))); } } @@ -292,7 +301,7 @@ void ServerWorld::submit_new_chunks(const std::string& uuid) { for (auto& [pos, task] : m_new_chunks) { if (!task.future.valid()) { task.future = - pool_ptr->enqueue([&task]() { task.chunk.gen_chunk(); }); + pool_ptr->enqueue([&task]() { task.chunk->gen_chunk(); }); } } break; @@ -320,7 +329,7 @@ void ServerWorld::submit_new_chunks(const std::string& uuid) { for (auto& [pos, task] : tasks) { if (!task->future.valid()) { task->future = - pool_ptr->enqueue([task]() { task->chunk.gen_chunk(); }); + pool_ptr->enqueue([task]() { task->chunk->gen_chunk(); }); } } } @@ -346,9 +355,8 @@ void ServerWorld::poll_finished_chunks() { return true; } // Spawn complete, move away - m_new_finished_chunk.emplace_back( - pair.first, - std::make_shared(std::move(pending.chunk))); + m_new_finished_chunk.emplace_back(pair.first, + std::move(pending.chunk)); return true; }); @@ -683,6 +691,7 @@ void ServerWorld::handle_player_exit(const std::string& uuid) { Arena arena; auto* rsp = Arena::Create(&arena); rsp->set_uuid(uuid); + rsp->set_server_stop(false); exit_session->send(make_packet(*rsp)); std::vector> sessions; @@ -800,6 +809,18 @@ int ServerWorld::change_pool_threads( thread_pool.store(std::make_shared(used_thread)); return used_thread; } + +void ServerWorld::send_server_stop() { + Arena arena; + auto* rsp = Arena::Create(&arena); + rsp->set_server_stop(true); + std::shared_lock lock(m_player_mutex); + for (auto& [uuid, player] : m_players) { + player.get_session()->send(make_packet(*rsp)); + } + Logger::info("Send Server Mesaage Success"); +} + int ServerWorld::chunk_load_style() const { return std::to_underlying(m_chunk_load_style.load()); } diff --git a/src/proto/auth/auth.proto b/src/proto/auth/auth.proto index ccd1b33..228044c 100644 --- a/src/proto/auth/auth.proto +++ b/src/proto/auth/auth.proto @@ -15,5 +15,6 @@ message LogoutReq { message LogoutRsp { string uuid = 1; + bool server_stop = 2; } diff --git a/src/renderer.cpp b/src/renderer.cpp index d89a1eb..4b9c624 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -276,7 +276,7 @@ void Renderer::render_outline() { const auto& shader = get_shader("outline"); shader.use(); - const auto& block_pos = m_world.get_look_block_pos("TestPlayer"); + const auto& block_pos = m_world.get_look_block_pos(); if (block_pos != std::nullopt) {