diff --git a/.gitignore b/.gitignore index b3536eb..34d5687 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,7 @@ CMakeError.log *~ .DS_Store assets/config.toml +assets/server-config.toml .venv/ pyout/ vcpkg_installed/ \ No newline at end of file diff --git a/include/Cubed/app.hpp b/include/Cubed/app.hpp index dcea01b..bde0f9c 100644 --- a/include/Cubed/app.hpp +++ b/include/Cubed/app.hpp @@ -5,6 +5,7 @@ #include "Cubed/gameplay/server_world.hpp" #define GLFW_INCLUDE_NONE #include "Cubed/camera.hpp" +#include "Cubed/config.hpp" #include "Cubed/dev_panel.hpp" #include "Cubed/render/renderer.hpp" #include "Cubed/texture_manager.hpp" @@ -49,23 +50,23 @@ public: Window& window(); ClientWorld& client_world(); ServerWorld& server_world(); + Config& config(); const Argument& argument() const; AudioEngine& audio(); private: + Config m_game_config; Camera m_camera; TextureManager m_texture_manager; NetworkServer m_server; std::shared_ptr m_client; + AudioEngine m_audio; ClientWorld m_client_world; - DevPanel m_dev_panel{*this}; - Renderer m_renderer{m_camera, m_client_world, m_texture_manager, - m_dev_panel}; + DevPanel m_dev_panel; + Renderer m_renderer; - Window m_window{m_renderer}; - - AudioEngine m_audio; + Window m_window; inline static double last_time = glfwGetTime(); inline static double current_time = glfwGetTime(); @@ -74,6 +75,7 @@ private: inline static int frame_count = 0; inline static int fps = 0; Argument m_argument; + void init(int argc, char** argv); void handle_argument(int argc, char** argv); void handle_toml(); diff --git a/include/Cubed/audio/audio_engine.hpp b/include/Cubed/audio/audio_engine.hpp index 84342e7..56a2b97 100644 --- a/include/Cubed/audio/audio_engine.hpp +++ b/include/Cubed/audio/audio_engine.hpp @@ -4,6 +4,7 @@ #include "Cubed/audio/audio_source.hpp" #include "Cubed/audio/sound_manager.hpp" #include "Cubed/audio/source_pool.hpp" +#include "Cubed/config.hpp" #include #include @@ -17,7 +18,7 @@ class ClientWorld; class AudioEngine { public: - AudioEngine(); + AudioEngine(Config& config); AudioEngine(const AudioEngine&) = delete; AudioEngine(AudioEngine&&) = delete; AudioEngine& operator=(const AudioEngine&) = delete; @@ -48,6 +49,7 @@ private: std::unique_ptr m_bgm; FadeMap m_fade_map; SoundManager m_sounds; + Config& m_config; std::shared_ptr m_pool; bool m_efx_supported = false; bool m_underwater = false; diff --git a/include/Cubed/config.hpp b/include/Cubed/config.hpp index 113dc2b..9acb689 100644 --- a/include/Cubed/config.hpp +++ b/include/Cubed/config.hpp @@ -1,99 +1,75 @@ #pragma once -#include "Cubed/tools/cubed_assert.hpp" #include "Cubed/tools/toml.utils.hpp" namespace Cubed { class Config { public: - Config(); + explicit Config(std::string_view path); + Config(const Config&) = delete; + Config(Config&&) = delete; + Config& operator=(const Config&) = delete; + Config& operator=(Config&&) = delete; ~Config(); - static Config& get(); - toml::table& table(); - void load_or_create_config(); + void load_config(); void save_to_file(); - template T get(std::string_view key) const { - size_t cur = 0; - auto pos = key.find('.'); - const toml::table* table = &m_tbl; - while (pos != std::string_view::npos) { - std::string_view s = key.substr(cur, pos - cur); - if (s.empty()) { - Logger::error("Empty key/table name in path '{}'", key); - ASSERT(false); - std::abort(); - } - cur = pos + 1; - pos = key.find('.', cur); - if (auto* next = (*table)[s].as_table()) { - table = next; - } else { - Logger::error("Can't find table {}", s); - ASSERT(false); - std::abort(); - } + template + T get(std::string_view key, T default_value) { + if (auto* node = find_node(m_tbl, key)) { + if (auto value = node->value()) + return *value; } - std::string_view n_key = key.substr(cur); - if (n_key.empty()) { - Logger::error("Trailing dot in path '{}'", key); - ASSERT(false); - std::abort(); - } - auto opt = (*table)[n_key].value(); - if (opt) { - return *opt; + + set(key, default_value); + save_to_file(); + + return default_value; + } + + template void set(std::string_view key, T&& value) { + auto pos = key.rfind('.'); + + toml::table* table; + std::string_view name; + + if (pos == std::string_view::npos) { + table = &m_tbl; + name = key; } else { - Logger::error("Can't find key {}", n_key); - ASSERT(false); - std::abort(); + table = find_or_create_table(key.substr(0, pos)); + name = key.substr(pos + 1); } + // Insert node at the last level's table + table->insert_or_assign(name, std::forward(value)); } - template void set(std::string_view key, T&& val) { - if constexpr (!TOML::TomlValueType>) { - static_assert(false, "Type Not Support"); - } - size_t cur = 0; - auto pos = key.find('.'); - toml::table* table = &m_tbl; - while (pos != std::string_view::npos) { - std::string_view s = key.substr(cur, pos - cur); - if (s.empty()) { - Logger::error("Empty key/table name in path '{}'", key); - ASSERT(false); - std::abort(); - } - cur = pos + 1; - pos = key.find('.', cur); - if (auto* next = (*table)[s].as_table()) { - table = next; - } else { - auto [it, inserted] = table->insert_or_assign(s, toml::table{}); - table = it->second.as_table(); - } - } - std::string_view n_key = key.substr(cur); - if (n_key.empty()) { - Logger::error("Trailing dot in path '{}'", key); - ASSERT(false); - std::abort(); - } - table->insert_or_assign(n_key, std::forward(val)); - } + template void set_and_save(std::string_view key, T&& val) { set(key, std::forward(val)); save_to_file(); } - toml::node_view val_view(std::string_view key); private: toml::table m_tbl; - constexpr static inline std::string_view CONGIF_PATH = - ASSETS_PATH "config.toml"; - void create_config(); + const std::string CONGIF_PATH; + const toml::node* find_node(const toml::table& root, + std::string_view path) const; + // Follow the path to find the last-level toml::table, creating it if it + // does not exist + toml::table* find_or_create_table(std::string_view path); }; +template <> +inline float Config::get(std::string_view key, float default_value) { + return static_cast( + Config::get(key, static_cast(default_value))); +} + +template <> inline void Config::set(std::string_view key, float&& value) { + Config::set(key, static_cast(value)); +} + } // namespace Cubed diff --git a/include/Cubed/dev_panel.hpp b/include/Cubed/dev_panel.hpp index e237c3a..1f927fd 100644 --- a/include/Cubed/dev_panel.hpp +++ b/include/Cubed/dev_panel.hpp @@ -1,5 +1,7 @@ #pragma once +#include "Cubed/config.hpp" + #include namespace Cubed { @@ -36,7 +38,8 @@ public: private: App& m_app; - ConfigView m_config; + Config& m_config; + ConfigView m_config_view; ClientPlayer* m_player; PlayerProfile m_player_profile; bool m_need_save_config = false; diff --git a/include/Cubed/gameplay/client_player.hpp b/include/Cubed/gameplay/client_player.hpp index cdaf56e..9baaecc 100644 --- a/include/Cubed/gameplay/client_player.hpp +++ b/include/Cubed/gameplay/client_player.hpp @@ -25,7 +25,7 @@ public: void update_chunk_set(const ChunkPosSet& set); const ChunkPosSet& get_chunk_pos_set() const; - ChunkPosSet& get_chunk_pos_set(); + ChunkPosSet get_chunk_pos_set(); static AABB get_aabb(const glm::vec3& pos); const glm::vec3& get_front() const; diff --git a/include/Cubed/gameplay/client_world.hpp b/include/Cubed/gameplay/client_world.hpp index 310a294..2ec0596 100644 --- a/include/Cubed/gameplay/client_world.hpp +++ b/include/Cubed/gameplay/client_world.hpp @@ -1,5 +1,6 @@ #pragma once #include "Cubed/audio/audio_engine.hpp" +#include "Cubed/config.hpp" #include "Cubed/gameplay/block.hpp" #include "Cubed/gameplay/chunk_pos.hpp" #include "Cubed/gameplay/client_chunk.hpp" @@ -43,7 +44,7 @@ struct PlayerRenderData { class ClientWorld { public: - ClientWorld(AudioEngine& auido); + ClientWorld(AudioEngine& auido, Config& config); ~ClientWorld(); void init(std::string_view player_name, std::shared_ptr client); @@ -95,6 +96,7 @@ public: int chunk_size() const; static AABB get_block_aabb(const glm::ivec3& pos); AudioEngine& get_audio(); + Config& get_config(); template void register_ticktimer(std::string_view id, TickType threshold, Fn&& f) { m_ticktimers.emplace( @@ -103,6 +105,12 @@ public: } private: + std::atomic m_is_pending_delete_queue_free{false}; + std::mutex m_delete_vbo_mutex; + std::mutex m_delete_vao_mutex; + std::vector> m_pending_delete_vbo; + std::vector> m_pending_delete_vao; + enum class ChunkLoadStyle { RANDOM, CENTER }; using ChunkHashMap = tbb::concurrent_hash_map, @@ -124,18 +132,15 @@ private: OtherPlayerHashMap m_player_info; ChunkHashMap m_chunks; AudioEngine& m_audio; + Config& m_config; std::vector m_planes; std::jthread m_client_thread; - std::mutex m_delete_vbo_mutex; - std::mutex m_delete_vao_mutex; mutable std::shared_mutex m_player_info_mutex; tbb::concurrent_queue> m_pending_upload_queue; tbb::concurrent_queue m_dirty_chunk_queue; tbb::concurrent_queue m_pending_sound; - std::vector> m_pending_delete_vbo; - std::vector> m_pending_delete_vao; std::deque m_dirty_queue; std::vector m_render_snapshots; diff --git a/include/Cubed/gameplay/network_server.hpp b/include/Cubed/gameplay/network_server.hpp index 5ed0ace..f12fbd6 100644 --- a/include/Cubed/gameplay/network_server.hpp +++ b/include/Cubed/gameplay/network_server.hpp @@ -1,4 +1,5 @@ #pragma once +#include "Cubed/config.hpp" #include "Cubed/gameplay/server_world.hpp" #include "Cubed/gameplay/session.hpp" @@ -8,17 +9,19 @@ namespace Cubed { class NetworkServer { public: - NetworkServer(int port = 25530); + explicit NetworkServer(); ~NetworkServer(); void stop(); // Run in another thread after initialization is complete - void start_server(int port = 25530); - + void start_server(int port); + void start_server(); int port() const; ServerWorld& server_world(); private: + Config m_config; + asio::io_context m_io; std::thread m_net_thread; int m_port = 25530; diff --git a/include/Cubed/gameplay/server_world.hpp b/include/Cubed/gameplay/server_world.hpp index 49e65a4..2c86e2e 100644 --- a/include/Cubed/gameplay/server_world.hpp +++ b/include/Cubed/gameplay/server_world.hpp @@ -1,5 +1,6 @@ #pragma once +#include "Cubed/config.hpp" #include "Cubed/gameplay/cave_carver.hpp" #include "Cubed/gameplay/chunk_pos.hpp" #include "Cubed/gameplay/game_time.hpp" @@ -25,7 +26,7 @@ class Session; class ServerWorld { public: enum class ThreadPoolKind { NET, GEN }; - ServerWorld(); + ServerWorld(Config& config); ~ServerWorld(); void stop(); void handle_player_exit(const std::string& uuid); @@ -118,6 +119,9 @@ private: using uuid_acc = PlayerUUIDMap::accessor; using uuid_cacc = PlayerUUIDMap::const_accessor; + + Config& m_config; + // key = uuid PlayerHashMap m_players; ChunkHashMap m_chunks; diff --git a/include/Cubed/map_table.hpp b/include/Cubed/map_table.hpp deleted file mode 100644 index 6a262f0..0000000 --- a/include/Cubed/map_table.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -// #include -// #include -// #include -namespace Cubed { - -class MapTable { -private: - /* - static inline std::unordered_map id_to_name_map; - static inline std::unordered_map name_to_id_map; - static inline std::vector item_id_to_name; - */ -public: - // please using reference - /* - static std::string_view get_name_from_id(unsigned id); - static unsigned get_id_from_name(const std::string& name); - - static std::string_view item_name(unsigned id); - static const std::vector& item_map(); - */ - static void init_map(); -}; - -} // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/render/renderer.hpp b/include/Cubed/render/renderer.hpp index 240a961..38f6949 100644 --- a/include/Cubed/render/renderer.hpp +++ b/include/Cubed/render/renderer.hpp @@ -1,5 +1,6 @@ #pragma once +#include "Cubed/config.hpp" #include "Cubed/constants.hpp" #include "Cubed/primitive_data.hpp" #include "Cubed/render/player_renderer.hpp" @@ -23,7 +24,8 @@ public: constexpr static int NUM_VAO = 7; Renderer(const Camera& camera, ClientWorld& world, - const TextureManager& texture_manager, DevPanel& dev_panel); + const TextureManager& texture_manager, DevPanel& dev_panel, + Config& config); ~Renderer(); void hot_reload(); void init(bool debug_on); @@ -109,7 +111,7 @@ private: std::vector m_ui; WorldRenderer m_world_renderer; - + Config& m_config; void init_quad(); void init_text(); diff --git a/include/Cubed/texture_manager.hpp b/include/Cubed/texture_manager.hpp index 5807aee..edd31f2 100644 --- a/include/Cubed/texture_manager.hpp +++ b/include/Cubed/texture_manager.hpp @@ -1,4 +1,5 @@ #pragma once +#include "Cubed/config.hpp" #include "Cubed/gameplay/block.hpp" #include "Cubed/render/texture.hpp" @@ -19,7 +20,7 @@ private: std::unique_ptr m_skin; std::vector> m_item_textures; GLfloat m_max_aniso = 0.0f; - + Config& m_config; int m_aniso = 1; void load_block_status(unsigned status_id); @@ -36,7 +37,7 @@ private: void hot_reload(); public: - TextureManager(); + TextureManager(Config& config); ~TextureManager(); void delete_texture(); diff --git a/include/Cubed/tools/toml.utils.hpp b/include/Cubed/tools/toml.utils.hpp index 97a2984..c332669 100644 --- a/include/Cubed/tools/toml.utils.hpp +++ b/include/Cubed/tools/toml.utils.hpp @@ -14,6 +14,7 @@ concept TomlValueType = std::same_as, toml::date> || std::same_as, toml::time> || std::same_as, toml::date_time> || + std::same_as, float> || std::same_as, std::string>; template diff --git a/include/Cubed/window.hpp b/include/Cubed/window.hpp index 4d23be0..d1de2e2 100644 --- a/include/Cubed/window.hpp +++ b/include/Cubed/window.hpp @@ -1,4 +1,7 @@ #pragma once + +#include "Cubed/config.hpp" + #define GLFW_INCLUDE_NONE #include namespace Cubed { @@ -6,7 +9,7 @@ namespace Cubed { class Renderer; class Window { public: - Window(Renderer& renderer); + Window(Renderer& renderer, Config& config); ~Window(); bool is_mouse_enable() const; @@ -29,6 +32,7 @@ private: int m_width; int m_height; Renderer& m_renderer; + Config& m_config; }; } // namespace Cubed \ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0aa2087..620bf53 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -10,7 +10,6 @@ target_sources(${PROJECT_NAME} gameplay/chunk_generator.cpp gameplay/tree.cpp input.cpp - map_table.cpp render/renderer.cpp shader.cpp texture_manager.cpp diff --git a/src/app.cpp b/src/app.cpp index b1ed66f..196b7e0 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -12,7 +12,14 @@ #include namespace Cubed { -App::App() : m_client_world(m_audio) {} +App::App() + + : m_game_config(ASSETS_PATH "config.toml"), + m_texture_manager(m_game_config), m_audio(m_game_config), + m_client_world(m_audio, m_game_config), m_dev_panel(*this), + m_renderer(m_camera, m_client_world, m_texture_manager, m_dev_panel, + m_game_config), + m_window(m_renderer, m_game_config) {} App::~App() { if (m_client) { @@ -357,7 +364,7 @@ void App::update() { const auto& player = m_client_world.get_player(); if (player_gait != player.get_gait()) { player_gait = player.get_gait(); - float fov = static_cast(Config::get().get("player.fov")); + float fov = m_game_config.get("player.fov", 70.0f); if (player_gait == Gait::WALK) { m_renderer.update_fov(fov); } @@ -401,6 +408,7 @@ TextureManager& App::texture_manager() { return m_texture_manager; } Window& App::window() { return m_window; } ClientWorld& App::client_world() { return m_client_world; } ServerWorld& App::server_world() { return m_server.server_world(); } +Config& App::config() { return m_game_config; } const App::Argument& App::argument() const { return m_argument; } AudioEngine& App::audio() { return m_audio; } } // namespace Cubed \ No newline at end of file diff --git a/src/audio/audio_engine.cpp b/src/audio/audio_engine.cpp index 85b9372..26f17ee 100644 --- a/src/audio/audio_engine.cpp +++ b/src/audio/audio_engine.cpp @@ -1,14 +1,13 @@ #include "Cubed/audio/audio_engine.hpp" #include "Cubed/audio/audio_error.hpp" -#include "Cubed/config.hpp" #include "Cubed/tools/cubed_assert.hpp" #include "Cubed/tools/log.hpp" #include namespace Cubed { -AudioEngine::AudioEngine() {}; +AudioEngine::AudioEngine(Config& config) : m_config(config) {}; AudioEngine::~AudioEngine() { if (!m_init) { @@ -64,10 +63,8 @@ void AudioEngine::init() { alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED); check_al_error(); - auto& config = Config::get(); - - m_music_volume = static_cast(config.get("volume.music")); - m_sfx_volume = static_cast(config.get("volume.SFX")); + m_music_volume = m_config.get("volume.music", 1.0f); + m_sfx_volume = m_config.get("volume.SFX", 1.0f); m_sounds.init(); @@ -187,10 +184,8 @@ void AudioEngine::update() { } void AudioEngine::reload_config() { - auto& config = Config::get(); - - m_music_volume = static_cast(config.get("volume.music")); - m_sfx_volume = static_cast(config.get("volume.SFX")); + m_music_volume = m_config.get("volume.music", 1.0f); + m_sfx_volume = m_config.get("volume.SFX", 1.0f); if (m_bgm) { m_bgm->set_target_volume(m_music_volume); } diff --git a/src/config.cpp b/src/config.cpp index 9af4922..762233b 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -1,6 +1,5 @@ #include "Cubed/config.hpp" -#include "Cubed/tools/cubed_assert.hpp" #include "Cubed/tools/log.hpp" #include @@ -11,71 +10,24 @@ using namespace std::string_view_literals; namespace Cubed { -Config::Config() { load_or_create_config(); } +Config::Config(std::string_view path) : CONGIF_PATH(path) { load_config(); } Config::~Config() { save_to_file(); } -Config& Config::get() { - static Config instance; - return instance; -} - toml::table& Config::table() { return m_tbl; } -void Config::create_config() { - static constexpr auto SOURCE = R"( - - [window] - width = 800 - height = 600 - fullscreen = false - V-Sync = true - - [player] - fov = 70.0 - mouse_sensitivity = 0.15 - - [world] - rendering_distance = 24 - - [devpanel] - theme = 0 # 0 is Dark Theme, 1 is Light Theme - - [texture] - aniso = 1 # i is the minimun value, indicating off - - [volume] - music = 1.0 - SFX = 1.0 - - - )"sv; - - try { - m_tbl = toml::parse(SOURCE); - } catch (const toml::parse_error& err) { - Logger::error("Load Config Error {}", err.what()); - ASSERT(false); - std::abort(); - } - Logger::info("Create New Config File Success"); -} - -void Config::load_or_create_config() { +void Config::load_config() { fs::path config_path{CONGIF_PATH}; - if (!fs::is_regular_file(config_path)) { - create_config(); - } else + + if (fs::is_regular_file(config_path)) { try { m_tbl = toml::parse_file(config_path.string()); + Logger::info("Load Config File Success"); } catch (const toml::parse_error& err) { Logger::error("Load Config Error: \"{}\"", err.what()); - create_config(); } - - Logger::info("Load Config File Success"); + } } - void Config::save_to_file() { fs::path config_path{CONGIF_PATH}; std::ofstream file{config_path}; @@ -83,40 +35,54 @@ void Config::save_to_file() { Logger::info("Save File Success"); } -toml::node_view Config::val_view(std::string_view key) { +const toml::node* Config::find_node(const toml::table& root, + std::string_view path) const { + const toml::table* table = &root; + size_t cur = 0; - auto pos = key.find('.'); - toml::table* table = &m_tbl; + auto pos = path.find('.'); + while (pos != std::string_view::npos) { - std::string_view s = key.substr(cur, pos - cur); - if (s.empty()) { - Logger::error("Empty key/table name in path '{}'", key); - ASSERT(false); - std::abort(); - } - cur = pos + 1; - pos = key.find('.', cur); - if (auto* next = (*table)[s].as_table()) { + auto name = path.substr(cur, pos - cur); + + if (auto* next = (*table)[name].as_table()) { table = next; } else { - Logger::error("Can't find table {}", s); - ASSERT(false); - std::abort(); + return nullptr; } + + cur = pos + 1; + pos = path.find('.', cur); } - std::string_view n_key = key.substr(cur); - if (n_key.empty()) { - Logger::error("Trailing dot in path '{}'", key); - ASSERT(false); - std::abort(); + + auto key = path.substr(cur); + + return (*table)[key].node(); +} + +toml::table* Config::find_or_create_table(std::string_view path) { + toml::table* table = &m_tbl; + + while (true) { + auto pos = path.find('.'); + auto part = pos == std::string_view::npos ? path : path.substr(0, pos); + + if (auto* next = (*table)[part].as_table()) { + // If there is a table, proceed to the next + table = next; + } else { + // If there is no table, create a new one + auto [it, _] = table->insert(part, toml::table{}); + table = it->second.as_table(); + } + + if (pos == std::string_view::npos) + break; + + path.remove_prefix(pos + 1); } - auto view = (*table)[n_key]; - if (!view) { - Logger::error("The view is null"); - ASSERT(false); - std::abort(); - } - return view; + + return table; } } // namespace Cubed \ No newline at end of file diff --git a/src/dev_panel.cpp b/src/dev_panel.cpp index 2f47eb0..a01faf8 100644 --- a/src/dev_panel.cpp +++ b/src/dev_panel.cpp @@ -46,7 +46,7 @@ constexpr float DELTA_ANGLE_MAX = 30.0f; constexpr int PATH_STEP_MIN = 1; constexpr int PATH_STEP_MAX = 1000; -DevPanel::DevPanel(App& app) : m_app(app) {} +DevPanel::DevPanel(App& app) : m_app(app), m_config(app.config()) {} void DevPanel::init() { m_player = &m_app.client_world().get_player(); @@ -355,96 +355,95 @@ void DevPanel::show_chunk_table_bar() { void DevPanel::show_settings_tab_item() { if (ImGui::BeginTabItem("settings")) { - if (ImGui::SliderFloat("FOV", &m_config.fov, 1.0f, 140.0f)) { - Config::get().set("player.fov", static_cast(m_config.fov)); + if (ImGui::SliderFloat("FOV", &m_config_view.fov, 1.0f, 140.0f)) { + m_config.set("player.fov", static_cast(m_config_view.fov)); m_app.renderer().hot_reload(); } ImGui::SameLine(); if (ImGui::Button("default##1")) { - m_config.fov = DEFAULT_FOV; - Config::get().set("player.fov", static_cast(m_config.fov)); + m_config_view.fov = DEFAULT_FOV; + m_config.set("player.fov", static_cast(m_config_view.fov)); m_app.renderer().hot_reload(); } - if (ImGui::SliderFloat("Sensitivity", &m_config.mouse_sensitivity, + if (ImGui::SliderFloat("Sensitivity", &m_config_view.mouse_sensitivity, 0.01f, 1.0f)) { - Config::get().set("player.mouse_sensitivity", - static_cast(m_config.mouse_sensitivity)); + m_config.set("player.mouse_sensitivity", + static_cast(m_config_view.mouse_sensitivity)); m_player->hot_reload(); } ImGui::SameLine(); if (ImGui::Button("default##2")) { - m_config.mouse_sensitivity = 0.15f; - Config::get().set("player.mouse_sensitivity", - static_cast(m_config.mouse_sensitivity)); + m_config_view.mouse_sensitivity = 0.15f; + m_config.set("player.mouse_sensitivity", + static_cast(m_config_view.mouse_sensitivity)); m_player->hot_reload(); } - if (ImGui::SliderInt("Distance", &m_config.rendering_distance, 2, + if (ImGui::SliderInt("Distance", &m_config_view.rendering_distance, 2, 128)) { - Config::get().set("world.rendering_distance", - m_config.rendering_distance); + m_config.set("world.rendering_distance", + m_config_view.rendering_distance); m_app.client_world().hot_reload(); } - if (ImGui::Checkbox("Fullscreen", &m_config.fullscreen)) { - Config::get().set("window.fullscreen", m_config.fullscreen); + if (ImGui::Checkbox("Fullscreen", &m_config_view.fullscreen)) { + m_config.set("window.fullscreen", m_config_view.fullscreen); m_app.window().hot_reload(); } ImGui::SameLine(); - if (ImGui::Checkbox("V-Sync", &m_config.v_sync)) { - Config::get().set("window.V-Sync", m_config.v_sync); + if (ImGui::Checkbox("V-Sync", &m_config_view.v_sync)) { + m_config.set("window.V-Sync", m_config_view.v_sync); m_app.window().hot_reload(); } - if (ImGui::Checkbox("Aniso", &m_config.is_enable_aniso)) { - m_config.is_reload = false; - if (m_config.is_enable_aniso) { - m_config.max_aniso = m_app.texture_manager().max_aniso(); - if (m_config.max_aniso < 2) { - m_config.is_support_aniso = false; + if (ImGui::Checkbox("Aniso", &m_config_view.is_enable_aniso)) { + m_config_view.is_reload = false; + if (m_config_view.is_enable_aniso) { + m_config_view.max_aniso = m_app.texture_manager().max_aniso(); + if (m_config_view.max_aniso < 2) { + m_config_view.is_support_aniso = false; } else { - m_config.aniso = 2; + m_config_view.aniso = 2; } } else { - m_config.aniso = 1; + m_config_view.aniso = 1; } } - if (m_config.is_enable_aniso) { + if (m_config_view.is_enable_aniso) { ImGui::SameLine(); - if (!m_config.is_support_aniso) { + if (!m_config_view.is_support_aniso) { ImGui::Text("Not Support\n"); } else { - if (ImGui::SliderInt("##aniso", &m_config.aniso, 2, - m_config.max_aniso)) { - m_config.is_reload = false; + if (ImGui::SliderInt("##aniso", &m_config_view.aniso, 2, + m_config_view.max_aniso)) { + m_config_view.is_reload = false; int log = - static_cast(std::log2(m_config.aniso) + 0.5f); - m_config.aniso = static_cast(std::pow(2, log)); - if (m_config.aniso < 2) { - m_config.aniso = 2; + static_cast(std::log2(m_config_view.aniso) + 0.5f); + m_config_view.aniso = static_cast(std::pow(2, log)); + if (m_config_view.aniso < 2) { + m_config_view.aniso = 2; } - if (m_config.aniso > m_config.max_aniso) { - m_config.aniso = m_config.max_aniso; + if (m_config_view.aniso > m_config_view.max_aniso) { + m_config_view.aniso = m_config_view.max_aniso; } } } } if (ImGui::Button("ReloadTexture")) { - Config::get().set("texture.aniso", m_config.aniso); + m_config.set("texture.aniso", m_config_view.aniso); m_app.texture_manager().need_reload(); - m_config.is_reload = true; + m_config_view.is_reload = true; } - if (!m_config.is_reload) { + if (!m_config_view.is_reload) { ImGui::SameLine(); ImGui::Text("Your need to click this button to apply config\n"); } - if (ImGui::SliderFloat("Music", &m_config.volume_music, 0.0f, 1.0f)) { - Config::get().set("volume.music", - static_cast(m_config.volume_music)); + if (ImGui::SliderFloat("Music", &m_config_view.volume_music, 0.0f, + 1.0f)) { + m_config.set("volume.music", m_config_view.volume_music); m_app.audio().reload_config(); } - if (ImGui::SliderFloat("SFX", &m_config.volume_sfx, 0.0f, 1.0f)) { - Config::get().set("volume.SFX", - static_cast(m_config.volume_sfx)); + if (ImGui::SliderFloat("SFX", &m_config_view.volume_sfx, 0.0f, 1.0f)) { + m_config.set("volume.SFX", m_config_view.volume_sfx); m_app.audio().reload_config(); } if (ImGui::Combo("Theme", &m_theme, THEMES, IM_ARRAYSIZE(THEMES))) { @@ -453,10 +452,10 @@ void DevPanel::show_settings_tab_item() { } else if (m_theme == 1) { ImGui::StyleColorsLight(); } - Config::get().set("devpanel.theme", m_theme); + m_config.set("devpanel.theme", m_theme); } if (ImGui::Button("save")) { - Config::get().save_to_file(); + m_config.save_to_file(); } ImGui::EndTabItem(); @@ -750,32 +749,28 @@ void DevPanel::show_shader_tab_item() { } void DevPanel::update_config_view() { - auto config = Config::get(); - m_config.fov = - static_cast(config.val_view("player.fov").value_or(70.0)); - m_config.fullscreen = config.val_view("window.fullscreen").value_or(false); - m_config.v_sync = config.val_view("window.V-Sync").value_or(true); - m_config.mouse_sensitivity = static_cast( - config.val_view("player.mouse_sensitivity").value_or(0.15)); - m_config.width = config.val_view("window.width").value_or(800); - m_config.height = config.val_view("window.height").value_or(600); - m_config.rendering_distance = - config.val_view("world.rendering_distance").value_or(24); - m_theme = config.val_view("devpanel.theme").value_or(0); + m_config_view.fov = m_config.get("player.fov", 70.0f); + m_config_view.fullscreen = m_config.get("window.fullscreen", false); + m_config_view.v_sync = m_config.get("window.V-Sync", true); + m_config_view.mouse_sensitivity = + m_config.get("player.mouse_sensitivity", 0.15f); + m_config_view.width = m_config.get("window.width", 800); + m_config_view.height = m_config.get("window.height", 600); + m_config_view.rendering_distance = + m_config.get("world.rendering_distance", 24); + m_theme = m_config.get("devpanel.theme", 0); if (m_theme != 1 && m_theme != 0) { m_theme = 0; } - m_config.aniso = config.val_view("texture.aniso").value_or(1); - m_config.max_aniso = m_app.texture_manager().max_aniso(); - if (m_config.aniso <= 1) { - m_config.is_enable_aniso = false; + m_config_view.aniso = m_config.get("texture.aniso", 1); + m_config_view.max_aniso = m_app.texture_manager().max_aniso(); + if (m_config_view.aniso <= 1) { + m_config_view.is_enable_aniso = false; } else { - m_config.is_enable_aniso = true; + m_config_view.is_enable_aniso = true; } - m_config.volume_music = - static_cast(config.val_view("volume.music").value_or(1.0)); - m_config.volume_sfx = - static_cast(config.val_view("volume.SFX").value_or(1.0)); + m_config_view.volume_music = m_config.get("volume.music", 1.0f); + m_config_view.volume_sfx = m_config.get("volume.SFX", 1.0f); } void DevPanel::update_player_profile() { if (!m_player) { diff --git a/src/gameplay/client_player.cpp b/src/gameplay/client_player.cpp index f1a0ccb..0e0acab 100644 --- a/src/gameplay/client_player.cpp +++ b/src/gameplay/client_player.cpp @@ -121,9 +121,8 @@ void ClientPlayer::change_mode(GameMode mode) { } } void ClientPlayer::hot_reload() { - auto& config = Config::get(); - m_sensitivity = - static_cast(config.get("player.mouse_sensitivity")); + auto& config = m_world.get_config(); + m_sensitivity = config.get("player.mouse_sensitivity", 0.15f); } void ClientPlayer::set_player_pos(const glm::vec3& pos) { m_player_pos = pos; } @@ -562,7 +561,7 @@ const ClientPlayer::ChunkPosSet& ClientPlayer::get_chunk_pos_set() const { return m_player_chunk_pos_set; } -ClientPlayer::ChunkPosSet& ClientPlayer::get_chunk_pos_set() { +ClientPlayer::ChunkPosSet ClientPlayer::get_chunk_pos_set() { std::lock_guard lock(m_chunk_pos_mutex); return m_player_chunk_pos_set; } diff --git a/src/gameplay/client_world.cpp b/src/gameplay/client_world.cpp index f75b4a8..d44e5de 100644 --- a/src/gameplay/client_world.cpp +++ b/src/gameplay/client_world.cpp @@ -21,15 +21,26 @@ struct ChunkRenderData { }; } // namespace -ClientWorld::ClientWorld(AudioEngine& auido) - : m_player(*this), m_audio(auido) {} +ClientWorld::ClientWorld(AudioEngine& auido, Config& config) + : m_player(*this), m_audio(auido), m_config(config) {} ClientWorld::~ClientWorld() { + m_client->close(); + stop_client_thread(); stop_thread_pool(); + // Must first clean up and push the generated chunk data into + // m_pending_delete_vbo and m_pending_delete_vao; cannot delete them in the + // destructor, otherwise it will cause leaks and use-after-free. + m_dirty_chunk_queue.clear(); + m_pending_upload_queue.clear(); m_chunks.clear(); + if (m_is_pending_delete_queue_free.exchange(true)) { + return; + } + { std::lock_guard lk(m_delete_vbo_mutex); m_pending_delete_vbo.clear(); @@ -262,10 +273,18 @@ void ClientWorld::set_block(const glm::ivec3& block_pos, unsigned id) { } } void ClientWorld::push_delete_vbo(std::unique_ptr& vbo) { + if (m_is_pending_delete_queue_free) { + Logger::error("Push delete vbo Use After Free"); + return; + } std::lock_guard lk(m_delete_vbo_mutex); m_pending_delete_vbo.push_back(std::move(vbo)); } void ClientWorld::push_delete_vao(std::unique_ptr& vao) { + if (m_is_pending_delete_queue_free) { + Logger::error("Push delete vao Use After Free"); + return; + } std::lock_guard lk(m_delete_vao_mutex); m_pending_delete_vao.push_back(std::move(vao)); } @@ -504,8 +523,7 @@ void ClientWorld::change_pool_threads(int threads) { } void ClientWorld::hot_reload() { - auto& config = Config::get(); - int dist = config.get("world.rendering_distance"); + int dist = m_config.get("world.rendering_distance", PRE_LOAD_DISTANCE); Logger::info("Get Config Randering dist {}", dist); m_rendering_distance = dist <= MAX_DISTANCE ? dist : MAX_DISTANCE; request_chunk(); @@ -591,7 +609,7 @@ void ClientWorld::request_chunk() { } } - ChunkPosSet old = std::move(m_player.get_chunk_pos_set()); + ChunkPosSet old = m_player.get_chunk_pos_set(); m_player.update_chunk_set(required_chunks); ChunkPosVector need_send_pos; @@ -699,6 +717,7 @@ AABB ClientWorld::get_block_aabb(const glm::ivec3& pos) { } AudioEngine& ClientWorld::get_audio() { return m_audio; } +Config& ClientWorld::get_config() { return m_config; } void ClientWorld::request_exit() { if (m_receive_exit) { diff --git a/src/gameplay/network_server.cpp b/src/gameplay/network_server.cpp index 9e696c8..39d1ca5 100644 --- a/src/gameplay/network_server.cpp +++ b/src/gameplay/network_server.cpp @@ -4,7 +4,10 @@ using asio::ip::tcp; namespace Cubed { -NetworkServer::NetworkServer(int port) : m_port(port) {} +NetworkServer::NetworkServer() + : m_config(ASSETS_PATH "server-config.toml"), m_world(m_config) { + m_port = m_config.get("port", 25530); +} NetworkServer::~NetworkServer() { stop(); } @@ -84,6 +87,11 @@ void NetworkServer::net_run() { void NetworkServer::start_server(int port) { m_port = port; + m_config.set("port", m_port); + start_server(); +} + +void NetworkServer::start_server() { m_world.init_world(); net_run(); m_started = true; diff --git a/src/gameplay/server_world.cpp b/src/gameplay/server_world.cpp index 4b99234..b75552b 100644 --- a/src/gameplay/server_world.cpp +++ b/src/gameplay/server_world.cpp @@ -1,6 +1,5 @@ #include "Cubed/gameplay/server_world.hpp" -#include "Cubed/config.hpp" #include "Cubed/gameplay/packet.hpp" #include "Cubed/gameplay/session.hpp" #include "Cubed/tools/cubed_assert.hpp" @@ -14,7 +13,7 @@ using namespace std::chrono_literals; using namespace google::protobuf; namespace Cubed { -ServerWorld::ServerWorld() {} +ServerWorld::ServerWorld(Config& config) : m_config(config) {} ServerWorld::~ServerWorld() { stop(); } @@ -501,8 +500,7 @@ bool ServerWorld::set_block(const glm::ivec3& block_pos, unsigned id) { } void ServerWorld::hot_reload() { - auto& config = Config::get(); - int dist = config.get("world.rendering_distance"); + int dist = m_config.get("server_distance", 24); m_rendering_distance = dist <= MAX_DISTANCE ? dist : MAX_DISTANCE; } diff --git a/src/map_table.cpp b/src/map_table.cpp deleted file mode 100644 index 35088dc..0000000 --- a/src/map_table.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "Cubed/map_table.hpp" - -namespace Cubed { -/* -std::string_view MapTable::get_name_from_id(unsigned id) { - auto it = id_to_name_map.find(id); - ASSERT_MSG(it != id_to_name_map.end(), - "Id: " + std::to_string(id) + " is not exist"); - return it->second; -} - -unsigned MapTable::get_id_from_name(const std::string& name) { - auto it = name_to_id_map.find(HASH::str(name)); - ASSERT_MSG(it != name_to_id_map.end(), "Name " + name + " is not exist"); - return it->second; -} - -std::string_view MapTable::item_name(unsigned id) { - ASSERT_MSG(id < item_id_to_name.size(), "ID is invalid"); - return item_id_to_name[id]; -} - -const std::vector& MapTable::item_map() { return item_id_to_name; } - */ -void MapTable::init_map() { - /* - id_to_name_map.reserve(MAX_BLOCK_NUM); - name_to_id_map.reserve(MAX_BLOCK_NUM); - - for (int i = 0; i < MAX_BLOCK_NUM; i++) { - id_to_name_map[i] = BLOCK_REISTER[i]; - name_to_id_map[HASH::str(BLOCK_REISTER[i])] = i; - } - for (auto s : BLOCK_REISTER) { - item_id_to_name.emplace_back(s); - } - */ -} - -} // namespace Cubed diff --git a/src/render/renderer.cpp b/src/render/renderer.cpp index 8cc4ba1..eab6096 100644 --- a/src/render/renderer.cpp +++ b/src/render/renderer.cpp @@ -20,10 +20,11 @@ namespace Cubed { Renderer::Renderer(const Camera& camera, ClientWorld& world, - const TextureManager& texture_manager, DevPanel& dev_panel) + const TextureManager& texture_manager, DevPanel& dev_panel, + Config& config) : m_camera(camera), m_dev_panel(dev_panel), m_texture_manager(texture_manager), m_world(world), - m_world_renderer(*this) {} + m_world_renderer(*this), m_config(config) {} Renderer::~Renderer() { if (m_init) { @@ -38,10 +39,7 @@ Renderer::~Renderer() { } } -void Renderer::hot_reload() { - auto& config = Config::get(); - update_fov(config.get("player.fov")); -} +void Renderer::hot_reload() { update_fov(m_config.get("player.fov", 70.0f)); } void Renderer::init(bool debug_on) { if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { diff --git a/src/texture_manager.cpp b/src/texture_manager.cpp index 7df233a..91ab0e8 100644 --- a/src/texture_manager.cpp +++ b/src/texture_manager.cpp @@ -2,7 +2,6 @@ #include "Cubed/config.hpp" #include "Cubed/constants.hpp" -#include "Cubed/map_table.hpp" #include "Cubed/tools/cubed_assert.hpp" #include "Cubed/tools/log.hpp" #include "Cubed/tools/shader_tools.hpp" @@ -32,7 +31,7 @@ unsigned char* generate_flat_normal_map(int width = BLOCK_NORMAL_SIZE, namespace Cubed { -TextureManager::TextureManager() {} +TextureManager::TextureManager(Config& config) : m_config(config) {} TextureManager::~TextureManager() { delete_texture(); } @@ -286,10 +285,9 @@ void TextureManager::init_texture() { Logger::info("Support anisotropic filtering max_aniso is {}", m_max_aniso); } - m_aniso = Config::get().get("texture.aniso"); + m_aniso = m_config.get("texture.aniso", 1); m_aniso = std::min(static_cast(m_max_aniso), m_aniso); Logger::info("Setting Texture Aniso is {}", m_aniso); - MapTable::init_map(); Logger::info("Map Init Success"); init_block(); diff --git a/src/window.cpp b/src/window.cpp index 45e1fd1..3343231 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1,6 +1,5 @@ #include "Cubed/window.hpp" -#include "Cubed/config.hpp" #include "Cubed/render/renderer.hpp" #include "Cubed/tools/cubed_assert.hpp" #include "Cubed/tools/font.hpp" @@ -15,7 +14,8 @@ namespace Cubed { static int windowed_xpos = 0, windowed_ypos = 0; static int windowed_width = 800, windowed_height = 600; -Window::Window(Renderer& renderer) : m_renderer(renderer) {} +Window::Window(Renderer& renderer, Config& config) + : m_renderer(renderer), m_config(config) {} Window::~Window() { if (m_imgui_init) { @@ -47,9 +47,8 @@ void Window::update_viewport() { glViewport(0, 0, m_width, m_height); m_renderer.update_proj_matrix(m_aspect, m_width, m_height); m_renderer.updata_framebuffer(m_width, m_height); - auto& config = Config::get(); - config.set("window.width", windowed_width); - config.set("window.height", windowed_height); + m_config.set("window.width", windowed_width); + m_config.set("window.height", windowed_height); } void Window::init() { @@ -61,10 +60,9 @@ void Window::init() { glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6); glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); - auto& config = Config::get(); - m_width = config.get("window.width"); - m_height = config.get("window.height"); - if (config.get("window.fullscreen")) { + m_width = m_config.get("window.width", 800); + m_height = m_config.get("window.height", 600); + if (m_config.get("window.fullscreen", false)) { GLFWmonitor* primary_monitor = glfwGetPrimaryMonitor(); const GLFWvidmode* mode = glfwGetVideoMode(primary_monitor); m_window = glfwCreateWindow(mode->width, mode->height, "Cubed", @@ -74,7 +72,7 @@ void Window::init() { } glfwMakeContextCurrent(m_window); - if (config.get("window.V-Sync")) { + if (m_config.get("window.V-Sync", true)) { glfwSwapInterval(1); } else { glfwSwapInterval(0); @@ -94,18 +92,17 @@ void Window::init() { } void Window::hot_reload() { - auto& config = Config::get(); // V-Sync - if (config.get("window.V-Sync")) { + if (m_config.get("window.V-Sync", true)) { glfwSwapInterval(1); } else { glfwSwapInterval(0); } // Window - windowed_width = config.get("window.width"); - windowed_height = config.get("window.height"); + windowed_width = m_config.get("window.width", 800); + windowed_height = m_config.get("window.height", 600); - if (config.get("window.fullscreen")) { + if (m_config.get("window.fullscreen", false)) { glfwGetWindowPos(m_window, &windowed_xpos, &windowed_ypos); glfwGetWindowSize(m_window, &windowed_width, &windowed_height); @@ -134,13 +131,12 @@ void Window::hot_reload() { void Window::toggle_fullscreen() { - auto& config = Config::get(); GLFWmonitor* monitor = glfwGetWindowMonitor(m_window); if (monitor != nullptr) { glfwSetWindowMonitor(m_window, nullptr, windowed_xpos, windowed_ypos, windowed_width, windowed_height, 0); - config.set("window.fullscreen", false); + m_config.set("window.fullscreen", false); } else { glfwGetWindowPos(m_window, &windowed_xpos, &windowed_ypos); glfwGetWindowSize(m_window, &windowed_width, &windowed_height); @@ -150,7 +146,7 @@ void Window::toggle_fullscreen() { glfwSetWindowMonitor(m_window, primary, 0, 0, mode->width, mode->height, GL_DONT_CARE); - config.set("window.fullscreen", true); + m_config.set("window.fullscreen", true); } update_viewport(); } @@ -194,14 +190,14 @@ void Window::imgui_init() { // the game to fully control // cursor appearance (e.g., // hidden/disabled custom cursor). - auto theme = Config::get().get("devpanel.theme"); + auto theme = m_config.get("devpanel.theme", 0); if (theme == 0) { ImGui::StyleColorsDark(); } else if (theme == 1) { ImGui::StyleColorsLight(); } else { ImGui::StyleColorsDark(); - Config::get().set("devpanel.theme", 0); + m_config.set("devpanel.theme", 0); } ImGuiStyle& style = ImGui::GetStyle();