From b9a013a9161f22e0db58ed5e4b94b6213aa4ca89 Mon Sep 17 00:00:00 2001 From: zhenyan121 <3367366583@qq.com> Date: Wed, 15 Jul 2026 21:03:18 +0800 Subject: [PATCH] feat(scene): add host game scene and world parameter handling --- include/Cubed/gameplay/chunk_generator.hpp | 1 + include/Cubed/scene/host_game_scene.hpp | 29 +++++++ include/Cubed/scene/scene.hpp | 2 +- include/Cubed/scene/scene_manager.hpp | 10 +++ include/Cubed/ui/host_game_ui.hpp | 16 ++++ src/CMakeLists.txt | 3 + src/gameplay/chunk_generator.cpp | 6 +- src/scene/host_game_scene.cpp | 18 +++++ src/scene/scene_manager.cpp | 4 + src/scene/world_scene.cpp | 15 ++-- src/ui/host_game_ui.cpp | 92 ++++++++++++++++++++++ src/ui/main_menu_ui_manager.cpp | 15 +++- 12 files changed, 200 insertions(+), 11 deletions(-) create mode 100644 include/Cubed/scene/host_game_scene.hpp create mode 100644 include/Cubed/ui/host_game_ui.hpp create mode 100644 src/scene/host_game_scene.cpp create mode 100644 src/ui/host_game_ui.cpp diff --git a/include/Cubed/gameplay/chunk_generator.hpp b/include/Cubed/gameplay/chunk_generator.hpp index 2fce476..27faca9 100644 --- a/include/Cubed/gameplay/chunk_generator.hpp +++ b/include/Cubed/gameplay/chunk_generator.hpp @@ -18,6 +18,7 @@ public: ChunkGenerator(ServerChunk& chunk); static void init(); + static void init(unsigned seed); static void reload(); static const unsigned& seed(); static void seed(unsigned s); diff --git a/include/Cubed/scene/host_game_scene.hpp b/include/Cubed/scene/host_game_scene.hpp new file mode 100644 index 0000000..0e16cca --- /dev/null +++ b/include/Cubed/scene/host_game_scene.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include "Cubed/scene/scene.hpp" +#include "Cubed/ui/host_game_ui.hpp" +namespace Cubed { +class SceneManager; +class HostGameScene : public Scene { +public: + HostGameScene(SceneManager& scene_manager); + ~HostGameScene(); + + HostGameScene(const HostGameScene&) = delete; + HostGameScene(HostGameScene&&) = delete; + HostGameScene& operator=(const HostGameScene&) = delete; + HostGameScene& operator=(HostGameScene&&) = delete; + + void update(float dt) override; + void render(Renderer& renderer) override; + bool handle_event(const Event& e) override; + void on_enter() override; + void on_leave() override; + void on_re_enter() override; + SceneManager& scene_manager(); + +private: + SceneManager& m_scene_manager; + HostGameUI m_ui; +}; +} // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/scene/scene.hpp b/include/Cubed/scene/scene.hpp index 5f2c78a..031bf89 100644 --- a/include/Cubed/scene/scene.hpp +++ b/include/Cubed/scene/scene.hpp @@ -3,7 +3,7 @@ namespace Cubed { class Renderer; -enum class SceneType { MAIN_MENU, WORLD, CREDITS, SETTINGS }; +enum class SceneType { MAIN_MENU, WORLD, CREDITS, SETTINGS, HOST_GAME }; class Scene { public: diff --git a/include/Cubed/scene/scene_manager.hpp b/include/Cubed/scene/scene_manager.hpp index cb216fc..c792a61 100644 --- a/include/Cubed/scene/scene_manager.hpp +++ b/include/Cubed/scene/scene_manager.hpp @@ -6,6 +6,14 @@ #include namespace Cubed { class App; + +struct WorldSceneParam { + bool host_game = true; + std::optional seed = std::nullopt; + std::string ip{"127.0.0.1"}; + int port = 25530; +}; + class SceneManager { public: SceneManager(const SceneManager&) = delete; @@ -25,6 +33,7 @@ public: void request_pop(); App& app(); + WorldSceneParam& world_scene_param(); private: enum class OperationType { PUSH, POP, CHANGE }; @@ -34,6 +43,7 @@ private: }; App& m_app; + WorldSceneParam m_world_param; std::vector> m_pending_delete_scene; std::optional m_operation; std::stack> m_scenes; diff --git a/include/Cubed/ui/host_game_ui.hpp b/include/Cubed/ui/host_game_ui.hpp new file mode 100644 index 0000000..4394b97 --- /dev/null +++ b/include/Cubed/ui/host_game_ui.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "Cubed/ui/ui_manager.hpp" +namespace Cubed { +class HostGameScene; +class HostGameUI : public UIManager { +public: + HostGameUI(HostGameScene& scene); + + void init() override; + void on_re_enter(); + +private: + HostGameScene& m_scene; +}; +} // namespace Cubed \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c9860b1..2edd818 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -78,4 +78,7 @@ target_sources(${PROJECT_NAME} scene/settings_scene.cpp ui/combo_button.cpp ui/text_field.cpp + scene/host_game_scene.cpp + scene/join_game_scene.cpp + ui/host_game_ui.cpp ) \ No newline at end of file diff --git a/src/gameplay/chunk_generator.cpp b/src/gameplay/chunk_generator.cpp index d7b15c6..8e02706 100644 --- a/src/gameplay/chunk_generator.cpp +++ b/src/gameplay/chunk_generator.cpp @@ -109,7 +109,11 @@ ChunkGenerator::ChunkGenerator(ServerChunk& chunk) : m_chunk(chunk) { void ChunkGenerator::init() { std::random_device d; - m_generator_seed = d(); + init(d()); +} + +void ChunkGenerator::init(unsigned seed) { + m_generator_seed = seed; Logger::info("Chunk Generator Seed {}", m_generator_seed); PerlinNoise3D::init(m_generator_seed); PerlinNoise2D::init(m_generator_seed); diff --git a/src/scene/host_game_scene.cpp b/src/scene/host_game_scene.cpp new file mode 100644 index 0000000..8eda54f --- /dev/null +++ b/src/scene/host_game_scene.cpp @@ -0,0 +1,18 @@ +#include "Cubed/scene/host_game_scene.hpp" + +namespace Cubed { +HostGameScene::HostGameScene(SceneManager& scene_manager) + : m_scene_manager(scene_manager), m_ui(*this) {} +HostGameScene::~HostGameScene() {} + +void HostGameScene::update(float dt) { m_ui.update(dt); } +void HostGameScene::render(Renderer& renderer) { m_ui.render(renderer); } +bool HostGameScene::handle_event(const Event& e) { + return m_ui.handle_event(e); +} +void HostGameScene::on_enter() { m_ui.init(); } +void HostGameScene::on_leave() {} +void HostGameScene::on_re_enter() { m_ui.on_re_enter(); } +SceneManager& HostGameScene::scene_manager() { return m_scene_manager; } + +} // namespace Cubed \ No newline at end of file diff --git a/src/scene/scene_manager.cpp b/src/scene/scene_manager.cpp index 79859ac..7e5bfdb 100644 --- a/src/scene/scene_manager.cpp +++ b/src/scene/scene_manager.cpp @@ -1,6 +1,7 @@ #include "Cubed/scene/scene_manager.hpp" #include "Cubed/scene/credits_scene.hpp" +#include "Cubed/scene/host_game_scene.hpp" #include "Cubed/scene/main_menu_scene.hpp" #include "Cubed/scene/settings_scene.hpp" #include "Cubed/scene/world_scene.hpp" @@ -97,6 +98,8 @@ std::unique_ptr SceneManager::create_scene(SceneType type) { return std::make_unique(*this); case SceneType::SETTINGS: return std::make_unique(*this); + case SceneType::HOST_GAME: + return std::make_unique(*this); } std::string err = std::format("Unknown Scene"); @@ -105,4 +108,5 @@ std::unique_ptr SceneManager::create_scene(SceneType type) { } App& SceneManager::app() { return m_app; } +WorldSceneParam& SceneManager::world_scene_param() { return m_world_param; } } // namespace Cubed \ No newline at end of file diff --git a/src/scene/world_scene.cpp b/src/scene/world_scene.cpp index e8b7d32..72ff7b7 100644 --- a/src/scene/world_scene.cpp +++ b/src/scene/world_scene.cpp @@ -97,15 +97,20 @@ bool WorldScene::handle_event(const Event& e) { e); } void WorldScene::on_enter() { + auto& param = m_scene_manager.world_scene_param(); + if (param.seed) { + ChunkGenerator::init(*param.seed); + param.seed = std::nullopt; + } else { + ChunkGenerator::init(); + } - ChunkGenerator::init(); - - if (!m_argument.is_client) { - m_server.start_server(m_argument.port); + if (param.host_game) { + m_server.start_server(param.port); } m_client = std::make_shared(m_client_world); - m_client->start(m_argument.ip, m_argument.port); + m_client->start(param.ip, param.port); // init will send packet m_client_world.init(m_argument.player, m_client); diff --git a/src/ui/host_game_ui.cpp b/src/ui/host_game_ui.cpp new file mode 100644 index 0000000..69cad90 --- /dev/null +++ b/src/ui/host_game_ui.cpp @@ -0,0 +1,92 @@ +#include "Cubed/ui/host_game_ui.hpp" + +#include "Cubed/app.hpp" +#include "Cubed/scene/host_game_scene.hpp" +#include "Cubed/scene/scene_manager.hpp" +#include "Cubed/ui/button.hpp" +#include "Cubed/ui/column_layout.hpp" +#include "Cubed/ui/image.hpp" +#include "Cubed/ui/text_field.hpp" +namespace Cubed { +HostGameUI::HostGameUI(HostGameScene& scene) : m_scene(scene) {} +void HostGameUI::init() { + auto bi = std::make_unique(nullptr); + auto& renderer = m_scene.scene_manager().app().renderer(); + auto& texture_manager = m_scene.scene_manager().app().texture_manager(); + + bi->set_window_size(renderer.window_width(), renderer.window_height()); + bi->set_anchor(Anchor::TOP_LEFT); + bi->set_image("texture/ui/background.png", texture_manager); + bi->set_fill(true); + + auto& rect = bi->add_child(); + rect.set_fill(true); + rect.set_alpha(0.7f); + rect.set_color(Color::BLACK); + + auto& layout = rect.add_child(); + layout.set_anchor(Anchor::CENTER); + layout.set_offset({0, 20}); + layout.set_spacing(20.0f); + auto& param = m_scene.scene_manager().world_scene_param(); + param.host_game = true; + { + auto& text_seed = layout.add_child(); + text_seed.set_show_text("WorldSeed"); + text_seed.set_default_image(texture_manager); + text_seed.set_on_finish([this, &text_seed]() { + unsigned seed = 0; + auto& text = text_seed.input_text(); + auto r = + std::from_chars(text.data(), text.data() + text.size(), seed); + + if (r.ec != std::errc{} || r.ptr != text.data() + text.size()) { + Logger::error("Invalid seed: {}", text); + return; + } + m_scene.scene_manager().world_scene_param().seed = seed; + }); + } + { + auto& text_port = layout.add_child(); + text_port.set_default_image(texture_manager); + text_port.set_show_text("Port"); + text_port.set_on_finish([this, &text_port]() { + int port = 25530; + auto& text = text_port.input_text(); + auto r = + std::from_chars(text.data(), text.data() + text.size(), port); + if (r.ec != std::errc{} || r.ptr != text.data() + text.size()) { + Logger::error("Invalid port: {}", text); + return; + } + if (port > 65535 || port < 0) { + + Logger::error("Port {} out of range", port); + return; + } + m_scene.scene_manager().world_scene_param().port = port; + }); + } + { + auto& button = layout.add_child