diff options
| author | untodesu <kirill@untode.su> | 2025-06-29 22:24:42 +0500 |
|---|---|---|
| committer | untodesu <kirill@untode.su> | 2025-06-29 22:24:42 +0500 |
| commit | 6cd00aacfa22fed6a54a9b812f6b069ad16feec0 (patch) | |
| tree | b77f4e665da3dd235cdb01e7e6ea78c1c02ecf2e /game/client | |
| parent | f440914e1ae453768d09383f332bc7844e0a700e (diff) | |
| download | voxelius-6cd00aacfa22fed6a54a9b812f6b069ad16feec0.tar.bz2 voxelius-6cd00aacfa22fed6a54a9b812f6b069ad16feec0.zip | |
Move game sources into src subdirectory
Diffstat (limited to 'game/client')
108 files changed, 0 insertions, 10083 deletions
diff --git a/game/client/CMakeLists.txt b/game/client/CMakeLists.txt deleted file mode 100644 index 15d2692..0000000 --- a/game/client/CMakeLists.txt +++ /dev/null @@ -1,126 +0,0 @@ -add_executable(vclient - "${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}/camera.cc" - "${CMAKE_CURRENT_LIST_DIR}/camera.hh" - "${CMAKE_CURRENT_LIST_DIR}/chat.cc" - "${CMAKE_CURRENT_LIST_DIR}/chat.hh" - "${CMAKE_CURRENT_LIST_DIR}/chunk_mesher.cc" - "${CMAKE_CURRENT_LIST_DIR}/chunk_mesher.hh" - "${CMAKE_CURRENT_LIST_DIR}/chunk_quad.hh" - "${CMAKE_CURRENT_LIST_DIR}/chunk_renderer.cc" - "${CMAKE_CURRENT_LIST_DIR}/chunk_renderer.hh" - "${CMAKE_CURRENT_LIST_DIR}/chunk_vbo.hh" - "${CMAKE_CURRENT_LIST_DIR}/chunk_visibility.cc" - "${CMAKE_CURRENT_LIST_DIR}/chunk_visibility.hh" - "${CMAKE_CURRENT_LIST_DIR}/const.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}/experiments.cc" - "${CMAKE_CURRENT_LIST_DIR}/experiments.hh" - "${CMAKE_CURRENT_LIST_DIR}/factory.cc" - "${CMAKE_CURRENT_LIST_DIR}/factory.hh" - "${CMAKE_CURRENT_LIST_DIR}/game.cc" - "${CMAKE_CURRENT_LIST_DIR}/game.hh" - "${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}/gamepad.cc" - "${CMAKE_CURRENT_LIST_DIR}/gamepad.hh" - "${CMAKE_CURRENT_LIST_DIR}/glfw.hh" - "${CMAKE_CURRENT_LIST_DIR}/globals.cc" - "${CMAKE_CURRENT_LIST_DIR}/globals.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}/interpolation.cc" - "${CMAKE_CURRENT_LIST_DIR}/interpolation.hh" - "${CMAKE_CURRENT_LIST_DIR}/keybind.cc" - "${CMAKE_CURRENT_LIST_DIR}/keybind.hh" - "${CMAKE_CURRENT_LIST_DIR}/language.cc" - "${CMAKE_CURRENT_LIST_DIR}/language.hh" - "${CMAKE_CURRENT_LIST_DIR}/listener.cc" - "${CMAKE_CURRENT_LIST_DIR}/listener.hh" - "${CMAKE_CURRENT_LIST_DIR}/main_menu.cc" - "${CMAKE_CURRENT_LIST_DIR}/main_menu.hh" - "${CMAKE_CURRENT_LIST_DIR}/main.cc" - "${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}/outline.cc" - "${CMAKE_CURRENT_LIST_DIR}/outline.hh" - "${CMAKE_CURRENT_LIST_DIR}/pch.hh" - "${CMAKE_CURRENT_LIST_DIR}/play_menu.cc" - "${CMAKE_CURRENT_LIST_DIR}/play_menu.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}/player_target.cc" - "${CMAKE_CURRENT_LIST_DIR}/player_target.hh" - "${CMAKE_CURRENT_LIST_DIR}/program.cc" - "${CMAKE_CURRENT_LIST_DIR}/program.hh" - "${CMAKE_CURRENT_LIST_DIR}/progress_bar.cc" - "${CMAKE_CURRENT_LIST_DIR}/progress_bar.hh" - "${CMAKE_CURRENT_LIST_DIR}/receive.cc" - "${CMAKE_CURRENT_LIST_DIR}/receive.hh" - "${CMAKE_CURRENT_LIST_DIR}/scoreboard.cc" - "${CMAKE_CURRENT_LIST_DIR}/scoreboard.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}/settings.cc" - "${CMAKE_CURRENT_LIST_DIR}/settings.hh" - "${CMAKE_CURRENT_LIST_DIR}/skybox.cc" - "${CMAKE_CURRENT_LIST_DIR}/skybox.hh" - "${CMAKE_CURRENT_LIST_DIR}/sound_effect.cc" - "${CMAKE_CURRENT_LIST_DIR}/sound_effect.hh" - "${CMAKE_CURRENT_LIST_DIR}/sound_emitter.cc" - "${CMAKE_CURRENT_LIST_DIR}/sound_emitter.hh" - "${CMAKE_CURRENT_LIST_DIR}/sound.cc" - "${CMAKE_CURRENT_LIST_DIR}/sound.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}/texture_gui.cc" - "${CMAKE_CURRENT_LIST_DIR}/texture_gui.hh" - "${CMAKE_CURRENT_LIST_DIR}/toggles.cc" - "${CMAKE_CURRENT_LIST_DIR}/toggles.hh" - "${CMAKE_CURRENT_LIST_DIR}/voxel_anims.cc" - "${CMAKE_CURRENT_LIST_DIR}/voxel_anims.hh" - "${CMAKE_CURRENT_LIST_DIR}/voxel_atlas.cc" - "${CMAKE_CURRENT_LIST_DIR}/voxel_atlas.hh" - "${CMAKE_CURRENT_LIST_DIR}/voxel_sounds.cc" - "${CMAKE_CURRENT_LIST_DIR}/voxel_sounds.hh" - "${CMAKE_CURRENT_LIST_DIR}/window_title.cc" - "${CMAKE_CURRENT_LIST_DIR}/window_title.hh") -target_compile_features(vclient PUBLIC cxx_std_20) -target_compile_definitions(vclient PUBLIC GLFW_INCLUDE_NONE) -target_include_directories(vclient PUBLIC "${DEPS_INCLUDE_DIR}") -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 glfw3 imgui imgui_glfw imgui_opengl3 salad) - -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/background.cc b/game/client/background.cc deleted file mode 100644 index 415b63c..0000000 --- a/game/client/background.cc +++ /dev/null @@ -1,37 +0,0 @@ -#include "client/pch.hh" - -#include "client/background.hh" - -#include "core/constexpr.hh" -#include "core/resource.hh" - -#include "client/globals.hh" -#include "client/texture_gui.hh" - -static resource_ptr<TextureGUI> texture; - -void background::init(void) -{ - texture = resource::load<TextureGUI>("textures/gui/background.png", TEXTURE_GUI_LOAD_VFLIP); - - if(texture == nullptr) { - spdlog::critical("background: texture load failed"); - std::terminate(); - } -} - -void background::deinit(void) -{ - texture = nullptr; -} - -void background::layout(void) -{ - auto viewport = ImGui::GetMainViewport(); - auto draw_list = ImGui::GetBackgroundDrawList(); - - auto scaled_width = 0.75f * static_cast<float>(globals::width / globals::gui_scale); - auto scaled_height = 0.75f * static_cast<float>(globals::height / globals::gui_scale); - auto scale_uv = ImVec2(scaled_width / static_cast<float>(texture->size.x), scaled_height / static_cast<float>(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/background.hh b/game/client/background.hh deleted file mode 100644 index 634caf5..0000000 --- a/game/client/background.hh +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef CLIENT_BACKGROUND_HH -#define CLIENT_BACKGROUND_HH 1 -#pragma once - -namespace background -{ -void init(void); -void deinit(void); -void layout(void); -} // namespace background - -#endif /* CLIENT_BACKGROUND_HH */ diff --git a/game/client/bother.cc b/game/client/bother.cc deleted file mode 100644 index 8bd7182..0000000 --- a/game/client/bother.cc +++ /dev/null @@ -1,163 +0,0 @@ -#include "client/pch.hh" - -#include "client/bother.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<unsigned int> bother_set; -static std::deque<BotherQueueItem> bother_queue; - -static void on_status_response_packet(const protocol::StatusResponse& packet) -{ - auto identity = static_cast<unsigned int>(reinterpret_cast<std::uintptr_t>(packet.peer->data)); - - bother_set.erase(identity); - - BotherResponseEvent event; - event.identity = identity; - event.is_server_unreachable = false; - event.protocol_version = packet.version; - event.num_players = packet.num_players; - event.max_players = packet.max_players; - event.motd = packet.motd; - globals::dispatcher.trigger(event); - - enet_peer_disconnect(packet.peer, protocol::CHANNEL); -} - -void bother::init(void) -{ - bother_host = enet_host_create(nullptr, BOTHER_PEERS, 1, 0, 0); - bother_dispatcher.clear(); - bother_set.clear(); - - bother_dispatcher.sink<protocol::StatusResponse>().connect<&on_status_response_packet>(); -} - -void bother::deinit(void) -{ - enet_host_destroy(bother_host); - bother_dispatcher.clear(); - bother_set.clear(); -} - -void 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<void*>(static_cast<std::uintptr_t>(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.version = protocol::VERSION; - 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<unsigned int>(reinterpret_cast<std::uintptr_t>(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 bother::ping(unsigned int identity, const char* 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 = std::string(host); - item.port = port; - - bother_queue.push_back(item); -} - -void 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<void*>(static_cast<std::uintptr_t>(identity))) { - enet_peer_reset(&bother_host->peers[i]); - break; - } - } -} diff --git a/game/client/bother.hh b/game/client/bother.hh deleted file mode 100644 index 5fbf247..0000000 --- a/game/client/bother.hh +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef CLIENT_BOTHER_HH -#define CLIENT_BOTHER_HH 1 -#pragma once - -struct BotherResponseEvent final { - unsigned int identity; - bool is_server_unreachable; - std::uint32_t protocol_version; - std::uint16_t num_players; - std::uint16_t max_players; - std::string motd; -}; - -namespace bother -{ -void init(void); -void deinit(void); -void update_late(void); -void ping(unsigned int identity, const char* host, std::uint16_t port); -void cancel(unsigned int identity); -} // namespace bother - -#endif /* CLIENT_BOTHER_HH */ diff --git a/game/client/camera.cc b/game/client/camera.cc deleted file mode 100644 index 724ae66..0000000 --- a/game/client/camera.cc +++ /dev/null @@ -1,107 +0,0 @@ -#include "client/pch.hh" - -#include "client/camera.hh" - -#include "core/angles.hh" -#include "core/config.hh" - -#include "shared/dimension.hh" -#include "shared/head.hh" -#include "shared/transform.hh" -#include "shared/velocity.hh" - -#include "client/const.hh" -#include "client/globals.hh" -#include "client/player_move.hh" -#include "client/session.hh" -#include "client/settings.hh" -#include "client/toggles.hh" - -ConfigFloat camera::roll_angle(2.0f, 0.0f, 4.0f); -ConfigFloat camera::vertical_fov(90.0f, 45.0f, 110.0f); -ConfigUnsigned camera::view_distance(16U, 4U, 32U); - -glm::fvec3 camera::angles; -glm::fvec3 camera::direction; -glm::fmat4x4 camera::matrix; -chunk_pos camera::position_chunk; -glm::fvec3 camera::position_local; - -static void reset_camera(void) -{ - camera::angles = glm::fvec3(0.0f, 0.0f, 0.0f); - camera::direction = DIR_FORWARD<float>; - camera::matrix = glm::identity<glm::fmat4x4>(); - camera::position_chunk = chunk_pos(0, 0, 0); - 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; - cxangles::vectors(angles, &forward, nullptr, &up); - - auto result = glm::identity<glm::fmat4x4>(); - 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 camera::init(void) -{ - globals::client_config.add_value("camera.roll_angle", camera::roll_angle); - globals::client_config.add_value("camera.vertical_fov", camera::vertical_fov); - globals::client_config.add_value("camera.view_distance", camera::view_distance); - - settings::add_slider(1, camera::vertical_fov, settings_location::GENERAL, "camera.vertical_fov", true, "%.0f"); - settings::add_slider(0, camera::view_distance, settings_location::VIDEO, "camera.view_distance", false); - settings::add_slider(10, camera::roll_angle, settings_location::VIDEO, "camera.roll_angle", true, "%.01f"); - - reset_camera(); -} - -void camera::update(void) -{ - if(!session::is_ingame()) { - reset_camera(); - return; - } - - const auto& head = globals::dimension->entities.get<HeadComponentIntr>(globals::player); - const auto& transform = globals::dimension->entities.get<TransformComponentIntr>(globals::player); - const auto& velocity = globals::dimension->entities.get<VelocityComponent>(globals::player); - - camera::angles = transform.angles + head.angles; - camera::position_chunk = transform.chunk; - camera::position_local = transform.local + head.offset; - - glm::fvec3 right_vector, up_vector; - cxangles::vectors(camera::angles, &camera::direction, &right_vector, &up_vector); - - auto client_angles = camera::angles; - - if(!toggles::get(TOGGLE_PM_FLIGHT)) { - // Apply the quake-like view rolling - client_angles[2] = vx::radians(-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<float>(CHUNK_SIZE * camera::view_distance.get_value()); - - auto proj = glm::perspective(vx::radians(camera::vertical_fov.get_value()), globals::aspect, z_near, z_far); - auto view = platinumsrc_viewmatrix(camera::position_local, client_angles); - - camera::matrix = proj * view; -} diff --git a/game/client/camera.hh b/game/client/camera.hh deleted file mode 100644 index 9718720..0000000 --- a/game/client/camera.hh +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef CLIENT_CAMERA_HH -#define CLIENT_CAMERA_HH 1 -#pragma once - -#include "shared/types.hh" - -class ConfigFloat; -class ConfigUnsigned; - -namespace camera -{ -extern ConfigFloat roll_angle; -extern ConfigFloat vertical_fov; -extern ConfigUnsigned view_distance; -} // namespace camera - -namespace camera -{ -extern glm::fvec3 angles; -extern glm::fvec3 direction; -extern glm::fmat4x4 matrix; -extern chunk_pos position_chunk; -extern glm::fvec3 position_local; -} // namespace camera - -namespace camera -{ -void init(void); -void update(void); -} // namespace camera - -#endif /* CLIENT_CAMERA_HH */ diff --git a/game/client/chat.cc b/game/client/chat.cc deleted file mode 100644 index 0a0c75d..0000000 --- a/game/client/chat.cc +++ /dev/null @@ -1,260 +0,0 @@ -#include "client/pch.hh" - -#include "client/chat.hh" - -#include "core/config.hh" -#include "core/resource.hh" -#include "core/strtools.hh" - -#include "shared/protocol.hh" - -#include "client/game.hh" -#include "client/glfw.hh" -#include "client/globals.hh" -#include "client/gui_screen.hh" -#include "client/keybind.hh" -#include "client/language.hh" -#include "client/session.hh" -#include "client/settings.hh" -#include "client/sound.hh" -#include "client/sound_effect.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 ConfigKeyBind key_chat(GLFW_KEY_ENTER); -static ConfigUnsigned history_size(32U, 0U, MAX_HISTORY_SIZE); - -static std::deque<GuiChatMessage> history; -static std::string chat_input; -static bool needs_focus; - -static resource_ptr<SoundEffect> 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, 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, language::resolve("chat.client_left"), 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 GlfwKeyEvent& event) -{ - if(event.action == GLFW_PRESS) { - if((event.key == GLFW_KEY_ENTER) && (globals::gui_screen == GUI_CHAT)) { - if(!strtools::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 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<protocol::ChatMessage>().connect<&on_chat_message_packet>(); - globals::dispatcher.sink<GlfwKeyEvent>().connect<&on_glfw_key>(); - - sfx_chat_message = resource::load<SoundEffect>("sounds/ui/chat_message.wav"); -} - -void client_chat::init_late(void) -{ -} - -void client_chat::deinit(void) -{ - sfx_chat_message = nullptr; -} - -void client_chat::update(void) -{ - while(history.size() > history_size.get_value()) { - history.pop_front(); - } -} - -void 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_chat); - - 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 * font->FontSize - 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<float>(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)); - - draw_list->AddRectFilled(rect_pos, rect_end, rect_col); - draw_list->AddText( - font, font->FontSize, text_pos, text_col, it->text.c_str(), it->text.c_str() + it->text.size(), window_size.x); - - ypos -= rect_size.y; - } - } - - ImGui::End(); - ImGui::PopFont(); -} - -void client_chat::clear(void) -{ - history.clear(); -} - -void 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 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/chat.hh b/game/client/chat.hh deleted file mode 100644 index f2ee4de..0000000 --- a/game/client/chat.hh +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef CLIENT_CHAT_HH -#define CLIENT_CHAT_HH 1 -#pragma once - -namespace client_chat -{ -void init(void); -void init_late(void); -void deinit(void); -void update(void); -void layout(void); -} // namespace client_chat - -namespace client_chat -{ -void clear(void); -void refresh_timings(void); -void print(const std::string& string); -} // namespace client_chat - -#endif /* CLIENT_CHAT_HH */ diff --git a/game/client/chunk_mesher.cc b/game/client/chunk_mesher.cc deleted file mode 100644 index 0271931..0000000 --- a/game/client/chunk_mesher.cc +++ /dev/null @@ -1,467 +0,0 @@ -#include "client/pch.hh" - -#include "client/chunk_mesher.hh" - -#include "core/crc64.hh" - -#include "shared/chunk.hh" -#include "shared/coord.hh" -#include "shared/dimension.hh" -#include "shared/threading.hh" -#include "shared/voxel_registry.hh" - -#include "client/chunk_quad.hh" -#include "client/globals.hh" -#include "client/session.hh" -#include "client/voxel_atlas.hh" - -using QuadBuilder = std::vector<ChunkQuad>; - -using CachedChunkCoord = unsigned short; -constexpr static CachedChunkCoord CPOS_ITSELF = 0x0000; -constexpr static CachedChunkCoord CPOS_NORTH = 0x0001; -constexpr static CachedChunkCoord CPOS_SOUTH = 0x0002; -constexpr static CachedChunkCoord CPOS_EAST = 0x0003; -constexpr static CachedChunkCoord CPOS_WEST = 0x0004; -constexpr static CachedChunkCoord CPOS_TOP = 0x0005; -constexpr static CachedChunkCoord CPOS_BOTTOM = 0x0006; -constexpr static const size_t NUM_CACHED_CPOS = 7; - -static const CachedChunkCoord get_cached_cpos(const chunk_pos& pivot, const chunk_pos& cpos) -{ - static const CachedChunkCoord nx[3] = { CPOS_WEST, 0, CPOS_EAST }; - static const CachedChunkCoord ny[3] = { CPOS_BOTTOM, 0, CPOS_TOP }; - static const CachedChunkCoord nz[3] = { CPOS_NORTH, 0, CPOS_SOUTH }; - - if(pivot != cpos) { - chunk_pos delta = pivot - cpos; - delta[0] = vx::clamp<std::int64_t>(delta[0], -1, 1); - delta[1] = vx::clamp<std::int64_t>(delta[1], -1, 1); - delta[2] = vx::clamp<std::int64_t>(delta[2], -1, 1); - - if(delta[0]) { - return nx[delta[0] + 1]; - } else if(delta[1]) { - return ny[delta[1] + 1]; - } else { - return nz[delta[2] + 1]; - } - } - - return CPOS_ITSELF; -} - -static voxel_facing get_facing(voxel_face face, voxel_type type) -{ - if(type == voxel_type::CROSS) { - switch(face) { - case voxel_face::CROSS_NESW: - return voxel_facing::NESW; - case voxel_face::CROSS_NWSE: - return voxel_facing::NWSE; - default: - return voxel_facing::NORTH; - } - } - - switch(face) { - case voxel_face::CUBE_NORTH: - return voxel_facing::NORTH; - case voxel_face::CUBE_SOUTH: - return voxel_facing::SOUTH; - case voxel_face::CUBE_EAST: - return voxel_facing::EAST; - case voxel_face::CUBE_WEST: - return voxel_facing::WEST; - case voxel_face::CUBE_TOP: - return voxel_facing::UP; - case voxel_face::CUBE_BOTTOM: - return voxel_facing::DOWN; - default: - return voxel_facing::NORTH; - } -} - -class GL_MeshingTask final : public Task { -public: - explicit GL_MeshingTask(entt::entity entity, const chunk_pos& cpos); - virtual ~GL_MeshingTask(void) = default; - virtual void process(void) override; - virtual void finalize(void) override; - -private: - bool vis_test(voxel_id voxel, const VoxelInfo* info, const local_pos& lpos) const; - void push_quad_a(const VoxelInfo* info, const glm::fvec3& pos, const glm::fvec2& size, voxel_face face); - void push_quad_v(const VoxelInfo* info, const glm::fvec3& pos, const glm::fvec2& size, voxel_face face, std::size_t entropy); - void make_cube(voxel_id voxel, const VoxelInfo* info, const local_pos& lpos, voxel_vis vis, std::size_t entropy); - void cache_chunk(const chunk_pos& cpos); - -private: - std::array<VoxelStorage, NUM_CACHED_CPOS> m_cache; - std::vector<QuadBuilder> m_quads_b; // blending - std::vector<QuadBuilder> m_quads_s; // solid - entt::entity m_entity; - chunk_pos m_cpos; -}; - -GL_MeshingTask::GL_MeshingTask(entt::entity entity, const chunk_pos& cpos) -{ - m_entity = entity; - m_cpos = cpos; - - cache_chunk(m_cpos); - cache_chunk(m_cpos + DIR_NORTH<chunk_pos::value_type>); - cache_chunk(m_cpos + DIR_SOUTH<chunk_pos::value_type>); - cache_chunk(m_cpos + DIR_EAST<chunk_pos::value_type>); - cache_chunk(m_cpos + DIR_WEST<chunk_pos::value_type>); - cache_chunk(m_cpos + DIR_DOWN<chunk_pos::value_type>); - cache_chunk(m_cpos + DIR_UP<chunk_pos::value_type>); -} - -void GL_MeshingTask::process(void) -{ - m_quads_b.resize(voxel_atlas::plane_count()); - m_quads_s.resize(voxel_atlas::plane_count()); - - const auto& voxels = m_cache.at(CPOS_ITSELF); - - for(std::size_t i = 0; i < CHUNK_VOLUME; ++i) { - if(m_status == task_status::CANCELLED) { - m_quads_b.clear(); - m_quads_s.clear(); - return; - } - - const auto voxel = voxels[i]; - const auto lpos = coord::to_local(i); - - const auto info = voxel_registry::find(voxel); - - if(info == nullptr) { - // Either a NULL_VOXEL_ID or something went - // horribly wrong and we don't what this is - continue; - } - - voxel_vis vis = 0; - - if(vis_test(voxel, info, lpos + DIR_NORTH<local_pos::value_type>)) { - vis |= VIS_NORTH; - } - - if(vis_test(voxel, info, lpos + DIR_SOUTH<local_pos::value_type>)) { - vis |= VIS_SOUTH; - } - - if(vis_test(voxel, info, lpos + DIR_EAST<local_pos::value_type>)) { - vis |= VIS_EAST; - } - - if(vis_test(voxel, info, lpos + DIR_WEST<local_pos::value_type>)) { - vis |= VIS_WEST; - } - - if(vis_test(voxel, info, lpos + DIR_UP<local_pos::value_type>)) { - vis |= VIS_UP; - } - - if(vis_test(voxel, info, lpos + DIR_DOWN<local_pos::value_type>)) { - vis |= VIS_DOWN; - } - - const auto vpos = coord::to_voxel(m_cpos, lpos); - const auto entropy_src = vpos[0] * vpos[1] * vpos[2]; - const auto entropy = crc64::get(&entropy_src, sizeof(entropy_src)); - - // FIXME: handle different voxel types - make_cube(voxel, info, lpos, vis, entropy); - } -} - -void GL_MeshingTask::finalize(void) -{ - if(!globals::dimension || !globals::dimension->chunks.valid(m_entity)) { - // We either disconnected or something - // else happened that invalidated the entity - return; - } - - auto& component = globals::dimension->chunks.emplace_or_replace<ChunkMeshComponent>(m_entity); - - const std::size_t plane_count_nb = m_quads_s.size(); - const std::size_t plane_count_b = m_quads_b.size(); - - bool has_no_submeshes_b = true; - bool has_no_submeshes_nb = true; - - component.quad_nb.resize(plane_count_nb); - component.quad_b.resize(plane_count_b); - - for(std::size_t plane = 0; plane < plane_count_nb; ++plane) { - QuadBuilder& builder = m_quads_s[plane]; - ChunkVBO& buffer = component.quad_nb[plane]; - - if(builder.empty()) { - if(buffer.handle) { - glDeleteBuffers(1, &buffer.handle); - buffer.handle = 0; - buffer.size = 0; - } - } else { - if(!buffer.handle) { - glGenBuffers(1, &buffer.handle); - } - - glBindBuffer(GL_ARRAY_BUFFER, buffer.handle); - glBufferData(GL_ARRAY_BUFFER, sizeof(ChunkQuad) * builder.size(), builder.data(), GL_STATIC_DRAW); - buffer.size = builder.size(); - has_no_submeshes_nb = false; - } - } - - for(std::size_t plane = 0; plane < plane_count_b; ++plane) { - QuadBuilder& builder = m_quads_b[plane]; - ChunkVBO& buffer = component.quad_b[plane]; - - if(builder.empty()) { - if(buffer.handle) { - glDeleteBuffers(1, &buffer.handle); - buffer.handle = 0; - buffer.size = 0; - } - } else { - if(!buffer.handle) { - glGenBuffers(1, &buffer.handle); - } - - glBindBuffer(GL_ARRAY_BUFFER, buffer.handle); - glBufferData(GL_ARRAY_BUFFER, sizeof(ChunkQuad) * builder.size(), builder.data(), GL_STATIC_DRAW); - buffer.size = builder.size(); - has_no_submeshes_b = false; - } - } - - if(has_no_submeshes_b && has_no_submeshes_nb) { - globals::dimension->chunks.remove<ChunkMeshComponent>(m_entity); - } -} - -bool GL_MeshingTask::vis_test(voxel_id voxel, const VoxelInfo* info, const local_pos& lpos) const -{ - const auto pvpos = coord::to_voxel(m_cpos, lpos); - const auto pcpos = coord::to_chunk(pvpos); - const auto plpos = coord::to_local(pvpos); - const auto index = coord::to_index(plpos); - - const auto cached_cpos = get_cached_cpos(m_cpos, pcpos); - const auto& voxels = m_cache.at(cached_cpos); - const auto neighbour = voxels[index]; - - bool result; - - if(neighbour == NULL_VOXEL_ID) { - result = true; - } else if(neighbour == voxel) { - result = false; - } else if(auto neighbour_info = voxel_registry::find(neighbour)) { - if(neighbour_info->blending != info->blending) { - // Voxel types that use blending are semi-transparent; - // this means they're rendered using a different setup - // and they must have visible faces with opaque voxels - result = neighbour_info->blending; - } else { - result = false; - } - } else { - result = false; - } - - return result; -} - -void GL_MeshingTask::push_quad_a(const VoxelInfo* info, const glm::fvec3& pos, const glm::fvec2& size, voxel_face face) -{ - const voxel_facing facing = get_facing(face, info->type); - const VoxelTexture& vtex = info->textures[static_cast<std::size_t>(face)]; - - if(info->blending) { - m_quads_b[vtex.cached_plane].push_back(make_chunk_quad(pos, size, facing, vtex.cached_offset, vtex.paths.size())); - } else { - m_quads_s[vtex.cached_plane].push_back(make_chunk_quad(pos, size, facing, vtex.cached_offset, vtex.paths.size())); - } -} - -void GL_MeshingTask::push_quad_v(const VoxelInfo* info, const glm::fvec3& pos, const glm::fvec2& size, voxel_face face, std::size_t entropy) -{ - const voxel_facing facing = get_facing(face, info->type); - const VoxelTexture& vtex = info->textures[static_cast<std::size_t>(face)]; - const std::size_t entropy_mod = entropy % vtex.paths.size(); - - if(info->blending) { - m_quads_b[vtex.cached_plane].push_back(make_chunk_quad(pos, size, facing, vtex.cached_offset + entropy_mod, 0)); - } else { - m_quads_s[vtex.cached_plane].push_back(make_chunk_quad(pos, size, facing, vtex.cached_offset + entropy_mod, 0)); - } -} - -void GL_MeshingTask::make_cube(voxel_id voxel, const VoxelInfo* info, const local_pos& lpos, voxel_vis vis, std::size_t entropy) -{ - const glm::fvec3 fpos = glm::fvec3(lpos); - const glm::fvec2 fsize = glm::fvec2(1.0f, 1.0f); - - if(info->animated) { - if(vis & VIS_NORTH) { - push_quad_a(info, fpos, fsize, voxel_face::CUBE_NORTH); - } - - if(vis & VIS_SOUTH) { - push_quad_a(info, fpos, fsize, voxel_face::CUBE_SOUTH); - } - - if(vis & VIS_EAST) { - push_quad_a(info, fpos, fsize, voxel_face::CUBE_EAST); - } - - if(vis & VIS_WEST) { - push_quad_a(info, fpos, fsize, voxel_face::CUBE_WEST); - } - - if(vis & VIS_UP) { - push_quad_a(info, fpos, fsize, voxel_face::CUBE_TOP); - } - - if(vis & VIS_DOWN) { - push_quad_a(info, fpos, fsize, voxel_face::CUBE_BOTTOM); - } - } else { - if(vis & VIS_NORTH) { - push_quad_v(info, fpos, fsize, voxel_face::CUBE_NORTH, entropy); - } - - if(vis & VIS_SOUTH) { - push_quad_v(info, fpos, fsize, voxel_face::CUBE_SOUTH, entropy); - } - - if(vis & VIS_EAST) { - push_quad_v(info, fpos, fsize, voxel_face::CUBE_EAST, entropy); - } - - if(vis & VIS_WEST) { - push_quad_v(info, fpos, fsize, voxel_face::CUBE_WEST, entropy); - } - - if(vis & VIS_UP) { - push_quad_v(info, fpos, fsize, voxel_face::CUBE_TOP, entropy); - } - - if(vis & VIS_DOWN) { - push_quad_v(info, fpos, fsize, voxel_face::CUBE_BOTTOM, entropy); - } - } -} - -void GL_MeshingTask::cache_chunk(const chunk_pos& cpos) -{ - const auto index = get_cached_cpos(m_cpos, cpos); - - if(const auto chunk = globals::dimension->find_chunk(cpos)) { - m_cache[index] = chunk->get_voxels(); - return; - } -} - -// Bogus internal flag component -struct NeedsMeshingComponent final {}; - -static void on_chunk_create(const ChunkCreateEvent& event) -{ - const std::array<chunk_pos, 6> neighbours = { - event.cpos + DIR_NORTH<chunk_pos::value_type>, - event.cpos + DIR_SOUTH<chunk_pos::value_type>, - event.cpos + DIR_EAST<chunk_pos::value_type>, - event.cpos + DIR_WEST<chunk_pos::value_type>, - event.cpos + DIR_UP<chunk_pos::value_type>, - event.cpos + DIR_DOWN<chunk_pos::value_type>, - }; - - globals::dimension->chunks.emplace_or_replace<NeedsMeshingComponent>(event.chunk->get_entity()); - - for(const chunk_pos& cpos : neighbours) { - if(const Chunk* chunk = globals::dimension->find_chunk(cpos)) { - globals::dimension->chunks.emplace_or_replace<NeedsMeshingComponent>(chunk->get_entity()); - continue; - } - } -} - -static void on_chunk_update(const ChunkUpdateEvent& event) -{ - const std::array<chunk_pos, 6> neighbours = { - event.cpos + DIR_NORTH<chunk_pos::value_type>, - event.cpos + DIR_SOUTH<chunk_pos::value_type>, - event.cpos + DIR_EAST<chunk_pos::value_type>, - event.cpos + DIR_WEST<chunk_pos::value_type>, - event.cpos + DIR_UP<chunk_pos::value_type>, - event.cpos + DIR_DOWN<chunk_pos::value_type>, - }; - - globals::dimension->chunks.emplace_or_replace<NeedsMeshingComponent>(event.chunk->get_entity()); - - for(const chunk_pos& cpos : neighbours) { - if(const Chunk* chunk = globals::dimension->find_chunk(cpos)) { - globals::dimension->chunks.emplace_or_replace<NeedsMeshingComponent>(chunk->get_entity()); - continue; - } - } -} - -static void on_voxel_set(const VoxelSetEvent& event) -{ - globals::dimension->chunks.emplace_or_replace<NeedsMeshingComponent>(event.chunk->get_entity()); - - std::vector<chunk_pos> neighbours; - - for(int dim = 0; dim < 3; dim += 1) { - chunk_pos offset = chunk_pos(0, 0, 0); - offset[dim] = 1; - - if(event.lpos[dim] == 0) { - neighbours.push_back(event.cpos - offset); - continue; - } - - if(event.lpos[dim] == (CHUNK_SIZE - 1)) { - neighbours.push_back(event.cpos + offset); - continue; - } - } - - for(const chunk_pos& cpos : neighbours) { - if(const Chunk* chunk = globals::dimension->find_chunk(cpos)) { - globals::dimension->chunks.emplace_or_replace<NeedsMeshingComponent>(chunk->get_entity()); - continue; - } - } -} - -void chunk_mesher::init(void) -{ - globals::dispatcher.sink<ChunkCreateEvent>().connect<&on_chunk_create>(); - globals::dispatcher.sink<ChunkUpdateEvent>().connect<&on_chunk_update>(); - globals::dispatcher.sink<VoxelSetEvent>().connect<&on_voxel_set>(); -} - -void chunk_mesher::deinit(void) -{ -} - -void chunk_mesher::update(void) -{ - if(session::is_ingame()) { - const auto group = globals::dimension->chunks.group<NeedsMeshingComponent>(entt::get<ChunkComponent>); - for(const auto [entity, chunk] : group.each()) { - globals::dimension->chunks.remove<NeedsMeshingComponent>(entity); - threading::submit<GL_MeshingTask>(entity, chunk.cpos); - } - } -} diff --git a/game/client/chunk_mesher.hh b/game/client/chunk_mesher.hh deleted file mode 100644 index 36580ac..0000000 --- a/game/client/chunk_mesher.hh +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef CLIENT_CHUNK_MESHER_HH -#define CLIENT_CHUNK_MESHER_HH 1 -#pragma once - -#include "client/chunk_vbo.hh" - -struct ChunkMeshComponent final { - std::vector<ChunkVBO> quad_nb; - std::vector<ChunkVBO> quad_b; -}; - -namespace chunk_mesher -{ -void init(void); -void deinit(void); -void update(void); -} // namespace chunk_mesher - -#endif /* CLIENT_CHUNK_MESHER_HH */ diff --git a/game/client/chunk_quad.hh b/game/client/chunk_quad.hh deleted file mode 100644 index 337bb1e..0000000 --- a/game/client/chunk_quad.hh +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef CLIENT_CHUNK_QUAD_HH -#define CLIENT_CHUNK_QUAD_HH 1 -#pragma once - -#include "core/constexpr.hh" - -#include "shared/voxel_registry.hh" - -// [0] XXXXXXXXYYYYYYYYZZZZZZZZWWWWHHHH -// [1] FFFFTTTTTTTTTTTAAAAA------------ -using ChunkQuad = std::array<std::uint32_t, 2>; - -constexpr inline static ChunkQuad make_chunk_quad( - const glm::fvec3& position, const glm::fvec2& size, voxel_facing facing, std::size_t texture, std::size_t frames) -{ - ChunkQuad result = {}; - result[0] = 0x00000000; - result[1] = 0x00000000; - - // [0] XXXXXXXXYYYYYYYYZZZZZZZZ-------- - result[0] |= (0x000000FFU & static_cast<std::uint32_t>(position.x * 16.0f)) << 24U; - result[0] |= (0x000000FFU & static_cast<std::uint32_t>(position.y * 16.0f)) << 16U; - result[0] |= (0x000000FFU & static_cast<std::uint32_t>(position.z * 16.0f)) << 8U; - - // [0] ------------------------WWWWHHHH - result[0] |= (0x0000000FU & static_cast<std::uint32_t>(size.x * 16.0f - 1.0f)) << 4U; - result[0] |= (0x0000000FU & static_cast<std::uint32_t>(size.y * 16.0f - 1.0f)); - - // [1] FFFF---------------------------- - result[1] |= (0x0000000FU & static_cast<std::uint32_t>(facing)) << 28U; - - // [1] ----TTTTTTTTTTTAAAAA------------ - result[1] |= (0x000007FFU & static_cast<std::uint32_t>(texture)) << 17U; - result[1] |= (0x0000001FU & static_cast<std::uint32_t>(frames)) << 12U; - - return result; -} - -#endif /* CLIENT_CHUNK_QUAD_HH */ diff --git a/game/client/chunk_renderer.cc b/game/client/chunk_renderer.cc deleted file mode 100644 index 54239af..0000000 --- a/game/client/chunk_renderer.cc +++ /dev/null @@ -1,196 +0,0 @@ -#include "client/pch.hh" - -#include "client/chunk_renderer.hh" - -#include "core/config.hh" - -#include "shared/chunk.hh" -#include "shared/coord.hh" -#include "shared/dimension.hh" - -#include "client/camera.hh" -#include "client/chunk_mesher.hh" -#include "client/chunk_quad.hh" -#include "client/game.hh" -#include "client/globals.hh" -#include "client/outline.hh" -#include "client/program.hh" -#include "client/settings.hh" -#include "client/skybox.hh" -#include "client/toggles.hh" -#include "client/voxel_anims.hh" -#include "client/voxel_atlas.hh" - -// ONLY TOUCH THESE IF THE RESPECTIVE SHADER -// VARIANT MACRO DECLARATIONS LAYOUT CHANGED AS WELL -constexpr static unsigned int WORLD_CURVATURE = 0U; -constexpr static unsigned int WORLD_FOG = 1U; - -static ConfigBoolean depth_sort_chunks(true); - -static GL_Program quad_program; -static std::size_t u_quad_vproj_matrix; -static std::size_t u_quad_world_position; -static std::size_t u_quad_timings; -static std::size_t u_quad_fog_color; -static std::size_t u_quad_view_distance; -static std::size_t u_quad_textures; -static GLuint quad_vaobj; -static GLuint quad_vbo; - -void chunk_renderer::init(void) -{ - globals::client_config.add_value("chunk_renderer.depth_sort_chunks", depth_sort_chunks); - - settings::add_checkbox(5, depth_sort_chunks, settings_location::VIDEO, "chunk_renderer.depth_sort_chunks", false); - - if(!quad_program.setup("shaders/chunk_quad.vert", "shaders/chunk_quad.frag")) { - spdlog::critical("chunk_renderer: quad_program: setup failed"); - std::terminate(); - } - - u_quad_vproj_matrix = quad_program.add_uniform("u_ViewProjMatrix"); - u_quad_world_position = quad_program.add_uniform("u_WorldPosition"); - u_quad_timings = quad_program.add_uniform("u_Timings"); - u_quad_fog_color = quad_program.add_uniform("u_FogColor"); - u_quad_view_distance = quad_program.add_uniform("u_ViewDistance"); - u_quad_textures = quad_program.add_uniform("u_Textures"); - - const glm::fvec3 vertices[4] = { - glm::fvec3(1.0f, 0.0f, 1.0f), - glm::fvec3(1.0f, 0.0f, 0.0f), - glm::fvec3(0.0f, 0.0f, 1.0f), - glm::fvec3(0.0f, 0.0f, 0.0f), - }; - - glGenVertexArrays(1, &quad_vaobj); - glBindVertexArray(quad_vaobj); - - glGenBuffers(1, &quad_vbo); - glBindBuffer(GL_ARRAY_BUFFER, quad_vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - - glEnableVertexAttribArray(0); - glVertexAttribDivisor(0, 0); - glVertexAttribPointer(0, 3, GL_FLOAT, false, sizeof(glm::fvec3), nullptr); -} - -void chunk_renderer::deinit(void) -{ - glDeleteBuffers(1, &quad_vbo); - glDeleteVertexArrays(1, &quad_vaobj); - quad_program.destroy(); -} - -void chunk_renderer::render(void) -{ - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LEQUAL); - glLineWidth(1.0f); - - if(toggles::get(TOGGLE_WIREFRAME)) { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - } else { - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - } - - quad_program.set_variant_vert(WORLD_CURVATURE, client_game::world_curvature.get_value()); - quad_program.set_variant_vert(WORLD_FOG, client_game::fog_mode.get_value()); - quad_program.set_variant_frag(WORLD_FOG, client_game::fog_mode.get_value()); - - if(!quad_program.update()) { - spdlog::critical("chunk_renderer: quad_program: update failed"); - quad_program.destroy(); - std::terminate(); - } - - GLuint timings[3]; - timings[0] = globals::window_frametime; - timings[1] = globals::window_frametime_avg; - timings[2] = voxel_anims::frame; - - const auto group = globals::dimension->chunks.group<ChunkComponent>(entt::get<ChunkMeshComponent>); - - if(depth_sort_chunks.get_value()) { - // FIXME: speed! sorting every frame doesn't look - // like a good idea. Can we store the group elsewhere and - // still have all the up-to-date chunk things inside? - group.sort([](entt::entity ea, entt::entity eb) { - const auto dir_a = globals::dimension->chunks.get<ChunkComponent>(ea).cpos - camera::position_chunk; - const auto dir_b = globals::dimension->chunks.get<ChunkComponent>(eb).cpos - camera::position_chunk; - - const auto da = dir_a[0] * dir_a[0] + dir_a[1] * dir_a[1] + dir_a[2] * dir_a[2]; - const auto db = dir_b[0] * dir_b[0] + dir_b[1] * dir_b[1] + dir_b[2] * dir_b[2]; - - return da > db; - }); - } - - for(std::size_t plane_id = 0; plane_id < voxel_atlas::plane_count(); ++plane_id) { - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D_ARRAY, voxel_atlas::plane_texture(plane_id)); - - glBindVertexArray(quad_vaobj); - - glUseProgram(quad_program.handle); - glUniformMatrix4fv(quad_program.uniforms[u_quad_vproj_matrix].location, 1, false, glm::value_ptr(camera::matrix)); - glUniform3uiv(quad_program.uniforms[u_quad_timings].location, 1, timings); - glUniform4fv(quad_program.uniforms[u_quad_fog_color].location, 1, glm::value_ptr(skybox::fog_color)); - glUniform1f(quad_program.uniforms[u_quad_view_distance].location, camera::view_distance.get_value() * CHUNK_SIZE); - glUniform1i(quad_program.uniforms[u_quad_textures].location, 0); // GL_TEXTURE0 - - glDisable(GL_BLEND); - - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - glFrontFace(GL_CCW); - - for(const auto [entity, chunk, mesh] : group.each()) { - if(plane_id < mesh.quad_nb.size() && mesh.quad_nb[plane_id].handle && mesh.quad_nb[plane_id].size) { - const auto wpos = coord::to_fvec3(chunk.cpos - camera::position_chunk); - glUniform3fv(quad_program.uniforms[u_quad_world_position].location, 1, glm::value_ptr(wpos)); - - glBindBuffer(GL_ARRAY_BUFFER, mesh.quad_nb[plane_id].handle); - - glEnableVertexAttribArray(1); - glVertexAttribDivisor(1, 1); - glVertexAttribIPointer(1, 2, GL_UNSIGNED_INT, sizeof(ChunkQuad), nullptr); - - glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, mesh.quad_nb[plane_id].size); - - globals::num_drawcalls += 1; - globals::num_triangles += 2 * mesh.quad_nb[plane_id].size; - } - } - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - for(const auto [entity, chunk, mesh] : group.each()) { - if(plane_id < mesh.quad_b.size() && mesh.quad_b[plane_id].handle && mesh.quad_b[plane_id].size) { - const auto wpos = coord::to_fvec3(chunk.cpos - camera::position_chunk); - glUniform3fv(quad_program.uniforms[u_quad_world_position].location, 1, glm::value_ptr(wpos)); - - glBindBuffer(GL_ARRAY_BUFFER, mesh.quad_b[plane_id].handle); - - glEnableVertexAttribArray(1); - glVertexAttribDivisor(1, 1); - glVertexAttribIPointer(1, 2, GL_UNSIGNED_INT, sizeof(ChunkQuad), nullptr); - - glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, mesh.quad_b[plane_id].size); - - globals::num_drawcalls += 1; - globals::num_triangles += 2 * mesh.quad_b[plane_id].size; - } - } - } - - if(toggles::get(TOGGLE_CHUNK_AABB)) { - outline::prepare(); - - for(const auto [entity, chunk, mesh] : group.each()) { - const auto size = glm::fvec3(CHUNK_SIZE, CHUNK_SIZE, CHUNK_SIZE); - outline::cube(chunk.cpos, glm::fvec3(0.0f, 0.0f, 0.0f), size, 1.0f, glm::fvec4(1.0f, 1.0f, 0.0f, 1.0f)); - } - } -} diff --git a/game/client/chunk_renderer.hh b/game/client/chunk_renderer.hh deleted file mode 100644 index 3ebcf76..0000000 --- a/game/client/chunk_renderer.hh +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef CLIENT_CHUNK_RENDERER_HH -#define CLIENT_CHUNK_RENDERER_HH 1 -#pragma once - -namespace chunk_renderer -{ -void init(void); -void deinit(void); -void render(void); -} // namespace chunk_renderer - -#endif /* CLIENT_CHUNK_RENDERER_HH */ diff --git a/game/client/chunk_vbo.hh b/game/client/chunk_vbo.hh deleted file mode 100644 index ba27552..0000000 --- a/game/client/chunk_vbo.hh +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef CLIENT_CHUNK_VBO_HH -#define CLIENT_CHUNK_VBO_HH 1 -#pragma once - -class ChunkVBO final { -public: - std::size_t size; - GLuint handle; - -public: - inline ~ChunkVBO(void) - { - // The ChunkVBO structure is meant to be a part - // of the ChunkMesh component within the EnTT registry; - // When the registry is cleaned or a chunk is removed, components - // are expected to be safely disposed of so we need a destructor; - if(handle) { - glDeleteBuffers(1, &handle); - } - } -}; - -#endif /* CLIENT_CHUNK_VBO_HH */ diff --git a/game/client/chunk_visibility.cc b/game/client/chunk_visibility.cc deleted file mode 100644 index f832529..0000000 --- a/game/client/chunk_visibility.cc +++ /dev/null @@ -1,87 +0,0 @@ -#include "client/pch.hh" - -#include "client/chunk_visibility.hh" - -#include "core/config.hh" -#include "core/vectors.hh" - -#include "shared/chunk.hh" -#include "shared/chunk_aabb.hh" -#include "shared/dimension.hh" -#include "shared/protocol.hh" - -#include "client/camera.hh" -#include "client/globals.hh" -#include "client/session.hh" - -// Sending a somewhat large amount of network packets -// can easily overwhelm both client, server and the network -// channel created between the two. To prevent this from happening -// we throttle the client's ever increasing itch for new chunks -constexpr static unsigned int MAX_CHUNKS_REQUESTS_PER_FRAME = 16U; - -static ChunkAABB current_view_box; -static ChunkAABB previous_view_box; -static std::vector<chunk_pos> requests; - -static void update_requests(void) -{ - requests.clear(); - - for(auto cx = current_view_box.min.x; cx != current_view_box.max.x; cx += 1) - for(auto cy = current_view_box.min.y; cy != current_view_box.max.y; cy += 1) - for(auto cz = current_view_box.min.z; cz != current_view_box.max.z; cz += 1) { - auto cpos = chunk_pos(cx, cy, cz); - - if(!globals::dimension->find_chunk(cpos)) { - requests.push_back(cpos); - } - } - - std::sort(requests.begin(), requests.end(), [](const chunk_pos& cpos_a, const chunk_pos& cpos_b) { - auto da = vx::distance2(cpos_a, camera::position_chunk); - auto db = vx::distance2(cpos_b, camera::position_chunk); - return da > db; - }); -} - -void chunk_visibility::update_late(void) -{ - current_view_box.min = camera::position_chunk - static_cast<chunk_pos::value_type>(camera::view_distance.get_value()); - current_view_box.max = camera::position_chunk + static_cast<chunk_pos::value_type>(camera::view_distance.get_value()); - - if(!session::is_ingame()) { - // This makes sure the previous view box - // is always different from the current one - previous_view_box.min = chunk_pos(INT32_MIN, INT32_MIN, INT32_MIN); - previous_view_box.max = chunk_pos(INT32_MAX, INT32_MAX, INT32_MAX); - return; - } - - if((current_view_box.min != previous_view_box.min) || (current_view_box.max != previous_view_box.max)) { - update_requests(); - } - - for(unsigned int i = 0U; i < MAX_CHUNKS_REQUESTS_PER_FRAME; ++i) { - if(requests.empty()) { - // Done sending requests - break; - } - - protocol::RequestChunk packet; - packet.cpos = requests.back(); - protocol::send(session::peer, protocol::encode(packet)); - - requests.pop_back(); - } - - auto view = globals::dimension->chunks.view<ChunkComponent>(); - - for(const auto [entity, chunk] : view.each()) { - if(!current_view_box.contains(chunk.cpos)) { - globals::dimension->remove_chunk(entity); - } - } - - previous_view_box = current_view_box; -} diff --git a/game/client/chunk_visibility.hh b/game/client/chunk_visibility.hh deleted file mode 100644 index 70352c9..0000000 --- a/game/client/chunk_visibility.hh +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef CLIENT_CHUNK_VISIBILITY_HH -#define CLIENT_CHUNK_VISIBILITY_HH 1 -#pragma once - -#include "shared/types.hh" - -namespace chunk_visibility -{ -void update_late(void); -} // namespace chunk_visibility - -#endif /* CLIENT_CHUNK_VISIBILITY_HH */ diff --git a/game/client/const.hh b/game/client/const.hh deleted file mode 100644 index 9bd8346..0000000 --- a/game/client/const.hh +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef CLIENT_CONST_HH -#define CLIENT_CONST_HH 1 -#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; - -#endif /* CLIENT_CONST_HH */ diff --git a/game/client/crosshair.cc b/game/client/crosshair.cc deleted file mode 100644 index 84a9a73..0000000 --- a/game/client/crosshair.cc +++ /dev/null @@ -1,41 +0,0 @@ -#include "client/pch.hh" - -#include "client/crosshair.hh" - -#include "core/constexpr.hh" -#include "core/resource.hh" - -#include "client/globals.hh" -#include "client/session.hh" -#include "client/texture_gui.hh" - -static resource_ptr<TextureGUI> texture; - -void crosshair::init(void) -{ - texture = resource::load<TextureGUI>( - "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 crosshair::deinit(void) -{ - texture = nullptr; -} - -void crosshair::layout(void) -{ - auto viewport = ImGui::GetMainViewport(); - auto draw_list = ImGui::GetForegroundDrawList(); - - auto scaled_width = vx::max<int>(texture->size.x, globals::gui_scale * texture->size.x / 2); - auto scaled_height = vx::max<int>(texture->size.y, globals::gui_scale * texture->size.y / 2); - auto start = ImVec2( - static_cast<int>(0.5f * viewport->Size.x) - (scaled_width / 2), static_cast<int>(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/crosshair.hh b/game/client/crosshair.hh deleted file mode 100644 index 6525792..0000000 --- a/game/client/crosshair.hh +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef CLIENT_CROSSHAIR_HH -#define CLIENT_CROSSHAIR_HH 1 -#pragma once - -namespace crosshair -{ -void init(void); -void deinit(void); -void layout(void); -} // namespace crosshair - -#endif /* CLIENT_CROSSHAIR_HH */ diff --git a/game/client/direct_connection.cc b/game/client/direct_connection.cc deleted file mode 100644 index c2efc4e..0000000 --- a/game/client/direct_connection.cc +++ /dev/null @@ -1,140 +0,0 @@ -#include "client/pch.hh" - -#include "client/direct_connection.hh" - -#include "core/config.hh" -#include "core/strtools.hh" - -#include "shared/protocol.hh" - -#include "client/game.hh" -#include "client/glfw.hh" -#include "client/globals.hh" -#include "client/gui_screen.hh" -#include "client/language.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 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 LanguageSetEvent& event) -{ - str_title = language::resolve("direct_connection.title"); - str_connect = language::resolve_gui("direct_connection.connect"); - str_cancel = language::resolve_gui("direct_connection.cancel"); - - str_hostname = language::resolve("direct_connection.hostname"); - str_password = language::resolve("direct_connection.password"); -} - -static void connect_to_server(void) -{ - auto parts = strtools::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 = vx::clamp<std::uint16_t>(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 direct_connection::init(void) -{ - globals::dispatcher.sink<GlfwKeyEvent>().connect<&on_glfw_key>(); - globals::dispatcher.sink<LanguageSetEvent>().connect<&on_language_set>(); -} - -void 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(strtools::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/direct_connection.hh b/game/client/direct_connection.hh deleted file mode 100644 index f94bcaf..0000000 --- a/game/client/direct_connection.hh +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef CLIENT_DIRECT_CONNECTION_HH -#define CLIENT_DIRECT_CONNECTION_HH 1 -#pragma once - -namespace direct_connection -{ -void init(void); -void layout(void); -} // namespace direct_connection - -#endif /* CLIENT_DIRECT_CONNECTION_HH */ diff --git a/game/client/experiments.cc b/game/client/experiments.cc deleted file mode 100644 index 70353b5..0000000 --- a/game/client/experiments.cc +++ /dev/null @@ -1,77 +0,0 @@ -#include "client/pch.hh" - -#include "client/experiments.hh" - -#include "shared/dimension.hh" -#include "shared/game_items.hh" -#include "shared/game_voxels.hh" -#include "shared/item_registry.hh" - -#include "client/chat.hh" -#include "client/glfw.hh" -#include "client/globals.hh" -#include "client/hotbar.hh" -#include "client/player_target.hh" -#include "client/session.hh" -#include "client/status_lines.hh" - -static void on_glfw_mouse_button(const GlfwMouseButtonEvent& event) -{ - if(!globals::gui_screen && session::is_ingame()) { - if((event.action == GLFW_PRESS) && (player_target::voxel != NULL_VOXEL_ID)) { - 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<GlfwMouseButtonEvent>().connect<&on_glfw_mouse_button>(); -} - -void experiments::init_late(void) -{ - hotbar::slots[0] = game_items::cobblestone; - hotbar::slots[1] = game_items::stone; - hotbar::slots[2] = game_items::dirt; - hotbar::slots[3] = game_items::grass; - hotbar::slots[4] = game_items::oak_leaves; - hotbar::slots[5] = game_items::oak_planks; - hotbar::slots[6] = game_items::oak_log; - hotbar::slots[7] = game_items::glass; - hotbar::slots[8] = game_items::slime; -} - -void experiments::deinit(void) -{ -} - -void experiments::update(void) -{ -} - -void experiments::update_late(void) -{ -} - -void experiments::attack(void) -{ - globals::dimension->set_voxel(NULL_VOXEL_ID, player_target::coord); -} - -void experiments::interact(void) -{ - if(auto info = item_registry::find(hotbar::slots[hotbar::active_slot])) { - if(info->place_voxel != NULL_VOXEL_ID) { - globals::dimension->set_voxel(info->place_voxel, player_target::coord + player_target::normal); - } - } -} diff --git a/game/client/experiments.hh b/game/client/experiments.hh deleted file mode 100644 index ae20426..0000000 --- a/game/client/experiments.hh +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef CLIENT_EXPERIMENTS_HH -#define CLIENT_EXPERIMENTS_HH 1 -#pragma once - -namespace experiments -{ -void init(void); -void init_late(void); -void deinit(void); -void update(void); -void update_late(void); -} // namespace experiments - -namespace experiments -{ -void attack(void); -void interact(void); -} // namespace experiments - -#endif /* CLIENT_EXPERIMENTS_HH */ diff --git a/game/client/factory.cc b/game/client/factory.cc deleted file mode 100644 index 4c1c24e..0000000 --- a/game/client/factory.cc +++ /dev/null @@ -1,28 +0,0 @@ -#include "client/pch.hh" - -#include "client/factory.hh" - -#include "shared/dimension.hh" -#include "shared/factory.hh" -#include "shared/head.hh" -#include "shared/transform.hh" - -#include "client/globals.hh" -#include "client/sound_emitter.hh" - -void client_factory::create_player(Dimension* dimension, entt::entity entity) -{ - shared_factory::create_player(dimension, entity); - - const auto& head = dimension->entities.get<HeadComponent>(entity); - dimension->entities.emplace_or_replace<HeadComponentIntr>(entity, head); - dimension->entities.emplace_or_replace<HeadComponentPrev>(entity, head); - - const auto& transform = dimension->entities.get<TransformComponent>(entity); - dimension->entities.emplace_or_replace<TransformComponentIntr>(entity, transform); - dimension->entities.emplace_or_replace<TransformComponentPrev>(entity, transform); - - if(globals::sound_ctx) { - dimension->entities.emplace_or_replace<SoundEmitterComponent>(entity); - } -} diff --git a/game/client/factory.hh b/game/client/factory.hh deleted file mode 100644 index 6f883c2..0000000 --- a/game/client/factory.hh +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef CLIENT_FACTORY_HH -#define CLIENT_FACTORY_HH 1 -#pragma once - -class Dimension; - -namespace client_factory -{ -void create_player(Dimension* dimension, entt::entity entity); -} // namespace client_factory - -#endif /* CLIENT_FACTORY_HH */ diff --git a/game/client/game.cc b/game/client/game.cc deleted file mode 100644 index 8dc39f6..0000000 --- a/game/client/game.cc +++ /dev/null @@ -1,690 +0,0 @@ -#include "client/pch.hh" - -#include "client/game.hh" - -#include "core/angles.hh" -#include "core/binfile.hh" -#include "core/config.hh" -#include "core/resource.hh" - -#include "shared/collision.hh" -#include "shared/coord.hh" -#include "shared/dimension.hh" -#include "shared/game_items.hh" -#include "shared/game_voxels.hh" -#include "shared/gravity.hh" -#include "shared/head.hh" -#include "shared/item_registry.hh" -#include "shared/player.hh" -#include "shared/protocol.hh" -#include "shared/ray_dda.hh" -#include "shared/stasis.hh" -#include "shared/transform.hh" -#include "shared/velocity.hh" -#include "shared/voxel_registry.hh" - -#include "client/background.hh" -#include "client/bother.hh" -#include "client/camera.hh" -#include "client/chat.hh" -#include "client/chunk_mesher.hh" -#include "client/chunk_renderer.hh" -#include "client/chunk_visibility.hh" -#include "client/const.hh" -#include "client/crosshair.hh" -#include "client/direct_connection.hh" -#include "client/experiments.hh" -#include "client/gamepad.hh" -#include "client/glfw.hh" -#include "client/globals.hh" -#include "client/gui_screen.hh" -#include "client/hotbar.hh" -#include "client/interpolation.hh" -#include "client/keybind.hh" -#include "client/language.hh" -#include "client/listener.hh" -#include "client/main_menu.hh" -#include "client/message_box.hh" -#include "client/metrics.hh" -#include "client/outline.hh" -#include "client/play_menu.hh" -#include "client/player_look.hh" -#include "client/player_move.hh" -#include "client/player_target.hh" -#include "client/progress_bar.hh" -#include "client/receive.hh" -#include "client/scoreboard.hh" -#include "client/screenshot.hh" -#include "client/session.hh" -#include "client/settings.hh" -#include "client/skybox.hh" -#include "client/sound.hh" -#include "client/sound_emitter.hh" -#include "client/splash.hh" -#include "client/status_lines.hh" -#include "client/texture_gui.hh" -#include "client/toggles.hh" -#include "client/voxel_anims.hh" -#include "client/voxel_atlas.hh" -#include "client/voxel_sounds.hh" -#include "client/window_title.hh" - -ConfigBoolean client_game::streamer_mode(false); -ConfigBoolean client_game::vertical_sync(true); -ConfigBoolean client_game::world_curvature(true); -ConfigUnsigned client_game::pixel_size(2U, 1U, 4U); -ConfigUnsigned client_game::fog_mode(1U, 0U, 2U); -ConfigString client_game::username("player"); - -bool client_game::hide_hud = false; - -static ConfigKeyBind hide_hud_toggle(GLFW_KEY_F1); - -static resource_ptr<BinFile> bin_unscii16; -static resource_ptr<BinFile> bin_unscii8; - -static void on_glfw_framebuffer_size(const GlfwFramebufferSizeEvent& event) -{ - auto width_float = static_cast<float>(event.size.x); - auto height_float = static_cast<float>(event.size.y); - auto wscale = vx::max(1U, vx::floor<unsigned int>(width_float / static_cast<float>(BASE_WIDTH))); - auto hscale = vx::max(1U, vx::floor<unsigned int>(height_float / static_cast<float>(BASE_HEIGHT))); - auto scale = vx::min(wscale, hscale); - - if(globals::gui_scale != scale) { - auto& io = ImGui::GetIO(); - auto& style = ImGui::GetStyle(); - - ImFontConfig font_config; - font_config.FontDataOwnedByAtlas = false; - - io.Fonts->Clear(); - - ImFontGlyphRangesBuilder builder; - - // This should cover a hefty range of glyph ranges. - // UNDONE: just slap the whole UNICODE Plane-0 here? - builder.AddRanges(io.Fonts->GetGlyphRangesDefault()); - builder.AddRanges(io.Fonts->GetGlyphRangesCyrillic()); - builder.AddRanges(io.Fonts->GetGlyphRangesGreek()); - builder.AddRanges(io.Fonts->GetGlyphRangesJapanese()); - - ImVector<ImWchar> ranges = {}; - builder.BuildRanges(&ranges); - - globals::font_default = io.Fonts->AddFontFromMemoryTTF( - bin_unscii16->buffer, bin_unscii16->size, 16.0f * scale, &font_config, ranges.Data); - globals::font_chat = io.Fonts->AddFontFromMemoryTTF( - bin_unscii16->buffer, bin_unscii16->size, 8.0f * scale, &font_config, ranges.Data); - globals::font_debug = io.Fonts->AddFontFromMemoryTTF(bin_unscii8->buffer, bin_unscii8->size, 4.0f * scale, &font_config); - - // Re-assign the default font - io.FontDefault = globals::font_default; - - // This should be here!!! Just calling Build() - // on the font atlas does not invalidate internal - // device objects defined by the implementation!!! - ImGui_ImplOpenGL3_CreateDeviceObjects(); - - if(globals::gui_scale) { - // Well, ImGuiStyle::ScaleAllSizes indeed takes - // the scale values as a RELATIVE scaling, not as - // absolute. So I have to make a special crutch - style.ScaleAllSizes(static_cast<float>(scale) / static_cast<float>(globals::gui_scale)); - } - - globals::gui_scale = scale; - } - - 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 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) -{ - bin_unscii16 = resource::load<BinFile>("fonts/unscii-16.ttf"); - bin_unscii8 = resource::load<BinFile>("fonts/unscii-8.ttf"); - - if((bin_unscii16 == nullptr) || (bin_unscii8 == nullptr)) { - spdlog::critical("client_game: font loading failed"); - std::terminate(); - } - - client_splash::init(); - 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.pixel_size", client_game::pixel_size); - 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_slider(1, client_game::pixel_size, settings_location::VIDEO, "game.pixel_size", 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(); - } - - language::init(); - - session::init(); - - player_look::init(); - player_move::init(); - player_target::init(); - - gamepad::init(); - - camera::init(); - - voxel_anims::init(); - - outline::init(); - chunk_mesher::init(); - chunk_renderer::init(); - - globals::world_fbo = 0; - globals::world_fbo_color = 0; - globals::world_fbo_depth = 0; - - voxel_sounds::init(); - - 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. - ImGui::GetIO().IniFilename = nullptr; - - toggles::init(); - - background::init(); - - scoreboard::init(); - - client_chat::init(); - - bother::init(); - - main_menu::init(); - play_menu::init(); - progress_bar::init(); - message_box::init(); - direct_connection::init(); - - crosshair::init(); - hotbar::init(); - metrics::init(); - 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<GlfwFramebufferSizeEvent>().connect<&on_glfw_framebuffer_size>(); - globals::dispatcher.sink<GlfwKeyEvent>().connect<&on_glfw_key>(); -} - -void client_game::init_late(void) -{ - toggles::init_late(); - - if(globals::sound_ctx) { - sound::init_late(); - } - - language::init_late(); - - settings::init_late(); - - client_chat::init_late(); - - 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 std::shared_ptr<VoxelInfo>& info : voxel_registry::voxels) { - for(const VoxelTexture& vtex : info->textures) { - max_texture_count += vtex.paths.size(); - } - } - - // UNDONE: asset packs for non-16x16 stuff - voxel_atlas::create(16, 16, max_texture_count); - - for(std::shared_ptr<VoxelInfo>& info : voxel_registry::voxels) { - for(VoxelTexture& vtex : info->textures) { - if(auto strip = voxel_atlas::find_or_load(vtex.paths)) { - vtex.cached_offset = strip->offset; - vtex.cached_plane = strip->plane; - continue; - } - - spdlog::critical("client_gl: {}: failed to load atlas strips", info->name); - std::terminate(); - } - } - - voxel_atlas::generate_mipmaps(); - - for(std::shared_ptr<ItemInfo>& info : item_registry::items) { - info->cached_texture = resource::load<TextureGUI>(info->texture.c_str(), TEXTURE_GUI_LOAD_CLAMP_S | TEXTURE_GUI_LOAD_CLAMP_T); - } - - experiments::init_late(); - - client_splash::init_late(); - - window_title::update(); -} - -void client_game::deinit(void) -{ - voxel_sounds::deinit(); - - experiments::deinit(); - - session::deinit(); - - if(globals::sound_ctx) { - sound::deinit(); - } - - hotbar::deinit(); - main_menu::deinit(); - play_menu::deinit(); - - bother::deinit(); - - client_chat::deinit(); - - background::deinit(); - - crosshair::deinit(); - - delete globals::dimension; - globals::player = entt::null; - globals::dimension = nullptr; - - item_registry::purge(); - voxel_registry::purge(); - - voxel_atlas::destroy(); - - glDeleteRenderbuffers(1, &globals::world_fbo_depth); - glDeleteTextures(1, &globals::world_fbo_color); - glDeleteFramebuffers(1, &globals::world_fbo); - - outline::deinit(); - chunk_renderer::deinit(); - chunk_mesher::deinit(); - - enet_host_destroy(globals::client_host); - - bin_unscii8 = nullptr; - bin_unscii16 = nullptr; -} - -void client_game::fixed_update(void) -{ - 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()) { - CollisionComponent::fixed_update(globals::dimension); - VelocityComponent::fixed_update(globals::dimension); - TransformComponent::fixed_update(globals::dimension); - GravityComponent::fixed_update(globals::dimension); - StasisComponent::fixed_update(globals::dimension); - } -} - -void client_game::fixed_update_late(void) -{ - if(session::is_ingame()) { - const auto& head = globals::dimension->entities.get<HeadComponent>(globals::player); - const auto& transform = globals::dimension->entities.get<TransformComponent>(globals::player); - const auto& velocity = globals::dimension->entities.get<VelocityComponent>(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<GravityComponent>(globals::player); - } else { - globals::dimension->entities.emplace_or_replace<GravityComponent>(globals::player); - } - } - - if(globals::sound_ctx) { - sound::update(); - - listener::update(); - - SoundEmitterComponent::update(); - } - - interpolation::update(); - - player_target::update(); - - camera::update(); - - voxel_anims::update(); - - chunk_mesher::update(); - - client_chat::update(); - - experiments::update(); -} - -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; - } - } - - player_look::update_late(); - player_move::update_late(); - - play_menu::update_late(); - - bother::update_late(); - - experiments::update_late(); - - gamepad::update_late(); - - chunk_visibility::update_late(); - - if(client_game::vertical_sync.get_value()) { - glfwSwapInterval(1); - } else { - glfwSwapInterval(0); - } -} - -void client_game::render(void) -{ - auto scaled_width = globals::width / vx::max<int>(1, client_game::pixel_size.get_value()); - auto scaled_height = globals::height / vx::max<int>(1, client_game::pixel_size.get_value()); - - glViewport(0, 0, scaled_width, scaled_height); - glBindFramebuffer(GL_FRAMEBUFFER, globals::world_fbo); - glClearColor(skybox::fog_color.r, skybox::fog_color.g, skybox::fog_color.b, 1.000f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - if(globals::dimension) { - chunk_renderer::render(); - } - - glEnable(GL_DEPTH_TEST); - - player_target::render(); - - if(globals::dimension) { - auto group = globals::dimension->entities.group( - entt::get<PlayerComponent, CollisionComponent, HeadComponentIntr, TransformComponentIntr>); - - outline::prepare(); - - for(const auto [entity, collision, head, transform] : group.each()) { - if(entity == globals::player) { - // Don't render ourselves - continue; - } - - glm::fvec3 forward; - cxangles::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; - - outline::cube(transform.chunk, hull_fpos, hull_size, 1.0f, glm::fvec4(1.0f, 0.0f, 0.0f, 1.0f)); - 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, scaled_width, scaled_height, 0, 0, globals::width, globals::height, GL_COLOR_BUFFER_BIT, GL_NEAREST); -} - -void client_game::layout(void) -{ - if(!session::is_ingame()) { - 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 - metrics::layout(); - } - } - - if(session::is_ingame()) { - client_chat::layout(); - scoreboard::layout(); - - if(!globals::gui_screen && !client_game::hide_hud) { - hotbar::layout(); - status_lines::layout(); - crosshair::layout(); - } - } - - if(globals::gui_screen) { - if(session::is_ingame() && (globals::gui_screen != GUI_CHAT)) { - const float width_f = static_cast<float>(globals::width); - const float height_f = static_cast<float>(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: - main_menu::layout(); - break; - case GUI_PLAY_MENU: - play_menu::layout(); - break; - case GUI_SETTINGS: - settings::layout(); - break; - case GUI_PROGRESS_BAR: - progress_bar::layout(); - break; - case GUI_MESSAGE_BOX: - message_box::layout(); - break; - case GUI_DIRECT_CONNECTION: - direct_connection::layout(); - break; - } - } -} diff --git a/game/client/game.hh b/game/client/game.hh deleted file mode 100644 index 0887703..0000000 --- a/game/client/game.hh +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef CLIENT_GAME_HH -#define CLIENT_GAME_HH 1 -#pragma once - -class ConfigBoolean; -class ConfigString; -class ConfigUnsigned; - -namespace client_game -{ -extern ConfigBoolean streamer_mode; -extern ConfigBoolean vertical_sync; -extern ConfigBoolean world_curvature; -extern ConfigUnsigned pixel_size; -extern ConfigUnsigned fog_mode; -extern ConfigString 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 deinit(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 - -#endif /* CLIENT_GAME_HH */ diff --git a/game/client/gamepad.cc b/game/client/gamepad.cc deleted file mode 100644 index 6cbcb3f..0000000 --- a/game/client/gamepad.cc +++ /dev/null @@ -1,168 +0,0 @@ -#include "client/pch.hh" - -#include "client/gamepad.hh" - -#include "core/cmdline.hh" -#include "core/config.hh" -#include "core/constexpr.hh" - -#include "client/glfw.hh" -#include "client/globals.hh" -#include "client/settings.hh" -#include "client/toggles.hh" - -constexpr static int INVALID_GAMEPAD_ID = INT_MAX; -constexpr static std::size_t NUM_AXES = static_cast<std::size_t>(GLFW_GAMEPAD_AXIS_LAST + 1); -constexpr static std::size_t NUM_BUTTONS = static_cast<std::size_t>(GLFW_GAMEPAD_BUTTON_LAST + 1); -constexpr static float GAMEPAD_AXIS_EVENT_THRESHOLD = 0.5f; - -static int active_gamepad_id; - -bool gamepad::available = false; -ConfigFloat gamepad::deadzone(0.00f, 0.00f, 0.66f); -ConfigBoolean gamepad::active(false); -GLFWgamepadstate gamepad::state; -GLFWgamepadstate gamepad::last_state; - -static void on_toggle_enable(const ToggleEnabledEvent& event) -{ - if(event.type == TOGGLE_USE_GAMEPAD) { - gamepad::active.set_value(true); - return; - } -} - -static void on_toggle_disable(const ToggleDisabledEvent& event) -{ - if(event.type == TOGGLE_USE_GAMEPAD) { - gamepad::active.set_value(false); - return; - } -} - -static void on_glfw_joystick_event(const GlfwJoystickEvent& event) -{ - if((event.event_type == GLFW_CONNECTED) && glfwJoystickIsGamepad(event.joystick_id) && (active_gamepad_id == INVALID_GAMEPAD_ID)) { - gamepad::available = true; - - active_gamepad_id = event.joystick_id; - - for(int i = 0; i < NUM_AXES; gamepad::last_state.axes[i++] = 0.0f) - ; - for(int i = 0; i < NUM_BUTTONS; gamepad::last_state.buttons[i++] = GLFW_RELEASE) - ; - - spdlog::info("gamepad: detected gamepad: {}", glfwGetGamepadName(event.joystick_id)); - - return; - } - - if((event.event_type == GLFW_DISCONNECTED) && (active_gamepad_id == event.joystick_id)) { - gamepad::available = false; - - active_gamepad_id = INVALID_GAMEPAD_ID; - - for(int i = 0; i < NUM_AXES; gamepad::last_state.axes[i++] = 0.0f) - ; - for(int i = 0; i < NUM_BUTTONS; gamepad::last_state.buttons[i++] = GLFW_RELEASE) - ; - - spdlog::warn("gamepad: disconnected"); - - return; - } -} - -void gamepad::init(void) -{ - gamepad::available = false; - - active_gamepad_id = INVALID_GAMEPAD_ID; - - globals::client_config.add_value("gamepad.deadzone", gamepad::deadzone); - globals::client_config.add_value("gamepad.active", gamepad::active); - - settings::add_checkbox(0, gamepad::active, settings_location::GAMEPAD, "gamepad.active", true); - settings::add_slider(1, gamepad::deadzone, settings_location::GAMEPAD, "gamepad.deadzone", true, "%.03f"); - - auto mappings_path = cmdline::get("gpmap", "misc/gamecontrollerdb.txt"); - auto mappings_file = PHYSFS_openRead(mappings_path); - - if(mappings_file) { - spdlog::info("gamepad: using mappings from {}", mappings_path); - auto mappings_string = std::string(PHYSFS_fileLength(mappings_file), char(0x00)); - PHYSFS_readBytes(mappings_file, mappings_string.data(), mappings_string.size()); - glfwUpdateGamepadMappings(mappings_string.c_str()); - PHYSFS_close(mappings_file); - } - - for(int joystick = 0; joystick <= GLFW_JOYSTICK_LAST; joystick += 1) { - if(glfwJoystickIsGamepad(joystick)) { - gamepad::available = true; - - active_gamepad_id = joystick; - - for(int i = 0; i < NUM_AXES; gamepad::last_state.axes[i++] = 0.0f) - ; - for(int i = 0; i < NUM_BUTTONS; gamepad::last_state.buttons[i++] = GLFW_RELEASE) - ; - - spdlog::info("gamepad: detected gamepad: {}", glfwGetGamepadName(joystick)); - - break; - } - } - - for(int i = 0; i < NUM_AXES; gamepad::state.axes[i++] = 0.0f) - ; - for(int i = 0; i < NUM_BUTTONS; gamepad::state.buttons[i++] = GLFW_RELEASE) - ; - - globals::dispatcher.sink<ToggleEnabledEvent>().connect<&on_toggle_enable>(); - globals::dispatcher.sink<ToggleDisabledEvent>().connect<&on_toggle_disable>(); - globals::dispatcher.sink<GlfwJoystickEvent>().connect<&on_glfw_joystick_event>(); -} - -void gamepad::update_late(void) -{ - if(active_gamepad_id == INVALID_GAMEPAD_ID) { - // No active gamepad found - return; - } - - if(glfwGetGamepadState(active_gamepad_id, &gamepad::state)) { - for(int i = 0; i < NUM_AXES; ++i) { - if((vx::abs(gamepad::state.axes[i]) > GAMEPAD_AXIS_EVENT_THRESHOLD) - && (vx::abs(gamepad::last_state.axes[i]) <= GAMEPAD_AXIS_EVENT_THRESHOLD)) { - GamepadAxisEvent event; - event.action = GLFW_PRESS; - event.axis = i; - globals::dispatcher.enqueue(event); - continue; - } - - if((vx::abs(gamepad::state.axes[i]) <= GAMEPAD_AXIS_EVENT_THRESHOLD) - && (vx::abs(gamepad::last_state.axes[i]) > GAMEPAD_AXIS_EVENT_THRESHOLD)) { - GamepadAxisEvent event; - event.action = GLFW_RELEASE; - event.axis = i; - globals::dispatcher.enqueue(event); - continue; - } - } - - for(int i = 0; i < NUM_BUTTONS; ++i) { - if(gamepad::state.buttons[i] == gamepad::last_state.buttons[i]) { - // Nothing happens - continue; - } - - GamepadButtonEvent event; - event.action = gamepad::state.buttons[i]; - event.button = i; - globals::dispatcher.enqueue(event); - } - } - - gamepad::last_state = gamepad::state; -} diff --git a/game/client/gamepad.hh b/game/client/gamepad.hh deleted file mode 100644 index d2483b7..0000000 --- a/game/client/gamepad.hh +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef CLIENT_GAMEPAD_HH -#define CLIENT_GAMEPAD_HH 1 -#pragma once - -constexpr static int INVALID_GAMEPAD_AXIS = INT_MAX; -constexpr static int INVALID_GAMEPAD_BUTTON = INT_MAX; - -class ConfigBoolean; -class ConfigFloat; - -struct GLFWgamepadstate; - -namespace gamepad -{ -extern bool available; -extern ConfigFloat deadzone; -extern ConfigBoolean active; -extern GLFWgamepadstate state; -extern GLFWgamepadstate last_state; -} // namespace gamepad - -namespace gamepad -{ -void init(void); -void update_late(void); -} // namespace gamepad - -// This simulates buttons using axes. When an axis -// value exceeds 1.5 times the deadzone, the event is -// queued with a GLFW_PRESS action, when it falls back -// below the threshold, the event is queued with GLFW_RELEASE action -struct GamepadAxisEvent final { - int action; - int axis; -}; - -// This smears GLFW event sugar over gamepad polling -// system. Whenever it detects a state change, the event -// is queued with an appropriate action -struct GamepadButtonEvent final { - int action; - int button; -}; - -#endif /* CLIENT_GAMEPAD_HH */ diff --git a/game/client/gamepad_axis.cc b/game/client/gamepad_axis.cc deleted file mode 100644 index 546c647..0000000 --- a/game/client/gamepad_axis.cc +++ /dev/null @@ -1,114 +0,0 @@ -#include "client/pch.hh" - -#include "client/gamepad_axis.hh" - -#include "core/constexpr.hh" - -#include "client/gamepad.hh" - -constexpr static const char* UNKNOWN_AXIS_NAME = "UNKNOWN"; - -static const std::pair<int, const char*> 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 const char* get_axis_name(int axis) -{ - for(const auto& it : axis_names) { - if(it.first != axis) { - continue; - } - - return it.second; - } - - return UNKNOWN_AXIS_NAME; -} - -ConfigGamepadAxis::ConfigGamepadAxis(void) : ConfigGamepadAxis(INVALID_GAMEPAD_AXIS, false) -{ -} - -ConfigGamepadAxis::ConfigGamepadAxis(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); -} - -const char* ConfigGamepadAxis::get(void) const -{ - return m_full_string.c_str(); -} - -void ConfigGamepadAxis::set(const char* value) -{ - char new_name[64]; - unsigned int new_invert; - - if(2 == std::sscanf(value, "%63[^:]:%u", new_name, &new_invert)) { - for(const auto& it : axis_names) { - if(!std::strcmp(it.second, 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 = INVALID_GAMEPAD_AXIS; - m_name = UNKNOWN_AXIS_NAME; - m_full_string = std::format("{}:{}", m_name, m_inverted ? 1U : 0U); -} - -int ConfigGamepadAxis::get_axis(void) const -{ - return m_gamepad_axis; -} - -void ConfigGamepadAxis::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 ConfigGamepadAxis::is_inverted(void) const -{ - return m_inverted; -} - -void ConfigGamepadAxis::set_inverted(bool inverted) -{ - m_inverted = inverted; - m_full_string = std::format("{}:{}", m_name, m_inverted ? 1U : 0U); -} - -float ConfigGamepadAxis::get_value(const GLFWgamepadstate& state, float deadzone) const -{ - if(m_gamepad_axis <= vx::array_size(state.axes)) { - auto value = state.axes[m_gamepad_axis]; - - if(vx::abs(value) > deadzone) { - return m_inverted ? -value : value; - } - - return 0.0f; - } - - return 0.0f; -} - -const char* ConfigGamepadAxis::get_name(void) const -{ - return m_name; -} diff --git a/game/client/gamepad_axis.hh b/game/client/gamepad_axis.hh deleted file mode 100644 index c0ed6ee..0000000 --- a/game/client/gamepad_axis.hh +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef CLIENT_GAMEPAD_AXIS_HH -#define CLIENT_GAMEPAD_AXIS_HH 1 -#pragma once - -#include "core/config.hh" - -struct GLFWgamepadstate; - -class ConfigGamepadAxis final : public IConfigValue { -public: - explicit ConfigGamepadAxis(void); - explicit ConfigGamepadAxis(int axis, bool inverted); - virtual ~ConfigGamepadAxis(void) = default; - - virtual const char* get(void) const override; - virtual void set(const char* 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 - const char* get_name(void) const; - -private: - bool m_inverted; - int m_gamepad_axis; - std::string m_full_string; - const char* m_name; -}; - -#endif /* CLIENT_GAMEPAD_AXIS_HH */ diff --git a/game/client/gamepad_button.cc b/game/client/gamepad_button.cc deleted file mode 100644 index dd3dca7..0000000 --- a/game/client/gamepad_button.cc +++ /dev/null @@ -1,90 +0,0 @@ -#include "client/pch.hh" - -#include "client/gamepad_button.hh" - -#include "core/constexpr.hh" - -#include "client/gamepad.hh" - -constexpr static const char* UNKNOWN_BUTTON_NAME = "UNKNOWN"; - -static const std::pair<int, const char*> 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 const char* get_button_name(int button) -{ - for(const auto& it : button_names) { - if(it.first == button) { - return it.second; - } - } - - return UNKNOWN_BUTTON_NAME; -} - -ConfigGamepadButton::ConfigGamepadButton(void) -{ - m_gamepad_button = INVALID_GAMEPAD_BUTTON; - m_name = UNKNOWN_BUTTON_NAME; -} - -ConfigGamepadButton::ConfigGamepadButton(int button) -{ - m_gamepad_button = button; - m_name = get_button_name(button); -} - -const char* ConfigGamepadButton::get(void) const -{ - return m_name; -} - -void ConfigGamepadButton::set(const char* value) -{ - for(const auto& it : button_names) { - if(!std::strcmp(it.second, value)) { - m_gamepad_button = it.first; - m_name = it.second; - return; - } - } - - m_gamepad_button = INVALID_GAMEPAD_BUTTON; - m_name = UNKNOWN_BUTTON_NAME; -} - -int ConfigGamepadButton::get_button(void) const -{ - return m_gamepad_button; -} - -void ConfigGamepadButton::set_button(int button) -{ - m_gamepad_button = button; - m_name = get_button_name(button); -} - -bool ConfigGamepadButton::equals(int button) const -{ - return m_gamepad_button == button; -} - -bool ConfigGamepadButton::is_pressed(const GLFWgamepadstate& state) const -{ - return m_gamepad_button < vx::array_size(state.buttons) && state.buttons[m_gamepad_button] == GLFW_PRESS; -} diff --git a/game/client/gamepad_button.hh b/game/client/gamepad_button.hh deleted file mode 100644 index 04b3a41..0000000 --- a/game/client/gamepad_button.hh +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef CLIENT_GAMEPAD_BUTTON_HH -#define CLIENT_GAMEPAD_BUTTON_HH 1 -#pragma once - -#include "core/config.hh" - -struct GLFWgamepadstate; - -class ConfigGamepadButton final : public IConfigValue { -public: - explicit ConfigGamepadButton(void); - explicit ConfigGamepadButton(int button); - virtual ~ConfigGamepadButton(void) = default; - - virtual const char* get(void) const override; - virtual void set(const char* 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; - const char* m_name; -}; - -#endif /* CLIENT_GAMEPAD_BUTTON_HH */ diff --git a/game/client/glfw.hh b/game/client/glfw.hh deleted file mode 100644 index 9cdf734..0000000 --- a/game/client/glfw.hh +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef CLIENTFW -#define CLIENTFW 1 -#pragma once - -struct GlfwCursorPosEvent final { - glm::fvec2 pos; -}; - -struct GlfwFramebufferSizeEvent final { - glm::ivec2 size; - float aspect; -}; - -struct GlfwJoystickEvent final { - int joystick_id; - int event_type; -}; - -struct GlfwKeyEvent final { - int key { GLFW_KEY_UNKNOWN }; - int scancode; - int action; - int mods; -}; - -struct GlfwMouseButtonEvent final { - int button { GLFW_KEY_UNKNOWN }; - int action; - int mods; -}; - -struct GlfwScrollEvent final { - float dx; - float dy; -}; - -#endif /* CLIENTFW */ diff --git a/game/client/globals.cc b/game/client/globals.cc deleted file mode 100644 index 6e00680..0000000 --- a/game/client/globals.cc +++ /dev/null @@ -1,48 +0,0 @@ -#include "client/pch.hh" - -#include "client/globals.hh" - -#include "core/config.hh" - -#include "client/gui_screen.hh" - -Config 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; - -Dimension* globals::dimension = nullptr; -entt::entity globals::player; - -ImFont* globals::font_debug; -ImFont* globals::font_default; -ImFont* globals::font_chat; - -ConfigKeyBind* globals::gui_keybind_ptr = nullptr; -ConfigGamepadAxis* globals::gui_gamepad_axis_ptr = nullptr; -ConfigGamepadButton* 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 3fc2223..0000000 --- a/game/client/globals.hh +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef CLIENTOBALS_HH -#define CLIENTOBALS_HH 1 -#pragma once - -#include "shared/globals.hh" - -class Config; -class ConfigKeyBind; -class ConfigGamepadAxis; -class ConfigGamepadButton; - -struct GLFWwindow; -struct ImFont; - -class Dimension; - -namespace globals -{ -extern Config 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 Dimension* dimension; -extern entt::entity player; - -extern ImFont* font_debug; -extern ImFont* font_default; -extern ImFont* font_chat; - -extern ConfigKeyBind* gui_keybind_ptr; -extern ConfigGamepadAxis* gui_gamepad_axis_ptr; -extern ConfigGamepadButton* gui_gamepad_button_ptr; - -extern unsigned int gui_scale; -extern unsigned int gui_screen; - -extern ALCdevice* sound_dev; -extern ALCcontext* sound_ctx; -} // namespace globals - -#endif /* CLIENTOBALS_HH */ diff --git a/game/client/gui_screen.hh b/game/client/gui_screen.hh deleted file mode 100644 index edad116..0000000 --- a/game/client/gui_screen.hh +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef CLIENT_GUI_SCREEN_HH -#define CLIENT_GUI_SCREEN_HH 1 -#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; - -#endif /* CLIENT_GUI_SCREEN_HH */ diff --git a/game/client/hotbar.cc b/game/client/hotbar.cc deleted file mode 100644 index a2ed859..0000000 --- a/game/client/hotbar.cc +++ /dev/null @@ -1,178 +0,0 @@ -#include "client/pch.hh" - -#include "client/hotbar.hh" - -#include "core/config.hh" -#include "core/resource.hh" - -#include "shared/item_registry.hh" - -#include "client/glfw.hh" -#include "client/globals.hh" -#include "client/keybind.hh" -#include "client/settings.hh" -#include "client/status_lines.hh" -#include "client/texture_gui.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 hotbar::active_slot = 0U; -item_id hotbar::slots[HOTBAR_SIZE]; - -static ConfigKeyBind hotbar_keys[HOTBAR_SIZE]; - -static resource_ptr<TextureGUI> hotbar_background; -static resource_ptr<TextureGUI> 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) -{ - if(hotbar::slots[hotbar::active_slot] == NULL_ITEM_ID) { - status_lines::unset(STATUS_HOTBAR); - return; - } - - if(auto info = item_registry::find(hotbar::slots[hotbar::active_slot])) { - status_lines::set(STATUS_HOTBAR, info->name, ImVec4(1.0f, 1.0f, 1.0f, 1.0f), 5.0f); - return; - } -} - -static void on_glfw_key(const 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)) { - hotbar::active_slot = i; - update_hotbar_item(); - break; - } - } - } -} - -static void on_glfw_scroll(const GlfwScrollEvent& event) -{ - if(!globals::gui_screen) { - if(event.dy < 0.0) { - hotbar::next_slot(); - return; - } - - if(event.dy > 0.0) { - hotbar::prev_slot(); - return; - } - } -} - -void 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<TextureGUI>("textures/gui/hud_hotbar.png", TEXTURE_GUI_LOAD_CLAMP_S | TEXTURE_GUI_LOAD_CLAMP_T); - hotbar_selector = resource::load<TextureGUI>("textures/gui/hud_selector.png", TEXTURE_GUI_LOAD_CLAMP_S | TEXTURE_GUI_LOAD_CLAMP_T); - - globals::dispatcher.sink<GlfwKeyEvent>().connect<&on_glfw_key>(); - globals::dispatcher.sink<GlfwScrollEvent>().connect<&on_glfw_scroll>(); -} - -void hotbar::deinit(void) -{ - hotbar_background = nullptr; - hotbar_selector = nullptr; -} - -void 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 + 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) { - const auto info = item_registry::find(hotbar::slots[i]); - - if((info == nullptr) || (info->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(info->cached_texture->handle, item_start, item_end); - } -} - -void hotbar::next_slot(void) -{ - hotbar::active_slot += 1U; - hotbar::active_slot %= HOTBAR_SIZE; - update_hotbar_item(); -} - -void hotbar::prev_slot(void) -{ - hotbar::active_slot += HOTBAR_SIZE - 1U; - hotbar::active_slot %= HOTBAR_SIZE; - update_hotbar_item(); -} diff --git a/game/client/hotbar.hh b/game/client/hotbar.hh deleted file mode 100644 index 318c631..0000000 --- a/game/client/hotbar.hh +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef CLIENT_HOTBAR_HH -#define CLIENT_HOTBAR_HH 1 -#pragma once - -#include "shared/types.hh" - -// TODO: design an inventory system and an item -// registry and integrate the hotbar into that system - -constexpr static unsigned int HOTBAR_SIZE = 9U; - -namespace hotbar -{ -extern unsigned int active_slot; -extern item_id slots[HOTBAR_SIZE]; -} // namespace hotbar - -namespace hotbar -{ -void init(void); -void deinit(void); -void layout(void); -} // namespace hotbar - -namespace hotbar -{ -void next_slot(void); -void prev_slot(void); -} // namespace hotbar - -#endif /* CLIENT_HOTBAR_HH */ diff --git a/game/client/imdraw_ext.cc b/game/client/imdraw_ext.cc deleted file mode 100644 index 67df3c8..0000000 --- a/game/client/imdraw_ext.cc +++ /dev/null @@ -1,13 +0,0 @@ -#include "client/pch.hh" - -#include "client/imdraw_ext.hh" - -#include "client/globals.hh" - -void imdraw_ext::text_shadow( - const std::string& text, const ImVec2& position, ImU32 text_color, ImU32 shadow_color, ImFont* font, ImDrawList* draw_list) -{ - const auto shadow_position = ImVec2(position.x + 0.5f * globals::gui_scale, position.y + 0.5f * globals::gui_scale); - draw_list->AddText(font, font->FontSize, shadow_position, shadow_color, text.c_str(), text.c_str() + text.size()); - draw_list->AddText(font, font->FontSize, position, text_color, text.c_str(), text.c_str() + text.size()); -} diff --git a/game/client/imdraw_ext.hh b/game/client/imdraw_ext.hh deleted file mode 100644 index 0a84e69..0000000 --- a/game/client/imdraw_ext.hh +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef CLIENT_IMDRAW_EXT_HH -#define CLIENT_IMDRAW_EXT_HH 1 -#pragma once - -namespace imdraw_ext -{ -void text_shadow( - const std::string& text, const ImVec2& position, ImU32 text_color, ImU32 shadow_color, ImFont* font, ImDrawList* draw_list); -} // namespace imdraw_ext - -#endif /* CLIENT_IMDRAW_EXT_HH */ diff --git a/game/client/interpolation.cc b/game/client/interpolation.cc deleted file mode 100644 index 27b6dfd..0000000 --- a/game/client/interpolation.cc +++ /dev/null @@ -1,61 +0,0 @@ -#include "client/pch.hh" - -#include "client/interpolation.hh" - -#include "core/constexpr.hh" - -#include "shared/coord.hh" -#include "shared/dimension.hh" -#include "shared/head.hh" -#include "shared/transform.hh" - -#include "client/globals.hh" - -static void transform_interpolate(float alpha) -{ - auto group = globals::dimension->entities.group<TransformComponentIntr>(entt::get<TransformComponent, TransformComponentPrev>); - - for(auto [entity, interp, current, previous] : group.each()) { - interp.angles[0] = vx::lerp(previous.angles[0], current.angles[0], alpha); - interp.angles[1] = vx::lerp(previous.angles[1], current.angles[1], alpha); - interp.angles[2] = vx::lerp(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 = vx::lerp(previous_local.x, current.local.x, alpha); - interp.local.y = vx::lerp(previous_local.y, current.local.y, alpha); - interp.local.z = vx::lerp(previous_local.z, current.local.z, alpha); - } -} - -static void head_interpolate(float alpha) -{ - auto group = globals::dimension->entities.group<HeadComponentIntr>(entt::get<HeadComponent, HeadComponentPrev>); - - for(auto [entity, interp, current, previous] : group.each()) { - interp.angles[0] = vx::lerp(previous.angles[0], current.angles[0], alpha); - interp.angles[1] = vx::lerp(previous.angles[1], current.angles[1], alpha); - interp.angles[2] = vx::lerp(previous.angles[2], current.angles[2], alpha); - - interp.offset.x = vx::lerp(previous.offset.x, current.offset.x, alpha); - interp.offset.y = vx::lerp(previous.offset.y, current.offset.y, alpha); - interp.offset.z = vx::lerp(previous.offset.z, current.offset.z, alpha); - } -} - -void interpolation::update(void) -{ - if(globals::dimension) { - auto alpha = static_cast<float>(globals::fixed_accumulator) / static_cast<float>(globals::fixed_frametime_us); - transform_interpolate(alpha); - head_interpolate(alpha); - } -}
\ No newline at end of file diff --git a/game/client/interpolation.hh b/game/client/interpolation.hh deleted file mode 100644 index 3565a26..0000000 --- a/game/client/interpolation.hh +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef CLIENT_INTERPOLATION_HH -#define CLIENT_INTERPOLATION_HH 1 -#pragma once - -namespace interpolation -{ -void update(void); -} // namespace interpolation - -#endif /* CLIENT_INTERPOLATION_HH */ diff --git a/game/client/keybind.cc b/game/client/keybind.cc deleted file mode 100644 index d47397d..0000000 --- a/game/client/keybind.cc +++ /dev/null @@ -1,200 +0,0 @@ -#include "client/pch.hh" - -#include "client/keybind.hh" - -#include "core/constexpr.hh" - -#include "client/const.hh" - -constexpr static const char* UNKNOWN_KEY_NAME = "UNKNOWN"; - -static const std::pair<int, const char*> 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 const char* get_key_name(int keycode) -{ - for(const auto& it : key_names) { - if(it.first == keycode) { - return it.second; - } - } - - return UNKNOWN_KEY_NAME; -} - -ConfigKeyBind::ConfigKeyBind(void) -{ - m_glfw_keycode = GLFW_KEY_UNKNOWN; - m_name = UNKNOWN_KEY_NAME; -} - -ConfigKeyBind::ConfigKeyBind(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 ConfigKeyBind::set(const char* value) -{ - for(const auto& it : key_names) { - if((it.first != DEBUG_KEY) && !std::strcmp(it.second, value)) { - m_glfw_keycode = it.first; - m_name = it.second; - return; - } - } - - m_glfw_keycode = GLFW_KEY_UNKNOWN; - m_name = UNKNOWN_KEY_NAME; -} - -const char* ConfigKeyBind::get(void) const -{ - return m_name; -} - -void ConfigKeyBind::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 ConfigKeyBind::get_key(void) const -{ - return m_glfw_keycode; -} - -bool ConfigKeyBind::equals(int keycode) const -{ - return m_glfw_keycode == keycode; -} diff --git a/game/client/keybind.hh b/game/client/keybind.hh deleted file mode 100644 index 8cf3c3c..0000000 --- a/game/client/keybind.hh +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef CLIENT_KEYBIND_HH -#define CLIENT_KEYBIND_HH 1 -#pragma once - -#include "core/config.hh" - -class ConfigKeyBind final : public IConfigValue { -public: - explicit ConfigKeyBind(void); - explicit ConfigKeyBind(int default_value); - virtual ~ConfigKeyBind(void) = default; - - virtual void set(const char* value) override; - virtual const char* get(void) const override; - - void set_key(int keycode); - int get_key(void) const; - - bool equals(int keycode) const; - -private: - const char* m_name; - int m_glfw_keycode; -}; - -#endif /* CLIENT_KEYBIND_HH */ diff --git a/game/client/language.cc b/game/client/language.cc deleted file mode 100644 index 2ae0bc6..0000000 --- a/game/client/language.cc +++ /dev/null @@ -1,196 +0,0 @@ -#include "client/pch.hh" - -#include "client/language.hh" - -#include "core/config.hh" - -#include "client/globals.hh" -#include "client/settings.hh" - -constexpr static const char* 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 const char* MANIFEST_PATH = "lang/manifest.json"; - -static LanguageManifest manifest; -static LanguageIterator current_language; -static std::unordered_map<std::string, std::string> language_map; -static std::unordered_map<std::string, LanguageIterator> ietf_map; -static ConfigString config_language(DEFAULT_LANGUAGE); - -static void send_language_event(LanguageIterator new_language) -{ - LanguageSetEvent event; - event.new_language = new_language; - globals::dispatcher.trigger(event); -} - -void language::init(void) -{ - globals::client_config.add_value("language", config_language); - - settings::add_language_select(0, settings_location::GENERAL, "language"); - - auto file = PHYSFS_openRead(MANIFEST_PATH); - - if(file == nullptr) { - spdlog::critical("language: {}: {}", MANIFEST_PATH, PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); - 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 language::init_late(void) -{ - auto user_language = ietf_map.find(config_language.get()); - - if(user_language != ietf_map.cend()) { - language::set(user_language->second); - return; - } - - auto fallback = ietf_map.find(DEFAULT_LANGUAGE); - - if(fallback != ietf_map.cend()) { - language::set(fallback->second); - return; - } - - spdlog::critical("language: we're doomed!"); - spdlog::critical("language: {} doesn't exist!", DEFAULT_LANGUAGE); - std::terminate(); -} - -void 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, PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); - 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); -} - -LanguageIterator language::get_current(void) -{ - return current_language; -} - -LanguageIterator language::find(const char* ietf) -{ - const auto it = ietf_map.find(ietf); - if(it != ietf_map.cend()) { - return it->second; - } else { - return manifest.cend(); - } -} - -LanguageIterator language::cbegin(void) -{ - return manifest.cbegin(); -} - -LanguageIterator language::cend(void) -{ - return manifest.cend(); -} - -const char* language::resolve(const char* key) -{ - const auto it = language_map.find(key); - if(it != language_map.cend()) { - return it->second.c_str(); - } else { - return key; - } -} - -std::string language::resolve_gui(const char* 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("{}###{}", language::resolve(key), key); -} diff --git a/game/client/language.hh b/game/client/language.hh deleted file mode 100644 index 680cd92..0000000 --- a/game/client/language.hh +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef CLIENT_LANGUAGE_HH -#define CLIENT_LANGUAGE_HH 1 -#pragma once - -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<LanguageInfo>; -using LanguageIterator = LanguageManifest::const_iterator; - -struct LanguageSetEvent final { - LanguageIterator new_language; -}; - -namespace language -{ -void init(void); -void init_late(void); -} // namespace language - -namespace language -{ -void set(LanguageIterator new_language); -} // namespace language - -namespace language -{ -LanguageIterator get_current(void); -LanguageIterator find(const char* ietf); -LanguageIterator cbegin(void); -LanguageIterator cend(void); -} // namespace language - -namespace language -{ -const char* resolve(const char* key); -std::string resolve_gui(const char* key); -} // namespace language - -#endif /* CLIENT_LANGUAGE_HH */ diff --git a/game/client/listener.cc b/game/client/listener.cc deleted file mode 100644 index 6b691eb..0000000 --- a/game/client/listener.cc +++ /dev/null @@ -1,38 +0,0 @@ -#include "client/pch.hh" - -#include "client/listener.hh" - -#include "core/config.hh" -#include "core/constexpr.hh" - -#include "shared/dimension.hh" -#include "shared/velocity.hh" - -#include "client/camera.hh" -#include "client/const.hh" -#include "client/globals.hh" -#include "client/session.hh" -#include "client/sound.hh" - -void listener::update(void) -{ - if(session::is_ingame()) { - const auto& velocity = globals::dimension->entities.get<VelocityComponent>(globals::player).value; - const auto& position = 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] = camera::direction.x; - orientation[1] = camera::direction.y; - orientation[2] = camera::direction.z; - orientation[3] = DIR_UP<float>.x; - orientation[4] = DIR_UP<float>.y; - orientation[5] = DIR_UP<float>.z; - - alListenerfv(AL_ORIENTATION, orientation); - } - - alListenerf(AL_GAIN, vx::clamp(sound::volume_master.get_value() * 0.01f, 0.0f, 1.0f)); -} diff --git a/game/client/listener.hh b/game/client/listener.hh deleted file mode 100644 index 731babc..0000000 --- a/game/client/listener.hh +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef CLIENT_LISTENER_HH -#define CLIENT_LISTENER_HH 1 -#pragma once - -namespace listener -{ -void update(void); -} // namespace listener - -#endif /* CLIENT_LISTENER_HH */ diff --git a/game/client/main.cc b/game/client/main.cc deleted file mode 100644 index d9e915c..0000000 --- a/game/client/main.cc +++ /dev/null @@ -1,441 +0,0 @@ -#include "client/pch.hh" - -#include "core/binfile.hh" -#include "core/cmdline.hh" -#include "core/config.hh" -#include "core/epoch.hh" -#include "core/image.hh" -#include "core/resource.hh" -#include "core/version.hh" - -#include "shared/game.hh" -#include "shared/splash.hh" -#include "shared/threading.hh" - -#include "client/const.hh" -#include "client/game.hh" -#include "client/glfw.hh" -#include "client/globals.hh" -#include "client/sound_effect.hh" -#include "client/texture_gui.hh" -#include "client/window_title.hh" - -#if defined(_WIN32) -extern "C" __declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001; -extern "C" __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; -#endif - -static void on_glfw_error(int code, const char* message) -{ - spdlog::error("glfw: {}", message); -} - -static void on_glfw_char(GLFWwindow* window, unsigned int codepoint) -{ - ImGui_ImplGlfw_CharCallback(window, codepoint); -} - -static void on_glfw_cursor_enter(GLFWwindow* window, int entered) -{ - ImGui_ImplGlfw_CursorEnterCallback(window, entered); -} - -static void on_glfw_cursor_pos(GLFWwindow* window, double xpos, double ypos) -{ - GlfwCursorPosEvent event; - event.pos.x = static_cast<float>(xpos); - event.pos.y = static_cast<float>(ypos); - globals::dispatcher.trigger(event); - - ImGui_ImplGlfw_CursorPosCallback(window, xpos, ypos); -} - -static void on_glfw_framebuffer_size(GLFWwindow* window, int width, int height) -{ - if(glfwGetWindowAttrib(window, GLFW_ICONIFIED)) { - // Don't do anything if the window was just - // iconified (minimized); as it turns out minimized - // windows on WIN32 seem to be forced into 0x0 - return; - } - - globals::width = width; - globals::height = height; - globals::aspect = static_cast<float>(width) / static_cast<float>(height); - - GlfwFramebufferSizeEvent fb_event; - fb_event.size.x = globals::width; - fb_event.size.y = globals::height; - fb_event.aspect = globals::aspect; - globals::dispatcher.trigger(fb_event); -} - -static void on_glfw_key(GLFWwindow* window, int key, int scancode, int action, int mods) -{ - GlfwKeyEvent event; - event.key = key; - event.scancode = scancode; - event.action = action; - event.mods = mods; - globals::dispatcher.trigger(event); - - ImGui_ImplGlfw_KeyCallback(window, key, scancode, action, mods); -} - -static void on_glfw_joystick(int joystick_id, int event_type) -{ - GlfwJoystickEvent event; - event.joystick_id = joystick_id; - event.event_type = event_type; - globals::dispatcher.trigger(event); -} - -static void on_glfw_monitor_event(GLFWmonitor* monitor, int event) -{ - ImGui_ImplGlfw_MonitorCallback(monitor, event); -} - -static void on_glfw_mouse_button(GLFWwindow* window, int button, int action, int mods) -{ - GlfwMouseButtonEvent event; - event.button = button; - event.action = action; - event.mods = mods; - globals::dispatcher.trigger(event); - - ImGui_ImplGlfw_MouseButtonCallback(window, button, action, mods); -} - -static void on_glfw_scroll(GLFWwindow* window, double dx, double dy) -{ - GlfwScrollEvent event; - event.dx = static_cast<float>(dx); - event.dy = static_cast<float>(dy); - globals::dispatcher.trigger(event); - - ImGui_ImplGlfw_ScrollCallback(window, dx, dy); -} - -static void on_glfw_window_focus(GLFWwindow* window, int focused) -{ - ImGui_ImplGlfw_WindowFocusCallback(window, focused); -} - -static void GLAD_API_PTR on_opengl_message( - GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* param) -{ - spdlog::info("opengl: {}", reinterpret_cast<const char*>(message)); -} - -static void on_termination_signal(int) -{ - spdlog::warn("client: received termination signal"); - glfwSetWindowShouldClose(globals::window, true); -} - -int main(int argc, char** argv) -{ - cmdline::create(argc, argv); - -#if defined(_WIN32) -#if defined(NDEBUG) - if(GetConsoleWindow() && !cmdline::contains("debug")) { - // Hide the console window on release builds - // unless explicitly specified to preserve it instead - FreeConsole(); - } -#else - if(GetConsoleWindow() && cmdline::contains("nodebug")) { - // Hide the console window on debug builds when - // explicitly specified by the user to hide it - FreeConsole(); - } -#endif -#endif - - shared_game::init(argc, argv); - - spdlog::info("Voxelius Client {}", project_version_string); - - glfwSetErrorCallback(&on_glfw_error); - -#if defined(__unix__) - // Wayland constantly throws random bullshit at me - // when I'm dealing with pretty much anything cross-platform - // on pretty much any kind of UNIX and Linux distribution - glfwInitHint(GLFW_PLATFORM, GLFW_PLATFORM_X11); -#endif - - if(!glfwInit()) { - spdlog::critical("glfw: init failed"); - std::terminate(); - } - - glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_SAMPLES, 0); - - globals::window = glfwCreateWindow(DEFAULT_WIDTH, DEFAULT_HEIGHT, "Client", nullptr, nullptr); - - if(!globals::window) { - spdlog::critical("glfw: failed to open a window"); - std::terminate(); - } - - std::signal(SIGINT, &on_termination_signal); - std::signal(SIGTERM, &on_termination_signal); - - glfwMakeContextCurrent(globals::window); - glfwSwapInterval(1); - - if(!gladLoadGL(&glfwGetProcAddress)) { - spdlog::critical("glad: failed to load function pointers"); - std::terminate(); - } - - if(GLAD_GL_KHR_debug) { - if(!cmdline::contains("nodebug")) { - glEnable(GL_DEBUG_OUTPUT); - glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - glDebugMessageCallback(&on_opengl_message, nullptr); - - // NVIDIA drivers tend to spam quote-unquote "useful" - // information about buffer usage into the debug callback - static const std::uint32_t ignore_nvidia_131185 = 131185; - glDebugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_OTHER, GL_DONT_CARE, 1, &ignore_nvidia_131185, GL_FALSE); - } else { - spdlog::warn("glad: nodebug command line parameter found"); - spdlog::warn("glad: OpenGL errors will not be logged"); - } - } else { - spdlog::warn("glad: KHR_debug extension not supported"); - spdlog::warn("glad: OpenGL errors will not be logged"); - } - - spdlog::info("opengl: version: {}", reinterpret_cast<const char*>(glGetString(GL_VERSION))); - spdlog::info("opengl: renderer: {}", reinterpret_cast<const char*>(glGetString(GL_RENDERER))); - - glDisable(GL_MULTISAMPLE); - - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - ImGui::StyleColorsDark(); - ImGui_ImplGlfw_InitForOpenGL(globals::window, false); - ImGui_ImplOpenGL3_Init(nullptr); - - // The UI is scaled against a resolution defined by BASE_WIDTH and BASE_HEIGHT - // constants. However, UI scale of 1 doesn't look that good, so the window size is - // limited to a resolution that allows at least UI scale of 2 and is defined by MIN_WIDTH and MIN_HEIGHT. - glfwSetWindowSizeLimits(globals::window, MIN_WIDTH, MIN_HEIGHT, GLFW_DONT_CARE, GLFW_DONT_CARE); - - glfwSetCharCallback(globals::window, &on_glfw_char); - glfwSetCursorEnterCallback(globals::window, &on_glfw_cursor_enter); - glfwSetCursorPosCallback(globals::window, &on_glfw_cursor_pos); - glfwSetFramebufferSizeCallback(globals::window, &on_glfw_framebuffer_size); - glfwSetKeyCallback(globals::window, &on_glfw_key); - glfwSetMouseButtonCallback(globals::window, &on_glfw_mouse_button); - glfwSetScrollCallback(globals::window, &on_glfw_scroll); - glfwSetWindowFocusCallback(globals::window, &on_glfw_window_focus); - - glfwSetJoystickCallback(&on_glfw_joystick); - glfwSetMonitorCallback(&on_glfw_monitor_event); - - if(auto image = resource::load<Image>("textures/gui/window_icon.png")) { - GLFWimage icon_image; - icon_image.width = image->size.x; - icon_image.height = image->size.y; - icon_image.pixels = reinterpret_cast<unsigned char*>(image->pixels); - glfwSetWindowIcon(globals::window, 1, &icon_image); - } - - if(cmdline::contains("nosound")) { - spdlog::warn("client: sound disabled [per command line]"); - globals::sound_dev = nullptr; - globals::sound_ctx = nullptr; - } else { - if(!saladLoadALdefault()) { - spdlog::warn("client: sound disabled [openal loading failed]"); - globals::sound_dev = nullptr; - globals::sound_ctx = nullptr; - } else { - globals::sound_dev = alcOpenDevice(nullptr); - - if(globals::sound_dev == nullptr) { - spdlog::warn("client: sound disabled [no device]"); - globals::sound_ctx = nullptr; - } else { - spdlog::info("sound: {}", reinterpret_cast<const char*>(alcGetString(globals::sound_dev, ALC_DEVICE_SPECIFIER))); - - globals::sound_ctx = alcCreateContext(globals::sound_dev, nullptr); - - if(globals::sound_ctx == nullptr) { - spdlog::warn("client: sound disabled [context creation failed]"); - alcCloseDevice(globals::sound_dev); - globals::sound_dev = nullptr; - } else { - alcMakeContextCurrent(globals::sound_ctx); - } - } - } - } - - splash::init_client(); - - window_title::update(); - - ImGuiIO& io = ImGui::GetIO(); - io.ConfigFlags &= ~ImGuiConfigFlags_NavEnableGamepad; - io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; - - globals::fixed_frametime = 0.0f; - globals::fixed_frametime_avg = 0.0f; - globals::fixed_frametime_us = UINT64_MAX; - globals::fixed_framecount = 0; - - globals::curtime = epoch::microseconds(); - - globals::window_frametime = 0.0f; - globals::window_frametime_avg = 0.0f; - globals::window_frametime_us = 0; - globals::window_framecount = 0; - - int vmode_width = DEFAULT_WIDTH; - int vmode_height = DEFAULT_HEIGHT; - - if(auto vmode = cmdline::get("mode")) { - std::sscanf(vmode, "%dx%d", &vmode_width, &vmode_height); - vmode_height = vx::max(vmode_height, MIN_HEIGHT); - vmode_width = vx::max(vmode_width, MIN_WIDTH); - } - - glfwSetWindowSize(globals::window, vmode_width, vmode_height); - - client_game::init(); - - int wwidth, wheight; - glfwGetFramebufferSize(globals::window, &wwidth, &wheight); - on_glfw_framebuffer_size(globals::window, wwidth, wheight); - - threading::init(); - - globals::client_config.load_file("client.conf"); - globals::client_config.load_cmdline(); - - client_game::init_late(); - - auto last_curtime = globals::curtime; - - while(!glfwWindowShouldClose(globals::window)) { - globals::curtime = epoch::microseconds(); - - globals::window_frametime_us = globals::curtime - last_curtime; - globals::window_frametime = static_cast<float>(globals::window_frametime_us) / 1000000.0f; - globals::window_frametime_avg += globals::window_frametime; - globals::window_frametime_avg *= 0.5f; - - if(globals::fixed_frametime_us == UINT64_MAX) { - globals::fixed_framecount = 0; - globals::fixed_accumulator = 0; - } else { - globals::fixed_accumulator += globals::window_frametime_us; - globals::fixed_framecount = globals::fixed_accumulator / globals::fixed_frametime_us; - globals::fixed_accumulator %= globals::fixed_frametime_us; - } - - globals::num_drawcalls = 0; - globals::num_triangles = 0; - - last_curtime = globals::curtime; - - for(std::uint64_t i = 0; i < globals::fixed_framecount; ++i) - client_game::fixed_update(); - client_game::update(); - - ImGui_ImplOpenGL3_NewFrame(); - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - glDisable(GL_BLEND); - - glDisable(GL_DEPTH_TEST); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glViewport(0, 0, globals::width, globals::height); - - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); - - // Make sure there is no stray program object - // being bound to the context. Usually third-party - // overlay software (such as RivaTuner) injects itself - // into the rendering loop and binds internal objects, - // which creates an incomprehensible visual mess - glUseProgram(0); - - client_game::render(); - - client_game::layout(); - - ImGui::Render(); - ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); - - glfwSwapBuffers(globals::window); - - for(std::uint64_t i = 0; i < globals::fixed_framecount; ++i) - client_game::fixed_update_late(); - client_game::update_late(); - - glfwPollEvents(); - - // EnTT provides two ways of dispatching events: - // queued and immediate. When glfwPollEvents() is - // called, immediate events are triggered across - // the application, whilst queued ones are triggered - // later by calling entt::dispatcher::update() - globals::dispatcher.update(); - - globals::window_framecount += 1; - - resource::soft_cleanup<BinFile>(); - resource::soft_cleanup<Image>(); - - resource::soft_cleanup<SoundEffect>(); - resource::soft_cleanup<TextureGUI>(); - - threading::update(); - } - - client_game::deinit(); - - resource::hard_cleanup<BinFile>(); - resource::hard_cleanup<Image>(); - - resource::hard_cleanup<SoundEffect>(); - resource::hard_cleanup<TextureGUI>(); - - spdlog::info("client: shutdown after {} frames", globals::window_framecount); - spdlog::info("client: average framerate: {:.03f} FPS", 1.0f / globals::window_frametime_avg); - spdlog::info("client: average frametime: {:.03f} ms", 1000.0f * globals::window_frametime_avg); - - ImGui_ImplOpenGL3_Shutdown(); - ImGui_ImplGlfw_Shutdown(); - ImGui::DestroyContext(); - - if(globals::sound_ctx) { - alcMakeContextCurrent(nullptr); - alcDestroyContext(globals::sound_ctx); - alcCloseDevice(globals::sound_dev); - } - - glfwDestroyWindow(globals::window); - glfwTerminate(); - - globals::client_config.save_file("client.conf"); - - threading::deinit(); - - shared_game::deinit(); - - return EXIT_SUCCESS; -} diff --git a/game/client/main_menu.cc b/game/client/main_menu.cc deleted file mode 100644 index 39763ec..0000000 --- a/game/client/main_menu.cc +++ /dev/null @@ -1,163 +0,0 @@ -#include "client/pch.hh" - -#include "client/main_menu.hh" - -#include "core/constexpr.hh" -#include "core/resource.hh" -#include "core/version.hh" - -#include "client/glfw.hh" -#include "client/globals.hh" -#include "client/gui_screen.hh" -#include "client/language.hh" -#include "client/session.hh" -#include "client/texture_gui.hh" -#include "client/window_title.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<TextureGUI> title; -static float title_aspect; - -static void on_glfw_key(const 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 LanguageSetEvent& event) -{ - str_play = language::resolve_gui("main_menu.play"); - str_resume = language::resolve_gui("main_menu.resume"); - str_settings = language::resolve("main_menu.settings"); - str_leave = language::resolve("main_menu.leave"); - str_quit = language::resolve("main_menu.quit"); -} - -void main_menu::init(void) -{ - title = resource::load<TextureGUI>("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<float>(title->size.x) / static_cast<float>(title->size.y); - } else { - title_aspect = static_cast<float>(title->size.y) / static_cast<float>(title->size.x); - } - - globals::dispatcher.sink<GlfwKeyEvent>().connect<&on_glfw_key>(); - globals::dispatcher.sink<LanguageSetEvent>().connect<&on_language_set>(); -} - -void main_menu::deinit(void) -{ - title = nullptr; -} - -void 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 = vx::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; - 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_debug); - ImGui::SetCursorScreenPos(ImVec2(padding.x + spacing.x, window_size.y - globals::font_debug->FontSize - padding.y - spacing.y)); - ImGui::Text("Voxelius %s", project_version_string.c_str()); - ImGui::PopFont(); - } - - ImGui::PopStyleVar(); - } - - ImGui::End(); -} diff --git a/game/client/main_menu.hh b/game/client/main_menu.hh deleted file mode 100644 index 9166722..0000000 --- a/game/client/main_menu.hh +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef CLIENT_MAIN_MENU_HH -#define CLIENT_MAIN_MENU_HH 1 -#pragma once - -namespace main_menu -{ -void init(void); -void deinit(void); -void layout(void); -} // namespace main_menu - -#endif /* CLIENT_MAIN_MENU_HH */ diff --git a/game/client/message_box.cc b/game/client/message_box.cc deleted file mode 100644 index da1b715..0000000 --- a/game/client/message_box.cc +++ /dev/null @@ -1,94 +0,0 @@ -#include "client/pch.hh" - -#include "client/message_box.hh" - -#include "client/globals.hh" -#include "client/gui_screen.hh" -#include "client/language.hh" - -constexpr static ImGuiWindowFlags WINDOW_FLAGS = ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDecoration; - -struct Button final { - message_box_action action; - std::string str_title; -}; - -static std::string str_title; -static std::string str_subtitle; -static std::vector<Button> buttons; - -void message_box::init(void) -{ - str_title = std::string(); - str_subtitle = std::string(); - buttons.clear(); -} - -void message_box::layout(void) -{ - const auto viewport = ImGui::GetMainViewport(); - const auto window_start = ImVec2(0.0f, viewport->Size.y * 0.30f); - const auto window_size = ImVec2(viewport->Size.x, viewport->Size.y * 0.70f); - - ImGui::SetNextWindowPos(window_start); - ImGui::SetNextWindowSize(window_size); - - if(ImGui::Begin("###UIProgress", nullptr, WINDOW_FLAGS)) { - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 1.0f * globals::gui_scale)); - - 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, 8.0f * globals::gui_scale)); - - if(!str_subtitle.empty()) { - const float subtitle_width = ImGui::CalcTextSize(str_subtitle.c_str()).x; - ImGui::SetCursorPosX(0.5f * (window_size.x - subtitle_width)); - ImGui::TextUnformatted(str_subtitle.c_str()); - } - - ImGui::Dummy(ImVec2(0.0f, 32.0f * globals::gui_scale)); - - for(const auto& button : buttons) { - const float button_width = 0.8f * ImGui::CalcItemWidth(); - ImGui::SetCursorPosX(0.5f * (window_size.x - button_width)); - - if(ImGui::Button(button.str_title.c_str(), ImVec2(button_width, 0.0f))) { - if(button.action) { - button.action(); - } - } - } - - ImGui::PopStyleVar(); - } - - ImGui::End(); -} - -void message_box::reset(void) -{ - str_title.clear(); - str_subtitle.clear(); - buttons.clear(); -} - -void message_box::set_title(const char* title) -{ - str_title = language::resolve(title); -} - -void message_box::set_subtitle(const char* subtitle) -{ - str_subtitle = language::resolve(subtitle); -} - -void message_box::add_button(const char* text, const message_box_action& action) -{ - Button button = {}; - button.str_title = std::format("{}###MessageBox_Button{}", language::resolve(text), buttons.size()); - button.action = action; - - buttons.push_back(button); -} diff --git a/game/client/message_box.hh b/game/client/message_box.hh deleted file mode 100644 index 7ea2466..0000000 --- a/game/client/message_box.hh +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef CLIENT_MESSAGE_BOX_HH -#define CLIENT_MESSAGE_BOX_HH 1 -#pragma once - -using message_box_action = void (*)(void); - -namespace message_box -{ -void init(void); -void layout(void); -void reset(void); -} // namespace message_box - -namespace message_box -{ -void set_title(const char* title); -void set_subtitle(const char* subtitle); -void add_button(const char* text, const message_box_action& action); -} // namespace message_box - -#endif /* CLIENT_MESSAGE_BOX_HH */ diff --git a/game/client/metrics.cc b/game/client/metrics.cc deleted file mode 100644 index 8b5b7dd..0000000 --- a/game/client/metrics.cc +++ /dev/null @@ -1,98 +0,0 @@ -#include "client/pch.hh" - -#include "client/metrics.hh" - -#include "core/version.hh" - -#include "shared/coord.hh" -#include "shared/dimension.hh" -#include "shared/grounded.hh" -#include "shared/head.hh" -#include "shared/transform.hh" -#include "shared/velocity.hh" - -#include "client/camera.hh" -#include "client/game.hh" -#include "client/globals.hh" -#include "client/imdraw_ext.hh" -#include "client/session.hh" - -constexpr static ImGuiWindowFlags WINDOW_FLAGS = - ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoNav; - -static std::basic_string<GLubyte> r_version; -static std::basic_string<GLubyte> r_renderer; - -void metrics::init(void) -{ - r_version = std::basic_string<GLubyte>(glGetString(GL_VERSION)); - r_renderer = std::basic_string<GLubyte>(glGetString(GL_RENDERER)); -} - -void metrics::layout(void) -{ - if(!session::is_ingame()) { - // Sanity check; we are checking this - // in client_game before calling layout - // on HUD-ish GUI systems but still - return; - } - - auto draw_list = ImGui::GetForegroundDrawList(); - - // FIXME: maybe use style colors instead of hardcoding? - auto text_color = ImGui::GetColorU32(ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); - auto shadow_color = ImGui::GetColorU32(ImVec4(0.1f, 0.1f, 0.1f, 1.0f)); - - auto position = ImVec2(8.0f, 8.0f); - auto y_step = 1.5f * globals::font_debug->FontSize; - - // Draw version - auto version_line = std::format("Voxelius {}", project_version_string); - imdraw_ext::text_shadow(version_line, position, text_color, shadow_color, globals::font_debug, draw_list); - position.y += 1.5f * y_step; - - // Draw client-side window framerate metrics - auto window_framerate = 1.0f / globals::window_frametime_avg; - auto window_frametime = 1000.0f * globals::window_frametime_avg; - auto window_fps_line = std::format("{:.02f} FPS [{:.02f} ms]", window_framerate, window_frametime); - imdraw_ext::text_shadow(window_fps_line, position, text_color, shadow_color, globals::font_debug, draw_list); - position.y += y_step; - - // Draw world rendering metrics - auto drawcall_line = std::format("World: {} DC / {} TRI", globals::num_drawcalls, globals::num_triangles); - imdraw_ext::text_shadow(drawcall_line, position, text_color, shadow_color, globals::font_debug, draw_list); - position.y += y_step; - - // Draw OpenGL version string - auto r_version_line = std::format("GL_VERSION: {}", reinterpret_cast<const char*>(r_version.c_str())); - imdraw_ext::text_shadow(r_version_line, position, text_color, shadow_color, globals::font_debug, draw_list); - position.y += y_step; - - // Draw OpenGL renderer string - auto r_renderer_line = std::format("GL_RENDERER: {}", reinterpret_cast<const char*>(r_renderer.c_str())); - imdraw_ext::text_shadow(r_renderer_line, position, text_color, shadow_color, globals::font_debug, draw_list); - position.y += 1.5f * y_step; - - const auto& head = globals::dimension->entities.get<HeadComponent>(globals::player); - const auto& transform = globals::dimension->entities.get<TransformComponent>(globals::player); - const auto& velocity = globals::dimension->entities.get<VelocityComponent>(globals::player); - - // Draw player voxel position - auto voxel_position = coord::to_voxel(transform.chunk, transform.local); - auto voxel_line = std::format("voxel: [{} {} {}]", voxel_position.x, voxel_position.y, voxel_position.z); - imdraw_ext::text_shadow(voxel_line, position, text_color, shadow_color, globals::font_debug, draw_list); - position.y += y_step; - - // Draw player world position - auto world_line = std::format("world: [{} {} {}] [{:.03f} {:.03f} {:.03f}]", transform.chunk.x, transform.chunk.y, transform.chunk.z, - transform.local.x, transform.local.y, transform.local.z); - imdraw_ext::text_shadow(world_line, position, text_color, shadow_color, globals::font_debug, draw_list); - position.y += y_step; - - // Draw player look angles - auto angles = glm::degrees(transform.angles + head.angles); - auto angle_line = std::format("angle: [{: .03f} {: .03f} {: .03f}]", angles[0], angles[1], angles[2]); - imdraw_ext::text_shadow(angle_line, position, text_color, shadow_color, globals::font_debug, draw_list); - position.y += y_step; -} diff --git a/game/client/metrics.hh b/game/client/metrics.hh deleted file mode 100644 index ba68a86..0000000 --- a/game/client/metrics.hh +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef CLIENT_METRICS_HH -#define CLIENT_METRICS_HH 1 -#pragma once - -namespace metrics -{ -void init(void); -void layout(void); -} // namespace metrics - -#endif /* CLIENT_METRICS_HH */ diff --git a/game/client/outline.cc b/game/client/outline.cc deleted file mode 100644 index 31a6bd9..0000000 --- a/game/client/outline.cc +++ /dev/null @@ -1,148 +0,0 @@ -#include "client/pch.hh" - -#include "client/outline.hh" - -#include "core/config.hh" - -#include "shared/coord.hh" - -#include "client/camera.hh" -#include "client/const.hh" -#include "client/game.hh" -#include "client/program.hh" - -// ONLY TOUCH THESE IF THE RESPECTIVE SHADER -// VARIANT MACRO DECLARATIONS LAYOUT CHANGED AS WELL -constexpr static unsigned int WORLD_CURVATURE = 0U; - -static GL_Program program; -static std::size_t u_vpmatrix; -static std::size_t u_worldpos; -static std::size_t u_viewdist; -static std::size_t u_modulate; -static std::size_t u_scale; - -static GLuint vaobj; -static GLuint cube_vbo; -static GLuint line_vbo; - -void outline::init(void) -{ - if(!program.setup("shaders/outline.vert", "shaders/outline.frag")) { - spdlog::critical("outline: program setup failed"); - std::terminate(); - } - - u_vpmatrix = program.add_uniform("u_ViewProjMatrix"); - u_worldpos = program.add_uniform("u_WorldPosition"); - u_viewdist = program.add_uniform("u_ViewDistance"); - u_modulate = program.add_uniform("u_Modulate"); - u_scale = program.add_uniform("u_Scale"); - - const glm::fvec3 cube_vertices[24] = { - glm::fvec3(0.0f, 0.0f, 0.0f), - glm::fvec3(0.0f, 1.0f, 0.0f), - glm::fvec3(0.0f, 1.0f, 0.0f), - glm::fvec3(1.0f, 1.0f, 0.0f), - glm::fvec3(1.0f, 1.0f, 0.0f), - glm::fvec3(1.0f, 0.0f, 0.0f), - glm::fvec3(1.0f, 0.0f, 0.0f), - glm::fvec3(0.0f, 0.0f, 0.0f), - - glm::fvec3(0.0f, 0.0f, 1.0f), - glm::fvec3(0.0f, 1.0f, 1.0f), - glm::fvec3(0.0f, 1.0f, 1.0f), - glm::fvec3(1.0f, 1.0f, 1.0f), - glm::fvec3(1.0f, 1.0f, 1.0f), - glm::fvec3(1.0f, 0.0f, 1.0f), - glm::fvec3(1.0f, 0.0f, 1.0f), - glm::fvec3(0.0f, 0.0f, 1.0f), - - glm::fvec3(0.0f, 0.0f, 0.0f), - glm::fvec3(0.0f, 0.0f, 1.0f), - glm::fvec3(0.0f, 1.0f, 0.0f), - glm::fvec3(0.0f, 1.0f, 1.0f), - glm::fvec3(1.0f, 0.0f, 0.0f), - glm::fvec3(1.0f, 0.0f, 1.0f), - glm::fvec3(1.0f, 1.0f, 0.0f), - glm::fvec3(1.0f, 1.0f, 1.0f), - }; - - glGenBuffers(1, &cube_vbo); - glBindBuffer(GL_ARRAY_BUFFER, cube_vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(cube_vertices), cube_vertices, GL_STATIC_DRAW); - - const glm::fvec3 line_vertices[2] = { - glm::fvec3(0.0f, 0.0f, 0.0f), - glm::fvec3(1.0f, 1.0f, 1.0f), - }; - - glGenBuffers(1, &line_vbo); - glBindBuffer(GL_ARRAY_BUFFER, line_vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(line_vertices), line_vertices, GL_STATIC_DRAW); - - glGenVertexArrays(1, &vaobj); - - glBindVertexArray(vaobj); - glEnableVertexAttribArray(0); - glVertexAttribDivisor(0, 0); -} - -void outline::deinit(void) -{ - glDeleteVertexArrays(1, &vaobj); - glDeleteBuffers(1, &line_vbo); - glDeleteBuffers(1, &cube_vbo); - program.destroy(); -} - -void outline::prepare(void) -{ - program.set_variant_vert(WORLD_CURVATURE, client_game::world_curvature.get_value()); - - if(!program.update()) { - spdlog::critical("outline_renderer: program update failed"); - std::terminate(); - } - - glDisable(GL_CULL_FACE); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - - glUseProgram(program.handle); - glUniformMatrix4fv(program.uniforms[u_vpmatrix].location, 1, false, glm::value_ptr(camera::matrix)); - glUniform1f(program.uniforms[u_viewdist].location, CHUNK_SIZE * camera::view_distance.get_value()); - - glBindVertexArray(vaobj); - glEnableVertexAttribArray(0); - glVertexAttribDivisor(0, 0); -} - -void outline::cube(const chunk_pos& cpos, const glm::fvec3& fpos, const glm::fvec3& size, float thickness, const glm::fvec4& color) -{ - auto patch_cpos = cpos - camera::position_chunk; - - glLineWidth(thickness); - - glUniform3fv(program.uniforms[u_worldpos].location, 1, glm::value_ptr(coord::to_fvec3(patch_cpos, fpos))); - glUniform4fv(program.uniforms[u_modulate].location, 1, glm::value_ptr(color)); - glUniform3fv(program.uniforms[u_scale].location, 1, glm::value_ptr(size)); - - glBindBuffer(GL_ARRAY_BUFFER, cube_vbo); - glVertexAttribPointer(0, 3, GL_FLOAT, false, sizeof(glm::fvec3), nullptr); - glDrawArrays(GL_LINES, 0, 24); -} - -void outline::line(const chunk_pos& cpos, const glm::fvec3& fpos, const glm::fvec3& size, float thickness, const glm::fvec4& color) -{ - auto patch_cpos = cpos - camera::position_chunk; - - glLineWidth(thickness); - - glUniform3fv(program.uniforms[u_worldpos].location, 1, glm::value_ptr(coord::to_fvec3(patch_cpos, fpos))); - glUniform4fv(program.uniforms[u_modulate].location, 1, glm::value_ptr(color)); - glUniform3fv(program.uniforms[u_scale].location, 1, glm::value_ptr(size)); - - glBindBuffer(GL_ARRAY_BUFFER, line_vbo); - glVertexAttribPointer(0, 3, GL_FLOAT, false, sizeof(glm::fvec3), nullptr); - glDrawArrays(GL_LINES, 0, 2); -} diff --git a/game/client/outline.hh b/game/client/outline.hh deleted file mode 100644 index a7789b2..0000000 --- a/game/client/outline.hh +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef CLIENT_OUTLINE_HH -#define CLIENT_OUTLINE_HH 1 -#pragma once - -#include "shared/types.hh" - -namespace outline -{ -void init(void); -void deinit(void); -void prepare(void); -} // namespace outline - -namespace outline -{ -void cube(const chunk_pos& cpos, const glm::fvec3& fpos, const glm::fvec3& size, float thickness, const glm::fvec4& color); -void line(const chunk_pos& cpos, const glm::fvec3& fpos, const glm::fvec3& size, float thickness, const glm::fvec4& color); -} // namespace outline - -#endif /* CLIENT_OUTLINE_HH */ diff --git a/game/client/pch.hh b/game/client/pch.hh deleted file mode 100644 index df9d2b5..0000000 --- a/game/client/pch.hh +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef CLIENT_PCH_HH -#define CLIENT_PCH_HH 1 -#pragma once - -#include <shared/pch.hh> - -#include <AL/al.h> -#include <AL/alc.h> -#include <AL/salad.h> - -#include <dr_mp3.h> -#include <dr_wav.h> - -#include <GLFW/glfw3.h> - -#include <glad/gl.h> - -#include <imgui.h> -#include <imgui_impl_glfw.h> -#include <imgui_impl_opengl3.h> -#include <imgui_stdlib.h> - -#if defined(_WIN32) -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#endif - -#if defined(__unix__) -#include <dlfcn.h> -#endif - -#endif /* CLIENT_PCH_HH */ diff --git a/game/client/play_menu.cc b/game/client/play_menu.cc deleted file mode 100644 index b9a6693..0000000 --- a/game/client/play_menu.cc +++ /dev/null @@ -1,548 +0,0 @@ -#include "client/pch.hh" - -#include "client/play_menu.hh" - -#include "core/config.hh" -#include "core/constexpr.hh" -#include "core/strtools.hh" - -#include "shared/protocol.hh" - -#include "client/bother.hh" -#include "client/game.hh" -#include "client/glfw.hh" -#include "client/globals.hh" -#include "client/gui_screen.hh" -#include "client/language.hh" -#include "client/session.hh" - -constexpr static ImGuiWindowFlags WINDOW_FLAGS = ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDecoration; -constexpr static const char* DEFAULT_SERVER_NAME = "Voxelius Server"; -constexpr static const char* SERVERS_TXT = "servers.txt"; -constexpr static const char* WARNING_TOAST = "[!]"; - -constexpr static std::size_t MAX_SERVER_ITEM_NAME = 24; - -enum class item_status : unsigned int { - UNKNOWN = 0x0000U, - PINGING = 0x0001U, - REACHED = 0x0002U, - FAILURE = 0x0003U, -}; - -struct ServerStatusItem final { - std::string name; - std::string password; - std::string hostname; - std::uint16_t port; - - // Things pulled from bother events - std::uint32_t protocol_version; - std::uint16_t num_players; - std::uint16_t max_players; - std::string motd; - - // Unique identifier that monotonically - // grows with each new server added and - // doesn't reset with each server removed - unsigned int identity; - - item_status status; -}; - -static std::string str_tab_servers; - -static std::string str_join; -static std::string str_connect; -static std::string str_add; -static std::string str_edit; -static std::string str_remove; -static std::string str_refresh; - -static std::string str_status_init; -static std::string str_status_ping; -static std::string str_status_fail; - -static std::string str_outdated_client; -static std::string str_outdated_server; - -static std::string input_itemname; -static std::string input_hostname; -static std::string input_password; - -static unsigned int next_identity; -static std::deque<ServerStatusItem*> servers_deque; -static ServerStatusItem* selected_server; -static bool editing_server; -static bool adding_server; -static bool needs_focus; - -static void parse_hostname(ServerStatusItem* item, const std::string& hostname) -{ - auto parts = strtools::split(hostname, ":"); - - if(!parts[0].empty()) { - item->hostname = parts[0]; - } else { - item->hostname = std::string("localhost"); - } - - if(parts.size() >= 2) { - item->port = vx::clamp<std::uint16_t>(strtoul(parts[1].c_str(), nullptr, 10), 1024, UINT16_MAX); - } else { - item->port = protocol::PORT; - } -} - -static void add_new_server(void) -{ - auto item = new ServerStatusItem(); - item->port = protocol::PORT; - item->protocol_version = protocol::VERSION; - item->max_players = UINT16_MAX; - item->num_players = UINT16_MAX; - item->identity = next_identity; - item->status = item_status::UNKNOWN; - - next_identity += 1U; - - input_itemname = DEFAULT_SERVER_NAME; - input_hostname = std::string(); - input_password = std::string(); - - servers_deque.push_back(item); - selected_server = item; - editing_server = true; - adding_server = true; - needs_focus = true; -} - -static void edit_selected_server(void) -{ - input_itemname = selected_server->name; - - if(selected_server->port != protocol::PORT) { - input_hostname = std::format("{}:{}", selected_server->hostname, selected_server->port); - } else { - input_hostname = selected_server->hostname; - } - - input_password = selected_server->password; - - editing_server = true; - needs_focus = true; -} - -static void remove_selected_server(void) -{ - bother::cancel(selected_server->identity); - - for(auto it = servers_deque.cbegin(); it != servers_deque.cend(); ++it) { - if(selected_server == (*it)) { - delete selected_server; - selected_server = nullptr; - servers_deque.erase(it); - return; - } - } -} - -static void join_selected_server(void) -{ - if(!session::peer) { - session::connect(selected_server->hostname.c_str(), selected_server->port, selected_server->password.c_str()); - } -} - -static void on_glfw_key(const GlfwKeyEvent& event) -{ - if((event.key == GLFW_KEY_ESCAPE) && (event.action == GLFW_PRESS)) { - if(globals::gui_screen == GUI_PLAY_MENU) { - if(editing_server) { - if(adding_server) { - remove_selected_server(); - } else { - input_itemname.clear(); - input_hostname.clear(); - input_password.clear(); - editing_server = false; - adding_server = false; - return; - } - } - - globals::gui_screen = GUI_MAIN_MENU; - selected_server = nullptr; - return; - } - } -} - -static void on_language_set(const LanguageSetEvent& event) -{ - str_tab_servers = language::resolve_gui("play_menu.tab.servers"); - - str_join = language::resolve_gui("play_menu.join"); - str_connect = language::resolve_gui("play_menu.connect"); - str_add = language::resolve_gui("play_menu.add"); - str_edit = language::resolve_gui("play_menu.edit"); - str_remove = language::resolve_gui("play_menu.remove"); - str_refresh = language::resolve_gui("play_menu.refresh"); - - str_status_init = language::resolve("play_menu.status.init"); - str_status_ping = language::resolve("play_menu.status.ping"); - str_status_fail = language::resolve("play_menu.status.fail"); - - str_outdated_client = language::resolve("play_menu.outdated_client"); - str_outdated_server = language::resolve("play_menu.outdated_server"); -} - -static void on_bother_response(const BotherResponseEvent& event) -{ - for(auto item : servers_deque) { - if(item->identity == event.identity) { - if(event.is_server_unreachable) { - item->protocol_version = 0U; - item->num_players = UINT16_MAX; - item->max_players = UINT16_MAX; - item->motd = str_status_fail; - item->status = item_status::FAILURE; - } else { - item->protocol_version = event.protocol_version; - item->num_players = event.num_players; - item->max_players = event.max_players; - item->motd = event.motd; - item->status = item_status::REACHED; - } - - break; - } - } -} - -static void layout_server_item(ServerStatusItem* item) -{ - // Preserve the cursor at which we draw stuff - const ImVec2& cursor = ImGui::GetCursorScreenPos(); - const ImVec2& padding = ImGui::GetStyle().FramePadding; - const ImVec2& spacing = ImGui::GetStyle().ItemSpacing; - - const float item_width = ImGui::GetContentRegionAvail().x; - const float line_height = ImGui::GetTextLineHeightWithSpacing(); - const std::string sid = std::format("###play_menu.servers.{}", static_cast<void*>(item)); - if(ImGui::Selectable(sid.c_str(), (item == selected_server), 0, ImVec2(0.0, 2.0f * (line_height + padding.y + spacing.y)))) { - selected_server = item; - editing_server = false; - } - - if(ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) { - // Double clicked - join the selected server - join_selected_server(); - } - - ImDrawList* draw_list = ImGui::GetWindowDrawList(); - - if(item == selected_server) { - const ImVec2 start = ImVec2(cursor.x, cursor.y); - const ImVec2 end = ImVec2(start.x + item_width, start.y + 2.0f * (line_height + padding.y + spacing.y)); - draw_list->AddRect(start, end, ImGui::GetColorU32(ImGuiCol_Text), 0.0f, 0, globals::gui_scale); - } - - const ImVec2 name_pos = ImVec2(cursor.x + padding.x + 0.5f * spacing.x, cursor.y + padding.y); - draw_list->AddText(name_pos, ImGui::GetColorU32(ImGuiCol_Text), item->name.c_str(), item->name.c_str() + item->name.size()); - - if(item->status == item_status::REACHED) { - auto stats = std::format("{}/{}", item->num_players, item->max_players); - auto stats_width = ImGui::CalcTextSize(stats.c_str(), stats.c_str() + stats.size()).x; - auto stats_pos = ImVec2(cursor.x + item_width - stats_width - padding.x, cursor.y + padding.y); - draw_list->AddText(stats_pos, ImGui::GetColorU32(ImGuiCol_TextDisabled), stats.c_str(), stats.c_str() + stats.size()); - - if(item->protocol_version != protocol::VERSION) { - auto warning_size = ImGui::CalcTextSize(WARNING_TOAST); - auto warning_pos = ImVec2(stats_pos.x - warning_size.x - padding.x - 4.0f * globals::gui_scale, cursor.y + padding.y); - auto warning_end = ImVec2(warning_pos.x + warning_size.x, warning_pos.y + warning_size.y); - draw_list->AddText(warning_pos, ImGui::GetColorU32(ImGuiCol_DragDropTarget), WARNING_TOAST); - - if(ImGui::IsMouseHoveringRect(warning_pos, warning_end)) { - ImGui::BeginTooltip(); - - if(item->protocol_version < protocol::VERSION) { - ImGui::TextUnformatted(str_outdated_server.c_str(), str_outdated_server.c_str() + str_outdated_server.size()); - } else { - ImGui::TextUnformatted(str_outdated_client.c_str(), str_outdated_client.c_str() + str_outdated_client.size()); - } - - ImGui::EndTooltip(); - } - } - } - - ImU32 motd_color = {}; - const std::string* motd_text; - - switch(item->status) { - case item_status::UNKNOWN: - motd_color = ImGui::GetColorU32(ImGuiCol_TextDisabled); - motd_text = &str_status_init; - break; - case item_status::PINGING: - motd_color = ImGui::GetColorU32(ImGuiCol_TextDisabled); - motd_text = &str_status_ping; - break; - case item_status::REACHED: - motd_color = ImGui::GetColorU32(ImGuiCol_TextDisabled); - motd_text = &item->motd; - break; - default: - motd_color = ImGui::GetColorU32(ImGuiCol_PlotLinesHovered); - motd_text = &str_status_fail; - break; - } - - const ImVec2 motd_pos = ImVec2(cursor.x + padding.x + 0.5f * spacing.x, cursor.y + padding.y + line_height); - draw_list->AddText(motd_pos, motd_color, motd_text->c_str(), motd_text->c_str() + motd_text->size()); -} - -static void layout_server_edit(ServerStatusItem* item) -{ - if(needs_focus) { - ImGui::SetKeyboardFocusHere(); - needs_focus = false; - } - - ImGui::SetNextItemWidth(-0.25f * ImGui::GetContentRegionAvail().x); - ImGui::InputText("###play_menu.servers.edit_itemname", &input_itemname); - ImGui::SameLine(); - - const bool ignore_input = strtools::is_whitespace(input_itemname) || input_hostname.empty(); - - ImGui::BeginDisabled(ignore_input); - - if(ImGui::Button("OK###play_menu.servers.submit_input", ImVec2(-1.0f, 0.0f)) - || (!ignore_input && ImGui::IsKeyPressed(ImGuiKey_Enter))) { - parse_hostname(item, input_hostname); - item->password = input_password; - item->name = input_itemname.substr(0, MAX_SERVER_ITEM_NAME); - item->status = item_status::UNKNOWN; - editing_server = false; - adding_server = false; - - input_itemname.clear(); - input_hostname.clear(); - - bother::cancel(item->identity); - } - - ImGui::EndDisabled(); - - 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; - } - - ImGui::SetNextItemWidth(-0.50f * ImGui::GetContentRegionAvail().x); - ImGui::InputText("###play_menu.servers.edit_hostname", &input_hostname, hostname_flags); - ImGui::SameLine(); - - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - ImGui::InputText("###play_menu.servers.edit_password", &input_password, ImGuiInputTextFlags_Password); -} - -static void layout_servers(void) -{ - if(ImGui::BeginListBox("###play_menu.servers.listbox", ImVec2(-1.0f, -1.0f))) { - for(ServerStatusItem* item : servers_deque) { - if(editing_server && item == selected_server) { - layout_server_edit(item); - } else { - layout_server_item(item); - } - } - - ImGui::EndListBox(); - } -} - -static void layout_servers_buttons(void) -{ - auto avail_width = ImGui::GetContentRegionAvail().x; - - // Can only join when selected and not editing - ImGui::BeginDisabled(!selected_server || editing_server); - - if(ImGui::Button(str_join.c_str(), ImVec2(-0.50f * avail_width, 0.0f))) { - join_selected_server(); - } - - ImGui::EndDisabled(); - ImGui::SameLine(); - - // Can only connect directly when not editing anything - ImGui::BeginDisabled(editing_server); - - if(ImGui::Button(str_connect.c_str(), ImVec2(-1.00f, 0.0f))) { - globals::gui_screen = GUI_DIRECT_CONNECTION; - } - - ImGui::EndDisabled(); - - // Can only add when not editing anything - ImGui::BeginDisabled(editing_server); - - if(ImGui::Button(str_add.c_str(), ImVec2(-0.75f * avail_width, 0.0f))) { - add_new_server(); - } - - ImGui::EndDisabled(); - ImGui::SameLine(); - - // Can only edit when selected and not editing - ImGui::BeginDisabled(!selected_server || editing_server); - - if(ImGui::Button(str_edit.c_str(), ImVec2(-0.50f * avail_width, 0.0f))) { - edit_selected_server(); - } - - ImGui::EndDisabled(); - ImGui::SameLine(); - - // Can only remove when selected and not editing - ImGui::BeginDisabled(!selected_server || editing_server); - - if(ImGui::Button(str_remove.c_str(), ImVec2(-0.25f * avail_width, 0.0f))) { - remove_selected_server(); - } - - ImGui::EndDisabled(); - ImGui::SameLine(); - - if(ImGui::Button(str_refresh.c_str(), ImVec2(-1.0f, 0.0f))) { - for(ServerStatusItem* item : servers_deque) { - if(item->status != item_status::PINGING) { - if(!editing_server || item != selected_server) { - item->status = item_status::UNKNOWN; - bother::cancel(item->identity); - } - } - } - } -} - -void play_menu::init(void) -{ - if(auto file = PHYSFS_openRead(SERVERS_TXT)) { - auto source = std::string(PHYSFS_fileLength(file), char(0x00)); - PHYSFS_readBytes(file, source.data(), source.size()); - PHYSFS_close(file); - - auto stream = std::istringstream(source); - auto line = std::string(); - - while(std::getline(stream, line)) { - auto parts = strtools::split(line, "%"); - - auto item = new ServerStatusItem(); - item->port = protocol::PORT; - item->protocol_version = protocol::VERSION; - item->max_players = UINT16_MAX; - item->num_players = UINT16_MAX; - item->identity = next_identity; - item->status = item_status::UNKNOWN; - - next_identity += 1U; - - parse_hostname(item, parts[0]); - - if(parts.size() >= 2) { - item->password = parts[1]; - } else { - item->password = std::string(); - } - - if(parts.size() >= 3) { - item->name = parts[2].substr(0, MAX_SERVER_ITEM_NAME); - } else { - item->name = DEFAULT_SERVER_NAME; - } - - servers_deque.push_back(item); - } - } - - globals::dispatcher.sink<GlfwKeyEvent>().connect<&on_glfw_key>(); - globals::dispatcher.sink<LanguageSetEvent>().connect<&on_language_set>(); - globals::dispatcher.sink<BotherResponseEvent>().connect<&on_bother_response>(); -} - -void play_menu::deinit(void) -{ - std::ostringstream stream; - - for(const auto item : servers_deque) { - stream << std::format("{}:{}%{}%{}", item->hostname, item->port, item->password, item->name) << std::endl; - } - - if(auto file = PHYSFS_openWrite(SERVERS_TXT)) { - auto source = stream.str(); - PHYSFS_writeBytes(file, source.data(), source.size()); - PHYSFS_close(file); - } - - for(auto item : servers_deque) - delete item; - servers_deque.clear(); -} - -void play_menu::layout(void) -{ - const auto viewport = ImGui::GetMainViewport(); - const auto window_start = ImVec2(viewport->Size.x * 0.05f, viewport->Size.y * 0.05f); - const auto window_size = ImVec2(viewport->Size.x * 0.90f, viewport->Size.y * 0.90f); - - ImGui::SetNextWindowPos(window_start); - ImGui::SetNextWindowSize(window_size); - - if(ImGui::Begin("###play_menu", nullptr, WINDOW_FLAGS)) { - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(3.0f * globals::gui_scale, 3.0f * globals::gui_scale)); - - if(ImGui::BeginTabBar("###play_menu.tabs", ImGuiTabBarFlags_FittingPolicyResizeDown)) { - if(ImGui::TabItemButton("<<")) { - globals::gui_screen = GUI_MAIN_MENU; - selected_server = nullptr; - editing_server = false; - } - - if(ImGui::BeginTabItem(str_tab_servers.c_str())) { - if(ImGui::BeginChild("###play_menu.servers.child", ImVec2(0.0f, -2.0f * ImGui::GetFrameHeightWithSpacing()))) { - layout_servers(); - } - - ImGui::EndChild(); - - layout_servers_buttons(); - - ImGui::EndTabItem(); - } - - ImGui::EndTabBar(); - } - - ImGui::PopStyleVar(); - } - - ImGui::End(); -} - -void play_menu::update_late(void) -{ - for(auto item : servers_deque) { - if(item->status == item_status::UNKNOWN) { - bother::ping(item->identity, item->hostname.c_str(), item->port); - item->status = item_status::PINGING; - continue; - } - } -} diff --git a/game/client/play_menu.hh b/game/client/play_menu.hh deleted file mode 100644 index 44193df..0000000 --- a/game/client/play_menu.hh +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef CLIENT_PLAY_MENU_HH -#define CLIENT_PLAY_MENU_HH 1 -#pragma once - -namespace play_menu -{ -void init(void); -void deinit(void); -void layout(void); -void update_late(void); -} // namespace play_menu - -#endif /* CLIENT_PLAY_MENU_HH */ diff --git a/game/client/player_look.cc b/game/client/player_look.cc deleted file mode 100644 index 767c171..0000000 --- a/game/client/player_look.cc +++ /dev/null @@ -1,146 +0,0 @@ -#include "client/pch.hh" - -#include "client/player_look.hh" - -#include "core/angles.hh" -#include "core/config.hh" - -#include "shared/dimension.hh" -#include "shared/head.hh" - -#include "client/const.hh" -#include "client/gamepad.hh" -#include "client/gamepad_axis.hh" -#include "client/gamepad_button.hh" -#include "client/glfw.hh" -#include "client/globals.hh" -#include "client/keybind.hh" -#include "client/session.hh" -#include "client/settings.hh" - -constexpr static float PITCH_MIN = -1.0f * vx::radians(90.0f); -constexpr static float PITCH_MAX = +1.0f * vx::radians(90.0f); - -// Mouse options -static ConfigBoolean mouse_raw_input(true); -static ConfigUnsigned mouse_sensitivity(25U, 1U, 100U); - -// Gamepad options -static ConfigFloat gamepad_fastlook_factor(1.5f, 1.0f, 5.0f); -static ConfigUnsigned gamepad_accel_pitch(15U, 1U, 100U); -static ConfigUnsigned gamepad_accel_yaw(25U, 1U, 100U); - -// Gamepad axes -static ConfigGamepadAxis axis_pitch(GLFW_GAMEPAD_AXIS_LEFT_Y, false); -static ConfigGamepadAxis axis_yaw(GLFW_GAMEPAD_AXIS_LEFT_X, false); - -// Gamepad buttons -static ConfigGamepadButton 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<HeadComponent>(globals::player); - - head.angles[0] += pitch; - head.angles[1] += yaw; - head.angles[0] = vx::clamp(head.angles[0], PITCH_MIN, PITCH_MAX); - head.angles = cxangles::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<HeadComponentPrev>(globals::player, head); - } -} - -static void on_glfw_cursor_pos(const GlfwCursorPosEvent& event) -{ - if(gamepad::available && 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<float>(mouse_sensitivity.get_value()) * vx::radians(event.pos.x - last_cursor.x); - auto dy = -0.01f * static_cast<float>(mouse_sensitivity.get_value()) * vx::radians(event.pos.y - last_cursor.y); - add_angles(dy, dx); - - last_cursor = event.pos; -} - -static void on_gamepad_button(const GamepadButtonEvent& event) -{ - if(button_fastlook.equals(event.button)) { - fastlook_enabled = event.action == GLFW_PRESS; - } -} - -void 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<float>(globals::width); - last_cursor.y = 0.5f * static_cast<float>(globals::height); - - globals::dispatcher.sink<GlfwCursorPosEvent>().connect<&on_glfw_cursor_pos>(); - globals::dispatcher.sink<GamepadButtonEvent>().connect<&on_gamepad_button>(); -} - -void player_look::update_late(void) -{ - if(gamepad::available && gamepad::active.get_value() && !globals::gui_screen) { - auto pitch_value = axis_pitch.get_value(gamepad::state, gamepad::deadzone.get_value()); - auto yaw_value = axis_yaw.get_value(gamepad::state, 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<float>(gamepad_accel_pitch.get_value()); - yaw_value *= 0.001f * static_cast<float>(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/player_look.hh b/game/client/player_look.hh deleted file mode 100644 index c10df0e..0000000 --- a/game/client/player_look.hh +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef CLIENT_PLAYER_LOOK_HH -#define CLIENT_PLAYER_LOOK_HH 1 -#pragma once - -namespace player_look -{ -void init(void); -void update_late(void); -} // namespace player_look - -#endif /* CLIENT_PLAYER_LOOK_HH */ diff --git a/game/client/player_move.cc b/game/client/player_move.cc deleted file mode 100644 index d949d53..0000000 --- a/game/client/player_move.cc +++ /dev/null @@ -1,283 +0,0 @@ -#include "client/pch.hh" - -#include "client/player_move.hh" - -#include "core/angles.hh" -#include "core/config.hh" -#include "core/constexpr.hh" - -#include "shared/dimension.hh" -#include "shared/grounded.hh" -#include "shared/head.hh" -#include "shared/transform.hh" -#include "shared/velocity.hh" - -#include "client/const.hh" -#include "client/gamepad.hh" -#include "client/gamepad_axis.hh" -#include "client/gamepad_button.hh" -#include "client/globals.hh" -#include "client/gui_screen.hh" -#include "client/keybind.hh" -#include "client/session.hh" -#include "client/settings.hh" -#include "client/sound.hh" -#include "client/status_lines.hh" -#include "client/toggles.hh" -#include "client/voxel_sounds.hh" - -constexpr static std::uint64_t PMOVE_JUMP_COOLDOWN = 500000; // 0.5 seconds - -constexpr static float PMOVE_FOOTSTEP_SIZE = 2.0f; - -// Movement keys -static ConfigKeyBind key_move_forward(GLFW_KEY_W); -static ConfigKeyBind key_move_back(GLFW_KEY_S); -static ConfigKeyBind key_move_left(GLFW_KEY_A); -static ConfigKeyBind key_move_right(GLFW_KEY_D); -static ConfigKeyBind key_move_down(GLFW_KEY_LEFT_SHIFT); -static ConfigKeyBind key_move_up(GLFW_KEY_SPACE); - -// Movement gamepad axes -static ConfigGamepadAxis axis_move_forward(GLFW_GAMEPAD_AXIS_RIGHT_X, false); -static ConfigGamepadAxis axis_move_sideways(GLFW_GAMEPAD_AXIS_RIGHT_Y, false); - -// Movement gamepad buttons -static ConfigGamepadButton button_move_down(GLFW_GAMEPAD_BUTTON_DPAD_DOWN); -static ConfigGamepadButton button_move_up(GLFW_GAMEPAD_BUTTON_DPAD_UP); - -// General movement options -static ConfigBoolean 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<float> 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 = vx::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 = vx::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 player_move::init(void) -{ - movement_direction = ZERO_VEC3<float>; - - 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<float>(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 player_move::fixed_update(void) -{ - const auto& head = globals::dimension->entities.get<HeadComponent>(globals::player); - auto& transform = globals::dimension->entities.get<TransformComponent>(globals::player); - auto& velocity = globals::dimension->entities.get<VelocityComponent>(globals::player); - - // Interpolation - preserve current component states - globals::dimension->entities.emplace_or_replace<TransformComponentPrev>(globals::player, transform); - - glm::fvec3 forward, right; - cxangles::vectors(glm::fvec3(0.0f, head.angles[1], 0.0f), &forward, &right, nullptr); - - glm::fvec3 wishdir = ZERO_VEC3<float>; - 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<GroundedComponent>(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 = 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(vx::abs(speed_change) < 0.01f) { - // No considerable speed increase within - // the precision we use to draw the speedometer - status_lines::set(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 - status_lines::set(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 - status_lines::set(STATUS_DEBUG, new_speed_text, ImVec4(0.0f, 1.0f, 0.0f, 1.0f), 1.0f); - } - } - - if(auto effect = voxel_sounds::get_footsteps(grounded->surface)) { - sound::play_player(effect, false, 1.0f); - } - } -} - -void player_move::update_late(void) -{ - movement_direction = ZERO_VEC3<float>; - - if(globals::gui_screen || !session::is_ingame()) { - // We're either disconnected or have the - // UI opened up; anyways we shouldn't move - return; - } - - if(gamepad::available && gamepad::active.get_value()) { - if(button_move_down.is_pressed(gamepad::state)) { - movement_direction += DIR_DOWN<float>; - } - - if(button_move_up.is_pressed(gamepad::state)) { - movement_direction += DIR_UP<float>; - } - - movement_direction.x += axis_move_sideways.get_value(gamepad::state, gamepad::deadzone.get_value()); - movement_direction.z -= axis_move_forward.get_value(gamepad::state, gamepad::deadzone.get_value()); - } else { - if(GLFW_PRESS == glfwGetKey(globals::window, key_move_forward.get_key())) { - movement_direction += DIR_FORWARD<float>; - } - - if(GLFW_PRESS == glfwGetKey(globals::window, key_move_back.get_key())) { - movement_direction += DIR_BACK<float>; - } - - if(GLFW_PRESS == glfwGetKey(globals::window, key_move_left.get_key())) { - movement_direction += DIR_LEFT<float>; - } - - if(GLFW_PRESS == glfwGetKey(globals::window, key_move_right.get_key())) { - movement_direction += DIR_RIGHT<float>; - } - - if(GLFW_PRESS == glfwGetKey(globals::window, key_move_down.get_key())) { - movement_direction += DIR_DOWN<float>; - } - - if(GLFW_PRESS == glfwGetKey(globals::window, key_move_up.get_key())) { - movement_direction += DIR_UP<float>; - } - } -} diff --git a/game/client/player_move.hh b/game/client/player_move.hh deleted file mode 100644 index 7730d08..0000000 --- a/game/client/player_move.hh +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef CLIENT_PLAYER_MOVE_HH -#define CLIENT_PLAYER_MOVE_HH 1 -#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 player_move -{ -void init(void); -void fixed_update(void); -void update_late(void); -} // namespace player_move - -#endif /* CLIENT_PLAYER_MOVE_HH */ diff --git a/game/client/player_target.cc b/game/client/player_target.cc deleted file mode 100644 index 9c60c00..0000000 --- a/game/client/player_target.cc +++ /dev/null @@ -1,66 +0,0 @@ -#include "client/pch.hh" - -#include "client/player_target.hh" - -#include "shared/coord.hh" -#include "shared/dimension.hh" -#include "shared/ray_dda.hh" - -#include "client/camera.hh" -#include "client/game.hh" -#include "client/globals.hh" -#include "client/outline.hh" -#include "client/session.hh" - -constexpr static float MAX_REACH = 16.0f; - -voxel_id player_target::voxel; -voxel_pos player_target::coord; -voxel_pos player_target::normal; -const VoxelInfo* player_target::info; - -void player_target::init(void) -{ - player_target::voxel = NULL_VOXEL_ID; - player_target::coord = voxel_pos(); - player_target::normal = voxel_pos(); - player_target::info = nullptr; -} - -void player_target::update(void) -{ - if(session::is_ingame()) { - RayDDA ray(globals::dimension, camera::position_chunk, camera::position_local, camera::direction); - - do { - player_target::voxel = ray.step(); - - if(player_target::voxel != NULL_VOXEL_ID) { - player_target::coord = ray.vpos; - player_target::normal = ray.vnormal; - player_target::info = voxel_registry::find(player_target::voxel); - break; - } - - player_target::coord = voxel_pos(); - player_target::normal = voxel_pos(); - player_target::info = nullptr; - } while(ray.distance < MAX_REACH); - } else { - player_target::voxel = NULL_VOXEL_ID; - player_target::coord = voxel_pos(); - player_target::normal = voxel_pos(); - player_target::info = nullptr; - } -} - -void player_target::render(void) -{ - if((player_target::voxel != NULL_VOXEL_ID) && !client_game::hide_hud) { - auto cpos = coord::to_chunk(player_target::coord); - auto fpos = coord::to_local(player_target::coord); - - outline::prepare(); - outline::cube(cpos, glm::fvec3(fpos), glm::fvec3(1.0f), 2.0f, glm::fvec4(0.0f, 0.0f, 0.0f, 1.0f)); - } -} diff --git a/game/client/player_target.hh b/game/client/player_target.hh deleted file mode 100644 index b60d1a5..0000000 --- a/game/client/player_target.hh +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef CLIENT_PLAYER_TARGET_HH -#define CLIENT_PLAYER_TARGET_HH 1 -#pragma once - -#include "shared/voxel_registry.hh" - -namespace player_target -{ -extern voxel_id voxel; -extern voxel_pos coord; -extern voxel_pos normal; -extern const VoxelInfo* info; -} // namespace player_target - -namespace player_target -{ -void init(void); -void update(void); -void render(void); -} // namespace player_target - -#endif /* CLIENT_PLAYER_TARGET_HH */ diff --git a/game/client/program.cc b/game/client/program.cc deleted file mode 100644 index 8d4403a..0000000 --- a/game/client/program.cc +++ /dev/null @@ -1,223 +0,0 @@ -#include "client/pch.hh" - -#include "client/program.hh" - -#include "core/strtools.hh" - -// This fills up the array of source lines and figures out -// which lines are to be dynamically resolved as variant macros -static void parse_source(const char* source, std::vector<std::string>& out_lines, std::vector<GL_VariedMacro>& out_variants) -{ - std::string line; - std::istringstream stream = std::istringstream(source); - unsigned long line_number = 0UL; - - out_lines.clear(); - out_variants.clear(); - - while(std::getline(stream, line)) { - unsigned int macro_index = {}; - char macro_name[128] = {}; - - if(std::sscanf(line.c_str(), " # pragma variant [ %u ] %127[^, \"\t\r\n]", ¯o_index, ¯o_name) == 2) { - if(out_variants.size() <= macro_index) { - out_variants.resize(macro_index + 1U); - } - - out_variants[macro_index].name = macro_name; - out_variants[macro_index].line = line_number; - out_variants[macro_index].value = std::numeric_limits<unsigned int>::max(); - - out_lines.push_back(std::string()); - line_number += 1UL; - } else { - out_lines.push_back(line); - line_number += 1UL; - } - } -} - -static GLuint compile_shader(const char* path, const char* source, GLenum shader_stage) -{ - GLuint shader = glCreateShader(shader_stage); - glShaderSource(shader, 1, &source, nullptr); - glCompileShader(shader); - - GLint info_log_length; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_log_length); - - if(info_log_length >= 2) { - std::basic_string<GLchar> info_log; - info_log.resize(info_log_length); - glGetShaderInfoLog(shader, info_log_length, nullptr, info_log.data()); - spdlog::info("gl_program: {}: shader information:", path); - spdlog::info(info_log); - } - - GLint compile_status; - glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status); - - if(!compile_status) { - glDeleteShader(shader); - return 0; - } - - return shader; -} - -bool GL_Program::setup(const char* vpath, const char* fpath) -{ - destroy(); - - vert_path = std::string(vpath); - frag_path = std::string(fpath); - - auto vfile = PHYSFS_openRead(vpath); - - if(vfile == nullptr) { - spdlog::warn("gl_program: {}: {}", vpath, PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); - return false; - } - - auto vsource = std::string(PHYSFS_fileLength(vfile), char(0x00)); - PHYSFS_readBytes(vfile, vsource.data(), vsource.size()); - PHYSFS_close(vfile); - - auto ffile = PHYSFS_openRead(fpath); - - if(ffile == nullptr) { - spdlog::warn("gl_program: {}: {}", fpath, PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); - return false; - } - - auto fsource = std::string(PHYSFS_fileLength(ffile), char(0x00)); - PHYSFS_readBytes(ffile, fsource.data(), fsource.size()); - PHYSFS_close(ffile); - - parse_source(vsource.c_str(), vert_source, vert_variants); - parse_source(fsource.c_str(), frag_source, frag_variants); - - needs_update = true; - handle = 0; - - return true; -} - -bool GL_Program::update(void) -{ - if(!needs_update) { - // The program is already up to - // date with the internal state - return true; - } - - for(const auto& macro : vert_variants) - vert_source[macro.line] = std::format("#define {} {}", macro.name, macro.value); - for(const auto& macro : frag_variants) - frag_source[macro.line] = std::format("#define {} {}", macro.name, macro.value); - - const std::string vsource = strtools::join(vert_source, "\r\n"); - const std::string fsource = strtools::join(frag_source, "\r\n"); - - GLuint vert = compile_shader(vert_path.c_str(), vsource.c_str(), GL_VERTEX_SHADER); - GLuint frag = compile_shader(frag_path.c_str(), fsource.c_str(), GL_FRAGMENT_SHADER); - - if(!vert || !frag) { - // needs_update = false; - glDeleteShader(frag); - glDeleteShader(vert); - return false; - } - - handle = glCreateProgram(); - glAttachShader(handle, vert); - glAttachShader(handle, frag); - glLinkProgram(handle); - - GLint info_log_length; - glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &info_log_length); - - if(info_log_length >= 2) { - std::basic_string<GLchar> info_log; - info_log.resize(info_log_length); - glGetProgramInfoLog(handle, info_log_length, nullptr, info_log.data()); - spdlog::info("gl_program: [{}; {}]: program information", vert, frag); - spdlog::info(info_log); - } - - glDeleteShader(frag); - glDeleteShader(vert); - - GLint link_status; - glGetProgramiv(handle, GL_LINK_STATUS, &link_status); - - if(!link_status) { - // needs_update = false; - glDeleteProgram(handle); - return false; - } - - for(auto& uniform : uniforms) { - // NOTE: GL seems to silently ignore invalid uniform - // locations (-1); should we write something into logs about this? - uniform.location = glGetUniformLocation(handle, uniform.name.c_str()); - } - - needs_update = false; - return true; -} - -void GL_Program::destroy(void) -{ - if(handle) { - glDeleteProgram(handle); - handle = 0; - } - - uniforms.clear(); - - frag_variants.clear(); - frag_source.clear(); - frag_path = std::string(); - - vert_variants.clear(); - vert_source.clear(); - vert_path = std::string(); - - needs_update = false; -} - -std::size_t GL_Program::add_uniform(const char* name) -{ - for(std::size_t i = 0; i < uniforms.size(); ++i) { - if(!uniforms[i].name.compare(name)) { - return i; - } - } - - const std::size_t index = uniforms.size(); - uniforms.push_back(GL_Uniform()); - uniforms[index].location = -1; - uniforms[index].name = name; - return index; -} - -void GL_Program::set_variant_vert(unsigned int variant, unsigned int value) -{ - if(variant < vert_variants.size()) { - if(value != vert_variants[variant].value) { - vert_variants[variant].value = value; - needs_update = true; - } - } -} - -void GL_Program::set_variant_frag(unsigned int variant, unsigned int value) -{ - if(variant < frag_variants.size()) { - if(value != frag_variants[variant].value) { - frag_variants[variant].value = value; - needs_update = true; - } - } -} diff --git a/game/client/program.hh b/game/client/program.hh deleted file mode 100644 index 4d83e14..0000000 --- a/game/client/program.hh +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef CLIENT_PROGRAM_HH -#define CLIENT_PROGRAM_HH 1 -#pragma once - -struct GL_VariedMacro final { - std::string name; - unsigned long line; - unsigned int value; -}; - -struct GL_Uniform final { - std::string name; - GLint location; -}; - -class GL_Program final { -public: - bool setup(const char* vpath, const char* fpath); - void destroy(void); - bool update(void); - - std::size_t add_uniform(const char* name); - void set_variant_vert(unsigned int variant, unsigned int value); - void set_variant_frag(unsigned int variant, unsigned int value); - -public: - std::string vert_path; - std::string frag_path; - std::vector<std::string> vert_source; - std::vector<std::string> frag_source; - std::vector<GL_VariedMacro> vert_variants; - std::vector<GL_VariedMacro> frag_variants; - std::vector<GL_Uniform> uniforms; - bool needs_update; - GLuint handle; -}; - -#endif /* CLIENT_PROGRAM_HH */ diff --git a/game/client/progress_bar.cc b/game/client/progress_bar.cc deleted file mode 100644 index dfab705..0000000 --- a/game/client/progress_bar.cc +++ /dev/null @@ -1,110 +0,0 @@ -#include "client/pch.hh" - -#include "client/progress_bar.hh" - -#include "core/constexpr.hh" - -#include "client/globals.hh" -#include "client/language.hh" - -constexpr static ImGuiWindowFlags WINDOW_FLAGS = ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDecoration; - -static std::string str_title; -static std::string str_button; -static progress_bar_action button_action; - -void progress_bar::init(void) -{ - str_title = "Loading"; - str_button = std::string(); - button_action = nullptr; -} - -void progress_bar::layout(void) -{ - const auto viewport = ImGui::GetMainViewport(); - const auto window_start = ImVec2(0.0f, viewport->Size.y * 0.30f); - const auto window_size = ImVec2(viewport->Size.x, viewport->Size.y * 0.70f); - - ImGui::SetNextWindowPos(window_start); - ImGui::SetNextWindowSize(window_size); - - if(ImGui::Begin("###UIProgress", nullptr, WINDOW_FLAGS)) { - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 1.0f * globals::gui_scale)); - - 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, 8.0f * globals::gui_scale)); - - const ImVec2 cursor = ImGui::GetCursorPos(); - - const std::size_t num_bars = 32; - const float spinner_width = 0.8f * ImGui::CalcItemWidth(); - const float bar_width = spinner_width / static_cast<float>(num_bars); - const float bar_height = 0.5f * ImGui::GetFrameHeight(); - - const float base_xpos = window_start.x + 0.5f * (window_size.x - spinner_width) + 0.5f; - const float base_ypos = window_start.y + cursor.y; - const float phase = 2.0f * ImGui::GetTime(); - - const ImVec4& background = ImGui::GetStyleColorVec4(ImGuiCol_Button); - const ImVec4& foreground = ImGui::GetStyleColorVec4(ImGuiCol_PlotHistogram); - - for(std::size_t i = 0; i < num_bars; ++i) { - const float sinval = std::sin(M_PI * static_cast<float>(i) / static_cast<float>(num_bars) - phase); - const float modifier = std::exp(-8.0f * (0.5f + 0.5f * sinval)); - - ImVec4 color = {}; - color.x = vx::lerp(background.x, foreground.x, modifier); - color.y = vx::lerp(background.y, foreground.y, modifier); - color.z = vx::lerp(background.z, foreground.z, modifier); - color.w = vx::lerp(background.w, foreground.w, modifier); - - const ImVec2 start = ImVec2(base_xpos + bar_width * i, base_ypos); - const ImVec2 end = ImVec2(start.x + bar_width, start.y + bar_height); - ImGui::GetWindowDrawList()->AddRectFilled(start, end, ImGui::GetColorU32(color)); - } - - // The NewLine call tricks ImGui into correctly padding the - // next widget that comes after the progress_bar spinner; this - // is needed to ensure the button is located in the correct place - ImGui::NewLine(); - - if(!str_button.empty()) { - ImGui::Dummy(ImVec2(0.0f, 32.0f * globals::gui_scale)); - - const float button_width = 0.8f * ImGui::CalcItemWidth(); - ImGui::SetCursorPosX(0.5f * (window_size.x - button_width)); - - if(ImGui::Button(str_button.c_str(), ImVec2(button_width, 0.0f))) { - if(button_action) { - button_action(); - } - } - } - - ImGui::PopStyleVar(); - } - - ImGui::End(); -} - -void progress_bar::reset(void) -{ - str_title.clear(); - str_button.clear(); - button_action = nullptr; -} - -void progress_bar::set_title(const char* title) -{ - str_title = language::resolve(title); -} - -void progress_bar::set_button(const char* text, const progress_bar_action& action) -{ - str_button = std::format("{}###ProgressBar_Button", language::resolve(text)); - button_action = action; -} diff --git a/game/client/progress_bar.hh b/game/client/progress_bar.hh deleted file mode 100644 index 5375d3f..0000000 --- a/game/client/progress_bar.hh +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef CLIENT_PROGRESS_BAR_HH -#define CLIENT_PROGRESS_BAR_HH 1 -#pragma once - -using progress_bar_action = void (*)(void); - -namespace progress_bar -{ -void init(void); -void layout(void); -} // namespace progress_bar - -namespace progress_bar -{ -void reset(void); -void set_title(const char* title); -void set_button(const char* text, const progress_bar_action& action); -} // namespace progress_bar - -#endif /* CLIENT_PROGRESS_BAR_HH */ diff --git a/game/client/receive.cc b/game/client/receive.cc deleted file mode 100644 index 742d3af..0000000 --- a/game/client/receive.cc +++ /dev/null @@ -1,187 +0,0 @@ -#include "client/pch.hh" - -#include "client/receive.hh" - -#include "shared/dimension.hh" -#include "shared/head.hh" -#include "shared/player.hh" -#include "shared/protocol.hh" -#include "shared/transform.hh" -#include "shared/velocity.hh" - -#include "client/chat.hh" -#include "client/factory.hh" -#include "client/globals.hh" -#include "client/gui_screen.hh" -#include "client/message_box.hh" -#include "client/session.hh" -#include "client/sound.hh" -#include "client/window_title.hh" - -static bool synchronize_entity_id(Dimension* dimension, entt::entity entity) -{ - if(dimension->entities.valid(entity)) { - // Entity ID already exists - return true; - } - - auto created = dimension->entities.create(entity); - - if(created == entity) { - // Synchronized successfully - return true; - } - - session::disconnect("protocol.entity_id_desync"); - spdlog::critical("receive: entity desync: network {} resolved as client {}", static_cast<std::uint64_t>(entity), - static_cast<std::uint64_t>(created)); - - message_box::reset(); - message_box::set_title("disconnected.disconnected"); - message_box::set_subtitle("protocol.entity_id_desync"); - message_box::add_button("disconnected.back", [](void) { - globals::gui_screen = GUI_PLAY_MENU; - window_title::update(); - }); - - globals::gui_screen = GUI_MESSAGE_BOX; - - return false; -} - -static void on_dimension_info_packet(const protocol::DimensionInfo& packet) -{ - if(session::peer) { - if(globals::dimension) { - delete globals::dimension; - globals::dimension = nullptr; - globals::player = entt::null; - } - - globals::dimension = new Dimension(packet.name.c_str(), packet.gravity); - } -} - -static void on_chunk_voxels_packet(const protocol::ChunkVoxels& packet) -{ - if(session::peer && globals::dimension) { - auto chunk = globals::dimension->create_chunk(packet.chunk); - chunk->set_voxels(packet.voxels); - - ChunkUpdateEvent event; - event.dimension = globals::dimension; - event.cpos = packet.chunk; - event.chunk = chunk; - - globals::dispatcher.trigger(event); - - return; - } -} - -static void on_entity_head_packet(const protocol::EntityHead& packet) -{ - if(session::peer && globals::dimension) { - if(synchronize_entity_id(globals::dimension, packet.entity)) { - auto& component = globals::dimension->entities.get_or_emplace<HeadComponent>(packet.entity); - auto& prevcomp = globals::dimension->entities.get_or_emplace<HeadComponentPrev>(packet.entity); - - // Store the previous component state - prevcomp.angles = component.angles; - prevcomp.offset = component.offset; - - // Assign the new component state - component.angles = packet.angles; - } - } -} - -static void on_entity_transform_packet(const protocol::EntityTransform& packet) -{ - if(session::peer && globals::dimension) { - if(synchronize_entity_id(globals::dimension, packet.entity)) { - auto& component = globals::dimension->entities.get_or_emplace<TransformComponent>(packet.entity); - auto& prevcomp = globals::dimension->entities.get_or_emplace<TransformComponentPrev>(packet.entity); - - // Store the previous component state - prevcomp.angles = component.angles; - prevcomp.chunk = component.chunk; - prevcomp.local = component.local; - - // Assign the new component state - component.angles = packet.angles; - component.chunk = packet.chunk; - component.local = packet.local; - } - } -} - -static void on_entity_velocity_packet(const protocol::EntityVelocity& packet) -{ - if(session::peer && globals::dimension) { - if(synchronize_entity_id(globals::dimension, packet.entity)) { - auto& component = globals::dimension->entities.get_or_emplace<VelocityComponent>(packet.entity); - component.value = packet.value; - } - } -} - -static void on_entity_player_packet(const protocol::EntityPlayer& packet) -{ - if(session::peer && globals::dimension) { - if(synchronize_entity_id(globals::dimension, packet.entity)) { - client_factory::create_player(globals::dimension, packet.entity); - } - } -} - -static void on_spawn_player_packet(const protocol::SpawnPlayer& packet) -{ - if(session::peer && globals::dimension) { - if(synchronize_entity_id(globals::dimension, packet.entity)) { - client_factory::create_player(globals::dimension, packet.entity); - - globals::player = packet.entity; - globals::gui_screen = GUI_SCREEN_NONE; - - client_chat::refresh_timings(); - - window_title::update(); - } - } -} - -static void on_remove_entity_packet(const protocol::RemoveEntity& packet) -{ - if(globals::dimension) { - if(packet.entity == globals::player) { - globals::player = entt::null; - } - - globals::dimension->entities.destroy(packet.entity); - } -} - -static void on_generic_sound_packet(const protocol::GenericSound& packet) -{ - sound::play_generic(packet.sound.c_str(), packet.looping, packet.pitch); -} - -static void on_entity_sound_packet(const protocol::EntitySound& packet) -{ - sound::play_entity(packet.entity, packet.sound.c_str(), packet.looping, packet.pitch); -} - -void client_receive::init(void) -{ - globals::dispatcher.sink<protocol::DimensionInfo>().connect<&on_dimension_info_packet>(); - globals::dispatcher.sink<protocol::ChunkVoxels>().connect<&on_chunk_voxels_packet>(); - globals::dispatcher.sink<protocol::EntityHead>().connect<&on_entity_head_packet>(); - globals::dispatcher.sink<protocol::EntityTransform>().connect<&on_entity_transform_packet>(); - globals::dispatcher.sink<protocol::EntityVelocity>().connect<&on_entity_velocity_packet>(); - globals::dispatcher.sink<protocol::EntityPlayer>().connect<&on_entity_player_packet>(); - globals::dispatcher.sink<protocol::SpawnPlayer>().connect<&on_spawn_player_packet>(); - globals::dispatcher.sink<protocol::RemoveEntity>().connect<&on_remove_entity_packet>(); - globals::dispatcher.sink<protocol::GenericSound>().connect<&on_generic_sound_packet>(); - globals::dispatcher.sink<protocol::EntitySound>().connect<&on_entity_sound_packet>(); -} diff --git a/game/client/receive.hh b/game/client/receive.hh deleted file mode 100644 index 27ed2b2..0000000 --- a/game/client/receive.hh +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef CLIENT_RECEIVE_HH -#define CLIENT_RECEIVE_HH 1 -#pragma once - -namespace client_receive -{ -void init(void); -} // namespace client_receive - -#endif /* CLIENT_RECEIVE_HH */ diff --git a/game/client/scoreboard.cc b/game/client/scoreboard.cc deleted file mode 100644 index 23010ea..0000000 --- a/game/client/scoreboard.cc +++ /dev/null @@ -1,100 +0,0 @@ -#include "client/pch.hh" - -#include "client/scoreboard.hh" - -#include "core/config.hh" - -#include "shared/protocol.hh" - -#include "client/globals.hh" -#include "client/gui_screen.hh" -#include "client/keybind.hh" -#include "client/session.hh" -#include "client/settings.hh" - -constexpr static ImGuiWindowFlags WINDOW_FLAGS = - ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoBackground; - -static ConfigKeyBind list_key(GLFW_KEY_TAB); - -static std::vector<std::string> usernames; -static float max_username_size; - -static void on_scoreboard_update_packet(const protocol::ScoreboardUpdate& packet) -{ - usernames = packet.names; - max_username_size = 0.0f; -} - -void scoreboard::init(void) -{ - globals::client_config.add_value("scoreboard.key", list_key); - - settings::add_keybind(3, list_key, settings_location::KEYBOARD_MISC, "key.scoreboard"); - - globals::dispatcher.sink<protocol::ScoreboardUpdate>().connect<&on_scoreboard_update_packet>(); -} - -void scoreboard::layout(void) -{ - if(globals::gui_screen == GUI_SCREEN_NONE && session::is_ingame() && glfwGetKey(globals::window, list_key.get_key()) == GLFW_PRESS) { - const auto viewport = ImGui::GetMainViewport(); - const auto window_start = ImVec2(0.0f, 0.0f); - const auto window_size = ImVec2(viewport->Size.x, viewport->Size.y); - - ImGui::SetNextWindowPos(window_start); - ImGui::SetNextWindowSize(window_size); - - if(!ImGui::Begin("###chat", nullptr, WINDOW_FLAGS)) { - ImGui::End(); - return; - } - - ImGui::PushFont(globals::font_chat); - - const auto& padding = ImGui::GetStyle().FramePadding; - const auto& spacing = ImGui::GetStyle().ItemSpacing; - auto font = globals::font_chat; - - // Figure out the maximum username size - for(const auto& username : usernames) { - const ImVec2 size = ImGui::CalcTextSize(username.c_str(), username.c_str() + username.size()); - - if(size.x > max_username_size) { - max_username_size = size.x; - } - } - - // Having a minimum size allows for - // generally better in-game visibility - const float true_size = vx::max<float>(0.25f * window_size.x, max_username_size); - - // Figure out username rect dimensions - const float rect_start_x = 0.5f * window_size.x - 0.5f * true_size; - const float rect_start_y = 0.15f * window_size.y; - const float rect_size_x = 2.0f * padding.x + true_size; - const float rect_size_y = 2.0f * padding.y + font->FontSize; - - // const ImU32 border_col = ImGui::GetColorU32(ImGuiCol_Border, 1.00f); - const ImU32 rect_col = ImGui::GetColorU32(ImGuiCol_FrameBg, 0.80f); - const ImU32 text_col = ImGui::GetColorU32(ImGuiCol_Text, 1.00f); - - ImDrawList* draw_list = ImGui::GetWindowDrawList(); - - // Slightly space apart individual rows - const float row_step_y = rect_size_y + 0.5f * spacing.y; - - for(std::size_t i = 0; i < usernames.size(); ++i) { - const ImVec2 rect_a = ImVec2(rect_start_x, rect_start_y + i * row_step_y); - const ImVec2 rect_b = ImVec2(rect_a.x + rect_size_x, rect_a.y + rect_size_y); - const ImVec2 text_pos = ImVec2(rect_a.x + padding.x, rect_a.y + padding.y); - - // draw_list->AddRect(rect_a, rect_b, border_col, 0.0f, ImDrawFlags_None, globals::gui_scale); - draw_list->AddRectFilled(rect_a, rect_b, rect_col, 0.0f, ImDrawFlags_None); - draw_list->AddText(font, font->FontSize, text_pos, text_col, usernames[i].c_str(), usernames[i].c_str() + usernames[i].size()); - } - - ImGui::PopFont(); - ImGui::End(); - } -} diff --git a/game/client/scoreboard.hh b/game/client/scoreboard.hh deleted file mode 100644 index 0ae1688..0000000 --- a/game/client/scoreboard.hh +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef CLIENT_SCOREBOARD_HH -#define CLIENT_SCOREBOARD_HH 1 -#pragma once - -namespace scoreboard -{ -void init(void); -void layout(void); -} // namespace scoreboard - -#endif /* CLIENT_SCOREBOARD_HH */ diff --git a/game/client/screenshot.cc b/game/client/screenshot.cc deleted file mode 100644 index a42a815..0000000 --- a/game/client/screenshot.cc +++ /dev/null @@ -1,82 +0,0 @@ -#include "client/pch.hh" - -#include "client/screenshot.hh" - -#include "core/config.hh" -#include "core/epoch.hh" - -#include "client/chat.hh" -#include "client/glfw.hh" -#include "client/globals.hh" -#include "client/keybind.hh" -#include "client/language.hh" -#include "client/settings.hh" -#include "client/toggles.hh" - -static ConfigKeyBind screenshot_key(GLFW_KEY_F2); - -static void stbi_png_physfs_callback(void* context, void* data, int size) -{ - PHYSFS_writeBytes(reinterpret_cast<PHYSFS_File*>(context), data, size); -} - -static void on_glfw_key(const GlfwKeyEvent& event) -{ - if(!globals::gui_keybind_ptr && !toggles::is_sequence_await) { - if(screenshot_key.equals(event.key) && (event.action == GLFW_PRESS)) { - screenshot::take(); - return; - } - } -} - -void screenshot::init(void) -{ - globals::client_config.add_value("screenshot.key", screenshot_key); - - settings::add_keybind(0, screenshot_key, settings_location::KEYBOARD_MISC, "key.screenshot"); - - globals::dispatcher.sink<GlfwKeyEvent>().connect<&on_glfw_key>(); -} - -void screenshot::take(void) -{ - auto stride = 3 * globals::width; - auto length = 3 * globals::width * globals::height; - auto pixels = new std::byte[length]; - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - GLint old_pack_alignment; - glGetIntegerv(GL_PACK_ALIGNMENT, &old_pack_alignment); - - // The window can be of any size, including irregular - // values such as, say 641x480, while there is a default - // alignment value of sorts that might result in a corrupted - // image; we set GL_PACK_ALIGNMENT to 1, enabling byte-alignment - glPixelStorei(GL_PACK_ALIGNMENT, 1); - - glReadPixels(0, 0, globals::width, globals::height, GL_RGB, GL_UNSIGNED_BYTE, pixels); - - // Restore the old pack alignment value - glPixelStorei(GL_PACK_ALIGNMENT, old_pack_alignment); - - const auto directory = std::string("screenshots"); - const auto filename = std::format("{}.png", epoch::microseconds()); - const auto filepath = std::format("{}/{}", directory, filename); - - PHYSFS_mkdir(directory.c_str()); - - if(auto file = PHYSFS_openWrite(filepath.c_str())) { - stbi_flip_vertically_on_write(true); - stbi_write_png_to_func(&stbi_png_physfs_callback, file, globals::width, globals::height, 3, pixels, stride); - - spdlog::info("screenshot: wrote {}", filepath); - - client_chat::print(std::format("{} {}", language::resolve("chat.screenshot_message"), filename)); - - PHYSFS_close(file); - } - - delete[] pixels; -} diff --git a/game/client/screenshot.hh b/game/client/screenshot.hh deleted file mode 100644 index 9888644..0000000 --- a/game/client/screenshot.hh +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef CLIENT_SCREENSHOT_HH -#define CLIENT_SCREENSHOT_HH 1 -#pragma once - -namespace screenshot -{ -void init(void); -void take(void); -} // namespace screenshot - -#endif /* CLIENT_SCREENSHOT_HH */ diff --git a/game/client/session.cc b/game/client/session.cc deleted file mode 100644 index d3676f3..0000000 --- a/game/client/session.cc +++ /dev/null @@ -1,300 +0,0 @@ -#include "client/pch.hh" - -#include "client/session.hh" - -#include "core/config.hh" -#include "core/crc64.hh" - -#include "shared/coord.hh" -#include "shared/dimension.hh" -#include "shared/head.hh" -#include "shared/item_registry.hh" -#include "shared/player.hh" -#include "shared/protocol.hh" -#include "shared/transform.hh" -#include "shared/velocity.hh" -#include "shared/voxel_registry.hh" - -#include "client/camera.hh" -#include "client/chat.hh" -#include "client/chunk_visibility.hh" -#include "client/game.hh" -#include "client/globals.hh" -#include "client/gui_screen.hh" -#include "client/message_box.hh" -#include "client/progress_bar.hh" -#include "client/window_title.hh" - -ENetPeer* session::peer = nullptr; -std::uint16_t session::client_index = UINT16_MAX; -std::uint64_t session::client_identity = UINT64_MAX; - -static std::uint64_t server_password_hash = UINT64_MAX; - -static void set_fixed_tickrate(std::uint16_t tickrate) -{ - globals::fixed_frametime_us = 1000000U / vx::clamp<std::uint64_t>(tickrate, 10U, 300U); - globals::fixed_frametime = static_cast<float>(globals::fixed_frametime_us) / 1000000.0f; - globals::fixed_accumulator = 0; -} - -static void on_login_response_packet(const protocol::LoginResponse& packet) -{ - spdlog::info("session: assigned client_index={}", packet.client_index); - spdlog::info("session: assigned client_identity={}", packet.client_identity); - spdlog::info("session: server ticks at {} TPS", packet.server_tickrate); - - session::client_index = packet.client_index; - session::client_identity = packet.client_identity; - - set_fixed_tickrate(packet.server_tickrate); - - progress_bar::set_title("connecting.loading_world"); -} - -static void on_disconnect_packet(const protocol::Disconnect& packet) -{ - enet_peer_disconnect(session::peer, 0); - - spdlog::info("session: disconnected: {}", packet.reason); - - client_chat::clear(); - - session::peer = nullptr; - session::client_index = UINT16_MAX; - session::client_identity = UINT64_MAX; - - globals::fixed_frametime_us = UINT64_MAX; - globals::fixed_frametime = 0.0f; - globals::fixed_accumulator = 0; - - server_password_hash = UINT64_MAX; - - delete globals::dimension; - globals::player = entt::null; - globals::dimension = nullptr; - - message_box::reset(); - message_box::set_title("disconnected.disconnected"); - message_box::set_subtitle(packet.reason.c_str()); - message_box::add_button("disconnected.back", [](void) { - globals::gui_screen = GUI_PLAY_MENU; - window_title::update(); - }); - - globals::gui_screen = GUI_MESSAGE_BOX; -} - -static void on_set_voxel_packet(const protocol::SetVoxel& packet) -{ - auto cpos = coord::to_chunk(packet.vpos); - auto lpos = coord::to_local(packet.vpos); - auto index = coord::to_index(lpos); - - if(auto chunk = globals::dimension->find_chunk(cpos)) { - if(chunk->get_voxel(index) != packet.voxel) { - chunk->set_voxel(packet.voxel, index); - - ChunkUpdateEvent event; - event.dimension = globals::dimension; - event.chunk = chunk; - event.cpos = cpos; - - // Send a generic ChunkUpdate event to shake - // up the mesher; directly calling world::set_voxel - // here would result in a networked feedback loop - // caused by event handler below tripping - globals::dispatcher.trigger(event); - } - } -} - -// NOTE: [session] is a good place for this since [receive] -// handles entity data sent by the server and [session] handles -// everything else network related that is not player movement -static void on_voxel_set(const VoxelSetEvent& event) -{ - if(session::peer) { - // Propagate changes to the server - // FIXME: should we also validate things here or wait for the server to do so - protocol::SetVoxel packet; - packet.vpos = coord::to_voxel(event.cpos, event.lpos); - packet.voxel = event.voxel; - - protocol::send(session::peer, protocol::encode(packet)); - } -} - -void session::init(void) -{ - session::peer = nullptr; - session::client_index = UINT16_MAX; - session::client_identity = UINT64_MAX; - - globals::fixed_frametime_us = UINT64_MAX; - globals::fixed_frametime = 0.0f; - globals::fixed_accumulator = 0; - - server_password_hash = UINT64_MAX; - - globals::dispatcher.sink<protocol::LoginResponse>().connect<&on_login_response_packet>(); - globals::dispatcher.sink<protocol::Disconnect>().connect<&on_disconnect_packet>(); - globals::dispatcher.sink<protocol::SetVoxel>().connect<&on_set_voxel_packet>(); - - globals::dispatcher.sink<VoxelSetEvent>().connect<&on_voxel_set>(); -} - -void session::deinit(void) -{ - session::disconnect("protocol.client_shutdown"); - - globals::fixed_frametime_us = UINT64_MAX; - globals::fixed_frametime = 0.0f; - globals::fixed_accumulator = 0; -} - -void session::invalidate(void) -{ - if(session::peer) { - enet_peer_reset(session::peer); - - message_box::reset(); - message_box::set_title("disconnected.disconnected"); - message_box::set_subtitle("enet.peer_connection_timeout"); - message_box::add_button("disconnected.back", [](void) { - globals::gui_screen = GUI_PLAY_MENU; - window_title::update(); - }); - - globals::gui_screen = GUI_MESSAGE_BOX; - } - - client_chat::clear(); - - session::peer = nullptr; - session::client_index = UINT16_MAX; - session::client_identity = UINT64_MAX; - - globals::fixed_frametime_us = UINT64_MAX; - globals::fixed_frametime = 0.0f; - globals::fixed_accumulator = 0; - - server_password_hash = UINT64_MAX; - - delete globals::dimension; - globals::player = entt::null; - globals::dimension = nullptr; -} - -void session::connect(const char* host, std::uint16_t port, const char* password) -{ - ENetAddress address; - enet_address_set_host(&address, host); - address.port = port; - - session::peer = enet_host_connect(globals::client_host, &address, 1, 0); - session::client_index = UINT16_MAX; - session::client_identity = UINT64_MAX; - - globals::fixed_frametime_us = UINT64_MAX; - globals::fixed_frametime = 0.0f; - globals::fixed_accumulator = 0; - - server_password_hash = crc64::get(password); - - if(!session::peer) { - server_password_hash = UINT64_MAX; - - message_box::reset(); - message_box::set_title("disconnected.disconnected"); - message_box::set_subtitle("enet.peer_connection_failed"); - message_box::add_button("disconnected.back", [](void) { - globals::gui_screen = GUI_PLAY_MENU; - window_title::update(); - }); - - globals::gui_screen = GUI_MESSAGE_BOX; - - return; - } - - progress_bar::reset(); - progress_bar::set_title("connecting.connecting"); - progress_bar::set_button("connecting.cancel_button", [](void) { - enet_peer_disconnect(session::peer, 0); - - session::peer = nullptr; - session::client_index = UINT16_MAX; - session::client_identity = UINT64_MAX; - - globals::fixed_frametime_us = UINT64_MAX; - globals::fixed_frametime = 0.0f; - globals::fixed_accumulator = 0; - - server_password_hash = UINT64_MAX; - - delete globals::dimension; - globals::player = entt::null; - globals::dimension = nullptr; - - globals::gui_screen = GUI_PLAY_MENU; - }); - - globals::gui_screen = GUI_PROGRESS_BAR; -} - -void session::disconnect(const char* reason) -{ - if(session::peer) { - protocol::Disconnect packet; - packet.reason = std::string(reason); - - protocol::send(session::peer, protocol::encode(packet)); - - enet_host_flush(globals::client_host); - enet_host_service(globals::client_host, nullptr, 50); - enet_peer_reset(session::peer); - - session::peer = nullptr; - session::client_index = UINT16_MAX; - session::client_identity = UINT64_MAX; - - globals::fixed_frametime_us = UINT64_MAX; - globals::fixed_frametime = 0.0f; - globals::fixed_accumulator = 0; - - server_password_hash = UINT64_MAX; - - delete globals::dimension; - globals::player = entt::null; - globals::dimension = nullptr; - - client_chat::clear(); - } -} - -void session::send_login_request(void) -{ - protocol::LoginRequest packet; - packet.version = protocol::VERSION; - packet.voxel_registry_checksum = voxel_registry::calcualte_checksum(); - packet.item_registry_checksum = item_registry::calcualte_checksum(); - packet.password_hash = server_password_hash; - packet.username = client_game::username.get(); - - protocol::send(session::peer, protocol::encode(packet)); - - server_password_hash = UINT64_MAX; - - progress_bar::set_title("connecting.logging_in"); - globals::gui_screen = GUI_PROGRESS_BAR; -} - -bool session::is_ingame(void) -{ - if(globals::dimension) { - return globals::dimension->entities.valid(globals::player); - } else { - return false; - } -} diff --git a/game/client/session.hh b/game/client/session.hh deleted file mode 100644 index 051b57f..0000000 --- a/game/client/session.hh +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef CLIENT_SESSION_HH -#define CLIENT_SESSION_HH 1 -#pragma once - -namespace session -{ -extern ENetPeer* peer; -extern std::uint16_t client_index; -extern std::uint64_t client_identity; -} // namespace session - -namespace session -{ -void init(void); -void deinit(void); -void invalidate(void); -} // namespace session - -namespace session -{ -void connect(const char* hostname, std::uint16_t port, const char* password); -void disconnect(const char* reason); -void send_login_request(void); -} // namespace session - -namespace session -{ -bool is_ingame(void); -} // namespace session - -#endif /* CLIENT_SESSION_HH */ diff --git a/game/client/settings.cc b/game/client/settings.cc deleted file mode 100644 index 46e1bde..0000000 --- a/game/client/settings.cc +++ /dev/null @@ -1,1055 +0,0 @@ -#include "client/pch.hh" - -#include "client/settings.hh" - -#include "core/config.hh" -#include "core/constexpr.hh" - -#include "client/const.hh" -#include "client/gamepad.hh" -#include "client/gamepad_axis.hh" -#include "client/gamepad_button.hh" -#include "client/glfw.hh" -#include "client/globals.hh" -#include "client/gui_screen.hh" -#include "client/keybind.hh" -#include "client/language.hh" - -constexpr static ImGuiWindowFlags WINDOW_FLAGS = ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDecoration; -constexpr static unsigned int NUM_LOCATIONS = static_cast<unsigned int>(settings_location::COUNT); - -enum class setting_type : unsigned int { - CHECKBOX = 0x0000U, ///< ConfigBoolean - INPUT_INT = 0x0001U, ///< ConfigNumber<int> - INPUT_FLOAT = 0x0002U, ///< ConfigNumber<float> - INPUT_UINT = 0x0003U, ///< ConfigNumber<unsigned int> - INPUT_STRING = 0x0004U, ///< ConfigString - SLIDER_INT = 0x0005U, ///< ConfigNumber<int> - SLIDER_FLOAT = 0x0006U, ///< ConfigNumber<float> - SLIDER_UINT = 0x0007U, ///< ConfigNumber<unsigned int> - STEPPER_INT = 0x0008U, ///< ConfigNumber<int> - STEPPER_UINT = 0x0009U, ///< ConfigNumber<unsigned int> - KEYBIND = 0x000AU, ///< ConfigKeyBind - GAMEPAD_AXIS = 0x000BU, ///< ConfigGamepadAxis - GAMEPAD_BUTTON = 0x000CU, ///< ConfigGamepadButton - LANGUAGE_SELECT = 0x000DU, ///< ConfigString internally -}; - -class SettingValue { -public: - virtual ~SettingValue(void) = default; - virtual void layout(void) const = 0; - void layout_tooltip(void) const; - void layout_label(void) const; - -public: - setting_type type; - std::string tooltip; - std::string title; - std::string name; - bool has_tooltip; - int priority; -}; - -class SettingValueWID : public SettingValue { -public: - virtual ~SettingValueWID(void) = default; - -public: - std::string wid; -}; - -class SettingValue_CheckBox final : public SettingValue { -public: - virtual ~SettingValue_CheckBox(void) = default; - virtual void layout(void) const override; - void refresh_wids(void); - -public: - ConfigBoolean* value; - std::string wids[2]; -}; - -class SettingValue_InputInt final : public SettingValueWID { -public: - virtual ~SettingValue_InputInt(void) = default; - virtual void layout(void) const override; - -public: - ConfigInt* value; -}; - -class SettingValue_InputFloat final : public SettingValueWID { -public: - virtual ~SettingValue_InputFloat(void) = default; - virtual void layout(void) const override; - -public: - std::string format; - ConfigFloat* value; -}; - -class SettingValue_InputUnsigned final : public SettingValueWID { -public: - virtual ~SettingValue_InputUnsigned(void) = default; - virtual void layout(void) const override; - -public: - ConfigUnsigned* value; -}; - -class SettingValue_InputString final : public SettingValueWID { -public: - virtual ~SettingValue_InputString(void) = default; - virtual void layout(void) const override; - -public: - ConfigString* value; - bool allow_whitespace; -}; - -class SettingValue_SliderInt final : public SettingValueWID { -public: - virtual ~SettingValue_SliderInt(void) = default; - virtual void layout(void) const override; - -public: - ConfigInt* value; -}; - -class SettingValue_SliderFloat final : public SettingValueWID { -public: - virtual ~SettingValue_SliderFloat(void) = default; - virtual void layout(void) const override; - -public: - std::string format; - ConfigFloat* value; -}; - -class SettingValue_SliderUnsigned final : public SettingValueWID { -public: - virtual ~SettingValue_SliderUnsigned(void) = default; - virtual void layout(void) const override; - -public: - ConfigUnsigned* value; -}; - -class SettingValue_StepperInt final : public SettingValue { -public: - virtual ~SettingValue_StepperInt(void) = default; - virtual void layout(void) const override; - void refresh_wids(void); - -public: - std::vector<std::string> wids; - ConfigInt* value; -}; - -class SettingValue_StepperUnsigned final : public SettingValue { -public: - virtual ~SettingValue_StepperUnsigned(void) = default; - virtual void layout(void) const override; - void refresh_wids(void); - -public: - std::vector<std::string> wids; - ConfigUnsigned* value; -}; - -class SettingValue_KeyBind final : public SettingValue { -public: - virtual ~SettingValue_KeyBind(void) = default; - virtual void layout(void) const override; - void refresh_wids(void); - -public: - std::string wids[2]; - ConfigKeyBind* value; -}; - -class SettingValue_GamepadAxis final : public SettingValue { -public: - virtual ~SettingValue_GamepadAxis(void) = default; - virtual void layout(void) const override; - void refresh_wids(void); - -public: - std::string wids[2]; - std::string wid_checkbox; - ConfigGamepadAxis* value; -}; - -class SettingValue_GamepadButton final : public SettingValue { -public: - virtual ~SettingValue_GamepadButton(void) = default; - virtual void layout(void) const override; - void refresh_wids(void); - -public: - std::string wids[2]; - ConfigGamepadButton* value; -}; - -class SettingValue_Language final : public SettingValueWID { -public: - virtual ~SettingValue_Language(void) = default; - virtual void layout(void) const override; -}; - -static std::string str_checkbox_false; -static std::string str_checkbox_true; - -static std::string str_tab_general; -static std::string str_tab_input; -static std::string str_tab_video; -static std::string str_tab_sound; - -static std::string str_input_keyboard; -static std::string str_input_gamepad; -static std::string str_input_mouse; - -static std::string str_keyboard_movement; -static std::string str_keyboard_gameplay; -static std::string str_keyboard_misc; - -static std::string str_gamepad_movement; -static std::string str_gamepad_gameplay; -static std::string str_gamepad_misc; - -static std::string str_gamepad_axis_prefix; -static std::string str_gamepad_button_prefix; -static std::string str_gamepad_checkbox_tooltip; - -static std::string str_video_gui; - -static std::string str_sound_levels; - -static std::vector<SettingValue*> values_all; -static std::vector<SettingValue*> values[NUM_LOCATIONS]; - -void SettingValue::layout_tooltip(void) const -{ - if(has_tooltip) { - ImGui::SameLine(); - ImGui::TextDisabled("[?]"); - - if(ImGui::BeginItemTooltip()) { - ImGui::PushTextWrapPos(ImGui::GetFontSize() * 16.0f); - ImGui::TextUnformatted(tooltip.c_str()); - ImGui::PopTextWrapPos(); - ImGui::EndTooltip(); - } - } -} - -void SettingValue::layout_label(void) const -{ - ImGui::SameLine(); - ImGui::TextUnformatted(title.c_str()); -} - -void SettingValue_CheckBox::refresh_wids(void) -{ - wids[0] = std::format("{}###{}", str_checkbox_false, static_cast<void*>(value)); - wids[1] = std::format("{}###{}", str_checkbox_true, static_cast<void*>(value)); -} - -void SettingValue_CheckBox::layout(void) const -{ - const auto& wid = value->get_value() ? wids[1] : wids[0]; - - if(ImGui::Button(wid.c_str(), ImVec2(ImGui::CalcItemWidth(), 0.0f))) { - value->set_value(!value->get_value()); - } - - layout_label(); - layout_tooltip(); -} - -void SettingValue_InputInt::layout(void) const -{ - auto current_value = value->get_value(); - - if(ImGui::InputInt(wid.c_str(), ¤t_value)) { - value->set_value(current_value); - } - - layout_label(); - layout_tooltip(); -} - -void SettingValue_InputFloat::layout(void) const -{ - auto current_value = value->get_value(); - - if(ImGui::InputFloat(wid.c_str(), ¤t_value, 0.0f, 0.0f, format.c_str())) { - value->set_value(current_value); - } - - layout_label(); - layout_tooltip(); -} - -void SettingValue_InputUnsigned::layout(void) const -{ - auto current_value = static_cast<std::uint32_t>(value->get_value()); - - if(ImGui::InputScalar(wid.c_str(), ImGuiDataType_U32, ¤t_value)) { - value->set_value(current_value); - } - - layout_label(); - layout_tooltip(); -} - -void SettingValue_InputString::layout(void) const -{ - ImGuiInputTextFlags flags; - std::string current_value = value->get(); - - if(allow_whitespace) { - flags = ImGuiInputTextFlags_AllowTabInput; - } else { - flags = 0; - } - - if(ImGui::InputText(wid.c_str(), ¤t_value, flags)) { - value->set(current_value.c_str()); - } - - layout_label(); - layout_tooltip(); -} - -void SettingValue_SliderInt::layout(void) const -{ - auto current_value = value->get_value(); - - if(ImGui::SliderInt(wid.c_str(), ¤t_value, value->get_min_value(), value->get_max_value())) { - value->set_value(current_value); - } - - layout_label(); - layout_tooltip(); -} - -void SettingValue_SliderFloat::layout(void) const -{ - auto current_value = value->get_value(); - - if(ImGui::SliderFloat(wid.c_str(), ¤t_value, value->get_min_value(), value->get_max_value(), format.c_str())) { - value->set_value(current_value); - } - - layout_label(); - layout_tooltip(); -} - -void SettingValue_SliderUnsigned::layout(void) const -{ - auto current_value = static_cast<std::uint32_t>(value->get_value()); - auto min_value = static_cast<std::uint32_t>(value->get_min_value()); - auto max_value = static_cast<std::uint32_t>(value->get_max_value()); - - if(ImGui::SliderScalar(wid.c_str(), ImGuiDataType_U32, ¤t_value, &min_value, &max_value)) { - value->set_value(current_value); - } - - layout_label(); - layout_tooltip(); -} - -void SettingValue_StepperInt::layout(void) const -{ - auto current_value = value->get_value(); - auto min_value = value->get_min_value(); - auto max_value = value->get_max_value(); - - auto current_wid = current_value - min_value; - - if(ImGui::Button(wids[current_wid].c_str(), ImVec2(ImGui::CalcItemWidth(), 0.0f))) { - current_value += 1; - } - - if(current_value > max_value) { - value->set_value(min_value); - } else { - value->set_value(current_value); - } - - layout_label(); - layout_tooltip(); -} - -void SettingValue_StepperInt::refresh_wids(void) -{ - for(std::size_t i = 0; i < wids.size(); ++i) { - auto key = std::format("settings.value.{}.{}", name, i); - wids[i] = std::format("{}###{}", language::resolve(key.c_str()), static_cast<const void*>(value)); - } -} - -void SettingValue_StepperUnsigned::layout(void) const -{ - auto current_value = value->get_value(); - auto min_value = value->get_min_value(); - auto max_value = value->get_max_value(); - - auto current_wid = current_value - min_value; - - if(ImGui::Button(wids[current_wid].c_str(), ImVec2(ImGui::CalcItemWidth(), 0.0f))) { - current_value += 1U; - } - - if(current_value > max_value) { - value->set_value(min_value); - } else { - value->set_value(current_value); - } - - layout_label(); - layout_tooltip(); -} - -void SettingValue_StepperUnsigned::refresh_wids(void) -{ - for(std::size_t i = 0; i < wids.size(); ++i) { - auto key = std::format("settings.value.{}.{}", name, i); - wids[i] = std::format("{}###{}", language::resolve(key.c_str()), static_cast<const void*>(value)); - } -} - -void SettingValue_KeyBind::layout(void) const -{ - const auto is_active = ((globals::gui_keybind_ptr == value) && !globals::gui_gamepad_axis_ptr && !globals::gui_gamepad_button_ptr); - const auto& wid = is_active ? wids[0] : wids[1]; - - if(ImGui::Button(wid.c_str(), ImVec2(ImGui::CalcItemWidth(), 0.0f))) { - auto& io = ImGui::GetIO(); - io.ConfigFlags &= ~ImGuiConfigFlags_NavEnableKeyboard; - globals::gui_keybind_ptr = value; - } - - layout_label(); -} - -void SettingValue_KeyBind::refresh_wids(void) -{ - wids[0] = std::format("...###{}", static_cast<const void*>(value)); - wids[1] = std::format("{}###{}", value->get(), static_cast<const void*>(value)); -} - -void SettingValue_GamepadAxis::layout(void) const -{ - const auto is_active = ((globals::gui_gamepad_axis_ptr == value) && !globals::gui_keybind_ptr && !globals::gui_gamepad_button_ptr); - const auto& wid = is_active ? wids[0] : wids[1]; - auto is_inverted = value->is_inverted(); - - if(ImGui::Button(wid.c_str(), ImVec2(ImGui::CalcItemWidth() - ImGui::GetFrameHeight() - ImGui::GetStyle().ItemSpacing.x, 0.0f))) { - auto& io = ImGui::GetIO(); - io.ConfigFlags &= ~ImGuiConfigFlags_NavEnableKeyboard; - globals::gui_gamepad_axis_ptr = value; - } - - ImGui::SameLine(); - - if(ImGui::Checkbox(wid_checkbox.c_str(), &is_inverted)) { - value->set_inverted(is_inverted); - } - - if(ImGui::BeginItemTooltip()) { - ImGui::PushTextWrapPos(ImGui::GetFontSize() * 16.0f); - ImGui::TextUnformatted(str_gamepad_checkbox_tooltip.c_str()); - ImGui::PopTextWrapPos(); - ImGui::EndTooltip(); - } - - layout_label(); -} - -void SettingValue_GamepadAxis::refresh_wids(void) -{ - wids[0] = std::format("...###{}", static_cast<const void*>(value)); - wids[1] = std::format("{}###{}", value->get_name(), static_cast<const void*>(value)); - wid_checkbox = std::format("###CHECKBOX_{}", static_cast<const void*>(value)); -} - -void SettingValue_GamepadButton::layout(void) const -{ - const auto is_active = ((globals::gui_gamepad_button_ptr == value) && !globals::gui_keybind_ptr && !globals::gui_gamepad_axis_ptr); - const auto& wid = is_active ? wids[0] : wids[1]; - - if(ImGui::Button(wid.c_str(), ImVec2(ImGui::CalcItemWidth(), 0.0f))) { - auto& io = ImGui::GetIO(); - io.ConfigFlags &= ~ImGuiConfigFlags_NavEnableKeyboard; - globals::gui_gamepad_button_ptr = value; - } - - layout_label(); -} - -void SettingValue_GamepadButton::refresh_wids(void) -{ - wids[0] = std::format("...###{}", static_cast<const void*>(value)); - wids[1] = std::format("{}###{}", value->get(), static_cast<const void*>(value)); -} - -void SettingValue_Language::layout(void) const -{ - auto current_language = language::get_current(); - - if(ImGui::BeginCombo(wid.c_str(), current_language->endonym.c_str())) { - for(auto it = language::cbegin(); it != language::cend(); ++it) { - if(ImGui::Selectable(it->display.c_str(), it == current_language)) { - language::set(it); - continue; - } - } - - ImGui::EndCombo(); - } - - layout_label(); - layout_tooltip(); -} - -static void refresh_input_wids(void) -{ - for(SettingValue* value : values_all) { - if(value->type == setting_type::KEYBIND) { - auto keybind = static_cast<SettingValue_KeyBind*>(value); - keybind->refresh_wids(); - continue; - } - - if(value->type == setting_type::GAMEPAD_AXIS) { - auto gamepad_axis = static_cast<SettingValue_GamepadAxis*>(value); - gamepad_axis->refresh_wids(); - continue; - } - - if(value->type == setting_type::GAMEPAD_BUTTON) { - auto gamepad_button = static_cast<SettingValue_GamepadButton*>(value); - gamepad_button->refresh_wids(); - } - } -} - -static void on_glfw_key(const GlfwKeyEvent& event) -{ - if((event.action == GLFW_PRESS) && (event.key != DEBUG_KEY)) { - if(globals::gui_keybind_ptr || globals::gui_gamepad_axis_ptr || globals::gui_gamepad_button_ptr) { - if(event.key == GLFW_KEY_ESCAPE) { - ImGuiIO& io = ImGui::GetIO(); - io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; - - globals::gui_keybind_ptr = nullptr; - globals::gui_gamepad_axis_ptr = nullptr; - globals::gui_gamepad_button_ptr = nullptr; - - return; - } - - ImGuiIO& io = ImGui::GetIO(); - io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; - - globals::gui_keybind_ptr->set_key(event.key); - globals::gui_keybind_ptr = nullptr; - - refresh_input_wids(); - - return; - } - - if((event.key == GLFW_KEY_ESCAPE) && (globals::gui_screen == GUI_SETTINGS)) { - globals::gui_screen = GUI_MAIN_MENU; - return; - } - } -} - -static void on_gamepad_axis(const GamepadAxisEvent& event) -{ - if(globals::gui_gamepad_axis_ptr) { - auto& io = ImGui::GetIO(); - io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; - - globals::gui_gamepad_axis_ptr->set_axis(event.axis); - globals::gui_gamepad_axis_ptr = nullptr; - - refresh_input_wids(); - - return; - } -} - -static void on_gamepad_button(const GamepadButtonEvent& event) -{ - if(globals::gui_gamepad_button_ptr) { - auto& io = ImGui::GetIO(); - io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; - - globals::gui_gamepad_button_ptr->set_button(event.button); - globals::gui_gamepad_button_ptr = nullptr; - - refresh_input_wids(); - - return; - } -} - -static void on_language_set(const LanguageSetEvent& event) -{ - str_checkbox_false = language::resolve("settings.checkbox.false"); - str_checkbox_true = language::resolve("settings.checkbox.true"); - - str_tab_general = language::resolve("settings.tab.general"); - str_tab_input = language::resolve("settings.tab.input"); - str_tab_video = language::resolve("settings.tab.video"); - str_tab_sound = language::resolve("settings.tab.sound"); - - str_input_keyboard = language::resolve("settings.input.keyboard"); - str_input_gamepad = language::resolve("settings.input.gamepad"); - str_input_mouse = language::resolve("settings.input.mouse"); - - str_keyboard_movement = language::resolve("settings.keyboard.movement"); - str_keyboard_gameplay = language::resolve("settings.keyboard.gameplay"); - str_keyboard_misc = language::resolve("settings.keyboard.misc"); - - str_gamepad_movement = language::resolve("settings.gamepad.movement"); - str_gamepad_gameplay = language::resolve("settings.gamepad.gameplay"); - str_gamepad_misc = language::resolve("settings.gamepad.misc"); - - str_gamepad_axis_prefix = language::resolve("settings.gamepad.axis"); - str_gamepad_button_prefix = language::resolve("settings.gamepad.button"); - str_gamepad_checkbox_tooltip = language::resolve("settings.gamepad.checkbox_tooltip"); - - str_video_gui = language::resolve("settings.video.gui"); - - str_sound_levels = language::resolve("settings.sound.levels"); - - for(SettingValue* value : values_all) { - if(value->type == setting_type::CHECKBOX) { - auto checkbox = static_cast<SettingValue_CheckBox*>(value); - checkbox->refresh_wids(); - } - - if(value->type == setting_type::STEPPER_INT) { - auto stepper = static_cast<SettingValue_StepperInt*>(value); - stepper->refresh_wids(); - } - - if(value->type == setting_type::STEPPER_UINT) { - auto stepper = static_cast<SettingValue_StepperUnsigned*>(value); - stepper->refresh_wids(); - } - - value->title = language::resolve(std::format("settings.value.{}", value->name).c_str()); - - if(value->has_tooltip) { - value->tooltip = language::resolve(std::format("settings.tooltip.{}", value->name).c_str()); - } - } -} - -static void layout_values(settings_location location) -{ - ImGui::PushItemWidth(ImGui::CalcItemWidth() * 0.70f); - - for(const SettingValue* value : values[static_cast<unsigned int>(location)]) { - value->layout(); - } - - ImGui::PopItemWidth(); -} - -static void layout_general(void) -{ - if(ImGui::BeginChild("###settings.general.child")) { - layout_values(settings_location::GENERAL); - } - - ImGui::EndChild(); -} - -static void layout_input_keyboard(void) -{ - if(ImGui::BeginChild("###settings.input.keyboard.child")) { - ImGui::SeparatorText(str_keyboard_movement.c_str()); - layout_values(settings_location::KEYBOARD_MOVEMENT); - ImGui::SeparatorText(str_keyboard_gameplay.c_str()); - layout_values(settings_location::KEYBOARD_GAMEPLAY); - ImGui::SeparatorText(str_keyboard_misc.c_str()); - layout_values(settings_location::KEYBOARD_MISC); - } - - ImGui::EndChild(); -} - -static void layout_input_gamepad(void) -{ - if(ImGui::BeginChild("###settings.input.gamepad.child")) { - layout_values(settings_location::GAMEPAD); - ImGui::SeparatorText(str_gamepad_movement.c_str()); - layout_values(settings_location::GAMEPAD_MOVEMENT); - ImGui::SeparatorText(str_gamepad_gameplay.c_str()); - layout_values(settings_location::GAMEPAD_GAMEPLAY); - ImGui::SeparatorText(str_gamepad_misc.c_str()); - layout_values(settings_location::GAMEPAD_MISC); - } - - ImGui::EndChild(); -} - -static void layout_input_mouse(void) -{ - if(ImGui::BeginChild("###settings.input.mouse.child")) { - layout_values(settings_location::MOUSE); - } - - ImGui::EndChild(); -} - -static void layout_input(void) -{ - if(ImGui::BeginTabBar("###settings.input.tabs", ImGuiTabBarFlags_FittingPolicyResizeDown)) { - if(ImGui::BeginTabItem(str_input_keyboard.c_str())) { - layout_input_keyboard(); - ImGui::EndTabItem(); - } - - if(gamepad::available) { - if(ImGui::BeginTabItem(str_input_gamepad.c_str())) { - globals::gui_keybind_ptr = nullptr; - layout_input_gamepad(); - ImGui::EndTabItem(); - } - } - - if(ImGui::BeginTabItem(str_input_mouse.c_str())) { - globals::gui_keybind_ptr = nullptr; - layout_input_mouse(); - ImGui::EndTabItem(); - } - - ImGui::EndTabBar(); - } -} - -static void layout_video(void) -{ - if(ImGui::BeginChild("###settings.video.child")) { - layout_values(settings_location::VIDEO); - ImGui::SeparatorText(str_video_gui.c_str()); - layout_values(settings_location::VIDEO_GUI); - } - - ImGui::EndChild(); -} - -static void layout_sound(void) -{ - if(ImGui::BeginChild("###settings.sound.child")) { - layout_values(settings_location::SOUND); - ImGui::SeparatorText(str_sound_levels.c_str()); - layout_values(settings_location::SOUND_LEVELS); - } - - ImGui::EndChild(); -} - -void settings::init(void) -{ - globals::dispatcher.sink<GlfwKeyEvent>().connect<&on_glfw_key>(); - globals::dispatcher.sink<GamepadAxisEvent>().connect<&on_gamepad_axis>(); - globals::dispatcher.sink<GamepadButtonEvent>().connect<&on_gamepad_button>(); - globals::dispatcher.sink<LanguageSetEvent>().connect<&on_language_set>(); -} - -void settings::init_late(void) -{ - for(std::size_t i = 0; i < NUM_LOCATIONS; ++i) { - std::sort(values[i].begin(), values[i].end(), [](const SettingValue* a, const SettingValue* b) { - return a->priority < b->priority; - }); - } - - refresh_input_wids(); -} - -void settings::deinit(void) -{ - for(const SettingValue* value : values_all) - delete value; - for(std::size_t i = 0; i < NUM_LOCATIONS; values[i++].clear()) - ; - values_all.clear(); -} - -void settings::layout(void) -{ - const ImGuiViewport* viewport = ImGui::GetMainViewport(); - const ImVec2 window_start = ImVec2(viewport->Size.x * 0.05f, viewport->Size.y * 0.05f); - const ImVec2 window_size = ImVec2(viewport->Size.x * 0.90f, viewport->Size.y * 0.90f); - - ImGui::SetNextWindowPos(window_start); - ImGui::SetNextWindowSize(window_size); - - if(ImGui::Begin("###settings", nullptr, WINDOW_FLAGS)) { - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(3.0f * globals::gui_scale, 3.0f * globals::gui_scale)); - - if(ImGui::BeginTabBar("###settings.tabs", ImGuiTabBarFlags_FittingPolicyResizeDown)) { - if(ImGui::TabItemButton("<<")) { - globals::gui_screen = GUI_MAIN_MENU; - globals::gui_keybind_ptr = nullptr; - } - - if(ImGui::BeginTabItem(str_tab_general.c_str())) { - globals::gui_keybind_ptr = nullptr; - layout_general(); - ImGui::EndTabItem(); - } - - if(ImGui::BeginTabItem(str_tab_input.c_str())) { - layout_input(); - ImGui::EndTabItem(); - } - - if(ImGui::BeginTabItem(str_tab_video.c_str())) { - globals::gui_keybind_ptr = nullptr; - layout_video(); - ImGui::EndTabItem(); - } - - if(globals::sound_ctx && globals::sound_dev) { - if(ImGui::BeginTabItem(str_tab_sound.c_str())) { - globals::gui_keybind_ptr = nullptr; - layout_sound(); - ImGui::EndTabItem(); - } - } - - ImGui::EndTabBar(); - } - - ImGui::PopStyleVar(); - } - - ImGui::End(); -} - -void settings::add_checkbox(int priority, ConfigBoolean& value, settings_location location, const char* name, bool tooltip) -{ - auto setting_value = new SettingValue_CheckBox; - setting_value->type = setting_type::CHECKBOX; - setting_value->priority = priority; - setting_value->has_tooltip = tooltip; - setting_value->value = &value; - setting_value->name = name; - - setting_value->refresh_wids(); - - values[static_cast<unsigned int>(location)].push_back(setting_value); - values_all.push_back(setting_value); -} - -void settings::add_input(int priority, ConfigInt& value, settings_location location, const char* name, bool tooltip) -{ - auto setting_value = new SettingValue_InputInt; - setting_value->type = setting_type::INPUT_INT; - setting_value->priority = priority; - setting_value->has_tooltip = tooltip; - setting_value->value = &value; - setting_value->name = name; - - setting_value->wid = std::format("###{}", static_cast<const void*>(setting_value->value)); - - values[static_cast<unsigned int>(location)].push_back(setting_value); - values_all.push_back(setting_value); -} - -void settings::add_input(int priority, ConfigFloat& value, settings_location location, const char* name, bool tooltip, const char* format) -{ - auto setting_value = new SettingValue_InputFloat; - setting_value->type = setting_type::INPUT_FLOAT; - setting_value->priority = priority; - setting_value->has_tooltip = tooltip; - setting_value->value = &value; - setting_value->name = name; - - setting_value->wid = std::format("###{}", static_cast<const void*>(setting_value->value)); - - values[static_cast<unsigned int>(location)].push_back(setting_value); - values_all.push_back(setting_value); -} - -void settings::add_input(int priority, ConfigUnsigned& value, settings_location location, const char* name, bool tooltip) -{ - auto setting_value = new SettingValue_InputUnsigned; - setting_value->type = setting_type::INPUT_UINT; - setting_value->priority = priority; - setting_value->has_tooltip = tooltip; - setting_value->value = &value; - setting_value->name = name; - - setting_value->wid = std::format("###{}", static_cast<const void*>(setting_value->value)); - - values[static_cast<unsigned int>(location)].push_back(setting_value); - values_all.push_back(setting_value); -} - -void settings::add_input( - int priority, ConfigString& value, settings_location location, const char* name, bool tooltip, bool allow_whitespace) -{ - auto setting_value = new SettingValue_InputString; - setting_value->type = setting_type::INPUT_STRING; - setting_value->priority = priority; - setting_value->has_tooltip = tooltip; - setting_value->value = &value; - setting_value->name = name; - - setting_value->allow_whitespace = allow_whitespace; - setting_value->wid = std::format("###{}", static_cast<const void*>(setting_value->value)); - - values[static_cast<unsigned int>(location)].push_back(setting_value); - values_all.push_back(setting_value); -} - -void settings::add_slider(int priority, ConfigInt& value, settings_location location, const char* name, bool tooltip) -{ - auto setting_value = new SettingValue_SliderInt; - setting_value->type = setting_type::SLIDER_INT; - setting_value->priority = priority; - setting_value->has_tooltip = tooltip; - setting_value->value = &value; - setting_value->name = name; - - setting_value->wid = std::format("###{}", static_cast<const void*>(setting_value->value)); - - values[static_cast<unsigned int>(location)].push_back(setting_value); - values_all.push_back(setting_value); -} - -void settings::add_slider(int priority, ConfigFloat& value, settings_location location, const char* name, bool tooltip, const char* format) -{ - auto setting_value = new SettingValue_SliderFloat; - setting_value->type = setting_type::SLIDER_FLOAT; - setting_value->priority = priority; - setting_value->has_tooltip = tooltip; - setting_value->value = &value; - setting_value->name = name; - - setting_value->format = format; - setting_value->wid = std::format("###{}", static_cast<const void*>(setting_value->value)); - - values[static_cast<unsigned int>(location)].push_back(setting_value); - values_all.push_back(setting_value); -} - -void settings::add_slider(int priority, ConfigUnsigned& value, settings_location location, const char* name, bool tooltip) -{ - auto setting_value = new SettingValue_SliderUnsigned; - setting_value->type = setting_type::SLIDER_UINT; - setting_value->priority = priority; - setting_value->has_tooltip = tooltip; - setting_value->value = &value; - setting_value->name = name; - - setting_value->wid = std::format("###{}", static_cast<const void*>(setting_value->value)); - - values[static_cast<unsigned int>(location)].push_back(setting_value); - values_all.push_back(setting_value); -} - -void settings::add_stepper(int priority, ConfigInt& value, settings_location location, const char* name, bool tooltip) -{ - auto setting_value = new SettingValue_StepperInt; - setting_value->type = setting_type::STEPPER_INT; - setting_value->priority = priority; - setting_value->has_tooltip = tooltip; - setting_value->value = &value; - setting_value->name = name; - - setting_value->wids.resize(value.get_max_value() - value.get_min_value() + 1); - setting_value->refresh_wids(); - - values[static_cast<unsigned int>(location)].push_back(setting_value); - values_all.push_back(setting_value); -} - -void settings::add_stepper(int priority, ConfigUnsigned& value, settings_location location, const char* name, bool tooltip) -{ - auto setting_value = new SettingValue_StepperUnsigned; - setting_value->type = setting_type::STEPPER_UINT; - setting_value->priority = priority; - setting_value->has_tooltip = tooltip; - setting_value->value = &value; - setting_value->name = name; - - setting_value->wids.resize(value.get_max_value() - value.get_min_value() + 1); - setting_value->refresh_wids(); - - values[static_cast<unsigned int>(location)].push_back(setting_value); - values_all.push_back(setting_value); -} - -void settings::add_keybind(int priority, ConfigKeyBind& value, settings_location location, const char* name) -{ - auto setting_value = new SettingValue_KeyBind; - setting_value->type = setting_type::KEYBIND; - setting_value->priority = priority; - setting_value->has_tooltip = false; - setting_value->value = &value; - setting_value->name = name; - - setting_value->refresh_wids(); - - values[static_cast<unsigned int>(location)].push_back(setting_value); - values_all.push_back(setting_value); -} - -void settings::add_gamepad_axis(int priority, ConfigGamepadAxis& value, settings_location location, const char* name) -{ - auto setting_value = new SettingValue_GamepadAxis; - setting_value->type = setting_type::GAMEPAD_AXIS; - setting_value->priority = priority; - setting_value->has_tooltip = false; - setting_value->value = &value; - setting_value->name = name; - - setting_value->refresh_wids(); - - values[static_cast<unsigned int>(location)].push_back(setting_value); - values_all.push_back(setting_value); -} - -void settings::add_gamepad_button(int priority, ConfigGamepadButton& value, settings_location location, const char* name) -{ - auto setting_value = new SettingValue_GamepadButton; - setting_value->type = setting_type::GAMEPAD_BUTTON; - setting_value->priority = priority; - setting_value->has_tooltip = false; - setting_value->value = &value; - setting_value->name = name; - - setting_value->refresh_wids(); - - values[static_cast<unsigned int>(location)].push_back(setting_value); - values_all.push_back(setting_value); -} - -void settings::add_language_select(int priority, settings_location location, const char* name) -{ - auto setting_value = new SettingValue_Language; - setting_value->type = setting_type::LANGUAGE_SELECT; - setting_value->priority = priority; - setting_value->has_tooltip = false; - setting_value->name = name; - - setting_value->wid = std::format("###{}", static_cast<const void*>(setting_value)); - - values[static_cast<unsigned int>(location)].push_back(setting_value); - values_all.push_back(setting_value); -} diff --git a/game/client/settings.hh b/game/client/settings.hh deleted file mode 100644 index 4704a58..0000000 --- a/game/client/settings.hh +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef CLIENT_SETTINGS_HH -#define CLIENT_SETTINGS_HH 1 -#pragma once - -class ConfigBoolean; -class ConfigString; - -class ConfigInt; -class ConfigFloat; -class ConfigUnsigned; - -class ConfigKeyBind; -class ConfigGamepadAxis; -class ConfigGamepadButton; - -enum class settings_location : unsigned int { - GENERAL = 0x0000U, - KEYBOARD_MOVEMENT = 0x0001U, - KEYBOARD_GAMEPLAY = 0x0002U, - KEYBOARD_MISC = 0x0003U, - GAMEPAD = 0x0004U, - GAMEPAD_MOVEMENT = 0x0005U, - GAMEPAD_GAMEPLAY = 0x0006U, - GAMEPAD_MISC = 0x0007U, - MOUSE = 0x0008U, - VIDEO = 0x0009U, - VIDEO_GUI = 0x000AU, - SOUND = 0x000BU, - SOUND_LEVELS = 0x000CU, - COUNT = 0x000DU, -}; - -namespace settings -{ -void init(void); -void init_late(void); -void deinit(void); -void layout(void); -} // namespace settings - -namespace settings -{ -void add_checkbox(int priority, ConfigBoolean& value, settings_location location, const char* name, bool tooltip); -} // namespace settings - -namespace settings -{ -void add_input(int priority, ConfigInt& value, settings_location location, const char* name, bool tooltip); -void add_input(int priority, ConfigFloat& value, settings_location location, const char* name, bool tooltip, const char* format = "%.3f"); -void add_input(int priority, ConfigUnsigned& value, settings_location location, const char* name, bool tooltip); -void add_input(int priority, ConfigString& value, settings_location location, const char* name, bool tooltip, bool allow_whitespace); -} // namespace settings - -namespace settings -{ -void add_slider(int priority, ConfigInt& value, settings_location location, const char* name, bool tooltip); -void add_slider(int priority, ConfigFloat& value, settings_location location, const char* name, bool tooltip, const char* format = "%.3f"); -void add_slider(int priority, ConfigUnsigned& value, settings_location location, const char* name, bool tooltip); -} // namespace settings - -namespace settings -{ -void add_stepper(int priority, ConfigInt& value, settings_location location, const char* name, bool tooltip); -void add_stepper(int priority, ConfigUnsigned& value, settings_location location, const char* name, bool tooltip); -} // namespace settings - -namespace settings -{ -void add_keybind(int priority, ConfigKeyBind& value, settings_location location, const char* name); -} // namespace settings - -namespace settings -{ -void add_gamepad_axis(int priority, ConfigGamepadAxis& value, settings_location location, const char* name); -void add_gamepad_button(int priority, ConfigGamepadButton& value, settings_location location, const char* name); -} // namespace settings - -namespace settings -{ -void add_language_select(int priority, settings_location location, const char* name); -} // namespace settings - -#endif /* CLIENT_SETTINGS_HH */ diff --git a/game/client/skybox.cc b/game/client/skybox.cc deleted file mode 100644 index 8578f0e..0000000 --- a/game/client/skybox.cc +++ /dev/null @@ -1,11 +0,0 @@ -#include "client/pch.hh" - -#include "client/skybox.hh" - -glm::fvec3 skybox::fog_color; - -void skybox::init(void) -{ - // https://convertingcolors.com/hex-color-B1F3FF.html - skybox::fog_color = glm::fvec3(0.690f, 0.950f, 1.000f); -} diff --git a/game/client/skybox.hh b/game/client/skybox.hh deleted file mode 100644 index a3853f0..0000000 --- a/game/client/skybox.hh +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef CLIENT_SKYBOX_HH -#define CLIENT_SKYBOX_HH 1 -#pragma once - -namespace skybox -{ -extern glm::fvec3 fog_color; -} // namespace skybox - -namespace skybox -{ -void init(void); -} // namespace skybox - -#endif /* CLIENT_SKYBOX_HH */ diff --git a/game/client/sound.cc b/game/client/sound.cc deleted file mode 100644 index 28e0143..0000000 --- a/game/client/sound.cc +++ /dev/null @@ -1,199 +0,0 @@ -#include "client/pch.hh" - -#include "client/sound.hh" - -#include "core/config.hh" -#include "core/constexpr.hh" -#include "core/resource.hh" - -#include "shared/coord.hh" -#include "shared/dimension.hh" -#include "shared/protocol.hh" - -#include "client/camera.hh" -#include "client/const.hh" -#include "client/globals.hh" -#include "client/session.hh" -#include "client/settings.hh" -#include "client/sound_effect.hh" -#include "client/sound_emitter.hh" - -ConfigFloat sound::volume_master(100.0f, 0.0f, 100.0f); -ConfigFloat sound::volume_effects(100.0f, 0.0f, 100.0f); -ConfigFloat sound::volume_music(100.0f, 0.0f, 100.0f); -ConfigFloat sound::volume_ui(100.0f, 0.0f, 100.0f); - -static ALuint generic_source; -static ALuint player_source; -static ALuint ui_source; - -static resource_ptr<SoundEffect> sfx_generic; -static resource_ptr<SoundEffect> sfx_player; -static resource_ptr<SoundEffect> sfx_ui; - -void sound::init_config(void) -{ - globals::client_config.add_value("sound.volume_master", sound::volume_master); - globals::client_config.add_value("sound.volume_effects", sound::volume_effects); - globals::client_config.add_value("sound.volume_music", sound::volume_music); - globals::client_config.add_value("sound.volume_ui", sound::volume_ui); - - settings::add_slider(1, sound::volume_master, settings_location::SOUND, "sound.volume_master", false, "%.0f%%"); - - settings::add_slider(0, sound::volume_effects, settings_location::SOUND_LEVELS, "sound.volume_effects", false, "%.0f%%"); - settings::add_slider(1, sound::volume_music, settings_location::SOUND_LEVELS, "sound.volume_music", false, "%.0f%%"); - settings::add_slider(2, sound::volume_ui, settings_location::SOUND_LEVELS, "sound.volume_ui", false, "%.0f%%"); -} - -void sound::init(void) -{ - alGenSources(1, &generic_source); - alSourcei(generic_source, AL_SOURCE_RELATIVE, AL_TRUE); - alSource3f(generic_source, AL_POSITION, 0.0f, 0.0f, 0.0f); - alSource3f(generic_source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); - - alGenSources(1, &player_source); - alSourcei(player_source, AL_SOURCE_RELATIVE, AL_TRUE); - alSource3f(player_source, AL_POSITION, 0.0f, 0.0f, 0.0f); - alSource3f(player_source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); - - alGenSources(1, &ui_source); - alSourcei(ui_source, AL_SOURCE_RELATIVE, AL_TRUE); - alSource3f(ui_source, AL_POSITION, 0.0f, 0.0f, 0.0f); - alSource3f(ui_source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); - - sfx_generic = nullptr; - sfx_player = nullptr; - sfx_ui = nullptr; -} - -void sound::init_late(void) -{ -} - -void sound::deinit(void) -{ - sfx_ui = nullptr; - sfx_player = nullptr; - sfx_generic = nullptr; - - alDeleteBuffers(1, &ui_source); - alDeleteSources(1, &generic_source); - alDeleteSources(1, &player_source); -} - -void sound::update(void) -{ - auto effects_gain = vx::clamp(0.01f * sound::volume_effects.get_value(), 0.0f, 1.0f); - alSourcef(generic_source, AL_GAIN, effects_gain); - alSourcef(player_source, AL_GAIN, effects_gain); - - auto ui_gain = vx::clamp(0.01f * sound::volume_ui.get_value(), 0.0f, 1.0f); - alSourcef(ui_source, AL_GAIN, ui_gain); -} - -void sound::play_generic(const char* sound, bool looping, float pitch) -{ - if(sound) { - sound::play_generic(resource::load<SoundEffect>(sound), looping, pitch); - } else { - sound::play_generic(static_cast<const char*>(nullptr), looping, pitch); - } -} - -void sound::play_entity(entt::entity entity, const char* sound, bool looping, float pitch) -{ - if(sound) { - sound::play_entity(entity, resource::load<SoundEffect>(sound), looping, pitch); - } else { - sound::play_entity(entity, static_cast<const char*>(nullptr), looping, pitch); - } -} - -void sound::play_player(const char* sound, bool looping, float pitch) -{ - if(sound) { - sound::play_player(resource::load<SoundEffect>(sound), looping, pitch); - } else { - sound::play_player(static_cast<const char*>(nullptr), looping, pitch); - } -} - -void sound::play_ui(const char* sound, bool looping, float pitch) -{ - if(sound) { - sound::play_ui(resource::load<SoundEffect>(sound), looping, pitch); - } else { - sound::play_ui(static_cast<const char*>(nullptr), looping, pitch); - } -} - -void sound::play_generic(resource_ptr<SoundEffect> sound, bool looping, float pitch) -{ - alSourceRewind(generic_source); - - sfx_generic = sound; - - if(sfx_generic) { - alSourcei(generic_source, AL_BUFFER, sfx_generic->buffer); - alSourcei(generic_source, AL_LOOPING, looping); - alSourcef(generic_source, AL_PITCH, vx::clamp(pitch, MIN_PITCH, MAX_PITCH)); - alSourcePlay(generic_source); - } -} - -void sound::play_entity(entt::entity entity, resource_ptr<SoundEffect> sound, bool looping, float pitch) -{ - if(globals::dimension && globals::dimension->entities.valid(entity)) { - if(auto emitter = globals::dimension->entities.try_get<SoundEmitterComponent>(entity)) { - alSourceRewind(emitter->source); - - emitter->sound = sound; - - if(emitter->sound) { - alSourcei(emitter->source, AL_BUFFER, emitter->sound->buffer); - alSourcei(emitter->source, AL_LOOPING, looping); - alSourcef(emitter->source, AL_PITCH, vx::clamp(pitch, MIN_PITCH, MAX_PITCH)); - alSourcePlay(emitter->source); - } - } - } -} - -void sound::play_player(resource_ptr<SoundEffect> sound, bool looping, float pitch) -{ - if(sound && session::is_ingame()) { - protocol::EntitySound packet; - packet.entity = globals::player; - packet.sound = sound->name; - packet.looping = looping; - packet.pitch = pitch; - - protocol::send(session::peer, protocol::encode(packet)); - } - - alSourceRewind(player_source); - - sfx_player = sound; - - if(sfx_player) { - alSourcei(player_source, AL_BUFFER, sfx_player->buffer); - alSourcei(player_source, AL_LOOPING, looping); - alSourcef(player_source, AL_PITCH, vx::clamp(pitch, MIN_PITCH, MAX_PITCH)); - alSourcePlay(player_source); - } -} - -void sound::play_ui(resource_ptr<SoundEffect> sound, bool looping, float pitch) -{ - alSourceRewind(ui_source); - - sfx_ui = sound; - - if(sfx_ui) { - alSourcei(ui_source, AL_BUFFER, sfx_ui->buffer); - alSourcei(ui_source, AL_LOOPING, looping); - alSourcef(ui_source, AL_PITCH, vx::clamp(pitch, MIN_PITCH, MAX_PITCH)); - alSourcePlay(ui_source); - } -}
\ No newline at end of file diff --git a/game/client/sound.hh b/game/client/sound.hh deleted file mode 100644 index 2701ae0..0000000 --- a/game/client/sound.hh +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef CLIENT_SOUND_HH -#define CLIENT_SOUND_HH 1 -#pragma once - -#include "core/resource.hh" - -class ConfigFloat; -struct SoundEffect; - -namespace sound -{ -extern ConfigFloat volume_master; -extern ConfigFloat volume_effects; -extern ConfigFloat volume_music; -extern ConfigFloat volume_ui; -} // namespace sound - -namespace sound -{ -void init_config(void); -void init(void); -void init_late(void); -void deinit(void); -void update(void); -} // namespace sound - -namespace sound -{ -void play_generic(const char* sound, bool looping, float pitch); -void play_entity(entt::entity entity, const char* sound, bool looping, float pitch); -void play_player(const char* sound, bool looping, float pitch); -void play_ui(const char* sound, bool looping, float pitch); -} // namespace sound - -namespace sound -{ -void play_generic(resource_ptr<SoundEffect> sound, bool looping, float pitch); -void play_entity(entt::entity entity, resource_ptr<SoundEffect> sound, bool looping, float pitch); -void play_player(resource_ptr<SoundEffect> sound, bool looping, float pitch); -void play_ui(resource_ptr<SoundEffect> sound, bool looping, float pitch); -} // namespace sound - -#endif /* CLIENT_SOUND_HH */ diff --git a/game/client/sound_effect.cc b/game/client/sound_effect.cc deleted file mode 100644 index 182f49d..0000000 --- a/game/client/sound_effect.cc +++ /dev/null @@ -1,115 +0,0 @@ -#include "client/pch.hh" - -#include "client/sound_effect.hh" - -#include "core/resource.hh" - -#include "client/globals.hh" - -static emhash8::HashMap<std::string, resource_ptr<SoundEffect>> resource_map; - -static std::size_t drwav_read_physfs(void* file, void* output, std::size_t count) -{ - return static_cast<std::size_t>(PHYSFS_readBytes(reinterpret_cast<PHYSFS_File*>(file), output, count)); -} - -static drwav_bool32 drwav_seek_physfs(void* file, int offset, drwav_seek_origin origin) -{ - if(origin == drwav_seek_origin_current) { - return PHYSFS_seek(reinterpret_cast<PHYSFS_File*>(file), PHYSFS_tell(reinterpret_cast<PHYSFS_File*>(file)) + offset); - } else { - return PHYSFS_seek(reinterpret_cast<PHYSFS_File*>(file), offset); - } -} - -template<> -resource_ptr<SoundEffect> resource::load<SoundEffect>(const char* name, unsigned int flags) -{ - auto it = resource_map.find(name); - - if(it != resource_map.cend()) { - // Return an existing resource - return it->second; - } - - if(globals::sound_ctx == nullptr) { - // Sound is disabled - return nullptr; - } - - auto file = PHYSFS_openRead(name); - - if(file == nullptr) { - spdlog::warn("resource: {} [SoundEffect]: {}", name, PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())); - return nullptr; - } - - drwav wav_info; - - if(!drwav_init(&wav_info, &drwav_read_physfs, &drwav_seek_physfs, file, nullptr)) { - spdlog::warn("resource: {} [SoundEffect]: drwav_init failed", name); - PHYSFS_close(file); - return nullptr; - } - - if(wav_info.channels != 1) { - spdlog::warn("resource: {} [SoundEffect]: only mono sound files are allowed", name); - drwav_uninit(&wav_info); - PHYSFS_close(file); - return nullptr; - } - - auto samples = new ALshort[wav_info.totalPCMFrameCount]; - auto count = drwav_read_pcm_frames_s16(&wav_info, wav_info.totalPCMFrameCount, reinterpret_cast<drwav_int16*>(samples)); - auto sample_rate = static_cast<ALsizei>(wav_info.sampleRate); - auto length = static_cast<ALsizei>(count * sizeof(ALshort)); - - drwav_uninit(&wav_info); - PHYSFS_close(file); - - auto new_resource = std::make_shared<SoundEffect>(); - new_resource->name = std::string(name); - - alGenBuffers(1, &new_resource->buffer); - alBufferData(new_resource->buffer, AL_FORMAT_MONO16, samples, length, sample_rate); - - delete[] samples; - - return resource_map.insert_or_assign(name, new_resource).first->second; -} - -template<> -void resource::hard_cleanup<SoundEffect>(void) -{ - for(const auto& it : resource_map) { - if(it.second.use_count() > 1L) { - spdlog::warn("resource: zombie resource [SoundEffect] {} [use_count={}]", it.first, it.second.use_count()); - } else { - spdlog::debug("resource: releasing [SoundEffect] {}", it.first); - } - - alDeleteBuffers(1, &it.second->buffer); - } - - resource_map.clear(); -} - -template<> -void resource::soft_cleanup<SoundEffect>(void) -{ - auto iter = resource_map.cbegin(); - - while(iter != resource_map.cend()) { - if(iter->second.use_count() == 1L) { - spdlog::debug("resource: releasing [SoundEffect] {}", iter->first); - - alDeleteBuffers(1, &iter->second->buffer); - - iter = resource_map.erase(iter); - - continue; - } - - iter = std::next(iter); - } -} diff --git a/game/client/sound_effect.hh b/game/client/sound_effect.hh deleted file mode 100644 index 83b5e4d..0000000 --- a/game/client/sound_effect.hh +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef CLIENT_SOUND_EFFECT_HH -#define CLIENT_SOUND_EFFECT_HH 1 -#pragma once - -struct SoundEffect final { - std::string name; - ALuint buffer; -}; - -#endif /* CLIENT_SOUND_EFFECT_HH */ diff --git a/game/client/sound_emitter.cc b/game/client/sound_emitter.cc deleted file mode 100644 index 9b84df2..0000000 --- a/game/client/sound_emitter.cc +++ /dev/null @@ -1,58 +0,0 @@ -#include "client/pch.hh" - -#include "client/sound_emitter.hh" - -#include "core/config.hh" -#include "core/constexpr.hh" - -#include "shared/coord.hh" -#include "shared/dimension.hh" -#include "shared/transform.hh" -#include "shared/velocity.hh" - -#include "client/camera.hh" -#include "client/globals.hh" -#include "client/sound.hh" - -SoundEmitterComponent::SoundEmitterComponent(void) -{ - alGenSources(1, &source); - sound = nullptr; -} - -SoundEmitterComponent::~SoundEmitterComponent(void) -{ - alSourceStop(source); - alDeleteSources(1, &source); -} - -void SoundEmitterComponent::update(void) -{ - if(globals::dimension) { - const auto view = globals::dimension->entities.view<SoundEmitterComponent>(); - - const auto& pivot = camera::position_chunk; - const auto gain = vx::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<TransformComponentIntr>(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<VelocityComponent>(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/sound_emitter.hh b/game/client/sound_emitter.hh deleted file mode 100644 index 88d99eb..0000000 --- a/game/client/sound_emitter.hh +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef CLIENT_SOUND_EMITTER_HH -#define CLIENT_SOUND_EMITTER_HH 1 -#pragma once - -#include "core/resource.hh" - -struct SoundEffect; - -struct SoundEmitterComponent final { - resource_ptr<SoundEffect> sound; - ALuint source; - -public: - explicit SoundEmitterComponent(void); - virtual ~SoundEmitterComponent(void); - -public: - static void update(void); -}; - -#endif /* CLIENT_SOUND_EMITTER_HH */ diff --git a/game/client/splash.cc b/game/client/splash.cc deleted file mode 100644 index f9c616b..0000000 --- a/game/client/splash.cc +++ /dev/null @@ -1,171 +0,0 @@ -#include "client/pch.hh" - -#include "client/splash.hh" - -#include "core/cmdline.hh" -#include "core/constexpr.hh" -#include "core/epoch.hh" -#include "core/resource.hh" - -#include "client/glfw.hh" -#include "client/globals.hh" -#include "client/gui_screen.hh" -#include "client/language.hh" -#include "client/texture_gui.hh" - -constexpr static ImGuiWindowFlags WINDOW_FLAGS = ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDecoration; - -constexpr static int SPLASH_COUNT = 4; -constexpr static std::size_t DELAY_MICROSECONDS = 2000000; -constexpr static const char* SPLASH_PATH = "textures/gui/client_splash.png"; - -static resource_ptr<TextureGUI> texture; -static float texture_aspect; -static float texture_alpha; - -static std::uint64_t end_time; -static std::string current_text; - -static void on_glfw_key(const GlfwKeyEvent& event) -{ - end_time = UINT64_C(0); -} - -static void on_glfw_mouse_button(const GlfwMouseButtonEvent& event) -{ - end_time = UINT64_C(0); -} - -static void on_glfw_scroll(const GlfwScrollEvent& event) -{ - end_time = UINT64_C(0); -} - -void client_splash::init(void) -{ - if(cmdline::contains("nosplash")) { - texture = nullptr; - texture_aspect = 0.0f; - texture_alpha = 0.0f; - return; - } - - std::random_device randev; - std::uniform_int_distribution<int> dist(0, SPLASH_COUNT - 1); - - texture = resource::load<TextureGUI>(SPLASH_PATH, TEXTURE_GUI_LOAD_CLAMP_S | TEXTURE_GUI_LOAD_CLAMP_T); - texture_aspect = 0.0f; - texture_alpha = 0.0f; - - if(texture) { - if(texture->size.x > texture->size.y) { - texture_aspect = static_cast<float>(texture->size.x) / static_cast<float>(texture->size.y); - } else { - texture_aspect = static_cast<float>(texture->size.y) / static_cast<float>(texture->size.x); - } - - texture_alpha = 1.0f; - } -} - -void client_splash::init_late(void) -{ - if(!texture) { - // We don't have to waste time - // rendering the missing client_splash texture - return; - } - - end_time = epoch::microseconds() + DELAY_MICROSECONDS; - - globals::dispatcher.sink<GlfwKeyEvent>().connect<&on_glfw_key>(); - globals::dispatcher.sink<GlfwMouseButtonEvent>().connect<&on_glfw_mouse_button>(); - globals::dispatcher.sink<GlfwScrollEvent>().connect<&on_glfw_scroll>(); - - current_text = language::resolve("splash.skip_prompt"); - - while(!glfwWindowShouldClose(globals::window)) { - const std::uint64_t curtime = epoch::microseconds(); - const std::uint64_t remains = end_time - curtime; - - if(curtime >= end_time) { - break; - } - - texture_alpha = vx::smoothstep(0.25f, 0.6f, static_cast<float>(remains) / static_cast<float>(DELAY_MICROSECONDS)); - - client_splash::render(); - } - - globals::dispatcher.sink<GlfwKeyEvent>().disconnect<&on_glfw_key>(); - globals::dispatcher.sink<GlfwMouseButtonEvent>().disconnect<&on_glfw_mouse_button>(); - globals::dispatcher.sink<GlfwScrollEvent>().disconnect<&on_glfw_scroll>(); - - texture = nullptr; - texture_aspect = 0.0f; - texture_alpha = 0.0f; - end_time = UINT64_C(0); -} - -void client_splash::render(void) -{ - if(!texture) { - // We don't have to waste time - // rendering the missing client_splash texture - return; - } - - // The client_splash is rendered outside the main - // render loop, so we have to manually begin - // and render both window and ImGui frames - ImGui_ImplOpenGL3_NewFrame(); - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - glDisable(GL_DEPTH_TEST); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glViewport(0, 0, globals::width, globals::height); - - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); - - auto viewport = ImGui::GetMainViewport(); - auto window_start = ImVec2(0.0f, 0.0f); - auto window_size = ImVec2(viewport->Size.x, viewport->Size.y); - - ImGui::SetNextWindowPos(window_start); - ImGui::SetNextWindowSize(window_size); - - if(ImGui::Begin("###client_splash", nullptr, WINDOW_FLAGS)) { - const float image_width = 0.60f * viewport->Size.x; - const float image_height = image_width / texture_aspect; - const ImVec2 image_size = ImVec2(image_width, image_height); - - const float image_x = 0.5f * (viewport->Size.x - image_width); - const float image_y = 0.5f * (viewport->Size.y - image_height); - const ImVec2 image_pos = ImVec2(image_x, image_y); - - if(!current_text.empty()) { - ImGui::PushFont(globals::font_chat); - ImGui::SetCursorPos(ImVec2(16.0f, 16.0f)); - ImGui::TextDisabled("%s", current_text.c_str()); - ImGui::PopFont(); - } - - const ImVec2 uv_a = ImVec2(0.0f, 0.0f); - const ImVec2 uv_b = ImVec2(1.0f, 1.0f); - const ImVec4 tint = ImVec4(1.0f, 1.0f, 1.0f, texture_alpha); - - ImGui::SetCursorPos(image_pos); - ImGui::ImageWithBg(texture->handle, image_size, uv_a, uv_b, ImVec4(0.0f, 0.0f, 0.0f, 0.0f), tint); - } - - ImGui::End(); - - ImGui::Render(); - ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); - - glfwSwapBuffers(globals::window); - - glfwPollEvents(); -} diff --git a/game/client/splash.hh b/game/client/splash.hh deleted file mode 100644 index 2b66e2c..0000000 --- a/game/client/splash.hh +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef CLIENT_SPLASH_HH -#define CLIENT_SPLASH_HH 1 -#pragma once - -namespace client_splash -{ -void init(void); -void init_late(void); -void render(void); -} // namespace client_splash - -#endif /* CLIENT_SPLASH_HH */ diff --git a/game/client/status_lines.cc b/game/client/status_lines.cc deleted file mode 100644 index ea7293c..0000000 --- a/game/client/status_lines.cc +++ /dev/null @@ -1,79 +0,0 @@ -#include "client/pch.hh" - -#include "client/status_lines.hh" - -#include "client/globals.hh" -#include "client/imdraw_ext.hh" - -static float line_offsets[STATUS_COUNT]; -static ImFont* line_fonts[STATUS_COUNT]; - -static ImVec4 line_text_colors[STATUS_COUNT]; -static ImVec4 line_shadow_colors[STATUS_COUNT]; -static std::string line_strings[STATUS_COUNT]; -static std::uint64_t line_spawns[STATUS_COUNT]; -static float line_fadeouts[STATUS_COUNT]; - -void status_lines::init(void) -{ - for(unsigned int i = 0U; i < STATUS_COUNT; ++i) { - line_text_colors[i] = ImVec4(0.0f, 0.0f, 0.0f, 0.0f); - line_shadow_colors[i] = ImVec4(0.0f, 0.0f, 0.0f, 0.0f); - line_strings[i] = std::string(); - line_spawns[i] = UINT64_MAX; - line_fadeouts[i] = 0.0f; - } -} - -void status_lines::init_late(void) -{ - line_offsets[STATUS_DEBUG] = 64.0f; - line_offsets[STATUS_HOTBAR] = 40.0f; -} - -void status_lines::layout(void) -{ - line_fonts[STATUS_DEBUG] = globals::font_debug; - line_fonts[STATUS_HOTBAR] = globals::font_chat; - - auto viewport = ImGui::GetMainViewport(); - auto draw_list = ImGui::GetForegroundDrawList(); - - for(unsigned int i = 0U; i < STATUS_COUNT; ++i) { - auto offset = line_offsets[i] * globals::gui_scale; - auto& text = line_strings[i]; - auto* font = line_fonts[i]; - - auto size = font->CalcTextSizeA(font->FontSize, FLT_MAX, 0.0f, text.c_str(), text.c_str() + text.size()); - auto pos = ImVec2(0.5f * (viewport->Size.x - size.x), viewport->Size.y - offset); - - auto spawn = line_spawns[i]; - auto fadeout = line_fadeouts[i]; - auto alpha = std::exp(-1.0f * std::pow(1.0e-6f * static_cast<float>(globals::curtime - spawn) / fadeout, 10.0f)); - - auto& color = line_text_colors[i]; - auto& shadow = line_shadow_colors[i]; - auto color_U32 = ImGui::GetColorU32(ImVec4(color.x, color.y, color.z, color.w * alpha)); - auto shadow_U32 = ImGui::GetColorU32(ImVec4(shadow.x, shadow.y, shadow.z, color.w * alpha)); - - imdraw_ext::text_shadow(text, pos, color_U32, shadow_U32, font, draw_list); - } -} - -void status_lines::set(unsigned int line, const std::string& text, const ImVec4& color, float fadeout) -{ - line_text_colors[line] = ImVec4(color.x, color.y, color.z, color.w); - line_shadow_colors[line] = ImVec4(color.x * 0.1f, color.y * 0.1f, color.z * 0.1f, color.w); - line_strings[line] = std::string(text); - line_spawns[line] = globals::curtime; - line_fadeouts[line] = fadeout; -} - -void status_lines::unset(unsigned int line) -{ - line_text_colors[line] = ImVec4(0.0f, 0.0f, 0.0f, 0.0f); - line_shadow_colors[line] = ImVec4(0.0f, 0.0f, 0.0f, 0.0f); - line_strings[line] = std::string(); - line_spawns[line] = UINT64_C(0); - line_fadeouts[line] = 0.0f; -} diff --git a/game/client/status_lines.hh b/game/client/status_lines.hh deleted file mode 100644 index c252a34..0000000 --- a/game/client/status_lines.hh +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef CLIENT_STATUS_LINES_HH -#define CLIENT_STATUS_LINES_HH 1 -#pragma once - -constexpr static unsigned int STATUS_DEBUG = 0x0000; // generic debug line -constexpr static unsigned int STATUS_HOTBAR = 0x0001; // hotbar item line -constexpr static unsigned int STATUS_COUNT = 0x0002; - -namespace status_lines -{ -void init(void); -void init_late(void); -void layout(void); -} // namespace status_lines - -namespace status_lines -{ -void set(unsigned int line, const std::string& text, const ImVec4& color, float fadeout); -void unset(unsigned int line); -} // namespace status_lines - -#endif /* CLIENT_STATUS_LINES_HH */ diff --git a/game/client/texture_gui.cc b/game/client/texture_gui.cc deleted file mode 100644 index 265f6c2..0000000 --- a/game/client/texture_gui.cc +++ /dev/null @@ -1,110 +0,0 @@ -#include "client/pch.hh" - -#include "client/texture_gui.hh" - -#include "core/image.hh" -#include "core/resource.hh" - -static emhash8::HashMap<std::string, resource_ptr<TextureGUI>> resource_map; - -template<> -resource_ptr<TextureGUI> resource::load<TextureGUI>(const char* name, unsigned int flags) -{ - auto it = resource_map.find(name); - - if(it != resource_map.cend()) { - // Return an existing resource - return it->second; - } - - unsigned int image_load_flags = 0U; - - if(flags & TEXTURE_GUI_LOAD_VFLIP) { - image_load_flags |= IMAGE_LOAD_FLIP; - } - - if(flags & TEXTURE_GUI_LOAD_GRAYSCALE) { - image_load_flags |= IMAGE_LOAD_GRAY; - } - - if(auto image = resource::load<Image>(name, image_load_flags)) { - GLuint gl_texture; - - glGenTextures(1, &gl_texture); - glBindTexture(GL_TEXTURE_2D, gl_texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, image->size.x, image->size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels); - - if(flags & TEXTURE_GUI_LOAD_CLAMP_S) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - } - - if(flags & TEXTURE_GUI_LOAD_CLAMP_T) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - } - - if(flags & TEXTURE_GUI_LOAD_LINEAR_MAG) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - } - - if(flags & TEXTURE_GUI_LOAD_LINEAR_MIN) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } - - auto new_resource = std::make_shared<TextureGUI>(); - new_resource->handle = static_cast<ImTextureID>(gl_texture); - new_resource->size.x = image->size.x; - new_resource->size.y = image->size.y; - - return resource_map.insert_or_assign(name, new_resource).first->second; - } - - return nullptr; -} - -template<> -void resource::hard_cleanup<TextureGUI>(void) -{ - for(const auto& it : resource_map) { - if(it.second.use_count() > 1L) { - spdlog::warn("resource: zombie resource [TextureGUI] {} [use_count={}]", it.first, it.second.use_count()); - } else { - spdlog::debug("resource: releasing [TextureGUI] {}", it.first); - } - - auto gl_texture = static_cast<GLuint>(it.second->handle); - - glDeleteTextures(1, &gl_texture); - } - - resource_map.clear(); -} - -template<> -void resource::soft_cleanup<TextureGUI>(void) -{ - auto iter = resource_map.cbegin(); - - while(iter != resource_map.cend()) { - if(iter->second.use_count() == 1L) { - spdlog::debug("resource: releasing [TextureGUI] {}", iter->first); - - auto gl_texture = static_cast<GLuint>(iter->second->handle); - - glDeleteTextures(1, &gl_texture); - - iter = resource_map.erase(iter); - - continue; - } - - iter = std::next(iter); - } -} diff --git a/game/client/texture_gui.hh b/game/client/texture_gui.hh deleted file mode 100644 index 97a91b4..0000000 --- a/game/client/texture_gui.hh +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef CLIENT_TEXTURE2D_HH -#define CLIENT_TEXTURE2D_HH 1 -#pragma once - -constexpr static unsigned int TEXTURE_GUI_LOAD_CLAMP_S = 0x0001; -constexpr static unsigned int TEXTURE_GUI_LOAD_CLAMP_T = 0x0002; -constexpr static unsigned int TEXTURE_GUI_LOAD_LINEAR_MAG = 0x0004; -constexpr static unsigned int TEXTURE_GUI_LOAD_LINEAR_MIN = 0x0008; -constexpr static unsigned int TEXTURE_GUI_LOAD_VFLIP = 0x0010; -constexpr static unsigned int TEXTURE_GUI_LOAD_GRAYSCALE = 0x0020; - -struct TextureGUI { - ImTextureID handle; - glm::ivec2 size; -}; - -#endif /* CLIENT_TEXTURE2D_HH */ diff --git a/game/client/toggles.cc b/game/client/toggles.cc deleted file mode 100644 index f40d6ed..0000000 --- a/game/client/toggles.cc +++ /dev/null @@ -1,154 +0,0 @@ -#include "client/pch.hh" - -#include "client/toggles.hh" - -#include "core/config.hh" - -#include "client/chat.hh" -#include "client/const.hh" -#include "client/gamepad.hh" -#include "client/glfw.hh" -#include "client/globals.hh" -#include "client/language.hh" - -struct ToggleInfo final { - const char* description; - int glfw_keycode; - bool is_enabled; -}; - -bool toggles::is_sequence_await = false; - -static ToggleInfo toggle_infos[TOGGLE_COUNT]; - -static void print_toggle_state(const ToggleInfo& info) -{ - if(info.description) { - if(info.is_enabled) { - client_chat::print(std::format("[toggles] {} ON", info.description)); - } else { - client_chat::print(std::format("[toggles] {} OFF", info.description)); - } - } -} - -static void toggle_value(ToggleInfo& info, toggle_type type) -{ - if(info.is_enabled) { - info.is_enabled = false; - globals::dispatcher.trigger(ToggleDisabledEvent { type }); - } else { - info.is_enabled = true; - globals::dispatcher.trigger(ToggleEnabledEvent { type }); - } - - print_toggle_state(info); -} - -static void on_glfw_key(const GlfwKeyEvent& event) -{ - if(globals::gui_keybind_ptr) { - // The UI keybind subsystem has the authority - // over debug toggles and it hogs the input keys - return; - } - - if(event.key == DEBUG_KEY) { - if(event.action == GLFW_PRESS) { - toggles::is_sequence_await = true; - ImGui::GetIO().ConfigFlags &= ~ImGuiConfigFlags_NavEnableKeyboard; - return; - } - - if(event.action == GLFW_RELEASE) { - toggles::is_sequence_await = false; - ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; - return; - } - } - - if((event.action == GLFW_PRESS) && toggles::is_sequence_await) { - if(event.key == GLFW_KEY_L) { - // This causes the language subsystem - // to re-parse the JSON file essentially - // causing the game to soft-reload language - language::set(language::get_current()); - return; - } - - for(toggle_type i = 0; i < TOGGLE_COUNT; ++i) { - if(event.key == toggle_infos[i].glfw_keycode) { - toggle_value(toggle_infos[i], i); - return; - } - } - } -} - -void toggles::init(void) -{ - toggle_infos[TOGGLE_WIREFRAME].description = "wireframe"; - toggle_infos[TOGGLE_WIREFRAME].glfw_keycode = GLFW_KEY_Z; - toggle_infos[TOGGLE_WIREFRAME].is_enabled = false; - - toggle_infos[TOGGLE_FULLBRIGHT].description = "fullbright"; - toggle_infos[TOGGLE_FULLBRIGHT].glfw_keycode = GLFW_KEY_J; - toggle_infos[TOGGLE_FULLBRIGHT].is_enabled = false; - - toggle_infos[TOGGLE_CHUNK_AABB].description = "chunk Borders"; - toggle_infos[TOGGLE_CHUNK_AABB].glfw_keycode = GLFW_KEY_G; - toggle_infos[TOGGLE_CHUNK_AABB].is_enabled = false; - - toggle_infos[TOGGLE_METRICS_UI].description = nullptr; - toggle_infos[TOGGLE_METRICS_UI].glfw_keycode = GLFW_KEY_V; - toggle_infos[TOGGLE_METRICS_UI].is_enabled = false; - - toggle_infos[TOGGLE_USE_GAMEPAD].description = "gamepad input"; - toggle_infos[TOGGLE_USE_GAMEPAD].glfw_keycode = GLFW_KEY_P; - toggle_infos[TOGGLE_USE_GAMEPAD].is_enabled = false; - - toggle_infos[TOGGLE_PM_FLIGHT].description = "flight mode"; - toggle_infos[TOGGLE_PM_FLIGHT].glfw_keycode = GLFW_KEY_F; - toggle_infos[TOGGLE_PM_FLIGHT].is_enabled = false; - -#ifndef NDEBUG - toggle_infos[TOGGLE_WIREFRAME].is_enabled = true; -#endif - - globals::dispatcher.sink<GlfwKeyEvent>().connect<&on_glfw_key>(); -} - -void toggles::init_late(void) -{ - for(toggle_type i = 0; i < TOGGLE_COUNT; ++i) { - if(toggle_infos[i].is_enabled) { - globals::dispatcher.trigger(ToggleEnabledEvent { i }); - } else { - globals::dispatcher.trigger(ToggleDisabledEvent { i }); - } - } -} - -bool toggles::get(toggle_type type) -{ - if(type < TOGGLE_COUNT) { - return toggle_infos[type].is_enabled; - } else { - return false; - } -} - -void toggles::set(toggle_type type, bool value) -{ - if(type < TOGGLE_COUNT) { - if(value) { - toggle_infos[type].is_enabled = true; - globals::dispatcher.trigger(ToggleEnabledEvent { type }); - } else { - toggle_infos[type].is_enabled = false; - globals::dispatcher.trigger(ToggleDisabledEvent { type }); - } - - print_toggle_state(toggle_infos[type]); - } -} diff --git a/game/client/toggles.hh b/game/client/toggles.hh deleted file mode 100644 index d892d33..0000000 --- a/game/client/toggles.hh +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef CLIENT_TOGGLES_HH -#define CLIENT_TOGGLES_HH 1 -#pragma once - -using toggle_type = unsigned int; -constexpr static toggle_type TOGGLE_WIREFRAME = 0x0000U; // Render things in wireframe mode -constexpr static toggle_type TOGGLE_FULLBRIGHT = 0x0001U; // Render things without lighting -constexpr static toggle_type TOGGLE_CHUNK_AABB = 0x0002U; // Render chunk bounding boxes -constexpr static toggle_type TOGGLE_METRICS_UI = 0x0003U; // Render debug metrics overlay -constexpr static toggle_type TOGGLE_USE_GAMEPAD = 0x0004U; // Use gamepad for player movement -constexpr static toggle_type TOGGLE_PM_FLIGHT = 0x0005U; // Enable flight for player movement -constexpr static std::size_t TOGGLE_COUNT = 0x0006U; - -struct ToggleEnabledEvent final { - toggle_type type; -}; - -struct ToggleDisabledEvent final { - toggle_type type; -}; - -namespace toggles -{ -// The value is true whenever the debug -// toggles manager awaits for a sequenced key -// to be pressed. During this no input should -// be processed by any other gameplay system -extern bool is_sequence_await; -} // namespace toggles - -namespace toggles -{ -void init(void); -void init_late(void); -bool get(toggle_type type); -void set(toggle_type type, bool value); -} // namespace toggles - -#endif /* CLIENT_TOGGLES_HH */ diff --git a/game/client/vclient.ico b/game/client/vclient.ico Binary files differdeleted file mode 100644 index 5f3ccd2..0000000 --- a/game/client/vclient.ico +++ /dev/null diff --git a/game/client/vclient.rc b/game/client/vclient.rc deleted file mode 100644 index 0268ca0..0000000 --- a/game/client/vclient.rc +++ /dev/null @@ -1 +0,0 @@ -IDI_ICON1 ICON DISCARDABLE "vclient.ico" diff --git a/game/client/voxel_anims.cc b/game/client/voxel_anims.cc deleted file mode 100644 index 4e0f168..0000000 --- a/game/client/voxel_anims.cc +++ /dev/null @@ -1,29 +0,0 @@ -#include "client/pch.hh" - -#include "client/voxel_anims.hh" - -#include "core/config.hh" -#include "core/constexpr.hh" - -#include "client/globals.hh" - -static ConfigUnsigned base_framerate(16U, 1U, 16U); - -std::uint64_t voxel_anims::nextframe = 0U; -std::uint32_t voxel_anims::frame = 0U; - -void voxel_anims::init(void) -{ - globals::client_config.add_value("voxel_anims.base_framerate", base_framerate); - - voxel_anims::nextframe = 0U; - voxel_anims::frame = 0U; -} - -void voxel_anims::update(void) -{ - if(globals::curtime >= voxel_anims::nextframe) { - voxel_anims::nextframe = globals::curtime + static_cast<std::uint64_t>(1000000.0 / static_cast<float>(base_framerate.get_value())); - voxel_anims::frame += 1U; - } -} diff --git a/game/client/voxel_anims.hh b/game/client/voxel_anims.hh deleted file mode 100644 index 5d6b9f9..0000000 --- a/game/client/voxel_anims.hh +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef CLIENT_VOXEL_ANIMS_HH -#define CLIENT_VOXEL_ANIMS_HH 1 -#pragma once - -namespace voxel_anims -{ -extern std::uint64_t nextframe; -extern std::uint32_t frame; -} // namespace voxel_anims - -namespace voxel_anims -{ -void init(void); -void update(void); -} // namespace voxel_anims - -#endif /* CLIENT_VOXEL_ANIMS_HH */ diff --git a/game/client/voxel_atlas.cc b/game/client/voxel_atlas.cc deleted file mode 100644 index ef996e2..0000000 --- a/game/client/voxel_atlas.cc +++ /dev/null @@ -1,183 +0,0 @@ -#include "client/pch.hh" - -#include "client/voxel_atlas.hh" - -#include "core/constexpr.hh" -#include "core/crc64.hh" -#include "core/image.hh" -#include "core/resource.hh" - -struct AtlasPlane final { - std::unordered_map<std::size_t, std::size_t> lookup; - std::vector<AtlasStrip> strips; - std::size_t layer_count_max; - std::size_t layer_count; - std::size_t plane_id; - GLuint gl_texture; -}; - -static int atlas_width; -static int atlas_height; -static std::size_t atlas_count; -static std::vector<AtlasPlane> planes; - -// Certain animated and varied voxels just double their -// textures (see the "default" texture part in VoxelInfoBuilder::build) -// so there could either be six UNIQUE atlas strips or only one -// https://crypto.stackexchange.com/questions/55162/best-way-to-hash-two-values-into-one -static std::size_t vector_hash(const std::vector<std::string>& strings) -{ - std::size_t source = 0; - for(const std::string& str : strings) - source += crc64::get(str); - return crc64::get(&source, sizeof(source)); -} - -static void plane_setup(AtlasPlane& plane) -{ - glGenTextures(1, &plane.gl_texture); - glBindTexture(GL_TEXTURE_2D_ARRAY, plane.gl_texture); - glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, atlas_width, atlas_height, plane.layer_count_max, 0, GL_RED, GL_UNSIGNED_BYTE, nullptr); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT); -} - -static AtlasStrip* plane_lookup(AtlasPlane& plane, std::size_t hash_value) -{ - const auto it = plane.lookup.find(hash_value); - - if(it != plane.lookup.cend()) { - return &plane.strips[it->second]; - } - - return nullptr; -} - -static AtlasStrip* plane_new_strip(AtlasPlane& plane, const std::vector<std::string>& paths, std::size_t hash_value) -{ - AtlasStrip strip = {}; - strip.offset = plane.layer_count; - strip.plane = plane.plane_id; - - glBindTexture(GL_TEXTURE_2D_ARRAY, plane.gl_texture); - - for(std::size_t i = 0; i < paths.size(); ++i) { - if(auto image = resource::load<Image>(paths[i].c_str(), IMAGE_LOAD_FLIP)) { - if((image->size.x != atlas_width) || (image->size.y != atlas_height)) { - spdlog::warn("atlas: {}: size mismatch", paths[i]); - continue; - } - - const std::size_t offset = strip.offset + i; - glTexSubImage3D( - GL_TEXTURE_2D_ARRAY, 0, 0, 0, offset, image->size.x, image->size.y, 1, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels); - } - } - - plane.layer_count += paths.size(); - - const std::size_t index = plane.strips.size(); - plane.lookup.emplace(hash_value, index); - plane.strips.push_back(std::move(strip)); - return &plane.strips[index]; -} - -void voxel_atlas::create(int width, int height, std::size_t count) -{ - GLint max_plane_layers; - - atlas_width = 1 << vx::log2(width); - atlas_height = 1 << vx::log2(height); - - // Clipping this at OpenGL 4.5 limit of 2048 is important due to - // how voxel quad meshes are packed in memory: each texture index is - // confined in 11 bits so having bigger atlas planes makes no sense; - glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &max_plane_layers); - max_plane_layers = vx::clamp(max_plane_layers, 256, 2048); - - for(long i = count; i > 0L; i -= max_plane_layers) { - AtlasPlane plane = {}; - plane.plane_id = planes.size(); - plane.layer_count_max = vx::min<std::size_t>(max_plane_layers, i); - plane.layer_count = 0; - - const std::size_t save_id = plane.plane_id; - planes.push_back(std::move(plane)); - plane_setup(planes[save_id]); - } - - spdlog::debug("voxel_atlas: count={}", count); - spdlog::debug("voxel_atlas: atlas_size=[{}x{}]", atlas_width, atlas_height); - spdlog::debug("voxel_atlas: max_plane_layers={}", max_plane_layers); -} - -void voxel_atlas::destroy(void) -{ - for(const AtlasPlane& plane : planes) - glDeleteTextures(1, &plane.gl_texture); - atlas_width = 0; - atlas_height = 0; - planes.clear(); -} - -std::size_t voxel_atlas::plane_count(void) -{ - return planes.size(); -} - -GLuint voxel_atlas::plane_texture(std::size_t plane_id) -{ - if(plane_id < planes.size()) { - return planes[plane_id].gl_texture; - } else { - return 0; - } -} - -void voxel_atlas::generate_mipmaps(void) -{ - for(const AtlasPlane& plane : planes) { - glBindTexture(GL_TEXTURE_2D_ARRAY, plane.gl_texture); - glGenerateMipmap(GL_TEXTURE_2D_ARRAY); - } -} - -AtlasStrip* voxel_atlas::find_or_load(const std::vector<std::string>& paths) -{ - const std::size_t hash_value = vector_hash(paths); - - for(AtlasPlane& plane : planes) { - if(AtlasStrip* strip = plane_lookup(plane, hash_value)) { - return strip; - } - - continue; - } - - for(AtlasPlane& plane : planes) { - if((plane.layer_count + paths.size()) <= plane.layer_count_max) { - return plane_new_strip(plane, paths, hash_value); - } - - continue; - } - - return nullptr; -} - -AtlasStrip* voxel_atlas::find(const std::vector<std::string>& paths) -{ - const std::size_t hash_value = vector_hash(paths); - - for(AtlasPlane& plane : planes) { - if(AtlasStrip* strip = plane_lookup(plane, hash_value)) { - return strip; - } - - continue; - } - - return nullptr; -} diff --git a/game/client/voxel_atlas.hh b/game/client/voxel_atlas.hh deleted file mode 100644 index 67036ca..0000000 --- a/game/client/voxel_atlas.hh +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef CLIENT_VOXEL_ATLAS_HH -#define CLIENT_VOXEL_ATLAS_HH 1 -#pragma once - -struct AtlasStrip final { - std::size_t offset; - std::size_t plane; -}; - -namespace voxel_atlas -{ -void create(int width, int height, std::size_t count); -void destroy(void); -} // namespace voxel_atlas - -namespace voxel_atlas -{ -std::size_t plane_count(void); -GLuint plane_texture(std::size_t plane_id); -void generate_mipmaps(void); -} // namespace voxel_atlas - -namespace voxel_atlas -{ -AtlasStrip* find_or_load(const std::vector<std::string>& paths); -AtlasStrip* find(const std::vector<std::string>& paths); -} // namespace voxel_atlas - -#endif /* CLIENT_VOXEL_ATLAS_HH */ diff --git a/game/client/voxel_sounds.cc b/game/client/voxel_sounds.cc deleted file mode 100644 index fd02a8e..0000000 --- a/game/client/voxel_sounds.cc +++ /dev/null @@ -1,86 +0,0 @@ -#include "client/pch.hh" - -#include "client/voxel_sounds.hh" - -#include "client/sound_effect.hh" - -constexpr static std::size_t NUM_SURFACES = static_cast<std::size_t>(voxel_surface::COUNT); - -static std::vector<resource_ptr<SoundEffect>> footsteps_sounds[NUM_SURFACES]; -static std::mt19937_64 randomizer; - -static void add_footsteps_effect(voxel_surface surface, const char* name) -{ - if(auto effect = resource::load<SoundEffect>(name)) { - auto surface_index = static_cast<std::size_t>(surface); - footsteps_sounds[surface_index].push_back(effect); - } -} - -static resource_ptr<SoundEffect> get_footsteps_effect(voxel_surface surface) -{ - auto surface_index = static_cast<std::size_t>(surface); - - if(surface_index >= NUM_SURFACES) { - // Surface index out of range - return nullptr; - } - - const auto& sounds = footsteps_sounds[surface_index]; - - if(sounds.empty()) { - // No sounds for this surface - return nullptr; - } - - auto dist = std::uniform_int_distribution<std::size_t>(0, sounds.size() - 1); - return sounds.at(dist(randomizer)); -} - -void voxel_sounds::init(void) -{ - add_footsteps_effect(voxel_surface::DEFAULT, "sounds/surface/default1.wav"); - add_footsteps_effect(voxel_surface::DEFAULT, "sounds/surface/default2.wav"); - add_footsteps_effect(voxel_surface::DEFAULT, "sounds/surface/default3.wav"); - add_footsteps_effect(voxel_surface::DEFAULT, "sounds/surface/default4.wav"); - - add_footsteps_effect(voxel_surface::DIRT, "sounds/surface/dirt1.wav"); - - add_footsteps_effect(voxel_surface::GRASS, "sounds/surface/grass1.wav"); - add_footsteps_effect(voxel_surface::GRASS, "sounds/surface/grass2.wav"); - add_footsteps_effect(voxel_surface::GRASS, "sounds/surface/grass3.wav"); - - add_footsteps_effect(voxel_surface::GRAVEL, "sounds/surface/gravel1.wav"); - - add_footsteps_effect(voxel_surface::SAND, "sounds/surface/sand1.wav"); - add_footsteps_effect(voxel_surface::SAND, "sounds/surface/sand2.wav"); - - add_footsteps_effect(voxel_surface::WOOD, "sounds/surface/wood1.wav"); - add_footsteps_effect(voxel_surface::WOOD, "sounds/surface/wood2.wav"); - add_footsteps_effect(voxel_surface::WOOD, "sounds/surface/wood3.wav"); -} - -void voxel_sounds::deinit(void) -{ - for(std::size_t i = 0; i < NUM_SURFACES; ++i) { - footsteps_sounds[i].clear(); - } -} - -resource_ptr<SoundEffect> voxel_sounds::get_footsteps(voxel_surface surface) -{ - if(auto effect = get_footsteps_effect(surface)) { - return effect; - } - - if(auto effect = get_footsteps_effect(voxel_surface::DEFAULT)) { - return effect; - } - - return nullptr; -} - -resource_ptr<SoundEffect> voxel_sounds::get_placebreak(voxel_surface surface) -{ - return nullptr; -} diff --git a/game/client/voxel_sounds.hh b/game/client/voxel_sounds.hh deleted file mode 100644 index ed11c0f..0000000 --- a/game/client/voxel_sounds.hh +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef CLIENT_VOXEL_SOUNDS_HH -#define CLIENT_VOXEL_SOUNDS_HH 1 -#pragma once - -#include "core/resource.hh" - -#include "shared/voxel_registry.hh" - -struct SoundEffect; - -namespace voxel_sounds -{ -void init(void); -void deinit(void); -} // namespace voxel_sounds - -namespace voxel_sounds -{ -resource_ptr<SoundEffect> get_footsteps(voxel_surface surface); -resource_ptr<SoundEffect> get_placebreak(voxel_surface surface); -} // namespace voxel_sounds - -#endif /* CLIENT_VOXEL_SOUNDS_HH */ diff --git a/game/client/window_title.cc b/game/client/window_title.cc deleted file mode 100644 index 517429d..0000000 --- a/game/client/window_title.cc +++ /dev/null @@ -1,22 +0,0 @@ -#include "client/pch.hh" - -#include "client/window_title.hh" - -#include "core/version.hh" - -#include "shared/splash.hh" - -#include "client/globals.hh" - -void window_title::update(void) -{ - std::string title; - - if(globals::sound_ctx && globals::sound_dev) { - title = std::format("Voxelius {}: {}", project_version_string, splash::get()); - } else { - title = std::format("Voxelius {}: {} [NOSOUND]", project_version_string, splash::get()); - } - - glfwSetWindowTitle(globals::window, title.c_str()); -} diff --git a/game/client/window_title.hh b/game/client/window_title.hh deleted file mode 100644 index 25051c8..0000000 --- a/game/client/window_title.hh +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef CLIENT_WINDOW_TITLE_HH -#define CLIENT_WINDOW_TITLE_HH 1 -#pragma once - -namespace window_title -{ -void update(void); -} // namespace window_title - -#endif /* CLIENT_WINDOW_TITLE_HH */ |
