From f40d09cb8f712e87691af4912f3630d92d692779 Mon Sep 17 00:00:00 2001 From: untodesu Date: Thu, 11 Dec 2025 15:14:26 +0500 Subject: Shuffle stuff around - Use the new and improved hierarchy I figured out when making Prospero chat - Re-add NSIS scripts, again from Prospero - Update most build and utility scripts with their most recent versions --- game/client/CMakeLists.txt | 47 -- game/client/config/CMakeLists.txt | 7 - game/client/config/gamepad_axis.cc | 115 ---- game/client/config/gamepad_axis.hh | 38 -- game/client/config/gamepad_button.cc | 90 --- game/client/config/gamepad_button.hh | 28 - game/client/config/keybind.cc | 202 ------- game/client/config/keybind.hh | 25 - game/client/const.hh | 23 - game/client/entity/CMakeLists.txt | 15 - game/client/entity/camera.cc | 114 ---- game/client/entity/camera.hh | 31 - game/client/entity/factory.cc | 30 - game/client/entity/factory.hh | 11 - game/client/entity/interpolation.cc | 64 -- game/client/entity/interpolation.hh | 6 - game/client/entity/listener.cc | 42 -- game/client/entity/listener.hh | 6 - game/client/entity/player_look.cc | 155 ----- game/client/entity/player_look.hh | 7 - game/client/entity/player_move.cc | 298 --------- game/client/entity/player_move.hh | 15 - game/client/entity/sound_emitter.cc | 63 -- game/client/entity/sound_emitter.hh | 20 - game/client/experiments.cc | 84 --- game/client/experiments.hh | 16 - game/client/game.cc | 709 ---------------------- game/client/game.hh | 35 -- game/client/globals.cc | 47 -- game/client/globals.hh | 71 --- game/client/gui/CMakeLists.txt | 38 -- game/client/gui/background.cc | 39 -- game/client/gui/background.hh | 8 - game/client/gui/bother.cc | 167 ----- game/client/gui/bother.hh | 24 - game/client/gui/chat.cc | 273 --------- game/client/gui/chat.hh | 17 - game/client/gui/crosshair.cc | 43 -- game/client/gui/crosshair.hh | 8 - game/client/gui/direct_connection.cc | 145 ----- game/client/gui/direct_connection.hh | 7 - game/client/gui/gui_screen.hh | 10 - game/client/gui/hotbar.cc | 182 ------ game/client/gui/hotbar.hh | 30 - game/client/gui/imdraw_ext.cc | 34 -- game/client/gui/imdraw_ext.hh | 17 - game/client/gui/language.cc | 202 ------- game/client/gui/language.hh | 42 -- game/client/gui/main_menu.cc | 172 ------ game/client/gui/main_menu.hh | 8 - game/client/gui/message_box.cc | 95 --- game/client/gui/message_box.hh | 20 - game/client/gui/metrics.cc | 103 ---- game/client/gui/metrics.hh | 7 - game/client/gui/play_menu.cc | 594 ------------------ game/client/gui/play_menu.hh | 9 - game/client/gui/progress_bar.cc | 111 ---- game/client/gui/progress_bar.hh | 19 - game/client/gui/scoreboard.cc | 103 ---- game/client/gui/scoreboard.hh | 7 - game/client/gui/settings.cc | 1069 --------------------------------- game/client/gui/settings.hh | 90 --- game/client/gui/splash.cc | 178 ------ game/client/gui/splash.hh | 8 - game/client/gui/status_lines.cc | 84 --- game/client/gui/status_lines.hh | 21 - game/client/gui/window_title.cc | 14 - game/client/gui/window_title.hh | 6 - game/client/io/CMakeLists.txt | 4 - game/client/io/gamepad.cc | 183 ------ game/client/io/gamepad.hh | 50 -- game/client/io/glfw.hh | 36 -- game/client/main.cc | 449 -------------- game/client/pch.hh | 28 - game/client/program.cc | 226 ------- game/client/program.hh | 34 -- game/client/receive.cc | 192 ------ game/client/receive.hh | 6 - game/client/resource/CMakeLists.txt | 5 - game/client/resource/sound_effect.cc | 90 --- game/client/resource/sound_effect.hh | 8 - game/client/resource/texture_gui.cc | 83 --- game/client/resource/texture_gui.hh | 15 - game/client/screenshot.cc | 86 --- game/client/screenshot.hh | 7 - game/client/session.cc | 313 ---------- game/client/session.hh | 27 - game/client/sound/CMakeLists.txt | 3 - game/client/sound/sound.cc | 211 ------- game/client/sound/sound.hh | 43 -- game/client/toggles.cc | 157 ----- game/client/toggles.hh | 35 -- game/client/vclient.ico | Bin 54361 -> 0 bytes game/client/vclient.rc | 1 - game/client/world/CMakeLists.txt | 21 - game/client/world/chunk_mesher.cc | 450 -------------- game/client/world/chunk_mesher.hh | 18 - game/client/world/chunk_quad.hh | 41 -- game/client/world/chunk_renderer.cc | 204 ------- game/client/world/chunk_renderer.hh | 8 - game/client/world/chunk_vbo.hh | 22 - game/client/world/chunk_visibility.cc | 90 --- game/client/world/chunk_visibility.hh | 6 - game/client/world/outline.cc | 150 ----- game/client/world/outline.hh | 16 - game/client/world/player_target.cc | 64 -- game/client/world/player_target.hh | 17 - game/client/world/skybox.cc | 11 - game/client/world/skybox.hh | 11 - game/client/world/voxel_anims.cc | 33 - game/client/world/voxel_anims.hh | 13 - game/client/world/voxel_atlas.cc | 185 ------ game/client/world/voxel_atlas.hh | 28 - game/client/world/voxel_sounds.cc | 83 --- game/client/world/voxel_sounds.hh | 19 - 115 files changed, 10200 deletions(-) delete mode 100644 game/client/CMakeLists.txt delete mode 100644 game/client/config/CMakeLists.txt delete mode 100644 game/client/config/gamepad_axis.cc delete mode 100644 game/client/config/gamepad_axis.hh delete mode 100644 game/client/config/gamepad_button.cc delete mode 100644 game/client/config/gamepad_button.hh delete mode 100644 game/client/config/keybind.cc delete mode 100644 game/client/config/keybind.hh delete mode 100644 game/client/const.hh delete mode 100644 game/client/entity/CMakeLists.txt delete mode 100644 game/client/entity/camera.cc delete mode 100644 game/client/entity/camera.hh delete mode 100644 game/client/entity/factory.cc delete mode 100644 game/client/entity/factory.hh delete mode 100644 game/client/entity/interpolation.cc delete mode 100644 game/client/entity/interpolation.hh delete mode 100644 game/client/entity/listener.cc delete mode 100644 game/client/entity/listener.hh delete mode 100644 game/client/entity/player_look.cc delete mode 100644 game/client/entity/player_look.hh delete mode 100644 game/client/entity/player_move.cc delete mode 100644 game/client/entity/player_move.hh delete mode 100644 game/client/entity/sound_emitter.cc delete mode 100644 game/client/entity/sound_emitter.hh delete mode 100644 game/client/experiments.cc delete mode 100644 game/client/experiments.hh delete mode 100644 game/client/game.cc delete mode 100644 game/client/game.hh delete mode 100644 game/client/globals.cc delete mode 100644 game/client/globals.hh delete mode 100644 game/client/gui/CMakeLists.txt delete mode 100644 game/client/gui/background.cc delete mode 100644 game/client/gui/background.hh delete mode 100644 game/client/gui/bother.cc delete mode 100644 game/client/gui/bother.hh delete mode 100644 game/client/gui/chat.cc delete mode 100644 game/client/gui/chat.hh delete mode 100644 game/client/gui/crosshair.cc delete mode 100644 game/client/gui/crosshair.hh delete mode 100644 game/client/gui/direct_connection.cc delete mode 100644 game/client/gui/direct_connection.hh delete mode 100644 game/client/gui/gui_screen.hh delete mode 100644 game/client/gui/hotbar.cc delete mode 100644 game/client/gui/hotbar.hh delete mode 100644 game/client/gui/imdraw_ext.cc delete mode 100644 game/client/gui/imdraw_ext.hh delete mode 100644 game/client/gui/language.cc delete mode 100644 game/client/gui/language.hh delete mode 100644 game/client/gui/main_menu.cc delete mode 100644 game/client/gui/main_menu.hh delete mode 100644 game/client/gui/message_box.cc delete mode 100644 game/client/gui/message_box.hh delete mode 100644 game/client/gui/metrics.cc delete mode 100644 game/client/gui/metrics.hh delete mode 100644 game/client/gui/play_menu.cc delete mode 100644 game/client/gui/play_menu.hh delete mode 100644 game/client/gui/progress_bar.cc delete mode 100644 game/client/gui/progress_bar.hh delete mode 100644 game/client/gui/scoreboard.cc delete mode 100644 game/client/gui/scoreboard.hh delete mode 100644 game/client/gui/settings.cc delete mode 100644 game/client/gui/settings.hh delete mode 100644 game/client/gui/splash.cc delete mode 100644 game/client/gui/splash.hh delete mode 100644 game/client/gui/status_lines.cc delete mode 100644 game/client/gui/status_lines.hh delete mode 100644 game/client/gui/window_title.cc delete mode 100644 game/client/gui/window_title.hh delete mode 100644 game/client/io/CMakeLists.txt delete mode 100644 game/client/io/gamepad.cc delete mode 100644 game/client/io/gamepad.hh delete mode 100644 game/client/io/glfw.hh delete mode 100644 game/client/main.cc delete mode 100644 game/client/pch.hh delete mode 100644 game/client/program.cc delete mode 100644 game/client/program.hh delete mode 100644 game/client/receive.cc delete mode 100644 game/client/receive.hh delete mode 100644 game/client/resource/CMakeLists.txt delete mode 100644 game/client/resource/sound_effect.cc delete mode 100644 game/client/resource/sound_effect.hh delete mode 100644 game/client/resource/texture_gui.cc delete mode 100644 game/client/resource/texture_gui.hh delete mode 100644 game/client/screenshot.cc delete mode 100644 game/client/screenshot.hh delete mode 100644 game/client/session.cc delete mode 100644 game/client/session.hh delete mode 100644 game/client/sound/CMakeLists.txt delete mode 100644 game/client/sound/sound.cc delete mode 100644 game/client/sound/sound.hh delete mode 100644 game/client/toggles.cc delete mode 100644 game/client/toggles.hh delete mode 100644 game/client/vclient.ico delete mode 100644 game/client/vclient.rc delete mode 100644 game/client/world/CMakeLists.txt delete mode 100644 game/client/world/chunk_mesher.cc delete mode 100644 game/client/world/chunk_mesher.hh delete mode 100644 game/client/world/chunk_quad.hh delete mode 100644 game/client/world/chunk_renderer.cc delete mode 100644 game/client/world/chunk_renderer.hh delete mode 100644 game/client/world/chunk_vbo.hh delete mode 100644 game/client/world/chunk_visibility.cc delete mode 100644 game/client/world/chunk_visibility.hh delete mode 100644 game/client/world/outline.cc delete mode 100644 game/client/world/outline.hh delete mode 100644 game/client/world/player_target.cc delete mode 100644 game/client/world/player_target.hh delete mode 100644 game/client/world/skybox.cc delete mode 100644 game/client/world/skybox.hh delete mode 100644 game/client/world/voxel_anims.cc delete mode 100644 game/client/world/voxel_anims.hh delete mode 100644 game/client/world/voxel_atlas.cc delete mode 100644 game/client/world/voxel_atlas.hh delete mode 100644 game/client/world/voxel_sounds.cc delete mode 100644 game/client/world/voxel_sounds.hh (limited to 'game/client') diff --git a/game/client/CMakeLists.txt b/game/client/CMakeLists.txt deleted file mode 100644 index 633e486..0000000 --- a/game/client/CMakeLists.txt +++ /dev/null @@ -1,47 +0,0 @@ -add_executable(vclient - "${CMAKE_CURRENT_LIST_DIR}/const.hh" - "${CMAKE_CURRENT_LIST_DIR}/experiments.cc" - "${CMAKE_CURRENT_LIST_DIR}/experiments.hh" - "${CMAKE_CURRENT_LIST_DIR}/game.cc" - "${CMAKE_CURRENT_LIST_DIR}/game.hh" - "${CMAKE_CURRENT_LIST_DIR}/globals.cc" - "${CMAKE_CURRENT_LIST_DIR}/globals.hh" - "${CMAKE_CURRENT_LIST_DIR}/main.cc" - "${CMAKE_CURRENT_LIST_DIR}/pch.hh" - "${CMAKE_CURRENT_LIST_DIR}/program.cc" - "${CMAKE_CURRENT_LIST_DIR}/program.hh" - "${CMAKE_CURRENT_LIST_DIR}/receive.cc" - "${CMAKE_CURRENT_LIST_DIR}/receive.hh" - "${CMAKE_CURRENT_LIST_DIR}/screenshot.cc" - "${CMAKE_CURRENT_LIST_DIR}/screenshot.hh" - "${CMAKE_CURRENT_LIST_DIR}/session.cc" - "${CMAKE_CURRENT_LIST_DIR}/session.hh" - "${CMAKE_CURRENT_LIST_DIR}/toggles.cc" - "${CMAKE_CURRENT_LIST_DIR}/toggles.hh") -target_compile_features(vclient PUBLIC cxx_std_20) -target_compile_definitions(vclient PUBLIC GLFW_INCLUDE_NONE) -target_include_directories(vclient PRIVATE "${PROJECT_SOURCE_DIR}") -target_include_directories(vclient PRIVATE "${PROJECT_SOURCE_DIR}/game") -target_precompile_headers(vclient PRIVATE "${CMAKE_CURRENT_LIST_DIR}/pch.hh") -target_link_libraries(vclient PUBLIC shared dr_libs glad glfw imgui imgui-glfw imgui-opengl3 salad) - -add_subdirectory(config) -add_subdirectory(entity) -add_subdirectory(gui) -add_subdirectory(io) -add_subdirectory(resource) -add_subdirectory(sound) -add_subdirectory(world) - -if(WIN32 AND MSVC) - # GLFW defines APIENTRY and ENet includes - # Windows API headers which also define APIENTRY - target_compile_options(vclient PRIVATE /wd4005) -endif() - -if(WIN32) - enable_language(RC) - target_sources(vclient PRIVATE "${CMAKE_CURRENT_LIST_DIR}/vclient.rc") -endif() - -install(TARGETS vclient RUNTIME DESTINATION ".") diff --git a/game/client/config/CMakeLists.txt b/game/client/config/CMakeLists.txt deleted file mode 100644 index 0536160..0000000 --- a/game/client/config/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -target_sources(vclient PRIVATE - "${CMAKE_CURRENT_LIST_DIR}/gamepad_axis.cc" - "${CMAKE_CURRENT_LIST_DIR}/gamepad_axis.hh" - "${CMAKE_CURRENT_LIST_DIR}/gamepad_button.cc" - "${CMAKE_CURRENT_LIST_DIR}/gamepad_button.hh" - "${CMAKE_CURRENT_LIST_DIR}/keybind.cc" - "${CMAKE_CURRENT_LIST_DIR}/keybind.hh") diff --git a/game/client/config/gamepad_axis.cc b/game/client/config/gamepad_axis.cc deleted file mode 100644 index 9cc731c..0000000 --- a/game/client/config/gamepad_axis.cc +++ /dev/null @@ -1,115 +0,0 @@ -#include "client/pch.hh" - -#include "client/config/gamepad_axis.hh" - -#include "core/math/constexpr.hh" - -#include "client/io/gamepad.hh" - -constexpr static std::string_view UNKNOWN_AXIS_NAME = "UNKNOWN"; - -static const std::pair axis_names[] = { - { GLFW_GAMEPAD_AXIS_LEFT_X, "LEFT_X" }, - { GLFW_GAMEPAD_AXIS_LEFT_Y, "LEFT_Y" }, - { GLFW_GAMEPAD_AXIS_RIGHT_X, "RIGHT_X" }, - { GLFW_GAMEPAD_AXIS_RIGHT_Y, "RIGHT_Y" }, - { GLFW_GAMEPAD_AXIS_LEFT_TRIGGER, "LEFT_TRIG" }, - { GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, "RIGHT_TRIG" }, -}; - -static std::string_view get_axis_name(int axis) -{ - for(const auto& it : axis_names) { - if(it.first != axis) { - continue; - } - - return it.second; - } - - return UNKNOWN_AXIS_NAME; -} - -config::GamepadAxis::GamepadAxis(void) : GamepadAxis(io::INVALID_GAMEPAD_AXIS, false) -{ -} - -config::GamepadAxis::GamepadAxis(int axis, bool inverted) -{ - m_inverted = inverted; - m_gamepad_axis = axis; - m_name = get_axis_name(axis); - m_full_string = std::format("{}:{}", m_name, m_inverted ? 1U : 0U); -} - -std::string_view config::GamepadAxis::get(void) const -{ - return m_full_string; -} - -void config::GamepadAxis::set(std::string_view value) -{ - char new_name[64]; - unsigned int new_invert; - std::string value_str(value); - - if(2 == std::sscanf(value_str.c_str(), "%63[^:]:%u", new_name, &new_invert)) { - for(const auto& it : axis_names) { - if(0 == it.second.compare(new_name)) { - m_inverted = new_invert; - m_gamepad_axis = it.first; - m_name = get_axis_name(m_gamepad_axis); - m_full_string = std::format("{}:{}", m_name, m_inverted ? 1U : 0U); - return; - } - } - } - - m_inverted = false; - m_gamepad_axis = io::INVALID_GAMEPAD_AXIS; - m_name = UNKNOWN_AXIS_NAME; - m_full_string = std::format("{}:{}", m_name, m_inverted ? 1U : 0U); -} - -int config::GamepadAxis::get_axis(void) const -{ - return m_gamepad_axis; -} - -void config::GamepadAxis::set_axis(int axis) -{ - m_gamepad_axis = axis; - m_name = get_axis_name(axis); - m_full_string = std::format("{}:{}", m_name, m_inverted ? 1U : 0U); -} - -bool config::GamepadAxis::is_inverted(void) const -{ - return m_inverted; -} - -void config::GamepadAxis::set_inverted(bool inverted) -{ - m_inverted = inverted; - m_full_string = std::format("{}:{}", m_name, m_inverted ? 1U : 0U); -} - -float config::GamepadAxis::get_value(const GLFWgamepadstate& state, float deadzone) const -{ - if(m_gamepad_axis <= math::array_size(state.axes)) { - auto value = state.axes[m_gamepad_axis]; - - if(glm::abs(value) > deadzone) { - return m_inverted ? -value : value; - } - - return 0.0f; - } - - return 0.0f; -} - -std::string_view config::GamepadAxis::get_name(void) const -{ - return m_name; -} diff --git a/game/client/config/gamepad_axis.hh b/game/client/config/gamepad_axis.hh deleted file mode 100644 index 80c323f..0000000 --- a/game/client/config/gamepad_axis.hh +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include "core/config/ivalue.hh" - -struct GLFWgamepadstate; - -namespace config -{ -class GamepadAxis final : public IValue { -public: - explicit GamepadAxis(void); - explicit GamepadAxis(int axis, bool inverted); - virtual ~GamepadAxis(void) = default; - - virtual std::string_view get(void) const override; - virtual void set(std::string_view value) override; - - int get_axis(void) const; - void set_axis(int axis); - - bool is_inverted(void) const; - void set_inverted(bool inverted); - - float get_value(const GLFWgamepadstate& state, float deadzone = 0.0f) const; - - // Conventional get/set methods implemented by - // this configuration value actually contain the - // inversion flag. Since we're updating that flag - // in the UI by means of a separate checkbox, we only need the name here - std::string_view get_name(void) const; - -private: - bool m_inverted; - int m_gamepad_axis; - std::string m_full_string; - std::string_view m_name; -}; -} // namespace config diff --git a/game/client/config/gamepad_button.cc b/game/client/config/gamepad_button.cc deleted file mode 100644 index 5141de3..0000000 --- a/game/client/config/gamepad_button.cc +++ /dev/null @@ -1,90 +0,0 @@ -#include "client/pch.hh" - -#include "client/config/gamepad_button.hh" - -#include "core/math/constexpr.hh" - -#include "client/io/gamepad.hh" - -constexpr static std::string_view UNKNOWN_BUTTON_NAME = "UNKNOWN"; - -static const std::pair button_names[] = { - { GLFW_GAMEPAD_BUTTON_A, "A" }, - { GLFW_GAMEPAD_BUTTON_B, "B" }, - { GLFW_GAMEPAD_BUTTON_X, "X" }, - { GLFW_GAMEPAD_BUTTON_Y, "Y" }, - { GLFW_GAMEPAD_BUTTON_LEFT_BUMPER, "L_BUMP" }, - { GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER, "R_BUMP" }, - { GLFW_GAMEPAD_BUTTON_BACK, "BACK" }, - { GLFW_GAMEPAD_BUTTON_START, "START" }, - { GLFW_GAMEPAD_BUTTON_GUIDE, "GUIDE" }, - { GLFW_GAMEPAD_BUTTON_LEFT_THUMB, "L_THUMB" }, - { GLFW_GAMEPAD_BUTTON_RIGHT_THUMB, "R_THUMB" }, - { GLFW_GAMEPAD_BUTTON_DPAD_UP, "DPAD_UP" }, - { GLFW_GAMEPAD_BUTTON_DPAD_RIGHT, "DPAD_RIGHT" }, - { GLFW_GAMEPAD_BUTTON_DPAD_DOWN, "DPAD_DOWN" }, - { GLFW_GAMEPAD_BUTTON_DPAD_LEFT, "DPAD_LEFT" }, -}; - -static std::string_view get_button_name(int button) -{ - for(const auto& it : button_names) { - if(it.first == button) { - return it.second; - } - } - - return UNKNOWN_BUTTON_NAME; -} - -config::GamepadButton::GamepadButton(void) -{ - m_gamepad_button = io::INVALID_GAMEPAD_BUTTON; - m_name = UNKNOWN_BUTTON_NAME; -} - -config::GamepadButton::GamepadButton(int button) -{ - m_gamepad_button = button; - m_name = get_button_name(button); -} - -std::string_view config::GamepadButton::get(void) const -{ - return m_name; -} - -void config::GamepadButton::set(std::string_view value) -{ - for(const auto& it : button_names) { - if(0 == it.second.compare(value)) { - m_gamepad_button = it.first; - m_name = it.second; - return; - } - } - - m_gamepad_button = io::INVALID_GAMEPAD_BUTTON; - m_name = UNKNOWN_BUTTON_NAME; -} - -int config::GamepadButton::get_button(void) const -{ - return m_gamepad_button; -} - -void config::GamepadButton::set_button(int button) -{ - m_gamepad_button = button; - m_name = get_button_name(button); -} - -bool config::GamepadButton::equals(int button) const -{ - return m_gamepad_button == button; -} - -bool config::GamepadButton::is_pressed(const GLFWgamepadstate& state) const -{ - return m_gamepad_button < math::array_size(state.buttons) && state.buttons[m_gamepad_button] == GLFW_PRESS; -} diff --git a/game/client/config/gamepad_button.hh b/game/client/config/gamepad_button.hh deleted file mode 100644 index f11fe4f..0000000 --- a/game/client/config/gamepad_button.hh +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include "core/config/ivalue.hh" - -struct GLFWgamepadstate; - -namespace config -{ -class GamepadButton final : public IValue { -public: - explicit GamepadButton(void); - explicit GamepadButton(int button); - virtual ~GamepadButton(void) = default; - - virtual std::string_view get(void) const override; - virtual void set(std::string_view value) override; - - int get_button(void) const; - void set_button(int button); - - bool equals(int button) const; - bool is_pressed(const GLFWgamepadstate& state) const; - -private: - int m_gamepad_button; - std::string_view m_name; -}; -} // namespace config diff --git a/game/client/config/keybind.cc b/game/client/config/keybind.cc deleted file mode 100644 index befdca2..0000000 --- a/game/client/config/keybind.cc +++ /dev/null @@ -1,202 +0,0 @@ -#include "client/pch.hh" - -#include "client/config/keybind.hh" - -#include "core/math/constexpr.hh" - -#include "client/const.hh" - -constexpr static std::string_view UNKNOWN_KEY_NAME = "UNKNOWN"; - -static const std::pair key_names[] = { - { GLFW_KEY_SPACE, "SPACE" }, - { GLFW_KEY_APOSTROPHE, "'" }, - { GLFW_KEY_COMMA, "," }, - { GLFW_KEY_MINUS, "-" }, - { GLFW_KEY_PERIOD, "." }, - { GLFW_KEY_SLASH, "/" }, - { GLFW_KEY_0, "0" }, - { GLFW_KEY_1, "1" }, - { GLFW_KEY_2, "2" }, - { GLFW_KEY_3, "3" }, - { GLFW_KEY_4, "4" }, - { GLFW_KEY_5, "5" }, - { GLFW_KEY_6, "6" }, - { GLFW_KEY_7, "7" }, - { GLFW_KEY_8, "8" }, - { GLFW_KEY_9, "9" }, - { GLFW_KEY_SEMICOLON, ";" }, - { GLFW_KEY_EQUAL, "=" }, - { GLFW_KEY_A, "A" }, - { GLFW_KEY_B, "B" }, - { GLFW_KEY_C, "C" }, - { GLFW_KEY_D, "D" }, - { GLFW_KEY_E, "E" }, - { GLFW_KEY_F, "F" }, - { GLFW_KEY_G, "G" }, - { GLFW_KEY_H, "H" }, - { GLFW_KEY_I, "I" }, - { GLFW_KEY_J, "J" }, - { GLFW_KEY_K, "K" }, - { GLFW_KEY_L, "L" }, - { GLFW_KEY_M, "M" }, - { GLFW_KEY_N, "N" }, - { GLFW_KEY_O, "O" }, - { GLFW_KEY_P, "P" }, - { GLFW_KEY_Q, "Q" }, - { GLFW_KEY_R, "R" }, - { GLFW_KEY_S, "S" }, - { GLFW_KEY_T, "T" }, - { GLFW_KEY_U, "U" }, - { GLFW_KEY_V, "V" }, - { GLFW_KEY_W, "W" }, - { GLFW_KEY_X, "X" }, - { GLFW_KEY_Y, "Y" }, - { GLFW_KEY_Z, "Z" }, - { GLFW_KEY_LEFT_BRACKET, "[" }, - { GLFW_KEY_BACKSLASH, "\\" }, - { GLFW_KEY_RIGHT_BRACKET, "]" }, - { GLFW_KEY_GRAVE_ACCENT, "`" }, - { GLFW_KEY_WORLD_1, "WORLD_1" }, - { GLFW_KEY_WORLD_2, "WORLD_2" }, - { GLFW_KEY_ESCAPE, "ESCAPE" }, - { GLFW_KEY_ENTER, "ENTER" }, - { GLFW_KEY_TAB, "TAB" }, - { GLFW_KEY_BACKSPACE, "BACKSPACE" }, - { GLFW_KEY_INSERT, "INSERT" }, - { GLFW_KEY_DELETE, "DELETE" }, - { GLFW_KEY_RIGHT, "RIGHT" }, - { GLFW_KEY_LEFT, "LEFT" }, - { GLFW_KEY_DOWN, "DOWN" }, - { GLFW_KEY_UP, "UP" }, - { GLFW_KEY_PAGE_UP, "PAGE_UP" }, - { GLFW_KEY_PAGE_DOWN, "PAGE_DOWN" }, - { GLFW_KEY_HOME, "HOME" }, - { GLFW_KEY_END, "END" }, - { GLFW_KEY_CAPS_LOCK, "CAPS_LOCK" }, - { GLFW_KEY_SCROLL_LOCK, "SCROLL_LOCK" }, - { GLFW_KEY_NUM_LOCK, "NUM_LOCK" }, - { GLFW_KEY_PRINT_SCREEN, "PRINT_SCREEN" }, - { GLFW_KEY_PAUSE, "PAUSE" }, - { GLFW_KEY_F1, "F1" }, - { GLFW_KEY_F2, "F2" }, - { GLFW_KEY_F3, "F3" }, - { GLFW_KEY_F4, "F4" }, - { GLFW_KEY_F5, "F5" }, - { GLFW_KEY_F6, "F6" }, - { GLFW_KEY_F7, "F7" }, - { GLFW_KEY_F8, "F8" }, - { GLFW_KEY_F9, "F9" }, - { GLFW_KEY_F10, "F10" }, - { GLFW_KEY_F11, "F11" }, - { GLFW_KEY_F12, "F12" }, - { GLFW_KEY_F13, "F13" }, - { GLFW_KEY_F14, "F14" }, - { GLFW_KEY_F15, "F15" }, - { GLFW_KEY_F16, "F16" }, - { GLFW_KEY_F17, "F17" }, - { GLFW_KEY_F18, "F18" }, - { GLFW_KEY_F19, "F19" }, - { GLFW_KEY_F20, "F20" }, - { GLFW_KEY_F21, "F21" }, - { GLFW_KEY_F22, "F22" }, - { GLFW_KEY_F23, "F23" }, - { GLFW_KEY_F24, "F24" }, - { GLFW_KEY_F25, "F25" }, - { GLFW_KEY_KP_0, "KEYPAD_0" }, - { GLFW_KEY_KP_1, "KEYPAD_1" }, - { GLFW_KEY_KP_2, "KEYPAD_2" }, - { GLFW_KEY_KP_3, "KEYPAD_3" }, - { GLFW_KEY_KP_4, "KEYPAD_4" }, - { GLFW_KEY_KP_5, "KEYPAD_5" }, - { GLFW_KEY_KP_6, "KEYPAD_6" }, - { GLFW_KEY_KP_7, "KEYPAD_7" }, - { GLFW_KEY_KP_8, "KEYPAD_8" }, - { GLFW_KEY_KP_9, "KEYPAD_9" }, - { GLFW_KEY_KP_DECIMAL, "KEYPAD_POINT" }, - { GLFW_KEY_KP_DIVIDE, "KEYPAD_DIV" }, - { GLFW_KEY_KP_MULTIPLY, "KEYPAD_MUL" }, - { GLFW_KEY_KP_SUBTRACT, "KEYPAD_MINUS" }, - { GLFW_KEY_KP_ADD, "KEYPAD_PLUS" }, - { GLFW_KEY_KP_ENTER, "KEYPAD_ENTER" }, - { GLFW_KEY_KP_EQUAL, "KEYPAD_EQUAL" }, - { GLFW_KEY_LEFT_SHIFT, "LEFT_SHIFT" }, - { GLFW_KEY_LEFT_CONTROL, "LEFT_CTRL" }, - { GLFW_KEY_LEFT_ALT, "LEFT_ALT" }, - { GLFW_KEY_LEFT_SUPER, "LEFT_SUPER" }, - { GLFW_KEY_RIGHT_SHIFT, "RIGHT_SHIFT" }, - { GLFW_KEY_RIGHT_CONTROL, "RIGHT_CTRL" }, - { GLFW_KEY_RIGHT_ALT, "RIGHT_ALT" }, - { GLFW_KEY_RIGHT_SUPER, "RIGHT_SUPER" }, - { GLFW_KEY_MENU, "MENU" }, -}; - -static std::string_view get_key_name(int keycode) -{ - for(const auto& it : key_names) { - if(it.first == keycode) { - return it.second; - } - } - - return UNKNOWN_KEY_NAME; -} - -config::KeyBind::KeyBind(void) -{ - m_glfw_keycode = GLFW_KEY_UNKNOWN; - m_name = UNKNOWN_KEY_NAME; -} - -config::KeyBind::KeyBind(int default_value) -{ - if(default_value == DEBUG_KEY) { - m_glfw_keycode = GLFW_KEY_UNKNOWN; - m_name = UNKNOWN_KEY_NAME; - } - else { - m_glfw_keycode = default_value; - m_name = get_key_name(default_value); - } -} - -void config::KeyBind::set(std::string_view value) -{ - for(const auto& it : key_names) { - if((it.first != DEBUG_KEY) && 0 == it.second.compare(value)) { - m_glfw_keycode = it.first; - m_name = it.second; - return; - } - } - - m_glfw_keycode = GLFW_KEY_UNKNOWN; - m_name = UNKNOWN_KEY_NAME; -} - -std::string_view config::KeyBind::get(void) const -{ - return m_name; -} - -void config::KeyBind::set_key(int keycode) -{ - if(keycode == DEBUG_KEY) { - m_glfw_keycode = GLFW_KEY_UNKNOWN; - m_name = UNKNOWN_KEY_NAME; - } - else { - m_glfw_keycode = keycode; - m_name = get_key_name(keycode); - } -} - -int config::KeyBind::get_key(void) const -{ - return m_glfw_keycode; -} - -bool config::KeyBind::equals(int keycode) const -{ - return m_glfw_keycode == keycode; -} diff --git a/game/client/config/keybind.hh b/game/client/config/keybind.hh deleted file mode 100644 index 51a67d6..0000000 --- a/game/client/config/keybind.hh +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "core/config/ivalue.hh" - -namespace config -{ -class KeyBind final : public IValue { -public: - explicit KeyBind(void); - explicit KeyBind(int default_value); - virtual ~KeyBind(void) = default; - - virtual void set(std::string_view value) override; - virtual std::string_view get(void) const override; - - void set_key(int keycode); - int get_key(void) const; - - bool equals(int keycode) const; - -private: - std::string_view m_name; - int m_glfw_keycode; -}; -} // namespace config diff --git a/game/client/const.hh b/game/client/const.hh deleted file mode 100644 index b1e458f..0000000 --- a/game/client/const.hh +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include "shared/const.hh" - -// This key is then going to be reserved for only -// the debug toggles and users won't be able to -// use this key for conventional gameplay things -constexpr static int DEBUG_KEY = GLFW_KEY_F3; - -constexpr static int BASE_WIDTH = 320; -constexpr static int BASE_HEIGHT = 240; - -constexpr static int MIN_WIDTH = 2 * BASE_WIDTH; -constexpr static int MIN_HEIGHT = 2 * BASE_HEIGHT; - -constexpr static int DEFAULT_WIDTH = 720; -constexpr static int DEFAULT_HEIGHT = 480; - -static_assert(DEFAULT_WIDTH >= MIN_WIDTH); -static_assert(DEFAULT_HEIGHT >= MIN_HEIGHT); - -constexpr static float MIN_PITCH = 0.0625f; -constexpr static float MAX_PITCH = 10.0f; diff --git a/game/client/entity/CMakeLists.txt b/game/client/entity/CMakeLists.txt deleted file mode 100644 index 4da10d6..0000000 --- a/game/client/entity/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -target_sources(vclient PRIVATE - "${CMAKE_CURRENT_LIST_DIR}/camera.cc" - "${CMAKE_CURRENT_LIST_DIR}/camera.hh" - "${CMAKE_CURRENT_LIST_DIR}/factory.cc" - "${CMAKE_CURRENT_LIST_DIR}/factory.hh" - "${CMAKE_CURRENT_LIST_DIR}/interpolation.cc" - "${CMAKE_CURRENT_LIST_DIR}/interpolation.hh" - "${CMAKE_CURRENT_LIST_DIR}/listener.cc" - "${CMAKE_CURRENT_LIST_DIR}/listener.hh" - "${CMAKE_CURRENT_LIST_DIR}/player_look.cc" - "${CMAKE_CURRENT_LIST_DIR}/player_look.hh" - "${CMAKE_CURRENT_LIST_DIR}/player_move.cc" - "${CMAKE_CURRENT_LIST_DIR}/player_move.hh" - "${CMAKE_CURRENT_LIST_DIR}/sound_emitter.cc" - "${CMAKE_CURRENT_LIST_DIR}/sound_emitter.hh") diff --git a/game/client/entity/camera.cc b/game/client/entity/camera.cc deleted file mode 100644 index 471f2b6..0000000 --- a/game/client/entity/camera.cc +++ /dev/null @@ -1,114 +0,0 @@ -#include "client/pch.hh" - -#include "client/entity/camera.hh" - -#include "core/config/number.hh" - -#include "core/io/config_map.hh" - -#include "core/math/angles.hh" - -#include "shared/entity/head.hh" -#include "shared/entity/transform.hh" -#include "shared/entity/velocity.hh" - -#include "shared/world/dimension.hh" - -#include "client/entity/player_move.hh" - -#include "client/gui/settings.hh" - -#include "client/const.hh" -#include "client/globals.hh" -#include "client/session.hh" -#include "client/toggles.hh" - -config::Float entity::camera::roll_angle(2.0f, 0.0f, 4.0f); -config::Float entity::camera::vertical_fov(90.0f, 45.0f, 110.0f); -config::Unsigned entity::camera::view_distance(16U, 4U, 32U); - -glm::fvec3 entity::camera::angles; -glm::fvec3 entity::camera::direction; -glm::fmat4x4 entity::camera::matrix; -chunk_pos entity::camera::position_chunk; -glm::fvec3 entity::camera::position_local; - -static void reset_camera(void) -{ - entity::camera::angles = glm::fvec3(0.0f, 0.0f, 0.0f); - entity::camera::direction = DIR_FORWARD; - entity::camera::matrix = glm::identity(); - entity::camera::position_chunk = chunk_pos(0, 0, 0); - entity::camera::position_local = glm::fvec3(0.0f, 0.0f, 0.0f); -} - -// Gracefully contributed by PQCraft himself in 2024 -// making PlatinumSrc and Voxelius kind of related to each other -static glm::fmat4x4 platinumsrc_viewmatrix(const glm::fvec3& position, const glm::fvec3& angles) -{ - glm::fvec3 forward, up; - math::vectors(angles, &forward, nullptr, &up); - - auto result = glm::identity(); - result[0][0] = forward.y * up.z - forward.z * up.y; - result[1][0] = forward.z * up.x - forward.x * up.z; - result[2][0] = forward.x * up.y - forward.y * up.x; - result[3][0] = -result[0][0] * position.x - result[1][0] * position.y - result[2][0] * position.z; - result[0][1] = up.x; - result[1][1] = up.y; - result[2][1] = up.z; - result[3][1] = -up.x * position.x - up.y * position.y - up.z * position.z; - result[0][2] = -forward.x; - result[1][2] = -forward.y; - result[2][2] = -forward.z; - result[3][2] = forward.x * position.x + forward.y * position.y + forward.z * position.z; - return result; -} - -void entity::camera::init(void) -{ - globals::client_config.add_value("camera.roll_angle", entity::camera::roll_angle); - globals::client_config.add_value("camera.vertical_fov", entity::camera::vertical_fov); - globals::client_config.add_value("camera.view_distance", entity::camera::view_distance); - - settings::add_slider(1, entity::camera::vertical_fov, settings_location::GENERAL, "camera.vertical_fov", true, "%.0f"); - settings::add_slider(0, entity::camera::view_distance, settings_location::VIDEO, "camera.view_distance", false); - settings::add_slider(10, entity::camera::roll_angle, settings_location::VIDEO, "camera.roll_angle", true, "%.01f"); - - reset_camera(); -} - -void entity::camera::update(void) -{ - if(!session::is_ingame()) { - reset_camera(); - return; - } - - const auto& head = globals::dimension->entities.get(globals::player); - const auto& transform = globals::dimension->entities.get(globals::player); - const auto& velocity = globals::dimension->entities.get(globals::player); - - entity::camera::angles = transform.angles + head.angles; - entity::camera::position_chunk = transform.chunk; - entity::camera::position_local = transform.local + head.offset; - - glm::fvec3 right_vector, up_vector; - math::vectors(entity::camera::angles, &entity::camera::direction, &right_vector, &up_vector); - - auto client_angles = entity::camera::angles; - - if(!toggles::get(TOGGLE_PM_FLIGHT)) { - // Apply the quake-like view rolling - client_angles[2] = math::radians(-entity::camera::roll_angle.get_value() - * glm::dot(velocity.value / PMOVE_MAX_SPEED_GROUND, right_vector)); - } - - const auto z_near = 0.01f; - const auto z_far = 1.25f * static_cast(CHUNK_SIZE * entity::camera::view_distance.get_value()); - - auto proj = glm::perspective(math::radians(entity::camera::vertical_fov.get_value()), globals::aspect, z_near, z_far); - auto view = platinumsrc_viewmatrix(entity::camera::position_local, client_angles); - - entity::camera::matrix = proj * view; -} diff --git a/game/client/entity/camera.hh b/game/client/entity/camera.hh deleted file mode 100644 index faefe78..0000000 --- a/game/client/entity/camera.hh +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include "shared/types.hh" - -namespace config -{ -class Float; -class Unsigned; -} // namespace config - -namespace entity::camera -{ -extern config::Float roll_angle; -extern config::Float vertical_fov; -extern config::Unsigned view_distance; -} // namespace entity::camera - -namespace entity::camera -{ -extern glm::fvec3 angles; -extern glm::fvec3 direction; -extern glm::fmat4x4 matrix; -extern chunk_pos position_chunk; -extern glm::fvec3 position_local; -} // namespace entity::camera - -namespace entity::camera -{ -void init(void); -void update(void); -} // namespace entity::camera diff --git a/game/client/entity/factory.cc b/game/client/entity/factory.cc deleted file mode 100644 index 5a1785a..0000000 --- a/game/client/entity/factory.cc +++ /dev/null @@ -1,30 +0,0 @@ -#include "client/pch.hh" - -#include "client/entity/factory.hh" - -#include "shared/entity/factory.hh" -#include "shared/entity/head.hh" -#include "shared/entity/transform.hh" - -#include "shared/world/dimension.hh" - -#include "client/entity/sound_emitter.hh" - -#include "client/globals.hh" - -void entity::client::create_player(world::Dimension* dimension, entt::entity entity) -{ - entity::shared::create_player(dimension, entity); - - const auto& head = dimension->entities.get(entity); - dimension->entities.emplace_or_replace(entity, head); - dimension->entities.emplace_or_replace(entity, head); - - const auto& transform = dimension->entities.get(entity); - dimension->entities.emplace_or_replace(entity, transform); - dimension->entities.emplace_or_replace(entity, transform); - - if(globals::sound_ctx) { - dimension->entities.emplace_or_replace(entity); - } -} diff --git a/game/client/entity/factory.hh b/game/client/entity/factory.hh deleted file mode 100644 index 8cc8208..0000000 --- a/game/client/entity/factory.hh +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -namespace world -{ -class Dimension; -} // namespace world - -namespace entity::client -{ -void create_player(world::Dimension* dimension, entt::entity entity); -} // namespace entity::client diff --git a/game/client/entity/interpolation.cc b/game/client/entity/interpolation.cc deleted file mode 100644 index c88fcf2..0000000 --- a/game/client/entity/interpolation.cc +++ /dev/null @@ -1,64 +0,0 @@ -#include "client/pch.hh" - -#include "client/entity/interpolation.hh" - -#include "core/math/constexpr.hh" - -#include "shared/entity/head.hh" -#include "shared/entity/transform.hh" - -#include "shared/world/dimension.hh" - -#include "shared/coord.hh" - -#include "client/globals.hh" - -static void transform_interpolate(float alpha) -{ - auto group = globals::dimension->entities.group( - entt::get); - - for(auto [entity, interp, current, previous] : group.each()) { - interp.angles[0] = glm::mix(previous.angles[0], current.angles[0], alpha); - interp.angles[1] = glm::mix(previous.angles[1], current.angles[1], alpha); - interp.angles[2] = glm::mix(previous.angles[2], current.angles[2], alpha); - - // Figure out previous chunk-local floating-point coordinates transformed - // to the current WorldCoord's chunk domain coordinates; we're interpolating - // against these instead of using previous.position.local to prevent jittering - auto previous_shift = coord::to_relative(current.chunk, current.local, previous.chunk, previous.local); - auto previous_local = current.local + previous_shift; - - interp.chunk.x = current.chunk.x; - interp.chunk.y = current.chunk.y; - interp.chunk.z = current.chunk.z; - - interp.local.x = glm::mix(previous_local.x, current.local.x, alpha); - interp.local.y = glm::mix(previous_local.y, current.local.y, alpha); - interp.local.z = glm::mix(previous_local.z, current.local.z, alpha); - } -} - -static void head_interpolate(float alpha) -{ - auto group = globals::dimension->entities.group(entt::get); - - for(auto [entity, interp, current, previous] : group.each()) { - interp.angles[0] = glm::mix(previous.angles[0], current.angles[0], alpha); - interp.angles[1] = glm::mix(previous.angles[1], current.angles[1], alpha); - interp.angles[2] = glm::mix(previous.angles[2], current.angles[2], alpha); - - interp.offset.x = glm::mix(previous.offset.x, current.offset.x, alpha); - interp.offset.y = glm::mix(previous.offset.y, current.offset.y, alpha); - interp.offset.z = glm::mix(previous.offset.z, current.offset.z, alpha); - } -} - -void entity::interpolation::update(void) -{ - if(globals::dimension) { - auto alpha = static_cast(globals::fixed_accumulator) / static_cast(globals::fixed_frametime_us); - transform_interpolate(alpha); - head_interpolate(alpha); - } -} \ No newline at end of file diff --git a/game/client/entity/interpolation.hh b/game/client/entity/interpolation.hh deleted file mode 100644 index a7c4dac..0000000 --- a/game/client/entity/interpolation.hh +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -namespace entity::interpolation -{ -void update(void); -} // namespace entity::interpolation diff --git a/game/client/entity/listener.cc b/game/client/entity/listener.cc deleted file mode 100644 index 1223438..0000000 --- a/game/client/entity/listener.cc +++ /dev/null @@ -1,42 +0,0 @@ -#include "client/pch.hh" - -#include "client/entity/listener.hh" - -#include "core/config/number.hh" - -#include "core/math/constexpr.hh" - -#include "shared/entity/velocity.hh" - -#include "shared/world/dimension.hh" - -#include "client/entity/camera.hh" - -#include "client/sound/sound.hh" - -#include "client/const.hh" -#include "client/globals.hh" -#include "client/session.hh" - -void entity::listener::update(void) -{ - if(session::is_ingame()) { - const auto& velocity = globals::dimension->entities.get(globals::player).value; - const auto& position = entity::camera::position_local; - - alListener3f(AL_POSITION, position.x, position.y, position.z); - alListener3f(AL_VELOCITY, velocity.x, velocity.y, velocity.z); - - float orientation[6]; - orientation[0] = entity::camera::direction.x; - orientation[1] = entity::camera::direction.y; - orientation[2] = entity::camera::direction.z; - orientation[3] = DIR_UP.x; - orientation[4] = DIR_UP.y; - orientation[5] = DIR_UP.z; - - alListenerfv(AL_ORIENTATION, orientation); - } - - alListenerf(AL_GAIN, glm::clamp(sound::volume_master.get_value() * 0.01f, 0.0f, 1.0f)); -} diff --git a/game/client/entity/listener.hh b/game/client/entity/listener.hh deleted file mode 100644 index 817e2fd..0000000 --- a/game/client/entity/listener.hh +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -namespace entity::listener -{ -void update(void); -} // namespace entity::listener diff --git a/game/client/entity/player_look.cc b/game/client/entity/player_look.cc deleted file mode 100644 index b6eaf16..0000000 --- a/game/client/entity/player_look.cc +++ /dev/null @@ -1,155 +0,0 @@ -#include "client/pch.hh" - -#include "client/entity/player_look.hh" - -#include "core/config/boolean.hh" -#include "core/config/number.hh" - -#include "core/io/config_map.hh" - -#include "core/math/angles.hh" - -#include "shared/entity/head.hh" - -#include "shared/world/dimension.hh" - -#include "client/config/gamepad_axis.hh" -#include "client/config/gamepad_button.hh" -#include "client/config/keybind.hh" - -#include "client/gui/settings.hh" - -#include "client/io/gamepad.hh" -#include "client/io/glfw.hh" - -#include "client/const.hh" -#include "client/globals.hh" -#include "client/session.hh" - -constexpr static float PITCH_MIN = -1.0f * math::radians(90.0f); -constexpr static float PITCH_MAX = +1.0f * math::radians(90.0f); - -// Mouse options -static config::Boolean mouse_raw_input(true); -static config::Unsigned mouse_sensitivity(25U, 1U, 100U); - -// Gamepad options -static config::Float gamepad_fastlook_factor(1.5f, 1.0f, 5.0f); -static config::Unsigned gamepad_accel_pitch(15U, 1U, 100U); -static config::Unsigned gamepad_accel_yaw(25U, 1U, 100U); - -// Gamepad axes -static config::GamepadAxis axis_pitch(GLFW_GAMEPAD_AXIS_LEFT_Y, false); -static config::GamepadAxis axis_yaw(GLFW_GAMEPAD_AXIS_LEFT_X, false); - -// Gamepad buttons -static config::GamepadButton button_fastlook(GLFW_GAMEPAD_BUTTON_LEFT_THUMB); - -static bool fastlook_enabled; -static glm::fvec2 last_cursor; - -static void add_angles(float pitch, float yaw) -{ - if(session::is_ingame()) { - auto& head = globals::dimension->entities.get(globals::player); - - head.angles[0] += pitch; - head.angles[1] += yaw; - head.angles[0] = glm::clamp(head.angles[0], PITCH_MIN, PITCH_MAX); - head.angles = math::wrap_180(head.angles); - - // Client-side head angles are not interpolated; - // Re-assigning the previous state after the current - // state has been already modified is certainly a way - // to circumvent the interpolation applied to anything with a head - globals::dimension->entities.emplace_or_replace(globals::player, head); - } -} - -static void on_glfw_cursor_pos(const io::GlfwCursorPosEvent& event) -{ - if(io::gamepad::available && io::gamepad::active.get_value()) { - // The player is assumed to be using - // a gamepad instead of mouse and keyboard - last_cursor = event.pos; - return; - } - - if(globals::gui_screen || !session::is_ingame()) { - // UI is visible or we're not in-game - last_cursor = event.pos; - return; - } - - auto dx = -0.01f * static_cast(mouse_sensitivity.get_value()) * math::radians(event.pos.x - last_cursor.x); - auto dy = -0.01f * static_cast(mouse_sensitivity.get_value()) * math::radians(event.pos.y - last_cursor.y); - add_angles(dy, dx); - - last_cursor = event.pos; -} - -static void on_gamepad_button(const io::GamepadButtonEvent& event) -{ - if(button_fastlook.equals(event.button)) { - fastlook_enabled = event.action == GLFW_PRESS; - } -} - -void entity::player_look::init(void) -{ - globals::client_config.add_value("player_look.mouse.raw_input", mouse_raw_input); - globals::client_config.add_value("player_look.mouse.sensitivity", mouse_sensitivity); - globals::client_config.add_value("player_look.gamepad.fastlook_factor", gamepad_fastlook_factor); - globals::client_config.add_value("player_look.gamepad.accel_pitch", gamepad_accel_pitch); - globals::client_config.add_value("player_look.gamepad.accel_yaw", gamepad_accel_yaw); - globals::client_config.add_value("player_look.gp_axis.pitch", axis_pitch); - globals::client_config.add_value("player_look.gp_axis.yaw", axis_yaw); - globals::client_config.add_value("player_look.gp_button.fastlook", button_fastlook); - - settings::add_slider(0, mouse_sensitivity, settings_location::MOUSE, "player_look.mouse.sensitivity", true); - settings::add_checkbox(1, mouse_raw_input, settings_location::MOUSE, "player_look.mouse.raw_input", true); - - settings::add_slider(0, gamepad_accel_pitch, settings_location::GAMEPAD_GAMEPLAY, "player_look.gamepad.accel_pitch", false); - settings::add_slider(1, gamepad_accel_yaw, settings_location::GAMEPAD_GAMEPLAY, "player_look.gamepad.accel_yaw", false); - settings::add_gamepad_axis(2, axis_pitch, settings_location::GAMEPAD_GAMEPLAY, "player_look.gp_axis.pitch"); - settings::add_gamepad_axis(3, axis_yaw, settings_location::GAMEPAD_GAMEPLAY, "player_look.gp_axis.yaw"); - settings::add_slider(4, gamepad_fastlook_factor, settings_location::GAMEPAD_GAMEPLAY, "player_look.gamepad.fastlook_factor", true, - "%.02f"); - settings::add_gamepad_button(5, button_fastlook, settings_location::GAMEPAD_GAMEPLAY, "player_look.gp_button.fastlook"); - - fastlook_enabled = false; - last_cursor.x = 0.5f * static_cast(globals::width); - last_cursor.y = 0.5f * static_cast(globals::height); - - globals::dispatcher.sink().connect<&on_glfw_cursor_pos>(); - globals::dispatcher.sink().connect<&on_gamepad_button>(); -} - -void entity::player_look::update_late(void) -{ - if(io::gamepad::available && io::gamepad::active.get_value() && !globals::gui_screen) { - auto pitch_value = axis_pitch.get_value(io::gamepad::state, io::gamepad::deadzone.get_value()); - auto yaw_value = axis_yaw.get_value(io::gamepad::state, io::gamepad::deadzone.get_value()); - - if(fastlook_enabled) { - // Fastlook allows the camera to - // rotate quicker when a button is held down - pitch_value *= gamepad_fastlook_factor.get_value(); - yaw_value *= gamepad_fastlook_factor.get_value(); - } - - pitch_value *= 0.001f * static_cast(gamepad_accel_pitch.get_value()); - yaw_value *= 0.001f * static_cast(gamepad_accel_yaw.get_value()); - - add_angles(pitch_value, yaw_value); - } - - if(!globals::gui_screen && session::is_ingame()) { - glfwSetInputMode(globals::window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); - glfwSetInputMode(globals::window, GLFW_RAW_MOUSE_MOTION, mouse_raw_input.get_value()); - } - else { - glfwSetInputMode(globals::window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); - glfwSetInputMode(globals::window, GLFW_RAW_MOUSE_MOTION, false); - } -} diff --git a/game/client/entity/player_look.hh b/game/client/entity/player_look.hh deleted file mode 100644 index b347031..0000000 --- a/game/client/entity/player_look.hh +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -namespace entity::player_look -{ -void init(void); -void update_late(void); -} // namespace entity::player_look diff --git a/game/client/entity/player_move.cc b/game/client/entity/player_move.cc deleted file mode 100644 index 17aaadd..0000000 --- a/game/client/entity/player_move.cc +++ /dev/null @@ -1,298 +0,0 @@ -#include "client/pch.hh" - -#include "client/entity/player_move.hh" - -#include "core/config/boolean.hh" -#include "core/config/number.hh" - -#include "core/io/config_map.hh" - -#include "core/math/angles.hh" -#include "core/math/constexpr.hh" - -#include "shared/entity/grounded.hh" -#include "shared/entity/head.hh" -#include "shared/entity/transform.hh" -#include "shared/entity/velocity.hh" - -#include "shared/world/dimension.hh" - -#include "client/config/gamepad_axis.hh" -#include "client/config/gamepad_button.hh" -#include "client/config/keybind.hh" - -#include "client/gui/gui_screen.hh" -#include "client/gui/settings.hh" -#include "client/gui/status_lines.hh" - -#include "client/io/gamepad.hh" - -#include "client/sound/sound.hh" - -#include "client/world/voxel_sounds.hh" - -#include "client/const.hh" -#include "client/globals.hh" -#include "client/session.hh" -#include "client/toggles.hh" - -constexpr static std::uint64_t PMOVE_JUMP_COOLDOWN = 500000; // 0.5 seconds - -constexpr static float PMOVE_FOOTSTEP_SIZE = 2.0f; - -// Movement keys -static config::KeyBind key_move_forward(GLFW_KEY_W); -static config::KeyBind key_move_back(GLFW_KEY_S); -static config::KeyBind key_move_left(GLFW_KEY_A); -static config::KeyBind key_move_right(GLFW_KEY_D); -static config::KeyBind key_move_down(GLFW_KEY_LEFT_SHIFT); -static config::KeyBind key_move_up(GLFW_KEY_SPACE); - -// Movement gamepad axes -static config::GamepadAxis axis_move_forward(GLFW_GAMEPAD_AXIS_RIGHT_X, false); -static config::GamepadAxis axis_move_sideways(GLFW_GAMEPAD_AXIS_RIGHT_Y, false); - -// Movement gamepad buttons -static config::GamepadButton button_move_down(GLFW_GAMEPAD_BUTTON_DPAD_DOWN); -static config::GamepadButton button_move_up(GLFW_GAMEPAD_BUTTON_DPAD_UP); - -// General movement options -static config::Boolean enable_speedometer(true); - -static glm::fvec3 movement_direction; - -static std::uint64_t next_jump_us; -static float speedometer_value; -static float footsteps_distance; - -static std::mt19937_64 pitch_random; -static std::uniform_real_distribution pitch_distrib; - -// Quake III's PM_Accelerate-ish function used for -// conventional (gravity-affected non-flight) movement -static glm::fvec3 pm_accelerate(const glm::fvec3& wishdir, const glm::fvec3& velocity, float wishspeed, float accel) -{ - auto current_speed = glm::dot(velocity, wishdir); - auto add_speed = wishspeed - current_speed; - - if(add_speed <= 0.0f) { - // Not accelerating - return velocity; - } - - auto accel_speed = glm::min(add_speed, accel * globals::fixed_frametime * wishspeed); - - auto result = glm::fvec3(velocity); - result.x += accel_speed * wishdir.x; - result.z += accel_speed * wishdir.z; - return result; -} - -// Conventional movement - velocity update when not on the ground -static glm::fvec3 pm_air_move(const glm::fvec3& wishdir, const glm::fvec3& velocity) -{ - return pm_accelerate(wishdir, velocity, PMOVE_ACCELERATION_AIR, PMOVE_MAX_SPEED_AIR); -} - -// Conventional movement - velocity uodate when on the ground -static glm::fvec3 pm_ground_move(const glm::fvec3& wishdir, const glm::fvec3& velocity) -{ - if(auto speed = glm::length(velocity)) { - auto speed_drop = speed * PMOVE_FRICTION_GROUND * globals::fixed_frametime; - auto speed_factor = glm::max(speed - speed_drop, 0.0f) / speed; - return pm_accelerate(wishdir, velocity * speed_factor, PMOVE_ACCELERATION_GROUND, PMOVE_MAX_SPEED_GROUND); - } - - return pm_accelerate(wishdir, velocity, PMOVE_ACCELERATION_GROUND, PMOVE_MAX_SPEED_GROUND); -} - -// A simpler minecraft-like acceleration model -// used whenever the TOGGLE_PM_FLIGHT is enabled -static glm::fvec3 pm_flight_move(const glm::fvec3& wishdir) -{ - // FIXME: make it smoother - return wishdir * PMOVE_MAX_SPEED_AIR; -} - -void entity::player_move::init(void) -{ - movement_direction = ZERO_VEC3; - - next_jump_us = 0x0000000000000000U; - speedometer_value = 0.0f; - footsteps_distance = 0.0f; - - // UNDONE: make this a separate subsystem - pitch_random.seed(std::random_device()()); - pitch_distrib = std::uniform_real_distribution(0.9f, 1.1f); - - globals::client_config.add_value("player_move.key.forward", key_move_forward); - globals::client_config.add_value("player_move.key.back", key_move_back); - globals::client_config.add_value("player_move.key.left", key_move_left); - globals::client_config.add_value("player_move.key.right", key_move_right); - globals::client_config.add_value("player_move.key.down", key_move_down); - globals::client_config.add_value("player_move.key.up", key_move_up); - globals::client_config.add_value("player_move.gp_axis.move_forward", axis_move_forward); - globals::client_config.add_value("player_move.gp_axis.move_sideways", axis_move_sideways); - globals::client_config.add_value("player_move.gp_button.move_down", button_move_down); - globals::client_config.add_value("player_move.gp_button.move_up", button_move_up); - globals::client_config.add_value("player_move.enable_speedometer", enable_speedometer); - - settings::add_keybind(1, key_move_forward, settings_location::KEYBOARD_MOVEMENT, "player_move.key.forward"); - settings::add_keybind(2, key_move_back, settings_location::KEYBOARD_MOVEMENT, "player_move.key.back"); - settings::add_keybind(3, key_move_left, settings_location::KEYBOARD_MOVEMENT, "player_move.key.left"); - settings::add_keybind(4, key_move_right, settings_location::KEYBOARD_MOVEMENT, "player_move.key.right"); - settings::add_keybind(5, key_move_down, settings_location::KEYBOARD_MOVEMENT, "player_move.key.down"); - settings::add_keybind(6, key_move_up, settings_location::KEYBOARD_MOVEMENT, "player_move.key.up"); - - settings::add_gamepad_axis(0, axis_move_forward, settings_location::GAMEPAD_MOVEMENT, "player_move.gp_axis.move_forward"); - settings::add_gamepad_axis(1, axis_move_sideways, settings_location::GAMEPAD_MOVEMENT, "player_move.gp_axis.move_sideways"); - settings::add_gamepad_button(2, button_move_down, settings_location::GAMEPAD_MOVEMENT, "player_move.gp_button.move_down"); - settings::add_gamepad_button(3, button_move_up, settings_location::GAMEPAD_MOVEMENT, "player_move.gp_button.move_up"); - - settings::add_checkbox(2, enable_speedometer, settings_location::VIDEO_GUI, "player_move.enable_speedometer", true); -} - -void entity::player_move::fixed_update(void) -{ - const auto& head = globals::dimension->entities.get(globals::player); - auto& transform = globals::dimension->entities.get(globals::player); - auto& velocity = globals::dimension->entities.get(globals::player); - - // Interpolation - preserve current component states - globals::dimension->entities.emplace_or_replace(globals::player, transform); - - glm::fvec3 forward, right; - math::vectors(glm::fvec3(0.0f, head.angles[1], 0.0f), &forward, &right, nullptr); - - glm::fvec3 wishdir = ZERO_VEC3; - glm::fvec3 movevars = glm::fvec3(movement_direction.x, 0.0f, movement_direction.z); - wishdir.x = glm::dot(movevars, right); - wishdir.z = glm::dot(movevars, forward); - - if(toggles::get(TOGGLE_PM_FLIGHT)) { - velocity.value = pm_flight_move(glm::fvec3(wishdir.x, movement_direction.y, wishdir.z)); - return; - } - - auto grounded = globals::dimension->entities.try_get(globals::player); - auto velocity_horizontal = glm::fvec3(velocity.value.x, 0.0f, velocity.value.z); - - if(grounded) { - auto new_velocity = pm_ground_move(wishdir, velocity_horizontal); - velocity.value.x = new_velocity.x; - velocity.value.z = new_velocity.z; - - auto new_speed = glm::length(new_velocity); - - if(new_speed > 0.01f) { - footsteps_distance += globals::fixed_frametime * new_speed; - } - else { - footsteps_distance = 0.0f; - } - - if(footsteps_distance >= PMOVE_FOOTSTEP_SIZE) { - if(auto effect = world::voxel_sounds::get_footsteps(grounded->surface)) { - sound::play_player(effect, false, pitch_distrib(pitch_random)); - } - - footsteps_distance = 0.0f; - } - } - else { - auto new_velocity = pm_air_move(wishdir, velocity_horizontal); - velocity.value.x = new_velocity.x; - velocity.value.z = new_velocity.z; - } - - if(movement_direction.y == 0.0f) { - // Allow players to queue bunny-jumps by quickly - // releasing and pressing the jump key again without a cooldown - next_jump_us = 0x0000000000000000U; - return; - } - - if(grounded && (movement_direction.y > 0.0f) && (globals::curtime >= next_jump_us)) { - velocity.value.y = -PMOVE_JUMP_FORCE * globals::dimension->get_gravity(); - - auto new_speed = glm::length(glm::fvec2(velocity.value.x, velocity.value.z)); - auto new_speed_text = std::format("{:.02f} M/S", new_speed); - auto speed_change = new_speed - speedometer_value; - - speedometer_value = new_speed; - - next_jump_us = globals::curtime + PMOVE_JUMP_COOLDOWN; - - if(enable_speedometer.get_value()) { - if(glm::abs(speed_change) < 0.01f) { - // No considerable speed increase within - // the precision we use to draw the speedometer - gui::status_lines::set(gui::STATUS_DEBUG, new_speed_text, ImVec4(0.7f, 0.7f, 0.7f, 1.0f), 1.0f); - } - else if(speed_change < 0.0f) { - // Speed change is negative, we are actively - // slowing down; use the red color for the status line - gui::status_lines::set(gui::STATUS_DEBUG, new_speed_text, ImVec4(1.0f, 0.0f, 0.0f, 1.0f), 1.0f); - } - else { - // Speed change is positive, we are actively - // speeding up; use the green color for the status line - gui::status_lines::set(gui::STATUS_DEBUG, new_speed_text, ImVec4(0.0f, 1.0f, 0.0f, 1.0f), 1.0f); - } - } - - if(auto effect = world::voxel_sounds::get_footsteps(grounded->surface)) { - sound::play_player(effect, false, 1.0f); - } - } -} - -void entity::player_move::update_late(void) -{ - movement_direction = ZERO_VEC3; - - if(globals::gui_screen || !session::is_ingame()) { - // We're either disconnected or have the - // UI opened up; anyways we shouldn't move - return; - } - - if(io::gamepad::available && io::gamepad::active.get_value()) { - if(button_move_down.is_pressed(io::gamepad::state)) { - movement_direction += DIR_DOWN; - } - - if(button_move_up.is_pressed(io::gamepad::state)) { - movement_direction += DIR_UP; - } - - movement_direction.x += axis_move_sideways.get_value(io::gamepad::state, io::gamepad::deadzone.get_value()); - movement_direction.z -= axis_move_forward.get_value(io::gamepad::state, io::gamepad::deadzone.get_value()); - } - else { - if(GLFW_PRESS == glfwGetKey(globals::window, key_move_forward.get_key())) { - movement_direction += DIR_FORWARD; - } - - if(GLFW_PRESS == glfwGetKey(globals::window, key_move_back.get_key())) { - movement_direction += DIR_BACK; - } - - if(GLFW_PRESS == glfwGetKey(globals::window, key_move_left.get_key())) { - movement_direction += DIR_LEFT; - } - - if(GLFW_PRESS == glfwGetKey(globals::window, key_move_right.get_key())) { - movement_direction += DIR_RIGHT; - } - - if(GLFW_PRESS == glfwGetKey(globals::window, key_move_down.get_key())) { - movement_direction += DIR_DOWN; - } - - if(GLFW_PRESS == glfwGetKey(globals::window, key_move_up.get_key())) { - movement_direction += DIR_UP; - } - } -} diff --git a/game/client/entity/player_move.hh b/game/client/entity/player_move.hh deleted file mode 100644 index 8026acf..0000000 --- a/game/client/entity/player_move.hh +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -constexpr static float PMOVE_MAX_SPEED_AIR = 16.0f; -constexpr static float PMOVE_MAX_SPEED_GROUND = 8.0f; -constexpr static float PMOVE_ACCELERATION_AIR = 3.0f; -constexpr static float PMOVE_ACCELERATION_GROUND = 6.0f; -constexpr static float PMOVE_FRICTION_GROUND = 10.0f; -constexpr static float PMOVE_JUMP_FORCE = 0.275f; - -namespace entity::player_move -{ -void init(void); -void fixed_update(void); -void update_late(void); -} // namespace entity::player_move diff --git a/game/client/entity/sound_emitter.cc b/game/client/entity/sound_emitter.cc deleted file mode 100644 index 84a66c0..0000000 --- a/game/client/entity/sound_emitter.cc +++ /dev/null @@ -1,63 +0,0 @@ -#include "client/pch.hh" - -#include "client/entity/sound_emitter.hh" - -#include "core/config/number.hh" - -#include "core/math/constexpr.hh" - -#include "shared/entity/transform.hh" -#include "shared/entity/velocity.hh" - -#include "shared/world/dimension.hh" - -#include "shared/coord.hh" - -#include "client/entity/camera.hh" - -#include "client/sound/sound.hh" - -#include "client/globals.hh" - -entity::SoundEmitter::SoundEmitter(void) -{ - alGenSources(1, &source); - sound = nullptr; -} - -entity::SoundEmitter::~SoundEmitter(void) -{ - alSourceStop(source); - alDeleteSources(1, &source); -} - -void entity::SoundEmitter::update(void) -{ - if(globals::dimension) { - const auto view = globals::dimension->entities.view(); - - const auto& pivot = entity::camera::position_chunk; - const auto gain = glm::clamp(sound::volume_effects.get_value() * 0.01f, 0.0f, 1.0f); - - for(const auto [entity, emitter] : view.each()) { - alSourcef(emitter.source, AL_GAIN, gain); - - if(const auto transform = globals::dimension->entities.try_get(entity)) { - auto position = coord::to_relative(pivot, transform->chunk, transform->local); - alSource3f(emitter.source, AL_POSITION, position.x, position.y, position.z); - } - - if(const auto velocity = globals::dimension->entities.try_get(entity)) { - alSource3f(emitter.source, AL_VELOCITY, velocity->value.x, velocity->value.y, velocity->value.z); - } - - ALint source_state; - alGetSourcei(emitter.source, AL_SOURCE_STATE, &source_state); - - if(source_state == AL_STOPPED) { - alSourceRewind(emitter.source); - emitter.sound = nullptr; - } - } - } -} diff --git a/game/client/entity/sound_emitter.hh b/game/client/entity/sound_emitter.hh deleted file mode 100644 index 14093db..0000000 --- a/game/client/entity/sound_emitter.hh +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include "core/resource/resource.hh" - -struct SoundEffect; - -namespace entity -{ -struct SoundEmitter final { - resource_ptr sound; - ALuint source; - -public: - explicit SoundEmitter(void); - virtual ~SoundEmitter(void); - -public: - static void update(void); -}; -} // namespace entity diff --git a/game/client/experiments.cc b/game/client/experiments.cc deleted file mode 100644 index 8b0b526..0000000 --- a/game/client/experiments.cc +++ /dev/null @@ -1,84 +0,0 @@ -#include "client/pch.hh" - -#include "client/experiments.hh" - -#include "shared/world/dimension.hh" -#include "shared/world/item_registry.hh" - -#include "shared/game_items.hh" -#include "shared/game_voxels.hh" - -#include "client/gui/chat.hh" -#include "client/gui/hotbar.hh" -#include "client/gui/status_lines.hh" - -#include "client/io/glfw.hh" - -#include "client/world/player_target.hh" - -#include "client/globals.hh" -#include "client/session.hh" - -static void on_glfw_mouse_button(const io::GlfwMouseButtonEvent& event) -{ - if(!globals::gui_screen && session::is_ingame()) { - if((event.action == GLFW_PRESS) && world::player_target::voxel) { - if(event.button == GLFW_MOUSE_BUTTON_LEFT) { - experiments::attack(); - return; - } - - if(event.button == GLFW_MOUSE_BUTTON_RIGHT) { - experiments::interact(); - return; - } - } - } -} - -void experiments::init(void) -{ - globals::dispatcher.sink().connect<&on_glfw_mouse_button>(); -} - -void experiments::init_late(void) -{ - gui::hotbar::slots[0] = game_items::cobblestone; - gui::hotbar::slots[1] = game_items::stone; - gui::hotbar::slots[2] = game_items::dirt; - gui::hotbar::slots[3] = game_items::grass; - gui::hotbar::slots[4] = game_items::oak_leaves; - gui::hotbar::slots[5] = game_items::oak_planks; - gui::hotbar::slots[6] = game_items::oak_log; - gui::hotbar::slots[7] = game_items::glass; - gui::hotbar::slots[8] = game_items::slime; -} - -void experiments::shutdown(void) -{ -} - -void experiments::update(void) -{ -} - -void experiments::update_late(void) -{ -} - -void experiments::attack(void) -{ - globals::dimension->set_voxel(nullptr, world::player_target::coord); -} - -void experiments::interact(void) -{ - auto active_item = gui::hotbar::slots[gui::hotbar::active_slot]; - - if(active_item) { - if(auto place_voxel = active_item->get_place_voxel()) { - globals::dimension->set_voxel(place_voxel, world::player_target::coord + world::player_target::normal); - return; - } - } -} diff --git a/game/client/experiments.hh b/game/client/experiments.hh deleted file mode 100644 index c1b0769..0000000 --- a/game/client/experiments.hh +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -namespace experiments -{ -void init(void); -void init_late(void); -void shutdown(void); -void update(void); -void update_late(void); -} // namespace experiments - -namespace experiments -{ -void attack(void); -void interact(void); -} // namespace experiments diff --git a/game/client/game.cc b/game/client/game.cc deleted file mode 100644 index e772ff8..0000000 --- a/game/client/game.cc +++ /dev/null @@ -1,709 +0,0 @@ -#include "client/pch.hh" - -#include "client/game.hh" - -#include "core/config/boolean.hh" -#include "core/config/number.hh" -#include "core/config/string.hh" - -#include "core/io/config_map.hh" - -#include "core/math/angles.hh" - -#include "core/resource/resource.hh" - -#include "core/io/physfs.hh" - -#include "shared/entity/collision.hh" -#include "shared/entity/gravity.hh" -#include "shared/entity/head.hh" -#include "shared/entity/player.hh" -#include "shared/entity/stasis.hh" -#include "shared/entity/transform.hh" -#include "shared/entity/velocity.hh" - -#include "shared/game_items.hh" -#include "shared/game_voxels.hh" - -#include "shared/world/dimension.hh" -#include "shared/world/item_registry.hh" -#include "shared/world/ray_dda.hh" -#include "shared/world/voxel_registry.hh" - -#include "shared/coord.hh" -#include "shared/protocol.hh" - -#include "client/config/keybind.hh" - -#include "client/entity/camera.hh" -#include "client/entity/interpolation.hh" -#include "client/entity/listener.hh" -#include "client/entity/player_look.hh" -#include "client/entity/player_move.hh" -#include "client/entity/sound_emitter.hh" - -#include "client/gui/background.hh" -#include "client/gui/bother.hh" -#include "client/gui/chat.hh" -#include "client/gui/crosshair.hh" -#include "client/gui/direct_connection.hh" -#include "client/gui/gui_screen.hh" -#include "client/gui/hotbar.hh" -#include "client/gui/language.hh" -#include "client/gui/main_menu.hh" -#include "client/gui/message_box.hh" -#include "client/gui/metrics.hh" -#include "client/gui/play_menu.hh" -#include "client/gui/progress_bar.hh" -#include "client/gui/scoreboard.hh" -#include "client/gui/settings.hh" -#include "client/gui/splash.hh" -#include "client/gui/status_lines.hh" -#include "client/gui/window_title.hh" - -#include "client/io/gamepad.hh" -#include "client/io/glfw.hh" - -#include "client/resource/texture_gui.hh" - -#include "client/sound/sound.hh" - -#include "client/world/chunk_mesher.hh" -#include "client/world/chunk_renderer.hh" -#include "client/world/chunk_visibility.hh" -#include "client/world/outline.hh" -#include "client/world/player_target.hh" -#include "client/world/skybox.hh" -#include "client/world/voxel_anims.hh" -#include "client/world/voxel_atlas.hh" -#include "client/world/voxel_sounds.hh" - -#include "client/const.hh" -#include "client/experiments.hh" -#include "client/globals.hh" -#include "client/receive.hh" -#include "client/screenshot.hh" -#include "client/session.hh" -#include "client/toggles.hh" - -config::Boolean client_game::streamer_mode(false); -config::Boolean client_game::vertical_sync(true); -config::Boolean client_game::world_curvature(true); -config::Unsigned client_game::fog_mode(1U, 0U, 2U); -config::String client_game::username("player"); - -bool client_game::hide_hud = false; - -static config::KeyBind hide_hud_toggle(GLFW_KEY_F1); - -static ImFont* load_font(std::string_view path, float size, ImFontConfig& font_config, ImVector& ranges) -{ - bool font_load_success; - std::vector font; - - if(!io::read_file(path, font)) { - spdlog::error("{}: utils::read_file failed", path); - std::terminate(); - } - - auto& io = ImGui::GetIO(); - auto font_ptr = io.Fonts->AddFontFromMemoryTTF(font.data(), font.size(), size, &font_config, ranges.Data); - - if(font_ptr == nullptr) { - spdlog::error("{}: AddFontFromMemoryTTF failed", path); - std::terminate(); - } - - return font_ptr; -} - -static void on_glfw_framebuffer_size(const io::GlfwFramebufferSizeEvent& event) -{ - if(globals::world_fbo) { - glDeleteRenderbuffers(1, &globals::world_fbo_depth); - glDeleteTextures(1, &globals::world_fbo_color); - glDeleteFramebuffers(1, &globals::world_fbo); - } - - glGenFramebuffers(1, &globals::world_fbo); - glGenTextures(1, &globals::world_fbo_color); - glGenRenderbuffers(1, &globals::world_fbo_depth); - - glBindTexture(GL_TEXTURE_2D, globals::world_fbo_color); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, event.size.x, event.size.y, 0, GL_RED, GL_UNSIGNED_BYTE, nullptr); - - glBindRenderbuffer(GL_RENDERBUFFER, globals::world_fbo_depth); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, event.size.x, event.size.y); - - glBindFramebuffer(GL_FRAMEBUFFER, globals::world_fbo); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, globals::world_fbo_color, 0); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, globals::world_fbo_depth); - - if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - spdlog::critical("opengl: world framebuffer is incomplete"); - glDeleteRenderbuffers(1, &globals::world_fbo_depth); - glDeleteTextures(1, &globals::world_fbo_color); - glDeleteFramebuffers(1, &globals::world_fbo); - std::terminate(); - } -} - -static void on_glfw_key(const io::GlfwKeyEvent& event) -{ - if(!globals::gui_keybind_ptr && hide_hud_toggle.equals(event.key) && (event.action == GLFW_PRESS)) { - client_game::hide_hud = !client_game::hide_hud; - } -} - -void client_game::init(void) -{ - auto& io = ImGui::GetIO(); - io.ConfigFlags &= ~ImGuiConfigFlags_NavEnableGamepad; - io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; - io.IniFilename = nullptr; - io.Fonts->Clear(); - - ImFontConfig font_config; - font_config.FontDataOwnedByAtlas = false; - - ImFontGlyphRangesBuilder builder; - builder.AddRanges(io.Fonts->GetGlyphRangesDefault()); - builder.AddRanges(io.Fonts->GetGlyphRangesCyrillic()); - - ImVector ranges; - builder.BuildRanges(&ranges); - - globals::font_unscii16 = load_font("fonts/unscii-16.ttf", 16.0f, font_config, ranges); - globals::font_unscii8 = load_font("fonts/unscii-8.ttf", 8.0f, font_config, ranges); - - gui::client_splash::init(); - gui::client_splash::render(); - - globals::client_config.add_value("game.streamer_mode", client_game::streamer_mode); - globals::client_config.add_value("game.vertical_sync", client_game::vertical_sync); - globals::client_config.add_value("game.world_curvature", client_game::world_curvature); - globals::client_config.add_value("game.fog_mode", client_game::fog_mode); - globals::client_config.add_value("game.username", client_game::username); - globals::client_config.add_value("game.key.toggle_hide_hud", hide_hud_toggle); - - settings::init(); - - settings::add_checkbox(0, client_game::streamer_mode, settings_location::VIDEO_GUI, "game.streamer_mode", true); - settings::add_checkbox(5, client_game::vertical_sync, settings_location::VIDEO, "game.vertical_sync", false); - settings::add_checkbox(4, client_game::world_curvature, settings_location::VIDEO, "game.world_curvature", true); - settings::add_stepper(3, client_game::fog_mode, settings_location::VIDEO, "game.fog_mode", false); - settings::add_input(1, client_game::username, settings_location::GENERAL, "game.username", true, false); - settings::add_keybind(4, hide_hud_toggle, settings_location::KEYBOARD_MISC, "game.key.toggle_hide_hud"); - - globals::client_host = enet_host_create(nullptr, 1, 1, 0, 0); - - if(!globals::client_host) { - spdlog::critical("game: unable to setup an ENet host"); - std::terminate(); - } - - gui::language::init(); - - session::init(); - - entity::player_look::init(); - entity::player_move::init(); - world::player_target::init(); - - io::gamepad::init(); - - entity::camera::init(); - - world::voxel_anims::init(); - - world::outline::init(); - world::chunk_mesher::init(); - world::chunk_renderer::init(); - - globals::world_fbo = 0; - globals::world_fbo_color = 0; - globals::world_fbo_depth = 0; - - world::voxel_sounds::init(); - - world::skybox::init(); - - ImGuiStyle& style = ImGui::GetStyle(); - - // Black buttons on a dark background - // may be harder to read than the text on them - style.FrameBorderSize = 1.0; - style.TabBorderSize = 1.0; - - // Rounding on elements looks cool but I am - // aiming for a more or less blocky and - // visually simple HiDPI-friendly UI style - style.TabRounding = 0.0f; - style.GrabRounding = 0.0f; - style.ChildRounding = 0.0f; - style.FrameRounding = 0.0f; - style.PopupRounding = 0.0f; - style.WindowRounding = 0.0f; - style.ScrollbarRounding = 0.0f; - - style.Colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); - style.Colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); - style.Colors[ImGuiCol_WindowBg] = ImVec4(0.06f, 0.06f, 0.06f, 0.94f); - style.Colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); - style.Colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f); - style.Colors[ImGuiCol_Border] = ImVec4(0.79f, 0.79f, 0.79f, 0.50f); - style.Colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); - style.Colors[ImGuiCol_FrameBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.54f); - style.Colors[ImGuiCol_FrameBgHovered] = ImVec4(0.36f, 0.36f, 0.36f, 0.40f); - style.Colors[ImGuiCol_FrameBgActive] = ImVec4(0.63f, 0.63f, 0.63f, 0.67f); - style.Colors[ImGuiCol_TitleBg] = ImVec4(0.04f, 0.04f, 0.04f, 1.00f); - style.Colors[ImGuiCol_TitleBgActive] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); - style.Colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f); - style.Colors[ImGuiCol_MenuBarBg] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f); - style.Colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.53f); - style.Colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.00f, 0.00f, 0.00f, 0.75f); - style.Colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.12f, 0.12f, 0.12f, 1.00f); - style.Colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f); - style.Colors[ImGuiCol_CheckMark] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); - style.Colors[ImGuiCol_SliderGrab] = ImVec4(0.81f, 0.81f, 0.81f, 0.75f); - style.Colors[ImGuiCol_SliderGrabActive] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); - style.Colors[ImGuiCol_Button] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); - style.Colors[ImGuiCol_ButtonHovered] = ImVec4(0.12f, 0.12f, 0.12f, 1.00f); - style.Colors[ImGuiCol_ButtonActive] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f); - style.Colors[ImGuiCol_Header] = ImVec4(0.00f, 0.00f, 0.00f, 0.75f); - style.Colors[ImGuiCol_HeaderHovered] = ImVec4(0.12f, 0.12f, 0.12f, 1.00f); - style.Colors[ImGuiCol_HeaderActive] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f); - style.Colors[ImGuiCol_Separator] = ImVec4(0.49f, 0.49f, 0.49f, 0.50f); - style.Colors[ImGuiCol_SeparatorHovered] = ImVec4(0.56f, 0.56f, 0.56f, 0.78f); - style.Colors[ImGuiCol_SeparatorActive] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f); - style.Colors[ImGuiCol_ResizeGrip] = ImVec4(0.34f, 0.34f, 0.34f, 0.20f); - style.Colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.57f, 0.57f, 0.57f, 0.67f); - style.Colors[ImGuiCol_ResizeGripActive] = ImVec4(1.00f, 1.00f, 1.00f, 0.95f); - style.Colors[ImGuiCol_Tab] = ImVec4(0.00f, 0.00f, 0.00f, 0.75f); - style.Colors[ImGuiCol_TabHovered] = ImVec4(0.12f, 0.12f, 0.12f, 1.00f); - style.Colors[ImGuiCol_TabActive] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f); - style.Colors[ImGuiCol_TabUnfocused] = ImVec4(0.13f, 0.13f, 0.13f, 0.97f); - style.Colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.44f, 0.44f, 0.44f, 1.00f); - style.Colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f); - style.Colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.69f, 0.00f, 0.00f, 1.00f); - style.Colors[ImGuiCol_PlotHistogram] = ImVec4(0.00f, 1.00f, 0.20f, 1.00f); - style.Colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); - style.Colors[ImGuiCol_TableHeaderBg] = ImVec4(0.19f, 0.19f, 0.20f, 1.00f); - style.Colors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.35f, 1.00f); - style.Colors[ImGuiCol_TableBorderLight] = ImVec4(0.23f, 0.23f, 0.25f, 1.00f); - style.Colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); - style.Colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.06f); - style.Colors[ImGuiCol_TextSelectedBg] = ImVec4(0.61f, 0.61f, 0.61f, 0.35f); - style.Colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 1.00f); - style.Colors[ImGuiCol_NavHighlight] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); - style.Colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); - style.Colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); - style.Colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f); - - // Making my own Game UI for Source Engine - // taught me one important thing: dimensions - // of UI elements must be calculated at semi-runtime - // so there's simply no point for an INI file. - io.IniFilename = nullptr; - - toggles::init(); - - gui::background::init(); - - gui::scoreboard::init(); - - gui::client_chat::init(); - - gui::bother::init(); - - gui::main_menu::init(); - gui::play_menu::init(); - gui::progress_bar::init(); - gui::message_box::init(); - gui::direct_connection::init(); - - gui::crosshair::init(); - gui::hotbar::init(); - gui::metrics::init(); - gui::status_lines::init(); - - screenshot::init(); - - globals::gui_keybind_ptr = nullptr; - globals::gui_scale = 0U; - globals::gui_screen = GUI_MAIN_MENU; - - sound::init_config(); - - if(globals::sound_ctx) { - sound::init(); - } - - client_receive::init(); - - experiments::init(); - - globals::dispatcher.sink().connect<&on_glfw_framebuffer_size>(); - globals::dispatcher.sink().connect<&on_glfw_key>(); -} - -void client_game::init_late(void) -{ - toggles::init_late(); - - if(globals::sound_ctx) { - sound::init_late(); - } - - gui::language::init_late(); - - settings::init_late(); - - gui::client_chat::init_late(); - - gui::status_lines::init_late(); - - game_voxels::populate(); - game_items::populate(); - - std::size_t max_texture_count = 0; - - // Figure out the total texture count - // NOTE: this is very debug, early and a quite - // conservative limit choice; there must be a better - // way to make this limit way smaller than it currently is - for(const auto& voxel : world::voxel_registry::voxels) { - max_texture_count += voxel->get_default_textures().size(); - max_texture_count += voxel->get_face_textures(world::VFACE_NORTH).size(); - max_texture_count += voxel->get_face_textures(world::VFACE_SOUTH).size(); - max_texture_count += voxel->get_face_textures(world::VFACE_EAST).size(); - max_texture_count += voxel->get_face_textures(world::VFACE_WEST).size(); - max_texture_count += voxel->get_face_textures(world::VFACE_TOP).size(); - max_texture_count += voxel->get_face_textures(world::VFACE_BOTTOM).size(); - max_texture_count += voxel->get_face_textures(world::VFACE_CROSS_NWSE).size(); - max_texture_count += voxel->get_face_textures(world::VFACE_CROSS_NESW).size(); - } - - // UNDONE: asset packs for non-16x16 stuff - world::voxel_atlas::create(16, 16, max_texture_count); - - for(auto& voxel : world::voxel_registry::voxels) { - constexpr std::array faces = { - world::VFACE_NORTH, - world::VFACE_SOUTH, - world::VFACE_EAST, - world::VFACE_WEST, - world::VFACE_TOP, - world::VFACE_BOTTOM, - world::VFACE_CROSS_NWSE, - world::VFACE_CROSS_NESW, - }; - - for(auto face : faces) { - if(auto strip = world::voxel_atlas::find_or_load(voxel->get_face_textures(face))) { - voxel->set_face_cache(face, strip->offset, strip->plane); - continue; - } - - spdlog::critical("client_gl: {}: failed to load atlas strips", voxel->get_name()); - std::terminate(); - } - } - - world::voxel_atlas::generate_mipmaps(); - - for(auto& item : world::item_registry::items) { - item->set_cached_texture(resource::load(item->get_texture(), TEXTURE_GUI_LOAD_CLAMP_S | TEXTURE_GUI_LOAD_CLAMP_T)); - } - - experiments::init_late(); - - gui::client_splash::init_late(); - - gui::window_title::update(); -} - -void client_game::shutdown(void) -{ - world::voxel_sounds::shutdown(); - - experiments::shutdown(); - - session::shutdown(); - - if(globals::sound_ctx) { - sound::shutdown(); - } - - gui::hotbar::shutdown(); - gui::main_menu::shutdown(); - gui::play_menu::shutdown(); - - gui::bother::shutdown(); - - gui::client_chat::shutdown(); - - gui::background::shutdown(); - - gui::crosshair::shutdown(); - - delete globals::dimension; - globals::player = entt::null; - globals::dimension = nullptr; - - world::item_registry::purge(); - world::voxel_registry::purge(); - - world::voxel_atlas::destroy(); - - glDeleteRenderbuffers(1, &globals::world_fbo_depth); - glDeleteTextures(1, &globals::world_fbo_color); - glDeleteFramebuffers(1, &globals::world_fbo); - - world::outline::shutdown(); - world::chunk_renderer::shutdown(); - world::chunk_mesher::shutdown(); - - enet_host_destroy(globals::client_host); -} - -void client_game::fixed_update(void) -{ - entity::player_move::fixed_update(); - - // Only update world simulation gamesystems - // if the player can actually observe all the - // changes these gamesystems cause visually - if(session::is_ingame()) { - entity::Collision::fixed_update(globals::dimension); - entity::Velocity::fixed_update(globals::dimension); - entity::Transform::fixed_update(globals::dimension); - entity::Gravity::fixed_update(globals::dimension); - entity::Stasis::fixed_update(globals::dimension); - } -} - -void client_game::fixed_update_late(void) -{ - if(session::is_ingame()) { - const auto& head = globals::dimension->entities.get(globals::player); - const auto& transform = globals::dimension->entities.get(globals::player); - const auto& velocity = globals::dimension->entities.get(globals::player); - - protocol::EntityHead head_packet; - head_packet.entity = entt::null; // ignored by server - head_packet.angles = head.angles; - - protocol::EntityTransform transform_packet; - transform_packet.entity = entt::null; // ignored by server - transform_packet.angles = transform.angles; - transform_packet.chunk = transform.chunk; - transform_packet.local = transform.local; - - protocol::EntityVelocity velocity_packet; - velocity_packet.entity = entt::null; // ignored by server - velocity_packet.value = velocity.value; - - protocol::send(session::peer, protocol::encode(head_packet)); - protocol::send(session::peer, protocol::encode(transform_packet)); - protocol::send(session::peer, protocol::encode(velocity_packet)); - } -} - -void client_game::update(void) -{ - if(session::is_ingame()) { - if(toggles::get(TOGGLE_PM_FLIGHT)) { - globals::dimension->entities.remove(globals::player); - } - else { - globals::dimension->entities.emplace_or_replace(globals::player); - } - } - - if(globals::sound_ctx) { - sound::update(); - - entity::listener::update(); - - entity::SoundEmitter::update(); - } - - entity::interpolation::update(); - - world::player_target::update(); - - entity::camera::update(); - - world::voxel_anims::update(); - - world::chunk_mesher::update(); - - gui::client_chat::update(); - - experiments::update(); - - constexpr auto half_base_width = 0.5f * static_cast(BASE_WIDTH); - constexpr auto half_base_height = 0.5f * static_cast(BASE_HEIGHT); - - auto twice_scale_x = static_cast(globals::width) / half_base_width; - auto twice_scale_y = static_cast(globals::height) / half_base_height; - - auto scale_x = glm::max(1.0f, 0.5f * glm::floor(twice_scale_x)); - auto scale_y = glm::max(1.0f, 0.5f * glm::floor(twice_scale_y)); - auto scale_min = static_cast(glm::ceil(glm::min(scale_x, scale_y))); - auto scale_int = glm::max(1U, (scale_min / 2U) * 2U); - - auto& io = ImGui::GetIO(); - io.FontGlobalScale = scale_int; - globals::gui_scale = scale_int; -} - -void client_game::update_late(void) -{ - ENetEvent enet_event; - - while(0 < enet_host_service(globals::client_host, &enet_event, 0)) { - switch(enet_event.type) { - case ENET_EVENT_TYPE_CONNECT: - session::send_login_request(); - break; - case ENET_EVENT_TYPE_DISCONNECT: - session::invalidate(); - break; - case ENET_EVENT_TYPE_RECEIVE: - protocol::decode(globals::dispatcher, enet_event.packet, enet_event.peer); - enet_packet_destroy(enet_event.packet); - break; - } - } - - entity::player_look::update_late(); - entity::player_move::update_late(); - - gui::play_menu::update_late(); - - gui::bother::update_late(); - - experiments::update_late(); - - io::gamepad::update_late(); - - world::chunk_visibility::update_late(); - - if(client_game::vertical_sync.get_value()) { - glfwSwapInterval(1); - } - else { - glfwSwapInterval(0); - } -} - -void client_game::render(void) -{ - glViewport(0, 0, globals::width, globals::height); - glBindFramebuffer(GL_FRAMEBUFFER, globals::world_fbo); - glClearColor(world::skybox::fog_color.r, world::skybox::fog_color.g, world::skybox::fog_color.b, 1.000f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - if(globals::dimension) { - world::chunk_renderer::render(); - } - - glEnable(GL_DEPTH_TEST); - - world::player_target::render(); - - if(globals::dimension) { - auto group = globals::dimension->entities.group( - entt::get); - - world::outline::prepare(); - - for(const auto [entity, collision, head, transform] : group.each()) { - if(entity == globals::player) { - // Don't render ourselves - continue; - } - - glm::fvec3 forward; - math::vectors(transform.angles + head.angles, forward); - forward *= 2.0f; - - glm::fvec3 hull_size = collision.aabb.max - collision.aabb.min; - glm::fvec3 hull_fpos = transform.local + collision.aabb.min; - glm::fvec3 look = transform.local + head.offset; - - world::outline::cube(transform.chunk, hull_fpos, hull_size, 1.0f, glm::fvec4(1.0f, 0.0f, 0.0f, 1.0f)); - world::outline::line(transform.chunk, look, forward, 1.0f, glm::fvec4(0.9f, 0.9f, 0.9f, 1.0f)); - } - } - - glEnable(GL_DEPTH_TEST); - - glViewport(0, 0, globals::width, globals::height); - glClearColor(0.000f, 0.000f, 0.000f, 1.000f); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glClear(GL_COLOR_BUFFER_BIT); - - glBindFramebuffer(GL_READ_FRAMEBUFFER, globals::world_fbo); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - glBlitFramebuffer(0, 0, globals::width, globals::height, 0, 0, globals::width, globals::height, GL_COLOR_BUFFER_BIT, GL_NEAREST); -} - -void client_game::layout(void) -{ - if(!session::is_ingame()) { - gui::background::layout(); - } - - if(!globals::gui_screen || (globals::gui_screen == GUI_CHAT)) { - if(toggles::get(TOGGLE_METRICS_UI) && !client_game::hide_hud) { - // This contains Minecraft-esque debug information - // about the hardware, world state and other - // things that might be uesful - gui::metrics::layout(); - } - } - - if(session::is_ingame()) { - gui::client_chat::layout(); - gui::scoreboard::layout(); - - if(!globals::gui_screen && !client_game::hide_hud) { - gui::hotbar::layout(); - gui::status_lines::layout(); - gui::crosshair::layout(); - } - } - - if(globals::gui_screen) { - if(session::is_ingame() && (globals::gui_screen != GUI_CHAT)) { - const float width_f = static_cast(globals::width); - const float height_f = static_cast(globals::height); - const ImU32 darken = ImGui::GetColorU32(ImVec4(0.00f, 0.00f, 0.00f, 0.75f)); - ImGui::GetBackgroundDrawList()->AddRectFilled(ImVec2(), ImVec2(width_f, height_f), darken); - } - - switch(globals::gui_screen) { - case GUI_MAIN_MENU: - gui::main_menu::layout(); - break; - case GUI_PLAY_MENU: - gui::play_menu::layout(); - break; - case GUI_SETTINGS: - settings::layout(); - break; - case GUI_PROGRESS_BAR: - gui::progress_bar::layout(); - break; - case GUI_MESSAGE_BOX: - gui::message_box::layout(); - break; - case GUI_DIRECT_CONNECTION: - gui::direct_connection::layout(); - break; - } - } -} diff --git a/game/client/game.hh b/game/client/game.hh deleted file mode 100644 index 649700a..0000000 --- a/game/client/game.hh +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -namespace config -{ -class Boolean; -class String; -class Unsigned; -} // namespace config - -namespace client_game -{ -extern config::Boolean streamer_mode; -extern config::Boolean vertical_sync; -extern config::Boolean world_curvature; -extern config::Unsigned fog_mode; -extern config::String username; -} // namespace client_game - -namespace client_game -{ -extern bool hide_hud; -} // namespace client_game - -namespace client_game -{ -void init(void); -void init_late(void); -void shutdown(void); -void fixed_update(void); -void fixed_update_late(void); -void update(void); -void update_late(void); -void render(void); -void layout(void); -} // namespace client_game diff --git a/game/client/globals.cc b/game/client/globals.cc deleted file mode 100644 index 1cf1aeb..0000000 --- a/game/client/globals.cc +++ /dev/null @@ -1,47 +0,0 @@ -#include "client/pch.hh" - -#include "client/globals.hh" - -#include "core/io/config_map.hh" - -#include "client/gui/gui_screen.hh" - -io::ConfigMap globals::client_config; - -GLFWwindow* globals::window; - -float globals::window_frametime; -float globals::window_frametime_avg; -std::uint64_t globals::window_frametime_us; -std::uint64_t globals::window_framecount; - -std::uint64_t globals::fixed_accumulator; - -int globals::width; -int globals::height; -float globals::aspect; - -GLuint globals::world_fbo; -GLuint globals::world_fbo_color; -GLuint globals::world_fbo_depth; - -std::size_t globals::num_drawcalls; -std::size_t globals::num_triangles; - -ENetHost* globals::client_host; - -world::Dimension* globals::dimension = nullptr; -entt::entity globals::player; - -ImFont* globals::font_unscii16; -ImFont* globals::font_unscii8; - -config::KeyBind* globals::gui_keybind_ptr = nullptr; -config::GamepadAxis* globals::gui_gamepad_axis_ptr = nullptr; -config::GamepadButton* globals::gui_gamepad_button_ptr = nullptr; - -unsigned int globals::gui_scale = 0U; -unsigned int globals::gui_screen = GUI_SCREEN_NONE; - -ALCdevice* globals::sound_dev; -ALCcontext* globals::sound_ctx; diff --git a/game/client/globals.hh b/game/client/globals.hh deleted file mode 100644 index 41531a9..0000000 --- a/game/client/globals.hh +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once - -#include "shared/globals.hh" - -namespace config -{ -class KeyBind; -class GamepadAxis; -class GamepadButton; -} // namespace config - -namespace io -{ -class ConfigMap; -} // namespace io - -struct GLFWwindow; -struct ImFont; - -namespace world -{ -class Dimension; -} // namespace world - -namespace globals -{ -extern io::ConfigMap client_config; - -extern GLFWwindow* window; - -// Some gamesystems that aren't really -// gameplay-oriented might still use client -// framerate to interpolate discrete things -// so it's still a good idea to keep these available -extern float window_frametime; -extern float window_frametime_avg; -extern std::uint64_t window_frametime_us; -extern std::uint64_t window_framecount; - -// https://gafferongames.com/post/fix_your_timestep/ -extern std::uint64_t fixed_accumulator; - -extern int width; -extern int height; -extern float aspect; - -extern GLuint world_fbo; -extern GLuint world_fbo_color; -extern GLuint world_fbo_depth; - -extern std::size_t num_drawcalls; -extern std::size_t num_triangles; - -extern ENetHost* client_host; - -extern world::Dimension* dimension; -extern entt::entity player; - -extern ImFont* font_unscii16; -extern ImFont* font_unscii8; - -extern config::KeyBind* gui_keybind_ptr; -extern config::GamepadAxis* gui_gamepad_axis_ptr; -extern config::GamepadButton* gui_gamepad_button_ptr; - -extern unsigned int gui_scale; -extern unsigned int gui_screen; - -extern ALCdevice* sound_dev; -extern ALCcontext* sound_ctx; -} // namespace globals diff --git a/game/client/gui/CMakeLists.txt b/game/client/gui/CMakeLists.txt deleted file mode 100644 index 46d64a1..0000000 --- a/game/client/gui/CMakeLists.txt +++ /dev/null @@ -1,38 +0,0 @@ -target_sources(vclient PRIVATE - "${CMAKE_CURRENT_LIST_DIR}/background.cc" - "${CMAKE_CURRENT_LIST_DIR}/background.hh" - "${CMAKE_CURRENT_LIST_DIR}/bother.cc" - "${CMAKE_CURRENT_LIST_DIR}/bother.hh" - "${CMAKE_CURRENT_LIST_DIR}/chat.cc" - "${CMAKE_CURRENT_LIST_DIR}/chat.hh" - "${CMAKE_CURRENT_LIST_DIR}/crosshair.cc" - "${CMAKE_CURRENT_LIST_DIR}/crosshair.hh" - "${CMAKE_CURRENT_LIST_DIR}/direct_connection.cc" - "${CMAKE_CURRENT_LIST_DIR}/direct_connection.hh" - "${CMAKE_CURRENT_LIST_DIR}/gui_screen.hh" - "${CMAKE_CURRENT_LIST_DIR}/hotbar.cc" - "${CMAKE_CURRENT_LIST_DIR}/hotbar.hh" - "${CMAKE_CURRENT_LIST_DIR}/imdraw_ext.cc" - "${CMAKE_CURRENT_LIST_DIR}/imdraw_ext.hh" - "${CMAKE_CURRENT_LIST_DIR}/language.cc" - "${CMAKE_CURRENT_LIST_DIR}/language.hh" - "${CMAKE_CURRENT_LIST_DIR}/main_menu.cc" - "${CMAKE_CURRENT_LIST_DIR}/main_menu.hh" - "${CMAKE_CURRENT_LIST_DIR}/message_box.cc" - "${CMAKE_CURRENT_LIST_DIR}/message_box.hh" - "${CMAKE_CURRENT_LIST_DIR}/metrics.cc" - "${CMAKE_CURRENT_LIST_DIR}/metrics.hh" - "${CMAKE_CURRENT_LIST_DIR}/play_menu.cc" - "${CMAKE_CURRENT_LIST_DIR}/play_menu.hh" - "${CMAKE_CURRENT_LIST_DIR}/progress_bar.cc" - "${CMAKE_CURRENT_LIST_DIR}/progress_bar.hh" - "${CMAKE_CURRENT_LIST_DIR}/scoreboard.cc" - "${CMAKE_CURRENT_LIST_DIR}/scoreboard.hh" - "${CMAKE_CURRENT_LIST_DIR}/settings.cc" - "${CMAKE_CURRENT_LIST_DIR}/settings.hh" - "${CMAKE_CURRENT_LIST_DIR}/splash.cc" - "${CMAKE_CURRENT_LIST_DIR}/splash.hh" - "${CMAKE_CURRENT_LIST_DIR}/status_lines.cc" - "${CMAKE_CURRENT_LIST_DIR}/status_lines.hh" - "${CMAKE_CURRENT_LIST_DIR}/window_title.cc" - "${CMAKE_CURRENT_LIST_DIR}/window_title.hh") diff --git a/game/client/gui/background.cc b/game/client/gui/background.cc deleted file mode 100644 index d1500bb..0000000 --- a/game/client/gui/background.cc +++ /dev/null @@ -1,39 +0,0 @@ -#include "client/pch.hh" - -#include "client/gui/background.hh" - -#include "core/math/constexpr.hh" - -#include "core/resource/resource.hh" - -#include "client/resource/texture_gui.hh" - -#include "client/globals.hh" - -static resource_ptr texture; - -void gui::background::init(void) -{ - texture = resource::load("textures/gui/background.png", TEXTURE_GUI_LOAD_VFLIP); - - if(texture == nullptr) { - spdlog::critical("background: texture load failed"); - std::terminate(); - } -} - -void gui::background::shutdown(void) -{ - texture = nullptr; -} - -void gui::background::layout(void) -{ - auto viewport = ImGui::GetMainViewport(); - auto draw_list = ImGui::GetBackgroundDrawList(); - - auto scaled_width = 0.75f * static_cast(globals::width / globals::gui_scale); - auto scaled_height = 0.75f * static_cast(globals::height / globals::gui_scale); - auto scale_uv = ImVec2(scaled_width / static_cast(texture->size.x), scaled_height / static_cast(texture->size.y)); - draw_list->AddImage(texture->handle, ImVec2(0.0f, 0.0f), viewport->Size, ImVec2(0.0f, 0.0f), scale_uv); -} diff --git a/game/client/gui/background.hh b/game/client/gui/background.hh deleted file mode 100644 index 6145484..0000000 --- a/game/client/gui/background.hh +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -namespace gui::background -{ -void init(void); -void shutdown(void); -void layout(void); -} // namespace gui::background diff --git a/game/client/gui/bother.cc b/game/client/gui/bother.cc deleted file mode 100644 index e87b9ff..0000000 --- a/game/client/gui/bother.cc +++ /dev/null @@ -1,167 +0,0 @@ -#include "client/pch.hh" - -#include "client/gui/bother.hh" - -#include "core/version.hh" - -#include "shared/protocol.hh" - -#include "client/globals.hh" - -// Maximum amount of peers used for bothering -constexpr static std::size_t BOTHER_PEERS = 4; - -struct BotherQueueItem final { - unsigned int identity; - std::string hostname; - std::uint16_t port; -}; - -static ENetHost* bother_host; -static entt::dispatcher bother_dispatcher; -static std::unordered_set bother_set; -static std::deque bother_queue; - -static void on_status_response_packet(const protocol::StatusResponse& packet) -{ - auto identity = static_cast(reinterpret_cast(packet.peer->data)); - - bother_set.erase(identity); - - gui::BotherResponseEvent event; - event.identity = identity; - event.is_server_unreachable = false; - event.num_players = packet.num_players; - event.max_players = packet.max_players; - event.motd = packet.motd; - event.game_version_major = packet.game_version_major; - event.game_version_minor = packet.game_version_minor; - event.game_version_patch = packet.game_version_patch; - globals::dispatcher.trigger(event); - - enet_peer_disconnect(packet.peer, protocol::CHANNEL); -} - -void gui::bother::init(void) -{ - bother_host = enet_host_create(nullptr, BOTHER_PEERS, 1, 0, 0); - bother_dispatcher.clear(); - bother_set.clear(); - - bother_dispatcher.sink().connect<&on_status_response_packet>(); -} - -void gui::bother::shutdown(void) -{ - enet_host_destroy(bother_host); - bother_dispatcher.clear(); - bother_set.clear(); -} - -void gui::bother::update_late(void) -{ - unsigned int free_peers = 0U; - - // Figure out how much times we can call - // enet_host_connect and reallistically succeed - for(unsigned int i = 0U; i < bother_host->peerCount; ++i) { - if(bother_host->peers[i].state != ENET_PEER_STATE_DISCONNECTED) { - continue; - } - - free_peers += 1U; - } - - for(unsigned int i = 0U; (i < free_peers) && bother_queue.size(); ++i) { - const auto& item = bother_queue.front(); - - ENetAddress address; - enet_address_set_host(&address, item.hostname.c_str()); - address.port = enet_uint16(item.port); - - if(auto peer = enet_host_connect(bother_host, &address, 1, 0)) { - peer->data = reinterpret_cast(static_cast(item.identity)); - bother_set.insert(item.identity); - enet_host_flush(bother_host); - } - - bother_queue.pop_front(); - } - - ENetEvent enet_event; - - if(0 < enet_host_service(bother_host, &enet_event, 0)) { - if(enet_event.type == ENET_EVENT_TYPE_CONNECT) { - protocol::StatusRequest packet; - packet.game_version_major = version::major; - protocol::send(enet_event.peer, protocol::encode(packet)); - return; - } - - if(enet_event.type == ENET_EVENT_TYPE_RECEIVE) { - protocol::decode(bother_dispatcher, enet_event.packet, enet_event.peer); - enet_packet_destroy(enet_event.packet); - return; - } - - if(enet_event.type == ENET_EVENT_TYPE_DISCONNECT) { - auto identity = static_cast(reinterpret_cast(enet_event.peer->data)); - - if(bother_set.count(identity)) { - BotherResponseEvent event; - event.identity = identity; - event.is_server_unreachable = true; - globals::dispatcher.trigger(event); - } - - bother_set.erase(identity); - - return; - } - } -} - -void gui::bother::ping(unsigned int identity, std::string_view host, std::uint16_t port) -{ - if(bother_set.count(identity)) { - // Already in the process - return; - } - - for(const auto& item : bother_queue) { - if(item.identity == identity) { - // Already in the queue - return; - } - } - - BotherQueueItem item; - item.identity = identity; - item.hostname = host; - item.port = port; - - bother_queue.push_back(item); -} - -void gui::bother::cancel(unsigned int identity) -{ - bother_set.erase(identity); - - auto item = bother_queue.cbegin(); - - while(item != bother_queue.cend()) { - if(item->identity == identity) { - item = bother_queue.erase(item); - continue; - } - - item = std::next(item); - } - - for(unsigned int i = 0U; i < bother_host->peerCount; ++i) { - if(bother_host->peers[i].data == reinterpret_cast(static_cast(identity))) { - enet_peer_reset(&bother_host->peers[i]); - break; - } - } -} diff --git a/game/client/gui/bother.hh b/game/client/gui/bother.hh deleted file mode 100644 index 75e56d1..0000000 --- a/game/client/gui/bother.hh +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -namespace gui -{ -struct BotherResponseEvent final { - unsigned int identity; - bool is_server_unreachable; - std::uint16_t num_players; - std::uint16_t max_players; - std::uint32_t game_version_major; - std::uint32_t game_version_minor; - std::uint32_t game_version_patch; - std::string motd; -}; -} // namespace gui - -namespace gui::bother -{ -void init(void); -void shutdown(void); -void update_late(void); -void ping(unsigned int identity, std::string_view host, std::uint16_t port); -void cancel(unsigned int identity); -} // namespace gui::bother diff --git a/game/client/gui/chat.cc b/game/client/gui/chat.cc deleted file mode 100644 index aaee8c6..0000000 --- a/game/client/gui/chat.cc +++ /dev/null @@ -1,273 +0,0 @@ -#include "client/pch.hh" - -#include "client/gui/chat.hh" - -#include "core/config/number.hh" -#include "core/config/string.hh" - -#include "core/io/config_map.hh" - -#include "core/resource/resource.hh" - -#include "core/utils/string.hh" - -#include "shared/protocol.hh" - -#include "client/config/keybind.hh" - -#include "client/gui/gui_screen.hh" -#include "client/gui/imdraw_ext.hh" -#include "client/gui/language.hh" -#include "client/gui/settings.hh" - -#include "client/io/glfw.hh" - -#include "client/resource/sound_effect.hh" - -#include "client/sound/sound.hh" - -#include "client/game.hh" -#include "client/globals.hh" -#include "client/session.hh" - -constexpr static ImGuiWindowFlags WINDOW_FLAGS = ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDecoration; -constexpr static unsigned int MAX_HISTORY_SIZE = 128U; - -struct GuiChatMessage final { - std::uint64_t spawn; - std::string text; - ImVec4 color; -}; - -static config::KeyBind key_chat(GLFW_KEY_ENTER); -static config::Unsigned history_size(32U, 0U, MAX_HISTORY_SIZE); - -static std::deque history; -static std::string chat_input; -static bool needs_focus; - -static resource_ptr sfx_chat_message; - -static void append_text_message(const std::string& sender, const std::string& text) -{ - GuiChatMessage message; - message.spawn = globals::curtime; - message.text = std::format("<{}> {}", sender, text); - message.color = ImGui::GetStyleColorVec4(ImGuiCol_Text); - history.push_back(message); - - if(sfx_chat_message && session::is_ingame()) { - sound::play_ui(sfx_chat_message, false, 1.0f); - } -} - -static void append_player_join(const std::string& sender) -{ - GuiChatMessage message; - message.spawn = globals::curtime; - message.text = std::format("{} {}", sender, gui::language::resolve("chat.client_join")); - message.color = ImGui::GetStyleColorVec4(ImGuiCol_DragDropTarget); - history.push_back(message); - - if(sfx_chat_message && session::is_ingame()) { - sound::play_ui(sfx_chat_message, false, 1.0f); - } -} - -static void append_player_leave(const std::string& sender, const std::string& reason) -{ - GuiChatMessage message; - message.spawn = globals::curtime; - message.text = std::format("{} {} ({})", sender, gui::language::resolve("chat.client_left"), gui::language::resolve(reason.c_str())); - message.color = ImGui::GetStyleColorVec4(ImGuiCol_DragDropTarget); - history.push_back(message); - - if(sfx_chat_message && session::is_ingame()) { - sound::play_ui(sfx_chat_message, false, 1.0f); - } -} - -static void on_chat_message_packet(const protocol::ChatMessage& packet) -{ - if(packet.type == protocol::ChatMessage::TEXT_MESSAGE) { - append_text_message(packet.sender, packet.message); - return; - } - - if(packet.type == protocol::ChatMessage::PLAYER_JOIN) { - append_player_join(packet.sender); - return; - } - - if(packet.type == protocol::ChatMessage::PLAYER_LEAVE) { - append_player_leave(packet.sender, packet.message); - return; - } -} - -static void on_glfw_key(const io::GlfwKeyEvent& event) -{ - if(event.action == GLFW_PRESS) { - if((event.key == GLFW_KEY_ENTER) && (globals::gui_screen == GUI_CHAT)) { - if(!utils::is_whitespace(chat_input)) { - protocol::ChatMessage packet; - packet.type = protocol::ChatMessage::TEXT_MESSAGE; - packet.sender = client_game::username.get(); - packet.message = chat_input; - - protocol::send(session::peer, protocol::encode(packet)); - } - - globals::gui_screen = GUI_SCREEN_NONE; - - chat_input.clear(); - - return; - } - - if((event.key == GLFW_KEY_ESCAPE) && (globals::gui_screen == GUI_CHAT)) { - globals::gui_screen = GUI_SCREEN_NONE; - return; - } - - if(key_chat.equals(event.key) && !globals::gui_screen) { - globals::gui_screen = GUI_CHAT; - needs_focus = true; - return; - } - } -} - -void gui::client_chat::init(void) -{ - globals::client_config.add_value("chat.key", key_chat); - globals::client_config.add_value("chat.history_size", history_size); - - settings::add_keybind(2, key_chat, settings_location::KEYBOARD_MISC, "key.chat"); - settings::add_slider(1, history_size, settings_location::VIDEO_GUI, "chat.history_size", false); - - globals::dispatcher.sink().connect<&on_chat_message_packet>(); - globals::dispatcher.sink().connect<&on_glfw_key>(); - - sfx_chat_message = resource::load("sounds/ui/chat_message.wav"); -} - -void gui::client_chat::init_late(void) -{ -} - -void gui::client_chat::shutdown(void) -{ - sfx_chat_message = nullptr; -} - -void gui::client_chat::update(void) -{ - while(history.size() > history_size.get_value()) { - history.pop_front(); - } -} - -void gui::client_chat::layout(void) -{ - auto viewport = ImGui::GetMainViewport(); - auto window_start = ImVec2(0.0f, 0.0f); - auto window_size = ImVec2(0.75f * viewport->Size.x, viewport->Size.y); - - ImGui::SetNextWindowPos(window_start); - ImGui::SetNextWindowSize(window_size); - - ImGui::PushFont(globals::font_unscii16, 8.0f); - - if(!ImGui::Begin("###chat", nullptr, WINDOW_FLAGS)) { - ImGui::End(); - return; - } - - auto& padding = ImGui::GetStyle().FramePadding; - auto& spacing = ImGui::GetStyle().ItemSpacing; - auto font = ImGui::GetFont(); - - auto draw_list = ImGui::GetWindowDrawList(); - - // The text input widget occupies the bottom part - // of the chat window, we need to reserve some space for it - auto ypos = window_size.y - 2.5f * ImGui::GetFontSize() - 2.0f * padding.y - 2.0f * spacing.y; - - if(globals::gui_screen == GUI_CHAT) { - if(needs_focus) { - ImGui::SetKeyboardFocusHere(); - needs_focus = false; - } - - ImGui::SetNextItemWidth(window_size.x + 32.0f * padding.x); - ImGui::SetCursorScreenPos(ImVec2(padding.x, ypos)); - ImGui::InputText("###chat.input", &chat_input); - } - - if(!client_game::hide_hud && ((globals::gui_screen == GUI_SCREEN_NONE) || (globals::gui_screen == GUI_CHAT))) { - for(auto it = history.crbegin(); it < history.crend(); ++it) { - auto text_size = ImGui::CalcTextSize(it->text.c_str(), it->text.c_str() + it->text.size(), false, window_size.x); - auto rect_size = ImVec2(window_size.x, text_size.y + 2.0f * padding.y); - - auto rect_pos = ImVec2(padding.x, ypos - text_size.y - 2.0f * padding.y); - auto rect_end = ImVec2(rect_pos.x + rect_size.x, rect_pos.y + rect_size.y); - auto text_pos = ImVec2(rect_pos.x + padding.x, rect_pos.y + padding.y); - - auto fadeout_seconds = 10.0f; - auto fadeout = std::exp(-1.0f * std::pow(1.0e-6 * static_cast(globals::curtime - it->spawn) / fadeout_seconds, 10.0f)); - - float rect_alpha; - float text_alpha; - - if(globals::gui_screen == GUI_CHAT) { - rect_alpha = 0.75f; - text_alpha = 1.00f; - } - else { - rect_alpha = 0.50f * fadeout; - text_alpha = 1.00f * fadeout; - } - - auto rect_col = ImGui::GetColorU32(ImGuiCol_FrameBg, rect_alpha); - auto text_col = ImGui::GetColorU32(ImVec4(it->color.x, it->color.y, it->color.z, it->color.w * text_alpha)); - auto shadow_col = ImGui::GetColorU32(ImVec4(0.0f, 0.0f, 0.0f, text_alpha)); - - draw_list->AddRectFilled(rect_pos, rect_end, rect_col); - - imdraw_ext::text_shadow_w(it->text, text_pos, text_col, shadow_col, font, draw_list, 8.0f, window_size.x); - - ypos -= rect_size.y; - } - } - - ImGui::End(); - ImGui::PopFont(); -} - -void gui::client_chat::clear(void) -{ - history.clear(); -} - -void gui::client_chat::refresh_timings(void) -{ - for(auto it = history.begin(); it < history.end(); ++it) { - // Reset the spawn time so the fadeout timer - // is reset; SpawnPlayer handler might call this - it->spawn = globals::curtime; - } -} - -void gui::client_chat::print(const std::string& text) -{ - GuiChatMessage message = {}; - message.spawn = globals::curtime; - message.text = text; - message.color = ImGui::GetStyleColorVec4(ImGuiCol_Text); - history.push_back(message); - - if(sfx_chat_message && session::is_ingame()) { - sound::play_ui(sfx_chat_message, false, 1.0f); - } -} diff --git a/game/client/gui/chat.hh b/game/client/gui/chat.hh deleted file mode 100644 index 2fc6fb3..0000000 --- a/game/client/gui/chat.hh +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -namespace gui::client_chat -{ -void init(void); -void init_late(void); -void shutdown(void); -void update(void); -void layout(void); -} // namespace gui::client_chat - -namespace gui::client_chat -{ -void clear(void); -void refresh_timings(void); -void print(const std::string& string); -} // namespace gui::client_chat diff --git a/game/client/gui/crosshair.cc b/game/client/gui/crosshair.cc deleted file mode 100644 index 2e6eeba..0000000 --- a/game/client/gui/crosshair.cc +++ /dev/null @@ -1,43 +0,0 @@ -#include "client/pch.hh" - -#include "client/gui/crosshair.hh" - -#include "core/math/constexpr.hh" - -#include "core/resource/resource.hh" - -#include "client/resource/texture_gui.hh" - -#include "client/globals.hh" -#include "client/session.hh" - -static resource_ptr texture; - -void gui::crosshair::init(void) -{ - texture = resource::load("textures/gui/hud_crosshair.png", - TEXTURE_GUI_LOAD_CLAMP_S | TEXTURE_GUI_LOAD_CLAMP_T | TEXTURE_GUI_LOAD_VFLIP); - - if(texture == nullptr) { - spdlog::critical("crosshair: texture load failed"); - std::terminate(); - } -} - -void gui::crosshair::shutdown(void) -{ - texture = nullptr; -} - -void gui::crosshair::layout(void) -{ - auto viewport = ImGui::GetMainViewport(); - auto draw_list = ImGui::GetForegroundDrawList(); - - auto scaled_width = glm::max(texture->size.x, globals::gui_scale * texture->size.x / 2); - auto scaled_height = glm::max(texture->size.y, globals::gui_scale * texture->size.y / 2); - auto start = ImVec2(static_cast(0.5f * viewport->Size.x) - (scaled_width / 2), - static_cast(0.5f * viewport->Size.y) - (scaled_height / 2)); - auto end = ImVec2(start.x + scaled_width, start.y + scaled_height); - draw_list->AddImage(texture->handle, start, end); -} diff --git a/game/client/gui/crosshair.hh b/game/client/gui/crosshair.hh deleted file mode 100644 index dca5725..0000000 --- a/game/client/gui/crosshair.hh +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -namespace gui::crosshair -{ -void init(void); -void shutdown(void); -void layout(void); -} // namespace gui::crosshair diff --git a/game/client/gui/direct_connection.cc b/game/client/gui/direct_connection.cc deleted file mode 100644 index c521232..0000000 --- a/game/client/gui/direct_connection.cc +++ /dev/null @@ -1,145 +0,0 @@ -#include "client/pch.hh" - -#include "client/gui/direct_connection.hh" - -#include "core/config/boolean.hh" - -#include "core/utils/string.hh" - -#include "shared/protocol.hh" - -#include "client/gui/gui_screen.hh" -#include "client/gui/language.hh" - -#include "client/io/glfw.hh" - -#include "client/game.hh" -#include "client/globals.hh" -#include "client/session.hh" - -constexpr static ImGuiWindowFlags WINDOW_FLAGS = ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDecoration; - -static std::string str_title; -static std::string str_connect; -static std::string str_cancel; - -static std::string str_hostname; -static std::string str_password; - -static std::string direct_hostname; -static std::string direct_password; - -static void on_glfw_key(const io::GlfwKeyEvent& event) -{ - if((event.key == GLFW_KEY_ESCAPE) && (event.action == GLFW_PRESS)) { - if(globals::gui_screen == GUI_DIRECT_CONNECTION) { - globals::gui_screen = GUI_PLAY_MENU; - return; - } - } -} - -static void on_language_set(const gui::LanguageSetEvent& event) -{ - str_title = gui::language::resolve("direct_connection.title"); - str_connect = gui::language::resolve_gui("direct_connection.connect"); - str_cancel = gui::language::resolve_gui("direct_connection.cancel"); - - str_hostname = gui::language::resolve("direct_connection.hostname"); - str_password = gui::language::resolve("direct_connection.password"); -} - -static void connect_to_server(void) -{ - auto parts = utils::split(direct_hostname, ":"); - std::string parsed_hostname; - std::uint16_t parsed_port; - - if(!parts[0].empty()) { - parsed_hostname = parts[0]; - } - else { - parsed_hostname = std::string("localhost"); - } - - if(parts.size() >= 2) { - parsed_port = glm::clamp(strtoul(parts[1].c_str(), nullptr, 10), 1024, UINT16_MAX); - } - else { - parsed_port = protocol::PORT; - } - - session::connect(parsed_hostname.c_str(), parsed_port, direct_password.c_str()); -} - -void gui::direct_connection::init(void) -{ - globals::dispatcher.sink().connect<&on_glfw_key>(); - globals::dispatcher.sink().connect<&on_language_set>(); -} - -void gui::direct_connection::layout(void) -{ - auto viewport = ImGui::GetMainViewport(); - auto window_start = ImVec2(0.25f * viewport->Size.x, 0.20f * viewport->Size.y); - auto window_size = ImVec2(0.50f * viewport->Size.x, 0.80f * viewport->Size.y); - - ImGui::SetNextWindowPos(window_start); - ImGui::SetNextWindowSize(window_size); - - if(ImGui::Begin("###UIDirectConnect", nullptr, WINDOW_FLAGS)) { - const float title_width = ImGui::CalcTextSize(str_title.c_str()).x; - ImGui::SetCursorPosX(0.5f * (window_size.x - title_width)); - ImGui::TextUnformatted(str_title.c_str()); - - ImGui::Dummy(ImVec2(0.0f, 16.0f * globals::gui_scale)); - - ImGuiInputTextFlags hostname_flags = ImGuiInputTextFlags_CharsNoBlank; - - if(client_game::streamer_mode.get_value()) { - // Hide server hostname to avoid things like - // followers flooding the server that is streamed online - hostname_flags |= ImGuiInputTextFlags_Password; - } - - auto avail_width = ImGui::GetContentRegionAvail().x; - - ImGui::PushItemWidth(avail_width); - - ImGui::InputText("###UIDirectConnect_hostname", &direct_hostname, hostname_flags); - - if(ImGui::BeginItemTooltip()) { - ImGui::PushTextWrapPos(ImGui::GetFontSize() * 16.0f); - ImGui::TextUnformatted(str_hostname.c_str()); - ImGui::PopTextWrapPos(); - ImGui::EndTooltip(); - } - - ImGui::InputText("###UIDirectConnect_password", &direct_password, ImGuiInputTextFlags_Password); - - if(ImGui::BeginItemTooltip()) { - ImGui::PushTextWrapPos(ImGui::GetFontSize() * 16.0f); - ImGui::TextUnformatted(str_password.c_str()); - ImGui::PopTextWrapPos(); - ImGui::EndTooltip(); - } - - ImGui::PopItemWidth(); - - ImGui::Dummy(ImVec2(0.0f, 4.0f * globals::gui_scale)); - - ImGui::BeginDisabled(utils::is_whitespace(direct_hostname)); - - if(ImGui::Button(str_connect.c_str(), ImVec2(avail_width, 0.0f))) { - connect_to_server(); - } - - ImGui::EndDisabled(); - - if(ImGui::Button(str_cancel.c_str(), ImVec2(avail_width, 0.0f))) { - globals::gui_screen = GUI_PLAY_MENU; - } - } - - ImGui::End(); -} diff --git a/game/client/gui/direct_connection.hh b/game/client/gui/direct_connection.hh deleted file mode 100644 index c63156b..0000000 --- a/game/client/gui/direct_connection.hh +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -namespace gui::direct_connection -{ -void init(void); -void layout(void); -} // namespace gui::direct_connection diff --git a/game/client/gui/gui_screen.hh b/game/client/gui/gui_screen.hh deleted file mode 100644 index c29f701..0000000 --- a/game/client/gui/gui_screen.hh +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -constexpr static unsigned int GUI_SCREEN_NONE = 0x0000U; -constexpr static unsigned int GUI_MAIN_MENU = 0x0001U; -constexpr static unsigned int GUI_PLAY_MENU = 0x0002U; -constexpr static unsigned int GUI_SETTINGS = 0x0003U; -constexpr static unsigned int GUI_PROGRESS_BAR = 0x0004U; -constexpr static unsigned int GUI_MESSAGE_BOX = 0x0005U; -constexpr static unsigned int GUI_CHAT = 0x0006U; -constexpr static unsigned int GUI_DIRECT_CONNECTION = 0x0007U; diff --git a/game/client/gui/hotbar.cc b/game/client/gui/hotbar.cc deleted file mode 100644 index e9458dd..0000000 --- a/game/client/gui/hotbar.cc +++ /dev/null @@ -1,182 +0,0 @@ -#include "client/pch.hh" - -#include "client/gui/hotbar.hh" - -#include "core/io/config_map.hh" - -#include "core/resource/resource.hh" - -#include "shared/world/item_registry.hh" - -#include "client/config/keybind.hh" - -#include "client/gui/settings.hh" -#include "client/gui/status_lines.hh" - -#include "client/io/glfw.hh" - -#include "client/resource/texture_gui.hh" - -#include "client/globals.hh" - -constexpr static float ITEM_SIZE = 20.0f; -constexpr static float ITEM_PADDING = 2.0f; -constexpr static float SELECTOR_PADDING = 1.0f; -constexpr static float HOTBAR_PADDING = 2.0f; - -unsigned int gui::hotbar::active_slot = 0U; -std::array gui::hotbar::slots = {}; - -static config::KeyBind hotbar_keys[HOTBAR_SIZE]; - -static resource_ptr hotbar_background; -static resource_ptr hotbar_selector; - -static ImU32 get_color_alpha(ImGuiCol style_color, float alpha) -{ - const auto& color = ImGui::GetStyleColorVec4(style_color); - return ImGui::GetColorU32(ImVec4(color.x, color.y, color.z, alpha)); -} - -static void update_hotbar_item(void) -{ - auto current_item = gui::hotbar::slots[gui::hotbar::active_slot]; - - if(current_item == nullptr) { - gui::status_lines::unset(gui::STATUS_HOTBAR); - } - else { - gui::status_lines::set(gui::STATUS_HOTBAR, current_item->get_name(), ImVec4(1.0f, 1.0f, 1.0f, 1.0f), 5.0f); - } -} - -static void on_glfw_key(const io::GlfwKeyEvent& event) -{ - if((event.action == GLFW_PRESS) && !globals::gui_screen) { - for(unsigned int i = 0U; i < HOTBAR_SIZE; ++i) { - if(hotbar_keys[i].equals(event.key)) { - gui::hotbar::active_slot = i; - update_hotbar_item(); - break; - } - } - } -} - -static void on_glfw_scroll(const io::GlfwScrollEvent& event) -{ - if(!globals::gui_screen) { - if(event.dy < 0.0) { - gui::hotbar::next_slot(); - return; - } - - if(event.dy > 0.0) { - gui::hotbar::prev_slot(); - return; - } - } -} - -void gui::hotbar::init(void) -{ - hotbar_keys[0].set_key(GLFW_KEY_1); - hotbar_keys[1].set_key(GLFW_KEY_2); - hotbar_keys[2].set_key(GLFW_KEY_3); - hotbar_keys[3].set_key(GLFW_KEY_4); - hotbar_keys[4].set_key(GLFW_KEY_5); - hotbar_keys[5].set_key(GLFW_KEY_6); - hotbar_keys[6].set_key(GLFW_KEY_7); - hotbar_keys[7].set_key(GLFW_KEY_8); - hotbar_keys[8].set_key(GLFW_KEY_9); - - globals::client_config.add_value("hotbar.key.0", hotbar_keys[0]); - globals::client_config.add_value("hotbar.key.1", hotbar_keys[1]); - globals::client_config.add_value("hotbar.key.3", hotbar_keys[2]); - globals::client_config.add_value("hotbar.key.4", hotbar_keys[3]); - globals::client_config.add_value("hotbar.key.5", hotbar_keys[4]); - globals::client_config.add_value("hotbar.key.6", hotbar_keys[5]); - globals::client_config.add_value("hotbar.key.7", hotbar_keys[6]); - globals::client_config.add_value("hotbar.key.8", hotbar_keys[7]); - globals::client_config.add_value("hotbar.key.9", hotbar_keys[8]); - - settings::add_keybind(10, hotbar_keys[0], settings_location::KEYBOARD_GAMEPLAY, "hotbar.slot.0"); - settings::add_keybind(11, hotbar_keys[1], settings_location::KEYBOARD_GAMEPLAY, "hotbar.slot.1"); - settings::add_keybind(12, hotbar_keys[2], settings_location::KEYBOARD_GAMEPLAY, "hotbar.slot.2"); - settings::add_keybind(13, hotbar_keys[3], settings_location::KEYBOARD_GAMEPLAY, "hotbar.slot.3"); - settings::add_keybind(14, hotbar_keys[4], settings_location::KEYBOARD_GAMEPLAY, "hotbar.slot.4"); - settings::add_keybind(15, hotbar_keys[5], settings_location::KEYBOARD_GAMEPLAY, "hotbar.slot.5"); - settings::add_keybind(16, hotbar_keys[6], settings_location::KEYBOARD_GAMEPLAY, "hotbar.slot.6"); - settings::add_keybind(17, hotbar_keys[7], settings_location::KEYBOARD_GAMEPLAY, "hotbar.slot.7"); - settings::add_keybind(18, hotbar_keys[8], settings_location::KEYBOARD_GAMEPLAY, "hotbar.slot.8"); - - hotbar_background = resource::load("textures/gui/hud_hotbar.png", TEXTURE_GUI_LOAD_CLAMP_S | TEXTURE_GUI_LOAD_CLAMP_T); - hotbar_selector = resource::load("textures/gui/hud_selector.png", TEXTURE_GUI_LOAD_CLAMP_S | TEXTURE_GUI_LOAD_CLAMP_T); - - globals::dispatcher.sink().connect<&on_glfw_key>(); - globals::dispatcher.sink().connect<&on_glfw_scroll>(); -} - -void gui::hotbar::shutdown(void) -{ - hotbar_background = nullptr; - hotbar_selector = nullptr; -} - -void gui::hotbar::layout(void) -{ - auto& style = ImGui::GetStyle(); - - auto item_size = ITEM_SIZE * globals::gui_scale; - auto hotbar_width = HOTBAR_SIZE * item_size; - auto hotbar_padding = HOTBAR_PADDING * globals::gui_scale; - - auto viewport = ImGui::GetMainViewport(); - auto draw_list = ImGui::GetForegroundDrawList(); - - // Draw the hotbar background image - auto background_start = ImVec2(0.5f * viewport->Size.x - 0.5f * hotbar_width, viewport->Size.y - item_size - hotbar_padding); - auto background_end = ImVec2(background_start.x + hotbar_width, background_start.y + item_size); - draw_list->AddImage(hotbar_background->handle, background_start, background_end); - - // Draw the hotbar selector image - auto selector_padding_a = SELECTOR_PADDING * globals::gui_scale; - auto selector_padding_b = SELECTOR_PADDING * globals::gui_scale * 2.0f; - auto selector_start = ImVec2(background_start.x + gui::hotbar::active_slot * item_size - selector_padding_a, - background_start.y - selector_padding_a); - auto selector_end = ImVec2(selector_start.x + item_size + selector_padding_b, selector_start.y + item_size + selector_padding_b); - draw_list->AddImage(hotbar_selector->handle, selector_start, selector_end); - - // Figure out item texture padding values - auto item_padding_a = ITEM_PADDING * globals::gui_scale; - auto item_padding_b = ITEM_PADDING * globals::gui_scale * 2.0f; - - // Draw individual item textures in the hotbar - for(std::size_t i = 0; i < HOTBAR_SIZE; ++i) { - auto item = gui::hotbar::slots[i]; - - if((item == nullptr) || (item->get_cached_texture() == nullptr)) { - // There's either no item in the slot - // or the item doesn't have a texture - continue; - } - - const auto item_start = ImVec2(background_start.x + i * item_size + item_padding_a, background_start.y + item_padding_a); - const auto item_end = ImVec2(item_start.x + item_size - item_padding_b, item_start.y + item_size - item_padding_b); - draw_list->AddImage(item->get_cached_texture()->handle, item_start, item_end); - } -} - -void gui::hotbar::next_slot(void) -{ - gui::hotbar::active_slot += 1U; - gui::hotbar::active_slot %= HOTBAR_SIZE; - update_hotbar_item(); -} - -void gui::hotbar::prev_slot(void) -{ - gui::hotbar::active_slot += HOTBAR_SIZE - 1U; - gui::hotbar::active_slot %= HOTBAR_SIZE; - update_hotbar_item(); -} diff --git a/game/client/gui/hotbar.hh b/game/client/gui/hotbar.hh deleted file mode 100644 index 223dbc9..0000000 --- a/game/client/gui/hotbar.hh +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -// TODO: design an inventory system and an item -// registry and integrate the hotbar into that system - -namespace world -{ -class Item; -} // namespace world - -constexpr static unsigned int HOTBAR_SIZE = 9U; - -namespace gui::hotbar -{ -extern unsigned int active_slot; -extern std::array slots; -} // namespace gui::hotbar - -namespace gui::hotbar -{ -void init(void); -void shutdown(void); -void layout(void); -} // namespace gui::hotbar - -namespace gui::hotbar -{ -void next_slot(void); -void prev_slot(void); -} // namespace gui::hotbar diff --git a/game/client/gui/imdraw_ext.cc b/game/client/gui/imdraw_ext.cc deleted file mode 100644 index c3d40c9..0000000 --- a/game/client/gui/imdraw_ext.cc +++ /dev/null @@ -1,34 +0,0 @@ -#include "client/pch.hh" - -#include "client/gui/imdraw_ext.hh" - -#include "client/globals.hh" - -void gui::imdraw_ext::text_shadow(const std::string& text, const ImVec2& position, ImU32 text_color, ImU32 shadow_color, ImFont* font, - ImDrawList* draw_list) -{ - imdraw_ext::text_shadow(text, position, text_color, shadow_color, font, draw_list, font->LegacySize); -} - -void gui::imdraw_ext::text_shadow(const std::string& text, const ImVec2& position, ImU32 text_color, ImU32 shadow_color, ImFont* font, - ImDrawList* draw_list, float font_size) -{ - const auto shadow_position = ImVec2(position.x + 0.5f * globals::gui_scale, position.y + 0.5f * globals::gui_scale); - draw_list->AddText(font, globals::gui_scale * font_size, shadow_position, shadow_color, text.c_str(), text.c_str() + text.size()); - draw_list->AddText(font, globals::gui_scale * font_size, position, text_color, text.c_str(), text.c_str() + text.size()); -} - -void gui::imdraw_ext::text_shadow_w(const std::string& text, const ImVec2& position, ImU32 text_color, ImU32 shadow_color, ImFont* font, - ImDrawList* draw_list, float wrap_width) -{ - imdraw_ext::text_shadow_w(text, position, text_color, shadow_color, font, draw_list, font->LegacySize, wrap_width); -} - -void gui::imdraw_ext::text_shadow_w(const std::string& text, const ImVec2& position, ImU32 text_color, ImU32 shadow_color, ImFont* font, - ImDrawList* draw_list, float font_size, float wrap_width) -{ - const auto shadow_position = ImVec2(position.x + 0.5f * globals::gui_scale, position.y + 0.5f * globals::gui_scale); - draw_list->AddText(font, globals::gui_scale * font_size, shadow_position, shadow_color, text.c_str(), text.c_str() + text.size(), - wrap_width); - draw_list->AddText(font, globals::gui_scale * font_size, position, text_color, text.c_str(), text.c_str() + text.size(), wrap_width); -} diff --git a/game/client/gui/imdraw_ext.hh b/game/client/gui/imdraw_ext.hh deleted file mode 100644 index e1475b2..0000000 --- a/game/client/gui/imdraw_ext.hh +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -namespace gui::imdraw_ext -{ -void text_shadow(const std::string& text, const ImVec2& position, ImU32 text_color, ImU32 shadow_color, ImFont* font, - ImDrawList* draw_list); -void text_shadow(const std::string& text, const ImVec2& position, ImU32 text_color, ImU32 shadow_color, ImFont* font, ImDrawList* draw_list, - float font_size); -} // namespace gui::imdraw_ext - -namespace gui::imdraw_ext -{ -void text_shadow_w(const std::string& text, const ImVec2& position, ImU32 text_color, ImU32 shadow_color, ImFont* font, - ImDrawList* draw_list, float wrap_width); -void text_shadow_w(const std::string& text, const ImVec2& position, ImU32 text_color, ImU32 shadow_color, ImFont* font, - ImDrawList* draw_list, float font_size, float wrap_width); -} // namespace gui::imdraw_ext diff --git a/game/client/gui/language.cc b/game/client/gui/language.cc deleted file mode 100644 index d10f88b..0000000 --- a/game/client/gui/language.cc +++ /dev/null @@ -1,202 +0,0 @@ -#include "client/pch.hh" - -#include "client/gui/language.hh" - -#include "core/config/string.hh" - -#include "core/io/config_map.hh" -#include "core/io/physfs.hh" - -#include "client/gui/settings.hh" - -#include "client/globals.hh" - -constexpr static std::string_view DEFAULT_LANGUAGE = "en_US"; - -// Available languages are kept in a special manifest file which -// is essentially a key-value map of semi-IETF-compliant language tags -// and the language's endonym; after reading the manifest, the translation -// system knows what language it can load and will act accordingly -constexpr static std::string_view MANIFEST_PATH = "lang/manifest.json"; - -static gui::LanguageManifest manifest; -static gui::LanguageIterator current_language; -static std::unordered_map language_map; -static std::unordered_map ietf_map; -static config::String config_language(DEFAULT_LANGUAGE); - -static void send_language_event(gui::LanguageIterator new_language) -{ - gui::LanguageSetEvent event; - event.new_language = new_language; - globals::dispatcher.trigger(event); -} - -void gui::language::init(void) -{ - globals::client_config.add_value("language", config_language); - - settings::add_language_select(0, settings_location::GENERAL, "language"); - - auto file = PHYSFS_openRead(std::string(MANIFEST_PATH).c_str()); - - if(file == nullptr) { - spdlog::critical("language: {}: {}", MANIFEST_PATH, io::physfs_error()); - std::terminate(); - } - - auto source = std::string(PHYSFS_fileLength(file), char(0x00)); - PHYSFS_readBytes(file, source.data(), source.size()); - PHYSFS_close(file); - - auto jsonv = json_parse_string(source.c_str()); - const auto json = json_value_get_object(jsonv); - const auto count = json_object_get_count(json); - - if((jsonv == nullptr) || (json == nullptr) || (count == 0)) { - spdlog::critical("language: {}: parse error", MANIFEST_PATH); - json_value_free(jsonv); - std::terminate(); - } - - for(std::size_t i = 0; i < count; ++i) { - const auto ietf = json_object_get_name(json, i); - const auto value = json_object_get_value_at(json, i); - const auto endonym = json_value_get_string(value); - - if(ietf && endonym) { - LanguageInfo info; - info.ietf = std::string(ietf); - info.endonym = std::string(endonym); - info.display = std::format("{} ({})", endonym, ietf); - manifest.push_back(info); - } - } - - for(auto it = manifest.cbegin(); it != manifest.cend(); ++it) { - ietf_map.emplace(it->ietf, it); - } - - json_value_free(jsonv); - - // This is temporary! This value will - // be overriden in init_late after the - // config system updates config_language - current_language = manifest.cend(); -} - -void gui::language::init_late(void) -{ - auto user_language = ietf_map.find(config_language.get_value()); - - if(user_language != ietf_map.cend()) { - gui::language::set(user_language->second); - return; - } - - auto fallback = ietf_map.find(std::string(DEFAULT_LANGUAGE)); - - if(fallback != ietf_map.cend()) { - gui::language::set(fallback->second); - return; - } - - spdlog::critical("language: we're doomed!"); - spdlog::critical("language: {} doesn't exist!", DEFAULT_LANGUAGE); - std::terminate(); -} - -void gui::language::set(LanguageIterator new_language) -{ - if(new_language != manifest.cend()) { - auto path = std::format("lang/lang.{}.json", new_language->ietf); - - auto file = PHYSFS_openRead(path.c_str()); - - if(file == nullptr) { - spdlog::warn("language: {}: {}", path, io::physfs_error()); - send_language_event(new_language); - return; - } - - auto source = std::string(PHYSFS_fileLength(file), char(0x00)); - PHYSFS_readBytes(file, source.data(), source.size()); - PHYSFS_close(file); - - auto jsonv = json_parse_string(source.c_str()); - const auto json = json_value_get_object(jsonv); - const auto count = json_object_get_count(json); - - if((jsonv == nullptr) || (json == nullptr) || (count == 0)) { - spdlog::warn("language: {}: parse error", path); - send_language_event(new_language); - json_value_free(jsonv); - return; - } - - language_map.clear(); - - for(size_t i = 0; i < count; ++i) { - const auto key = json_object_get_name(json, i); - const auto value = json_object_get_value_at(json, i); - const auto value_str = json_value_get_string(value); - - if(key && value_str) { - language_map.emplace(key, value_str); - continue; - } - } - - json_value_free(jsonv); - - current_language = new_language; - config_language.set(new_language->ietf.c_str()); - } - - send_language_event(new_language); -} - -gui::LanguageIterator gui::language::get_current(void) -{ - return current_language; -} - -gui::LanguageIterator gui::language::find(std::string_view ietf) -{ - const auto it = ietf_map.find(std::string(ietf)); - if(it != ietf_map.cend()) { - return it->second; - } - else { - return manifest.cend(); - } -} - -gui::LanguageIterator gui::language::cbegin(void) -{ - return manifest.cbegin(); -} - -gui::LanguageIterator gui::language::cend(void) -{ - return manifest.cend(); -} - -std::string_view gui::language::resolve(std::string_view key) -{ - const auto it = language_map.find(std::string(key)); - - if(it != language_map.cend()) { - return it->second; - } - - return key; -} - -std::string gui::language::resolve_gui(std::string_view key) -{ - // We need window tags to retain their hierarchy when a language - // dynamically changes; ImGui allows to provide hidden unique identifiers - // to GUI primitives that have their name change dynamically, so we're using this - return std::format("{}###{}", gui::language::resolve(key), key); -} diff --git a/game/client/gui/language.hh b/game/client/gui/language.hh deleted file mode 100644 index 0628941..0000000 --- a/game/client/gui/language.hh +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -namespace gui -{ -struct LanguageInfo final { - std::string endonym; // Language's self-name - std::string display; // Display for the settings GUI - std::string ietf; // Semi-compliant language abbreviation -}; - -using LanguageManifest = std::vector; -using LanguageIterator = LanguageManifest::const_iterator; - -struct LanguageSetEvent final { - LanguageIterator new_language; -}; -} // namespace gui - -namespace gui::language -{ -void init(void); -void init_late(void); -} // namespace gui::language - -namespace gui::language -{ -void set(LanguageIterator new_language); -} // namespace gui::language - -namespace gui::language -{ -LanguageIterator get_current(void); -LanguageIterator find(std::string_view ietf); -LanguageIterator cbegin(void); -LanguageIterator cend(void); -} // namespace gui::language - -namespace gui::language -{ -std::string_view resolve(std::string_view key); -std::string resolve_gui(std::string_view key); -} // namespace gui::language diff --git a/game/client/gui/main_menu.cc b/game/client/gui/main_menu.cc deleted file mode 100644 index 6c0ee37..0000000 --- a/game/client/gui/main_menu.cc +++ /dev/null @@ -1,172 +0,0 @@ -#include "client/pch.hh" - -#include "client/gui/main_menu.hh" - -#include "core/math/constexpr.hh" - -#include "core/resource/resource.hh" - -#include "core/version.hh" - -#include "client/gui/gui_screen.hh" -#include "client/gui/language.hh" -#include "client/gui/window_title.hh" - -#include "client/io/glfw.hh" - -#include "client/resource/texture_gui.hh" - -#include "client/globals.hh" -#include "client/session.hh" - -constexpr static ImGuiWindowFlags WINDOW_FLAGS = ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDecoration; - -static std::string str_play; -static std::string str_resume; -static std::string str_settings; -static std::string str_leave; -static std::string str_quit; - -static resource_ptr title; -static float title_aspect; - -static void on_glfw_key(const io::GlfwKeyEvent& event) -{ - if(session::is_ingame() && (event.key == GLFW_KEY_ESCAPE) && (event.action == GLFW_PRESS)) { - if(globals::gui_screen == GUI_SCREEN_NONE) { - globals::gui_screen = GUI_MAIN_MENU; - return; - } - - if(globals::gui_screen == GUI_MAIN_MENU) { - globals::gui_screen = GUI_SCREEN_NONE; - return; - } - } -} - -static void on_language_set(const gui::LanguageSetEvent& event) -{ - str_play = gui::language::resolve_gui("main_menu.play"); - str_resume = gui::language::resolve_gui("main_menu.resume"); - str_settings = gui::language::resolve("main_menu.settings"); - str_leave = gui::language::resolve("main_menu.leave"); - str_quit = gui::language::resolve("main_menu.quit"); -} - -void gui::main_menu::init(void) -{ - title = resource::load("textures/gui/menu_title.png", TEXTURE_GUI_LOAD_CLAMP_S | TEXTURE_GUI_LOAD_CLAMP_T); - - if(title == nullptr) { - spdlog::critical("main_menu: texture load failed"); - std::terminate(); - } - - if(title->size.x > title->size.y) { - title_aspect = static_cast(title->size.x) / static_cast(title->size.y); - } - else { - title_aspect = static_cast(title->size.y) / static_cast(title->size.x); - } - - globals::dispatcher.sink().connect<&on_glfw_key>(); - globals::dispatcher.sink().connect<&on_language_set>(); -} - -void gui::main_menu::shutdown(void) -{ - title = nullptr; -} - -void gui::main_menu::layout(void) -{ - const auto viewport = ImGui::GetMainViewport(); - const auto window_start = ImVec2(0.0f, viewport->Size.y * 0.15f); - const auto window_size = ImVec2(viewport->Size.x, viewport->Size.y); - - ImGui::SetNextWindowPos(window_start); - ImGui::SetNextWindowSize(window_size); - - if(ImGui::Begin("###main_menu", nullptr, WINDOW_FLAGS)) { - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 2.0f * globals::gui_scale)); - - if(session::is_ingame()) { - ImGui::Dummy(ImVec2(0.0f, 32.0f * globals::gui_scale)); - } - else { - auto reference_height = 0.225f * window_size.y; - auto image_width = glm::min(window_size.x, reference_height * title_aspect); - auto image_height = image_width / title_aspect; - ImGui::SetCursorPosX(0.5f * (window_size.x - image_width)); - ImGui::Image(title->handle, ImVec2(image_width, image_height)); - } - - ImGui::Dummy(ImVec2(0.0f, 24.0f * globals::gui_scale)); - - const float button_width = 240.0f * globals::gui_scale; - const float button_xpos = 0.5f * (window_size.x - button_width); - - if(session::is_ingame()) { - ImGui::SetCursorPosX(button_xpos); - - if(ImGui::Button(str_resume.c_str(), ImVec2(button_width, 0.0f))) { - globals::gui_screen = GUI_SCREEN_NONE; - } - - ImGui::Spacing(); - } - else { - ImGui::SetCursorPosX(button_xpos); - - if(ImGui::Button(str_play.c_str(), ImVec2(button_width, 0.0f))) { - globals::gui_screen = GUI_PLAY_MENU; - } - - ImGui::Spacing(); - } - - ImGui::SetCursorPosX(button_xpos); - - if(ImGui::Button(str_settings.c_str(), ImVec2(button_width, 0.0f))) { - globals::gui_screen = GUI_SETTINGS; - } - - ImGui::Spacing(); - - if(session::is_ingame()) { - ImGui::SetCursorPosX(button_xpos); - - if(ImGui::Button(str_leave.c_str(), ImVec2(button_width, 0.0f))) { - session::disconnect("protocol.client_disconnect"); - globals::gui_screen = GUI_PLAY_MENU; - gui::window_title::update(); - } - - ImGui::Spacing(); - } - else { - ImGui::SetCursorPosX(button_xpos); - - if(ImGui::Button(str_quit.c_str(), ImVec2(button_width, 0.0f))) { - glfwSetWindowShouldClose(globals::window, true); - } - - ImGui::Spacing(); - } - - if(!session::is_ingame()) { - const auto& padding = ImGui::GetStyle().FramePadding; - const auto& spacing = ImGui::GetStyle().ItemSpacing; - - ImGui::PushFont(globals::font_unscii8, 4.0f); - ImGui::SetCursorScreenPos(ImVec2(padding.x + spacing.x, window_size.y - ImGui::GetFontSize() - padding.y - spacing.y)); - ImGui::Text("Voxelius %*s", version::semver.size(), version::semver.data()); // string_view is not always null-terminated - ImGui::PopFont(); - } - - ImGui::PopStyleVar(); - } - - ImGui::End(); -} diff --git a/game/client/gui/main_menu.hh b/game/client/gui/main_menu.hh deleted file mode 100644 index 8e30e38..0000000 --- a/game/client/gui/main_menu.hh +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -namespace gui::main_menu -{ -void init(void); -void shutdown(void); -void layout(void); -} // namespace gui::main_menu diff --git a/game/client/gui/message_box.cc b/game/client/gui/message_box.cc deleted file mode 100644 index b7f109a..0000000 --- a/game/client/gui/message_box.cc +++ /dev/null @@ -1,95 +0,0 @@ -#include "client/pch.hh" - -#include "client/gui/message_box.hh" - -#include "client/gui/gui_screen.hh" -#include "client/gui/language.hh" - -#include "client/globals.hh" - -constexpr static ImGuiWindowFlags WINDOW_FLAGS = ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDecoration; - -struct Button final { - gui::message_box_action action; - std::string str_title; -}; - -static std::string str_title; -static std::string str_subtitle; -static std::vector