summaryrefslogtreecommitdiffstats
path: root/game
diff options
context:
space:
mode:
authoruntodesu <kirill@untode.su>2025-06-29 22:24:42 +0500
committeruntodesu <kirill@untode.su>2025-06-29 22:24:42 +0500
commit6cd00aacfa22fed6a54a9b812f6b069ad16feec0 (patch)
treeb77f4e665da3dd235cdb01e7e6ea78c1c02ecf2e /game
parentf440914e1ae453768d09383f332bc7844e0a700e (diff)
downloadvoxelius-6cd00aacfa22fed6a54a9b812f6b069ad16feec0.tar.bz2
voxelius-6cd00aacfa22fed6a54a9b812f6b069ad16feec0.zip
Move game sources into src subdirectory
Diffstat (limited to 'game')
-rw-r--r--game/CMakeLists.txt11
-rw-r--r--game/client/CMakeLists.txt126
-rw-r--r--game/client/background.cc37
-rw-r--r--game/client/background.hh12
-rw-r--r--game/client/bother.cc163
-rw-r--r--game/client/bother.hh23
-rw-r--r--game/client/camera.cc107
-rw-r--r--game/client/camera.hh32
-rw-r--r--game/client/chat.cc260
-rw-r--r--game/client/chat.hh21
-rw-r--r--game/client/chunk_mesher.cc467
-rw-r--r--game/client/chunk_mesher.hh19
-rw-r--r--game/client/chunk_quad.hh39
-rw-r--r--game/client/chunk_renderer.cc196
-rw-r--r--game/client/chunk_renderer.hh12
-rw-r--r--game/client/chunk_vbo.hh23
-rw-r--r--game/client/chunk_visibility.cc87
-rw-r--r--game/client/chunk_visibility.hh12
-rw-r--r--game/client/const.hh27
-rw-r--r--game/client/crosshair.cc41
-rw-r--r--game/client/crosshair.hh12
-rw-r--r--game/client/direct_connection.cc140
-rw-r--r--game/client/direct_connection.hh11
-rw-r--r--game/client/experiments.cc77
-rw-r--r--game/client/experiments.hh20
-rw-r--r--game/client/factory.cc28
-rw-r--r--game/client/factory.hh12
-rw-r--r--game/client/game.cc690
-rw-r--r--game/client/game.hh37
-rw-r--r--game/client/gamepad.cc168
-rw-r--r--game/client/gamepad.hh45
-rw-r--r--game/client/gamepad_axis.cc114
-rw-r--r--game/client/gamepad_axis.hh39
-rw-r--r--game/client/gamepad_button.cc90
-rw-r--r--game/client/gamepad_button.hh29
-rw-r--r--game/client/glfw.hh37
-rw-r--r--game/client/globals.cc48
-rw-r--r--game/client/globals.hh66
-rw-r--r--game/client/gui_screen.hh14
-rw-r--r--game/client/hotbar.cc178
-rw-r--r--game/client/hotbar.hh31
-rw-r--r--game/client/imdraw_ext.cc13
-rw-r--r--game/client/imdraw_ext.hh11
-rw-r--r--game/client/interpolation.cc61
-rw-r--r--game/client/interpolation.hh10
-rw-r--r--game/client/keybind.cc200
-rw-r--r--game/client/keybind.hh26
-rw-r--r--game/client/language.cc196
-rw-r--r--game/client/language.hh43
-rw-r--r--game/client/listener.cc38
-rw-r--r--game/client/listener.hh10
-rw-r--r--game/client/main.cc441
-rw-r--r--game/client/main_menu.cc163
-rw-r--r--game/client/main_menu.hh12
-rw-r--r--game/client/message_box.cc94
-rw-r--r--game/client/message_box.hh21
-rw-r--r--game/client/metrics.cc98
-rw-r--r--game/client/metrics.hh11
-rw-r--r--game/client/outline.cc148
-rw-r--r--game/client/outline.hh20
-rw-r--r--game/client/pch.hh32
-rw-r--r--game/client/play_menu.cc548
-rw-r--r--game/client/play_menu.hh13
-rw-r--r--game/client/player_look.cc146
-rw-r--r--game/client/player_look.hh11
-rw-r--r--game/client/player_move.cc283
-rw-r--r--game/client/player_move.hh19
-rw-r--r--game/client/player_target.cc66
-rw-r--r--game/client/player_target.hh22
-rw-r--r--game/client/program.cc223
-rw-r--r--game/client/program.hh38
-rw-r--r--game/client/progress_bar.cc110
-rw-r--r--game/client/progress_bar.hh20
-rw-r--r--game/client/receive.cc187
-rw-r--r--game/client/receive.hh10
-rw-r--r--game/client/scoreboard.cc100
-rw-r--r--game/client/scoreboard.hh11
-rw-r--r--game/client/screenshot.cc82
-rw-r--r--game/client/screenshot.hh11
-rw-r--r--game/client/session.cc300
-rw-r--r--game/client/session.hh31
-rw-r--r--game/client/settings.cc1055
-rw-r--r--game/client/settings.hh83
-rw-r--r--game/client/skybox.cc11
-rw-r--r--game/client/skybox.hh15
-rw-r--r--game/client/sound.cc199
-rw-r--r--game/client/sound.hh43
-rw-r--r--game/client/sound_effect.cc115
-rw-r--r--game/client/sound_effect.hh10
-rw-r--r--game/client/sound_emitter.cc58
-rw-r--r--game/client/sound_emitter.hh21
-rw-r--r--game/client/splash.cc171
-rw-r--r--game/client/splash.hh12
-rw-r--r--game/client/status_lines.cc79
-rw-r--r--game/client/status_lines.hh22
-rw-r--r--game/client/texture_gui.cc110
-rw-r--r--game/client/texture_gui.hh17
-rw-r--r--game/client/toggles.cc154
-rw-r--r--game/client/toggles.hh39
-rw-r--r--game/client/vclient.icobin54361 -> 0 bytes
-rw-r--r--game/client/vclient.rc1
-rw-r--r--game/client/voxel_anims.cc29
-rw-r--r--game/client/voxel_anims.hh17
-rw-r--r--game/client/voxel_atlas.cc183
-rw-r--r--game/client/voxel_atlas.hh29
-rw-r--r--game/client/voxel_sounds.cc86
-rw-r--r--game/client/voxel_sounds.hh23
-rw-r--r--game/client/window_title.cc22
-rw-r--r--game/client/window_title.hh10
-rw-r--r--game/server/CMakeLists.txt39
-rw-r--r--game/server/chat.cc54
-rw-r--r--game/server/chat.hh16
-rw-r--r--game/server/game.cc148
-rw-r--r--game/server/game.hh26
-rw-r--r--game/server/globals.cc18
-rw-r--r--game/server/globals.hh25
-rw-r--r--game/server/inhabited.hh7
-rw-r--r--game/server/main.cc103
-rw-r--r--game/server/overworld.cc380
-rw-r--r--game/server/overworld.hh63
-rw-r--r--game/server/pch.hh7
-rw-r--r--game/server/receive.cc170
-rw-r--r--game/server/receive.hh10
-rw-r--r--game/server/sessions.cc419
-rw-r--r--game/server/sessions.hh53
-rw-r--r--game/server/status.cc26
-rw-r--r--game/server/status.hh10
-rw-r--r--game/server/universe.cc215
-rw-r--r--game/server/universe.hh25
-rw-r--r--game/server/unloader.cc76
-rw-r--r--game/server/unloader.hh14
-rw-r--r--game/server/vserver.icobin60201 -> 0 bytes
-rw-r--r--game/server/vserver.rc1
-rw-r--r--game/server/whitelist.cc95
-rw-r--r--game/server/whitelist.hh27
-rw-r--r--game/server/worldgen.cc148
-rw-r--r--game/server/worldgen.hh21
-rw-r--r--game/shared/CMakeLists.txt57
-rw-r--r--game/shared/chunk.cc69
-rw-r--r--game/shared/chunk.hh39
-rw-r--r--game/shared/chunk_aabb.cc54
-rw-r--r--game/shared/chunk_aabb.hh32
-rw-r--r--game/shared/collision.cc169
-rw-r--r--game/shared/collision.hh19
-rw-r--r--game/shared/const.hh47
-rw-r--r--game/shared/coord.hh149
-rw-r--r--game/shared/dimension.cc169
-rw-r--r--game/shared/dimension.hh85
-rw-r--r--game/shared/factory.cc35
-rw-r--r--game/shared/factory.hh12
-rw-r--r--game/shared/feature.cc52
-rw-r--r--game/shared/feature.hh22
-rw-r--r--game/shared/game.cc121
-rw-r--r--game/shared/game.hh11
-rw-r--r--game/shared/game_items.cc61
-rw-r--r--game/shared/game_items.hh26
-rw-r--r--game/shared/game_voxels.cc122
-rw-r--r--game/shared/game_voxels.hh28
-rw-r--r--game/shared/globals.cc12
-rw-r--r--game/shared/globals.hh23
-rw-r--r--game/shared/gravity.cc18
-rw-r--r--game/shared/gravity.hh12
-rw-r--r--game/shared/grounded.hh13
-rw-r--r--game/shared/head.hh14
-rw-r--r--game/shared/item_registry.cc103
-rw-r--r--game/shared/item_registry.hh62
-rw-r--r--game/shared/pch.hh25
-rw-r--r--game/shared/player.hh7
-rw-r--r--game/shared/protocol.cc491
-rw-r--r--game/shared/protocol.hh213
-rw-r--r--game/shared/ray_dda.cc96
-rw-r--r--game/shared/ray_dda.hh37
-rw-r--r--game/shared/splash.cc64
-rw-r--r--game/shared/splash.hh12
-rw-r--r--game/shared/stasis.cc19
-rw-r--r--game/shared/stasis.hh14
-rw-r--r--game/shared/threading.cc111
-rw-r--r--game/shared/threading.hh50
-rw-r--r--game/shared/transform.cc32
-rw-r--r--game/shared/transform.hh25
-rw-r--r--game/shared/types.hh44
-rw-r--r--game/shared/velocity.cc17
-rw-r--r--game/shared/velocity.hh17
-rw-r--r--game/shared/voxel_registry.cc192
-rw-r--r--game/shared/voxel_registry.hh144
-rw-r--r--game/shared/voxel_storage.cc46
-rw-r--r--game/shared/voxel_storage.hh18
187 files changed, 0 insertions, 15600 deletions
diff --git a/game/CMakeLists.txt b/game/CMakeLists.txt
deleted file mode 100644
index c6c32bf..0000000
--- a/game/CMakeLists.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-if(BUILD_VCLIENT)
- add_subdirectory(client)
-endif()
-
-if(BUILD_VSERVER)
- add_subdirectory(server)
-endif()
-
-if(BUILD_VCLIENT OR BUILD_VSERVER)
- add_subdirectory(shared)
-endif()
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]", &macro_index, &macro_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(), &current_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(), &current_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, &current_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(), &current_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(), &current_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(), &current_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, &current_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
deleted file mode 100644
index 5f3ccd2..0000000
--- a/game/client/vclient.ico
+++ /dev/null
Binary files differ
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 */
diff --git a/game/server/CMakeLists.txt b/game/server/CMakeLists.txt
deleted file mode 100644
index a9c5cc9..0000000
--- a/game/server/CMakeLists.txt
+++ /dev/null
@@ -1,39 +0,0 @@
-add_executable(vserver
- "${CMAKE_CURRENT_LIST_DIR}/chat.cc"
- "${CMAKE_CURRENT_LIST_DIR}/chat.hh"
- "${CMAKE_CURRENT_LIST_DIR}/game.cc"
- "${CMAKE_CURRENT_LIST_DIR}/game.hh"
- "${CMAKE_CURRENT_LIST_DIR}/globals.cc"
- "${CMAKE_CURRENT_LIST_DIR}/globals.hh"
- "${CMAKE_CURRENT_LIST_DIR}/inhabited.hh"
- "${CMAKE_CURRENT_LIST_DIR}/main.cc"
- "${CMAKE_CURRENT_LIST_DIR}/overworld.cc"
- "${CMAKE_CURRENT_LIST_DIR}/overworld.hh"
- "${CMAKE_CURRENT_LIST_DIR}/pch.hh"
- "${CMAKE_CURRENT_LIST_DIR}/receive.cc"
- "${CMAKE_CURRENT_LIST_DIR}/receive.hh"
- "${CMAKE_CURRENT_LIST_DIR}/sessions.cc"
- "${CMAKE_CURRENT_LIST_DIR}/sessions.hh"
- "${CMAKE_CURRENT_LIST_DIR}/status.cc"
- "${CMAKE_CURRENT_LIST_DIR}/status.hh"
- "${CMAKE_CURRENT_LIST_DIR}/universe.cc"
- "${CMAKE_CURRENT_LIST_DIR}/universe.hh"
- "${CMAKE_CURRENT_LIST_DIR}/unloader.cc"
- "${CMAKE_CURRENT_LIST_DIR}/unloader.hh"
- "${CMAKE_CURRENT_LIST_DIR}/whitelist.cc"
- "${CMAKE_CURRENT_LIST_DIR}/whitelist.hh"
- "${CMAKE_CURRENT_LIST_DIR}/worldgen.cc"
- "${CMAKE_CURRENT_LIST_DIR}/worldgen.hh")
-target_compile_features(vserver PUBLIC cxx_std_20)
-target_include_directories(vserver PUBLIC "${DEPS_INCLUDE_DIR}")
-target_include_directories(vserver PRIVATE "${PROJECT_SOURCE_DIR}")
-target_include_directories(vserver PRIVATE "${PROJECT_SOURCE_DIR}/game")
-target_precompile_headers(vserver PRIVATE "${CMAKE_CURRENT_LIST_DIR}/pch.hh")
-target_link_libraries(vserver PUBLIC shared)
-
-if(WIN32)
- enable_language(RC)
- target_sources(vserver PRIVATE "${CMAKE_CURRENT_LIST_DIR}/vserver.rc")
-endif()
-
-install(TARGETS vserver RUNTIME DESTINATION ".")
diff --git a/game/server/chat.cc b/game/server/chat.cc
deleted file mode 100644
index 1634c59..0000000
--- a/game/server/chat.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-#include "server/pch.hh"
-
-#include "server/chat.hh"
-
-#include "server/globals.hh"
-#include "server/sessions.hh"
-#include "shared/protocol.hh"
-
-static void on_chat_message_packet(const protocol::ChatMessage& packet)
-{
- if(packet.type == protocol::ChatMessage::TEXT_MESSAGE) {
- if(auto session = sessions::find(packet.peer)) {
- server_chat::broadcast(packet.message.c_str(), session->client_username.c_str());
- } else {
- server_chat::broadcast(packet.message.c_str(), packet.sender.c_str());
- }
- }
-}
-
-void server_chat::init(void)
-{
- globals::dispatcher.sink<protocol::ChatMessage>().connect<&on_chat_message_packet>();
-}
-
-void server_chat::broadcast(const char* message)
-{
- server_chat::broadcast(message, "server");
-}
-
-void server_chat::broadcast(const char* message, const char* sender)
-{
- protocol::ChatMessage packet;
- packet.type = protocol::ChatMessage::TEXT_MESSAGE;
- packet.message = std::string(message);
- packet.sender = std::string(sender);
-
- protocol::broadcast(globals::server_host, protocol::encode(packet));
-
- spdlog::info("<{}> {}", sender, message);
-}
-
-void server_chat::send(Session* session, const char* message)
-{
- server_chat::send(session, message, "server");
-}
-
-void server_chat::send(Session* session, const char* message, const char* sender)
-{
- protocol::ChatMessage packet;
- packet.type = protocol::ChatMessage::TEXT_MESSAGE;
- packet.message = std::string(message);
- packet.sender = std::string(sender);
- protocol::broadcast(globals::server_host, protocol::encode(packet));
-}
diff --git a/game/server/chat.hh b/game/server/chat.hh
deleted file mode 100644
index 2557290..0000000
--- a/game/server/chat.hh
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef SERVER_CHAT_HH
-#define SERVER_CHAT_HH 1
-#pragma once
-
-struct Session;
-
-namespace server_chat
-{
-void init(void);
-void broadcast(const char* message);
-void broadcast(const char* message, const char* sender);
-void send(Session* session, const char* message);
-void send(Session* session, const char* message, const char* sender);
-} // namespace server_chat
-
-#endif /* SERVER_CHAT_HH */
diff --git a/game/server/game.cc b/game/server/game.cc
deleted file mode 100644
index 978474c..0000000
--- a/game/server/game.cc
+++ /dev/null
@@ -1,148 +0,0 @@
-#include "server/pch.hh"
-
-#include "server/game.hh"
-
-#include "core/cmdline.hh"
-#include "core/config.hh"
-#include "core/constexpr.hh"
-#include "core/crc64.hh"
-#include "core/epoch.hh"
-
-#include "shared/collision.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/player.hh"
-#include "shared/protocol.hh"
-#include "shared/splash.hh"
-#include "shared/stasis.hh"
-#include "shared/transform.hh"
-#include "shared/velocity.hh"
-
-#include "server/chat.hh"
-#include "server/globals.hh"
-#include "server/receive.hh"
-#include "server/sessions.hh"
-#include "server/status.hh"
-#include "server/universe.hh"
-#include "server/unloader.hh"
-#include "server/whitelist.hh"
-#include "server/worldgen.hh"
-
-ConfigUnsigned server_game::view_distance(4U, 4U, 32U);
-
-std::uint64_t server_game::password_hash = UINT64_MAX;
-
-static ConfigNumber<enet_uint16> listen_port(protocol::PORT, 1024U, UINT16_MAX);
-static ConfigUnsigned status_peers(2U, 1U, 16U);
-static ConfigString password_string("");
-
-void server_game::init(void)
-{
- globals::server_config.add_value("game.listen_port", listen_port);
- globals::server_config.add_value("game.status_peers", status_peers);
- globals::server_config.add_value("game.password", password_string);
- globals::server_config.add_value("game.view_distance", server_game::view_distance);
-
- sessions::init();
-
- whitelist::init();
-
- splash::init_server();
-
- status::init();
-
- server_chat::init();
- server_recieve::init();
-
- worldgen::init();
-
- unloader::init();
- universe::init();
-}
-
-void server_game::init_late(void)
-{
- server_game::password_hash = crc64::get(password_string.get());
-
- sessions::init_late();
-
- whitelist::init_late();
-
- ENetAddress address;
- address.host = ENET_HOST_ANY;
- address.port = listen_port.get_value();
-
- globals::server_host = enet_host_create(&address, sessions::max_players.get_value() + status_peers.get_value(), 1, 0, 0);
-
- if(!globals::server_host) {
- spdlog::critical("game: unable to setup an ENet host");
- std::terminate();
- }
-
- spdlog::info("game: host: {} player + {} status peers", sessions::max_players.get_value(), status_peers.get_value());
- spdlog::info("game: host: listening on UDP port {}", address.port);
-
- game_voxels::populate();
- game_items::populate();
-
- unloader::init_late();
- universe::init_late();
-
- sessions::init_post_universe();
-}
-
-void server_game::deinit(void)
-{
- protocol::Disconnect packet;
- packet.reason = "protocol.server_shutdown";
- protocol::broadcast(globals::server_host, protocol::encode(packet));
-
- whitelist::deinit();
-
- sessions::deinit();
-
- enet_host_flush(globals::server_host);
- enet_host_service(globals::server_host, nullptr, 500);
- enet_host_destroy(globals::server_host);
-
- universe::deinit();
-}
-
-void server_game::fixed_update(void)
-{
- // FIXME: threading
- for(auto dimension : globals::dimensions) {
- CollisionComponent::fixed_update(dimension.second);
- VelocityComponent::fixed_update(dimension.second);
- TransformComponent::fixed_update(dimension.second);
- GravityComponent::fixed_update(dimension.second);
- StasisComponent::fixed_update(dimension.second);
- }
-}
-
-void server_game::fixed_update_late(void)
-{
- ENetEvent enet_event;
-
- while(0 < enet_host_service(globals::server_host, &enet_event, 0)) {
- if(enet_event.type == ENET_EVENT_TYPE_DISCONNECT) {
- sessions::destroy(sessions::find(enet_event.peer));
- sessions::refresh_scoreboard();
- continue;
- }
-
- if(enet_event.type == ENET_EVENT_TYPE_RECEIVE) {
- protocol::decode(globals::dispatcher, enet_event.packet, enet_event.peer);
- enet_packet_destroy(enet_event.packet);
- continue;
- }
- }
-
- // FIXME: threading
- for(auto dimension : globals::dimensions) {
- unloader::fixed_update_late(dimension.second);
- }
-}
diff --git a/game/server/game.hh b/game/server/game.hh
deleted file mode 100644
index 98c6bf3..0000000
--- a/game/server/game.hh
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef SERVER_GAME_HH
-#define SERVER_GAME_HH 1
-#pragma once
-
-class ConfigUnsigned;
-
-namespace server_game
-{
-extern ConfigUnsigned view_distance;
-} // namespace server_game
-
-namespace server_game
-{
-extern std::uint64_t password_hash;
-} // namespace server_game
-
-namespace server_game
-{
-void init(void);
-void init_late(void);
-void deinit(void);
-void fixed_update(void);
-void fixed_update_late(void);
-} // namespace server_game
-
-#endif /* SERVER_GAME_HH */
diff --git a/game/server/globals.cc b/game/server/globals.cc
deleted file mode 100644
index 883588b..0000000
--- a/game/server/globals.cc
+++ /dev/null
@@ -1,18 +0,0 @@
-#include "server/pch.hh"
-
-#include "server/globals.hh"
-
-#include "core/config.hh"
-
-#include "shared/protocol.hh"
-
-Config globals::server_config;
-
-ENetHost* globals::server_host;
-
-bool globals::is_running;
-unsigned int globals::tickrate;
-std::uint64_t globals::tickrate_dt;
-
-Dimension* globals::spawn_dimension;
-std::unordered_map<std::string, Dimension*> globals::dimensions;
diff --git a/game/server/globals.hh b/game/server/globals.hh
deleted file mode 100644
index 54f025a..0000000
--- a/game/server/globals.hh
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef SERVER_GLOBALS_HH
-#define SERVER_GLOBALS_HH 1
-#pragma once
-
-#include "shared/globals.hh"
-
-class Config;
-
-class Dimension;
-
-namespace globals
-{
-extern Config server_config;
-
-extern ENetHost* server_host;
-
-extern bool is_running;
-extern unsigned int tickrate;
-extern std::uint64_t tickrate_dt;
-
-extern Dimension* spawn_dimension;
-extern std::unordered_map<std::string, Dimension*> dimensions;
-} // namespace globals
-
-#endif /* SERVER_GLOBALS_HH */
diff --git a/game/server/inhabited.hh b/game/server/inhabited.hh
deleted file mode 100644
index c68ddaa..0000000
--- a/game/server/inhabited.hh
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef SERVER_INHABITED_HH
-#define SERVER_INHABITED_HH 1
-#pragma once
-
-struct InhabitedComponent final {};
-
-#endif /* SERVER_INHABITED_HH */
diff --git a/game/server/main.cc b/game/server/main.cc
deleted file mode 100644
index 734ae6a..0000000
--- a/game/server/main.cc
+++ /dev/null
@@ -1,103 +0,0 @@
-#include "server/pch.hh"
-
-#include "core/binfile.hh"
-#include "core/cmdline.hh"
-#include "core/config.hh"
-#include "core/constexpr.hh"
-#include "core/epoch.hh"
-#include "core/image.hh"
-#include "core/resource.hh"
-#include "core/version.hh"
-
-#include "shared/game.hh"
-#include "shared/protocol.hh"
-#include "shared/threading.hh"
-
-#include "server/game.hh"
-#include "server/globals.hh"
-
-static ConfigUnsigned server_tickrate(protocol::TICKRATE, 10U, 300U);
-
-static void on_termination_signal(int)
-{
- spdlog::warn("server: received termination signal");
- globals::is_running = false;
-}
-
-int main(int argc, char** argv)
-{
- cmdline::create(argc, argv);
-
- shared_game::init(argc, argv);
-
- spdlog::info("Voxelius Server {}", project_version_string);
-
- globals::fixed_frametime = 0.0f;
- globals::fixed_frametime_avg = 0.0f;
- globals::fixed_frametime_us = 0;
- globals::fixed_framecount = 0;
-
- globals::curtime = epoch::microseconds();
-
- globals::is_running = true;
-
- std::signal(SIGINT, &on_termination_signal);
- std::signal(SIGTERM, &on_termination_signal);
-
- server_game::init();
-
- threading::init();
-
- globals::server_config.add_value("server.tickrate", server_tickrate);
- globals::server_config.load_file("server.conf");
- globals::server_config.load_cmdline();
-
- globals::tickrate = server_tickrate.get_value();
- globals::tickrate_dt = static_cast<std::uint64_t>(1000000.0f / static_cast<float>(globals::tickrate));
-
- server_game::init_late();
-
- std::uint64_t last_curtime = globals::curtime;
-
- while(globals::is_running) {
- globals::curtime = epoch::microseconds();
-
- globals::fixed_frametime_us = globals::curtime - last_curtime;
- globals::fixed_frametime = static_cast<float>(globals::fixed_frametime_us) / 1000000.0f;
- globals::fixed_frametime_avg += globals::fixed_frametime;
- globals::fixed_frametime_avg *= 0.5f;
-
- last_curtime = globals::curtime;
-
- server_game::fixed_update();
- server_game::fixed_update_late();
-
- globals::dispatcher.update();
-
- globals::fixed_framecount += 1;
-
- std::this_thread::sleep_for(std::chrono::microseconds(globals::tickrate_dt));
-
- resource::soft_cleanup<BinFile>();
- resource::soft_cleanup<Image>();
-
- threading::update();
- }
-
- server_game::deinit();
-
- resource::hard_cleanup<BinFile>();
- resource::hard_cleanup<Image>();
-
- threading::deinit();
-
- spdlog::info("server: shutdown after {} frames", globals::fixed_framecount);
- spdlog::info("server: average framerate: {:.03f} TPS", 1.0f / globals::fixed_frametime_avg);
- spdlog::info("server: average frametime: {:.03f} MSPT", 1000.0f * globals::fixed_frametime_avg);
-
- globals::server_config.save_file("server.conf");
-
- shared_game::deinit();
-
- return EXIT_SUCCESS;
-}
diff --git a/game/server/overworld.cc b/game/server/overworld.cc
deleted file mode 100644
index a280e06..0000000
--- a/game/server/overworld.cc
+++ /dev/null
@@ -1,380 +0,0 @@
-#include "server/pch.hh"
-
-#include "server/overworld.hh"
-
-#include "core/vectors.hh"
-
-#include "shared/coord.hh"
-#include "shared/game_voxels.hh"
-#include "shared/voxel_storage.hh"
-
-// FIXME: load these from a file
-static void compute_tree_feature(unsigned int height, Feature& feature, voxel_id log_voxel, voxel_id leaves_voxel)
-{
- // Ensure the tree height is too small
- height = vx::max<unsigned int>(height, 4U);
-
- // Put down a single piece of dirt
- feature.push_back({ voxel_pos(0, -1, 0), game_voxels::dirt, true });
-
- // Generate tree stem
- for(unsigned int i = 0; i < height; ++i) {
- feature.push_back({ voxel_pos(0, i, 0), log_voxel, true });
- }
-
- auto leaves_start = height - 3U;
- auto leaves_thick_end = height - 2U;
- auto leaves_thin_end = height - 1U;
-
- // Generate the thin 3x3 layer of leaves that
- // starts from leaves_start and ends at leaves_thin_end
- for(unsigned int i = leaves_start; i <= leaves_thin_end; ++i) {
- feature.push_back({ local_pos(-1, i, -1), leaves_voxel, false });
- feature.push_back({ local_pos(-1, i, +0), leaves_voxel, false });
- feature.push_back({ local_pos(-1, i, +1), leaves_voxel, false });
- feature.push_back({ local_pos(+0, i, -1), leaves_voxel, false });
- feature.push_back({ local_pos(+0, i, +1), leaves_voxel, false });
- feature.push_back({ local_pos(+1, i, -1), leaves_voxel, false });
- feature.push_back({ local_pos(+1, i, +0), leaves_voxel, false });
- feature.push_back({ local_pos(+1, i, +1), leaves_voxel, false });
- }
-
- // Generate the tree cap; a 3x3 patch of leaves
- // that is slapped right on top of the thin 3x3 layer
- feature.push_back({ local_pos(-1, height, +0), leaves_voxel, false });
- feature.push_back({ local_pos(+0, height, -1), leaves_voxel, false });
- feature.push_back({ local_pos(+0, height, +0), leaves_voxel, false });
- feature.push_back({ local_pos(+0, height, +1), leaves_voxel, false });
- feature.push_back({ local_pos(+1, height, +0), leaves_voxel, false });
-
- // Generate the thin 5x5 layer of leaves that
- // starts from leaves_start and ends at leaves_thin_end
- for(unsigned int i = leaves_start; i <= leaves_thick_end; ++i) {
- feature.push_back({ local_pos(-1, i, -2), leaves_voxel, false });
- feature.push_back({ local_pos(-1, i, +2), leaves_voxel, false });
- feature.push_back({ local_pos(-2, i, -1), leaves_voxel, false });
- feature.push_back({ local_pos(-2, i, -2), leaves_voxel, false });
- feature.push_back({ local_pos(-2, i, +0), leaves_voxel, false });
- feature.push_back({ local_pos(-2, i, +1), leaves_voxel, false });
- feature.push_back({ local_pos(-2, i, +2), leaves_voxel, false });
- feature.push_back({ local_pos(+0, i, -2), leaves_voxel, false });
- feature.push_back({ local_pos(+0, i, +2), leaves_voxel, false });
- feature.push_back({ local_pos(+1, i, -2), leaves_voxel, false });
- feature.push_back({ local_pos(+1, i, +2), leaves_voxel, false });
- feature.push_back({ local_pos(+2, i, -1), leaves_voxel, false });
- feature.push_back({ local_pos(+2, i, -2), leaves_voxel, false });
- feature.push_back({ local_pos(+2, i, +0), leaves_voxel, false });
- feature.push_back({ local_pos(+2, i, +1), leaves_voxel, false });
- feature.push_back({ local_pos(+2, i, +2), leaves_voxel, false });
- }
-}
-
-Overworld::Overworld(const char* name) : Dimension(name, -30.0f)
-{
- m_bottommost_chunk.set_limits(-64, -4);
- m_terrain_variation.set_limits(16, 256);
-
- compute_tree_feature(4U, m_feat_tree[0], game_voxels::oak_log, game_voxels::oak_leaves);
- compute_tree_feature(5U, m_feat_tree[1], game_voxels::oak_log, game_voxels::oak_leaves);
- compute_tree_feature(6U, m_feat_tree[2], game_voxels::oak_log, game_voxels::oak_leaves);
- compute_tree_feature(8U, m_feat_tree[3], game_voxels::oak_log, game_voxels::oak_leaves);
-}
-
-void Overworld::init(Config& config)
-{
- m_terrain_variation.set_value(64);
- m_bottommost_chunk.set_value(-4);
-
- config.add_value("overworld.terrain_variation", m_terrain_variation);
- config.add_value("overworld.bottommost_chunk", m_bottommost_chunk);
-}
-
-void Overworld::init_late(std::uint64_t global_seed)
-{
- std::mt19937 twister(global_seed);
-
- m_fnl_variation = fnlCreateState();
- m_fnl_variation.seed = static_cast<int>(twister());
- m_fnl_variation.noise_type = FNL_NOISE_PERLIN;
- m_fnl_variation.frequency = 0.001f;
-
- m_fnl_terrain = fnlCreateState();
- m_fnl_terrain.seed = static_cast<int>(twister());
- m_fnl_terrain.noise_type = FNL_NOISE_OPENSIMPLEX2S;
- m_fnl_terrain.fractal_type = FNL_FRACTAL_FBM;
- m_fnl_terrain.frequency = 0.005f;
- m_fnl_terrain.octaves = 4;
-
- m_fnl_caves_a = fnlCreateState();
- m_fnl_caves_a.seed = static_cast<int>(twister());
- m_fnl_caves_a.noise_type = FNL_NOISE_PERLIN;
- m_fnl_caves_a.fractal_type = FNL_FRACTAL_RIDGED;
- m_fnl_caves_a.frequency = 0.0125f;
- m_fnl_caves_a.octaves = 1;
-
- m_fnl_caves_b = fnlCreateState();
- m_fnl_caves_b.seed = static_cast<int>(twister());
- m_fnl_caves_b.noise_type = FNL_NOISE_OPENSIMPLEX2S;
- m_fnl_caves_b.fractal_type = FNL_FRACTAL_RIDGED;
- m_fnl_caves_b.frequency = 0.0125f;
- m_fnl_caves_b.octaves = 1;
-
- m_fnl_nvdi = fnlCreateState();
- m_fnl_nvdi.seed = static_cast<int>(twister());
- m_fnl_nvdi.noise_type = FNL_NOISE_OPENSIMPLEX2S;
- m_fnl_nvdi.frequency = 1.0f;
-
- m_metamap.clear();
-}
-
-bool Overworld::generate(const chunk_pos& cpos, VoxelStorage& voxels)
-{
- if(cpos.y <= m_bottommost_chunk.get_value()) {
- // If the player asks the generator
- // to generate a lot of stuff below
- // the surface, it will happily chew
- // through all the server threads
- return false;
- }
-
- voxels.fill(NULL_VOXEL_ID);
-
- m_mutex.lock();
- generate_terrain(cpos, voxels);
- m_mutex.unlock();
-
- m_mutex.lock();
- generate_surface(cpos, voxels);
- m_mutex.unlock();
-
- m_mutex.lock();
- generate_caves(cpos, voxels);
- m_mutex.unlock();
-
- m_mutex.lock();
- generate_features(cpos, voxels);
- m_mutex.unlock();
-
- return true;
-}
-
-bool Overworld::is_inside_cave(const voxel_pos& vpos)
-{
- auto noise_a = fnlGetNoise3D(&m_fnl_caves_a, vpos.x, vpos.y * 2.0f, vpos.z);
- auto noise_b = fnlGetNoise3D(&m_fnl_caves_b, vpos.x, vpos.y * 2.0f, vpos.z);
- return (noise_a > 0.95f) && (noise_b > 0.85f);
-}
-
-bool Overworld::is_inside_terrain(const voxel_pos& vpos)
-{
- auto variation_noise = fnlGetNoise3D(&m_fnl_terrain, vpos.x, vpos.y, vpos.z);
- auto variation = m_terrain_variation.get_value() * (1.0f - (variation_noise * variation_noise));
- auto noise = variation * fnlGetNoise3D(&m_fnl_terrain, vpos.x, vpos.y, vpos.z) - vpos.y;
- return noise > 0.0f;
-}
-
-const Overworld_Metadata& Overworld::get_or_create_metadata(const chunk_pos_xz& cpos)
-{
- auto it = m_metamap.find(cpos);
-
- if(it != m_metamap.cend()) {
- // Metadata is present
- return it->second;
- }
-
- auto& metadata = m_metamap.insert_or_assign(cpos, Overworld_Metadata()).first->second;
- metadata.entropy.fill(std::numeric_limits<std::uint64_t>::max());
- metadata.heightmap.fill(std::numeric_limits<voxel_pos::value_type>::min());
-
- auto twister = std::mt19937_64(std::hash<chunk_pos_xz>()(cpos));
- auto variation = m_terrain_variation.get_value();
-
- // Generator might need some randomness
- // that depends on 2D coordinates, so we
- // generate this entropy ahead of time
- for(int i = 0; i < CHUNK_AREA; ++i) {
- metadata.entropy[i] = twister();
- }
-
- // Generate speculative heightmap;
- // Cave generation might have issues with placing
- // surface features such as trees but I genuinely don't give a shit
- for(int lx = 0; lx < CHUNK_SIZE; lx += 1) {
- for(int lz = 0; lz < CHUNK_SIZE; lz += 1) {
- auto hdx = static_cast<std::size_t>(lx + lz * CHUNK_SIZE);
- auto vpos = coord::to_voxel(chunk_pos(cpos.x, 0, cpos.y), local_pos(lx, 0, lz));
-
- for(vpos.y = variation; vpos.y >= -variation; vpos.y -= 1) {
- if(is_inside_terrain(vpos)) {
- metadata.heightmap[hdx] = vpos.y;
- break;
- }
- }
- }
- }
-
- auto nvdi_value = 0.5f + 0.5f * fnlGetNoise2D(&m_fnl_nvdi, cpos.x, cpos.y);
- auto tree_density = (nvdi_value >= 0.33f) ? vx::floor<unsigned int>(nvdi_value * 4.0f) : 0U;
-
- for(unsigned int i = 0U; i < tree_density; ++i) {
- auto lpos = local_pos((twister() % CHUNK_SIZE), (twister() % OW_NUM_TREES), (twister() % CHUNK_SIZE));
- auto is_unique = true;
-
- for(const auto& check_lpos : metadata.trees) {
- if(vx::distance2(check_lpos, lpos) <= 9) {
- is_unique = false;
- break;
- }
- }
-
- if(is_unique) {
- metadata.trees.push_back(lpos);
- }
- }
-
- return metadata;
-}
-
-void Overworld::generate_terrain(const chunk_pos& cpos, VoxelStorage& voxels)
-{
- auto& metadata = get_or_create_metadata(chunk_pos_xz(cpos.x, cpos.z));
- auto variation = m_terrain_variation.get_value();
-
- for(unsigned long i = 0; i < CHUNK_VOLUME; ++i) {
- auto lpos = coord::to_local(i);
- auto vpos = coord::to_voxel(cpos, lpos);
-
- if(vpos.y > variation) {
- voxels[i] = NULL_VOXEL_ID;
- continue;
- }
-
- if(vpos.y < -variation) {
- voxels[i] = game_voxels::stone;
- continue;
- }
-
- if(is_inside_terrain(vpos)) {
- voxels[i] = game_voxels::stone;
- continue;
- }
- }
-}
-
-void Overworld::generate_surface(const chunk_pos& cpos, VoxelStorage& voxels)
-{
- auto& metadata = get_or_create_metadata(chunk_pos_xz(cpos.x, cpos.z));
- auto variation = m_terrain_variation.get_value();
-
- for(unsigned long i = 0; i < CHUNK_VOLUME; ++i) {
- auto lpos = coord::to_local(i);
- auto vpos = coord::to_voxel(cpos, lpos);
- auto hdx = static_cast<std::size_t>(lpos.x + lpos.z * CHUNK_SIZE);
-
- if((vpos.y > variation) || (vpos.y < -variation)) {
- // Speculative optimization
- continue;
- }
-
- if(voxels[i] == NULL_VOXEL_ID) {
- // Surface voxel checks only apply for solid voxels;
- // it's kind of obvious you can't replace air with grass
- continue;
- }
-
- unsigned int depth = 0U;
-
- for(unsigned int dy = 0U; dy < 5U; dy += 1U) {
- auto d_lpos = local_pos(lpos.x, lpos.y + dy + 1, lpos.z);
- auto d_vpos = coord::to_voxel(cpos, d_lpos);
- auto d_index = coord::to_index(d_lpos);
-
- if(d_lpos.y >= CHUNK_SIZE) {
- if(!is_inside_terrain(d_vpos)) {
- break;
- }
-
- depth += 1U;
- } else {
- if(voxels[d_index] == NULL_VOXEL_ID) {
- break;
- }
-
- depth += 1U;
- }
- }
-
- if(depth < 5U) {
- if(depth == 0U) {
- voxels[i] = game_voxels::grass;
- } else {
- voxels[i] = game_voxels::dirt;
- }
- }
- }
-}
-
-void Overworld::generate_caves(const chunk_pos& cpos, VoxelStorage& voxels)
-{
- auto& metadata = get_or_create_metadata(chunk_pos_xz(cpos.x, cpos.z));
- auto variation = m_terrain_variation.get_value();
-
- for(unsigned long i = 0U; i < CHUNK_VOLUME; ++i) {
- auto lpos = coord::to_local(i);
- auto vpos = coord::to_voxel(cpos, lpos);
-
- if(vpos.y > variation) {
- // Speculative optimization - there's no solid
- // terrain above variation to carve caves out from
- continue;
- }
-
- if(is_inside_cave(vpos)) {
- voxels[i] = NULL_VOXEL_ID;
- continue;
- }
- }
-}
-
-void Overworld::generate_features(const chunk_pos& cpos, VoxelStorage& voxels)
-{
- const chunk_pos_xz tree_chunks[] = {
- chunk_pos_xz(cpos.x - 0, cpos.z - 1),
- chunk_pos_xz(cpos.x - 1, cpos.z - 1),
- chunk_pos_xz(cpos.x - 1, cpos.z + 0),
- chunk_pos_xz(cpos.x - 1, cpos.z + 1),
- chunk_pos_xz(cpos.x + 0, cpos.z + 0),
- chunk_pos_xz(cpos.x + 0, cpos.z + 1),
- chunk_pos_xz(cpos.x + 1, cpos.z - 1),
- chunk_pos_xz(cpos.x + 1, cpos.z + 0),
- chunk_pos_xz(cpos.x + 1, cpos.z + 1),
- };
-
- for(unsigned int i = 0U; i < vx::array_size(tree_chunks); ++i) {
- const auto& cpos_xz = tree_chunks[i];
- const auto& metadata = get_or_create_metadata(cpos_xz);
-
- for(const auto& tree_info : metadata.trees) {
- auto hdx = static_cast<std::size_t>(tree_info.x + tree_info.z * CHUNK_SIZE);
- auto height = metadata.heightmap[hdx];
-
- if(height == std::numeric_limits<voxel_pos::value_type>::min()) {
- // What happened? Cave happened
- continue;
- }
-
- auto cpos_xyz = chunk_pos(cpos_xz.x, 0, cpos_xz.y);
- auto lpos_xyz = local_pos(tree_info.x, 0, tree_info.z);
-
- auto vpos = coord::to_voxel(cpos_xyz, lpos_xyz);
- vpos.y = height;
-
- if(is_inside_cave(vpos)) {
- // Cave is in the way
- continue;
- }
-
- m_feat_tree[tree_info.y].place(vpos + DIR_UP<voxel_pos::value_type>, cpos, voxels);
- }
- }
-}
diff --git a/game/server/overworld.hh b/game/server/overworld.hh
deleted file mode 100644
index 972a91d..0000000
--- a/game/server/overworld.hh
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifndef SERVER_OVERWORLD_HH
-#define SERVER_OVERWORLD_HH 1
-#pragma once
-
-#include "core/config.hh"
-
-#include "shared/const.hh"
-#include "shared/dimension.hh"
-#include "shared/feature.hh"
-
-constexpr static unsigned int OW_NUM_TREES = 4U;
-
-struct Overworld_Metadata final {
- dimension_entropy_map entropy;
- dimension_height_map heightmap;
- std::vector<local_pos> trees;
-};
-
-class Overworld final : public Dimension {
-public:
- explicit Overworld(const char* name);
- virtual ~Overworld(void) = default;
-
-public:
- virtual void init(Config& config) override;
- virtual void init_late(std::uint64_t global_seed) override;
- virtual bool generate(const chunk_pos& cpos, VoxelStorage& voxels) override;
-
-private:
- bool is_inside_cave(const voxel_pos& vpos);
- bool is_inside_terrain(const voxel_pos& vpos);
-
-private:
- const Overworld_Metadata& get_or_create_metadata(const chunk_pos_xz& cpos);
-
-private:
- void generate_terrain(const chunk_pos& cpos, VoxelStorage& voxels);
- void generate_surface(const chunk_pos& cpos, VoxelStorage& voxels);
- void generate_caves(const chunk_pos& cpos, VoxelStorage& voxels);
- void generate_features(const chunk_pos& cpos, VoxelStorage& voxels);
-
-private:
- ConfigInt m_terrain_variation;
- ConfigInt m_bottommost_chunk;
-
-private:
- emhash8::HashMap<chunk_pos_xz, Overworld_Metadata> m_metamap;
-
-private:
- fnl_state m_fnl_variation;
- fnl_state m_fnl_terrain;
- fnl_state m_fnl_caves_a;
- fnl_state m_fnl_caves_b;
- fnl_state m_fnl_nvdi;
-
-private:
- Feature m_feat_tree[OW_NUM_TREES];
-
-private:
- std::mutex m_mutex;
-};
-
-#endif /* SERVER_OVERWORLD_HH */
diff --git a/game/server/pch.hh b/game/server/pch.hh
deleted file mode 100644
index 89b396b..0000000
--- a/game/server/pch.hh
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef SERVER_PCH_HH
-#define SERVER_PCH_HH 1
-#pragma once
-
-#include <shared/pch.hh>
-
-#endif /* SERVER_PCH_HH */
diff --git a/game/server/receive.cc b/game/server/receive.cc
deleted file mode 100644
index 7674122..0000000
--- a/game/server/receive.cc
+++ /dev/null
@@ -1,170 +0,0 @@
-#include "server/pch.hh"
-
-#include "server/receive.hh"
-
-#include "core/config.hh"
-
-#include "shared/chunk_aabb.hh"
-#include "shared/coord.hh"
-#include "shared/dimension.hh"
-#include "shared/head.hh"
-#include "shared/protocol.hh"
-#include "shared/transform.hh"
-#include "shared/velocity.hh"
-
-#include "server/game.hh"
-#include "server/globals.hh"
-#include "server/inhabited.hh"
-#include "server/sessions.hh"
-#include "server/universe.hh"
-#include "server/worldgen.hh"
-
-static void on_entity_transform_packet(const protocol::EntityTransform& packet)
-{
- if(auto session = sessions::find(packet.peer)) {
- if(session->dimension && session->dimension->entities.valid(session->player_entity)) {
- auto& component = session->dimension->entities.emplace_or_replace<TransformComponent>(session->player_entity);
- component.angles = packet.angles;
- component.chunk = packet.chunk;
- component.local = packet.local;
-
- protocol::EntityTransform response;
- response.entity = session->player_entity;
- response.angles = component.angles;
- response.chunk = component.chunk;
- response.local = component.local;
-
- // Propagate changes to the rest of the world
- // except the peer that has sent the packet in the first place
- sessions::broadcast(session->dimension, protocol::encode(response), session->peer);
- }
- }
-}
-
-static void on_entity_velocity_packet(const protocol::EntityVelocity& packet)
-{
- if(auto session = sessions::find(packet.peer)) {
- if(session->dimension && session->dimension->entities.valid(session->player_entity)) {
- auto& component = session->dimension->entities.emplace_or_replace<VelocityComponent>(session->player_entity);
- component.value = packet.value;
-
- protocol::EntityVelocity response;
- response.entity = session->player_entity;
- response.value = component.value;
-
- // Propagate changes to the rest of the world
- // except the peer that has sent the packet in the first place
- sessions::broadcast(session->dimension, protocol::encode(response), session->peer);
- }
- }
-}
-
-static void on_entity_head_packet(const protocol::EntityHead& packet)
-{
- if(auto session = sessions::find(packet.peer)) {
- if(session->dimension && session->dimension->entities.valid(session->player_entity)) {
- auto& component = session->dimension->entities.emplace_or_replace<HeadComponent>(session->player_entity);
- component.angles = packet.angles;
-
- protocol::EntityHead response;
- response.entity = session->player_entity;
- response.angles = component.angles;
-
- // Propagate changes to the rest of the world
- // except the peer that has sent the packet in the first place
- sessions::broadcast(session->dimension, protocol::encode(response), session->peer);
- }
- }
-}
-
-static void on_set_voxel_packet(const protocol::SetVoxel& packet)
-{
- if(auto session = sessions::find(packet.peer)) {
- if(session->dimension && !session->dimension->set_voxel(packet.voxel, packet.vpos)) {
- auto cpos = coord::to_chunk(packet.vpos);
- auto lpos = coord::to_local(packet.vpos);
- auto index = coord::to_index(lpos);
-
- if(worldgen::is_generating(session->dimension, cpos)) {
- // The chunk is currently being generated;
- // ignore all requests from players to build there
- return;
- }
-
- auto chunk = session->dimension->find_chunk(cpos);
-
- if(chunk == nullptr) {
- // The chunk is not loaded, so we must
- // ignore any requests from players to build there
- return;
- }
-
- chunk->set_voxel(packet.voxel, index);
-
- session->dimension->chunks.emplace_or_replace<InhabitedComponent>(chunk->get_entity());
-
- protocol::SetVoxel response;
- response.vpos = packet.vpos;
- response.voxel = packet.voxel;
- sessions::broadcast(session->dimension, protocol::encode(response), session->peer);
-
- return;
- }
- }
-}
-
-static void on_request_chunk_packet(const protocol::RequestChunk& packet)
-{
- if(auto session = sessions::find(packet.peer)) {
- if(!session->dimension || !session->dimension->entities.valid(session->player_entity)) {
- // De-spawned sessions cannot request
- // chunks from the server; that's cheating!!!
- return;
- }
-
- if(auto transform = session->dimension->entities.try_get<TransformComponent>(session->player_entity)) {
- ChunkAABB view_box;
- view_box.min = transform->chunk - static_cast<chunk_pos::value_type>(server_game::view_distance.get_value());
- view_box.max = transform->chunk + static_cast<chunk_pos::value_type>(server_game::view_distance.get_value());
-
- if(view_box.contains(packet.cpos)) {
- if(auto chunk = universe::load_chunk(session->dimension, packet.cpos)) {
- protocol::ChunkVoxels response;
- response.chunk = packet.cpos;
- response.voxels = chunk->get_voxels();
- protocol::send(packet.peer, protocol::encode(response));
- } else {
- worldgen::request_chunk(session, packet.cpos);
- }
- }
- }
- }
-}
-
-static void on_entity_sound_packet(const protocol::EntitySound& packet)
-{
- if(auto session = sessions::find(packet.peer)) {
- if(!session->dimension || !session->dimension->entities.valid(session->player_entity)) {
- // De-spawned sessions cannot play sounds
- return;
- }
-
- protocol::EntitySound response;
- response.entity = session->player_entity;
- response.sound = packet.sound;
- response.looping = packet.looping;
- response.pitch = packet.pitch;
-
- sessions::broadcast(session->dimension, protocol::encode(response), packet.peer);
- }
-}
-
-void server_recieve::init(void)
-{
- globals::dispatcher.sink<protocol::EntityTransform>().connect<&on_entity_transform_packet>();
- globals::dispatcher.sink<protocol::EntityVelocity>().connect<&on_entity_velocity_packet>();
- globals::dispatcher.sink<protocol::EntityHead>().connect<&on_entity_head_packet>();
- globals::dispatcher.sink<protocol::SetVoxel>().connect<&on_set_voxel_packet>();
- globals::dispatcher.sink<protocol::RequestChunk>().connect<&on_request_chunk_packet>();
- globals::dispatcher.sink<protocol::EntitySound>().connect<&on_entity_sound_packet>();
-}
diff --git a/game/server/receive.hh b/game/server/receive.hh
deleted file mode 100644
index 57090b5..0000000
--- a/game/server/receive.hh
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef SERVER_RECEIVE_HH
-#define SERVER_RECEIVE_HH 1
-#pragma once
-
-namespace server_recieve
-{
-void init(void);
-} // namespace server_recieve
-
-#endif /* SERVER_RECEIVE_HH */
diff --git a/game/server/sessions.cc b/game/server/sessions.cc
deleted file mode 100644
index 43abbb7..0000000
--- a/game/server/sessions.cc
+++ /dev/null
@@ -1,419 +0,0 @@
-#include "server/pch.hh"
-
-#include "server/sessions.hh"
-
-#include "core/config.hh"
-#include "core/constexpr.hh"
-#include "core/crc64.hh"
-#include "core/strtools.hh"
-
-#include "shared/chunk.hh"
-#include "shared/coord.hh"
-#include "shared/dimension.hh"
-#include "shared/factory.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 "server/game.hh"
-#include "server/globals.hh"
-#include "server/whitelist.hh"
-
-class DimensionListener final {
-public:
- explicit DimensionListener(Dimension* dimension);
- void on_destroy_entity(const entt::registry& registry, entt::entity entity);
-
-private:
- Dimension* dimension;
-};
-
-ConfigUnsigned sessions::max_players(8U, 1U, 128U);
-unsigned int sessions::num_players = 0U;
-
-static emhash8::HashMap<std::string, Session*> username_map;
-static emhash8::HashMap<std::uint64_t, Session*> identity_map;
-static std::vector<DimensionListener> dimension_listeners;
-static std::vector<Session> sessions_vector;
-
-static void on_login_request_packet(const protocol::LoginRequest& packet)
-{
- if(packet.version > protocol::VERSION) {
- protocol::Disconnect response;
- response.reason = "protocol.outdated_server";
- protocol::send(packet.peer, protocol::encode(response));
- return;
- }
-
- if(packet.version < protocol::VERSION) {
- protocol::Disconnect response;
- response.reason = "protocol.outdated_client";
- protocol::send(packet.peer, protocol::encode(response));
- return;
- }
-
- // FIXME: calculate voxel registry checksum ahead of time
- // instead of figuring it out every time a new player connects
- if(packet.voxel_registry_checksum != voxel_registry::calcualte_checksum()) {
- protocol::Disconnect response;
- response.reason = "protocol.voxel_registry_checksum";
- protocol::send(packet.peer, protocol::encode(response));
- return;
- }
-
- if(packet.item_registry_checksum != item_registry::calcualte_checksum()) {
- protocol::Disconnect response;
- response.reason = "protocol.item_registry_checksum";
- protocol::send(packet.peer, protocol::encode(response));
- return;
- }
-
- // Don't assign new usernames and just kick the player if
- // an another client using the same username is already connected
- // and playing; since we have a whitelist, adding "(1)" isn't feasible anymore
- if(username_map.contains(packet.username)) {
- protocol::Disconnect response;
- response.reason = "protocol.username_taken";
- protocol::send(packet.peer, protocol::encode(response));
- return;
- }
-
- if(whitelist::enabled.get_value()) {
- if(!whitelist::contains(packet.username.c_str())) {
- protocol::Disconnect response;
- response.reason = "protocol.not_whitelisted";
- protocol::send(packet.peer, protocol::encode(response));
- return;
- }
-
- if(!whitelist::matches(packet.username.c_str(), packet.password_hash)) {
- protocol::Disconnect response;
- response.reason = "protocol.password_incorrect";
- protocol::send(packet.peer, protocol::encode(response));
- return;
- }
- } else if(packet.password_hash != server_game::password_hash) {
- protocol::Disconnect response;
- response.reason = "protocol.password_incorrect";
- protocol::send(packet.peer, protocol::encode(response));
- return;
- }
-
- if(Session* session = sessions::create(packet.peer, packet.username.c_str())) {
- protocol::LoginResponse response;
- response.client_index = session->client_index;
- response.client_identity = session->client_identity;
- response.server_tickrate = globals::tickrate;
- protocol::send(packet.peer, protocol::encode(response));
-
- protocol::DimensionInfo dim_info;
- dim_info.name = globals::spawn_dimension->get_name();
- dim_info.gravity = globals::spawn_dimension->get_gravity();
- protocol::send(packet.peer, protocol::encode(dim_info));
-
- spdlog::info("sessions: {} [{}] logged in with client_index={} in {}", session->client_username, session->client_identity,
- session->client_index, globals::spawn_dimension->get_name());
-
- // FIXME: only send entities that are present within the current
- // player's view bounding box; this also would mean we're not sending
- // anything here and just straight up spawing the player and await them
- // to receive all the chunks and entites they feel like requesting
- for(auto entity : globals::spawn_dimension->entities.view<entt::entity>()) {
- if(const auto head = globals::spawn_dimension->entities.try_get<HeadComponent>(entity)) {
- protocol::EntityHead head_packet;
- head_packet.entity = entity;
- head_packet.angles = head->angles;
- protocol::send(session->peer, protocol::encode(head_packet));
- }
-
- if(const auto transform = globals::spawn_dimension->entities.try_get<TransformComponent>(entity)) {
- protocol::EntityTransform transform_packet;
- transform_packet.entity = entity;
- transform_packet.angles = transform->angles;
- transform_packet.chunk = transform->chunk;
- transform_packet.local = transform->local;
- protocol::send(session->peer, protocol::encode(transform_packet));
- }
-
- if(const auto velocity = globals::spawn_dimension->entities.try_get<VelocityComponent>(entity)) {
- protocol::EntityVelocity velocity_packet;
- velocity_packet.entity = entity;
- velocity_packet.value = velocity->value;
- protocol::send(session->peer, protocol::encode(velocity_packet));
- }
-
- if(globals::spawn_dimension->entities.all_of<PlayerComponent>(entity)) {
- protocol::EntityPlayer player_packet;
- player_packet.entity = entity;
- protocol::send(session->peer, protocol::encode(player_packet));
- }
- }
-
- session->dimension = globals::spawn_dimension;
- session->player_entity = globals::spawn_dimension->entities.create();
- shared_factory::create_player(globals::spawn_dimension, session->player_entity);
-
- const auto& head = globals::spawn_dimension->entities.get<HeadComponent>(session->player_entity);
- const auto& transform = globals::spawn_dimension->entities.get<TransformComponent>(session->player_entity);
- const auto& velocity = globals::spawn_dimension->entities.get<VelocityComponent>(session->player_entity);
-
- protocol::EntityHead head_packet;
- head_packet.entity = session->player_entity;
- head_packet.angles = head.angles;
-
- protocol::EntityTransform transform_packet;
- transform_packet.entity = session->player_entity;
- transform_packet.angles = transform.angles;
- transform_packet.chunk = transform.chunk;
- transform_packet.local = transform.local;
-
- protocol::EntityVelocity velocity_packet;
- velocity_packet.entity = session->player_entity;
- velocity_packet.value = velocity.value;
-
- protocol::EntityPlayer player_packet;
- player_packet.entity = session->player_entity;
-
- protocol::broadcast(globals::server_host, protocol::encode(head_packet));
- protocol::broadcast(globals::server_host, protocol::encode(transform_packet));
- protocol::broadcast(globals::server_host, protocol::encode(velocity_packet));
- protocol::broadcast(globals::server_host, protocol::encode(player_packet));
-
- protocol::SpawnPlayer spawn_packet;
- spawn_packet.entity = session->player_entity;
-
- // SpawnPlayer serves a different purpose compared to EntityPlayer
- // The latter is used to construct entities (as in "attach a component")
- // whilst the SpawnPlayer packet is used to notify client-side that the
- // entity identifier in the packet is to be treated as the local player entity
- protocol::send(session->peer, protocol::encode(spawn_packet));
-
- protocol::ChatMessage message;
- message.type = protocol::ChatMessage::PLAYER_JOIN;
- message.sender = session->client_username;
- message.message = std::string();
-
- protocol::broadcast(globals::server_host, protocol::encode(message));
-
- sessions::refresh_scoreboard();
-
- return;
- }
-
- protocol::Disconnect response;
- response.reason = "protocol.server_full";
- protocol::send(packet.peer, protocol::encode(response));
-}
-
-static void on_disconnect_packet(const protocol::Disconnect& packet)
-{
- if(Session* session = sessions::find(packet.peer)) {
- protocol::ChatMessage message;
- message.type = protocol::ChatMessage::PLAYER_LEAVE;
- message.sender = session->client_username;
- message.message = packet.reason;
-
- protocol::broadcast(globals::server_host, protocol::encode(message), session->peer);
-
- spdlog::info("{} disconnected ({})", session->client_username, packet.reason);
-
- sessions::destroy(session);
- sessions::refresh_scoreboard();
- }
-}
-
-// NOTE: [sessions] is a good place for this since [receive]
-// handles entity data sent by players and [sessions] handles
-// everything else network related that is not player movement
-static void on_voxel_set(const VoxelSetEvent& event)
-{
- protocol::SetVoxel packet;
- packet.vpos = coord::to_voxel(event.cpos, event.lpos);
- packet.voxel = event.voxel;
- packet.flags = 0U; // UNDONE
- protocol::broadcast(globals::server_host, protocol::encode(packet));
-}
-
-DimensionListener::DimensionListener(Dimension* dimension)
-{
- this->dimension = dimension;
-}
-
-void DimensionListener::on_destroy_entity(const entt::registry& registry, entt::entity entity)
-{
- protocol::RemoveEntity packet;
- packet.entity = entity;
- sessions::broadcast(dimension, protocol::encode(packet));
-}
-
-void sessions::init(void)
-{
- globals::server_config.add_value("sessions.max_players", sessions::max_players);
-
- globals::dispatcher.sink<protocol::LoginRequest>().connect<&on_login_request_packet>();
- globals::dispatcher.sink<protocol::Disconnect>().connect<&on_disconnect_packet>();
-
- globals::dispatcher.sink<VoxelSetEvent>().connect<&on_voxel_set>();
-}
-
-void sessions::init_late(void)
-{
- sessions::num_players = 0U;
-
- username_map.clear();
- identity_map.clear();
- sessions_vector.resize(sessions::max_players.get_value(), Session());
-
- for(unsigned int i = 0U; i < sessions::max_players.get_value(); ++i) {
- sessions_vector[i].client_index = UINT16_MAX;
- sessions_vector[i].client_identity = UINT64_MAX;
- sessions_vector[i].client_username = std::string();
- sessions_vector[i].player_entity = entt::null;
- sessions_vector[i].peer = nullptr;
- }
-}
-
-void sessions::init_post_universe(void)
-{
- for(auto& dimension : globals::dimensions) {
- dimension_listeners.push_back(DimensionListener(dimension.second));
- dimension.second->entities.on_destroy<entt::entity>().connect<&DimensionListener::on_destroy_entity>(dimension_listeners.back());
- }
-}
-
-void sessions::deinit(void)
-{
- username_map.clear();
- identity_map.clear();
- sessions_vector.clear();
- dimension_listeners.clear();
-}
-
-Session* sessions::create(ENetPeer* peer, const char* client_username)
-{
- for(unsigned int i = 0U; i < sessions::max_players.get_value(); ++i) {
- if(!sessions_vector[i].peer) {
- std::uint64_t client_identity = crc64::get(client_username);
-
- sessions_vector[i].client_index = i;
- sessions_vector[i].client_identity = client_identity;
- sessions_vector[i].client_username = client_username;
- sessions_vector[i].player_entity = entt::null;
- sessions_vector[i].peer = peer;
-
- username_map[client_username] = &sessions_vector[i];
- identity_map[client_identity] = &sessions_vector[i];
-
- peer->data = &sessions_vector[i];
-
- sessions::num_players += 1U;
-
- return &sessions_vector[i];
- }
- }
-
- return nullptr;
-}
-
-Session* sessions::find(const char* client_username)
-{
- const auto it = username_map.find(client_username);
- if(it != username_map.cend()) {
- return it->second;
- } else {
- return nullptr;
- }
-}
-
-Session* sessions::find(std::uint16_t client_index)
-{
- if(client_index < sessions_vector.size()) {
- if(!sessions_vector[client_index].peer) {
- return nullptr;
- } else {
- return &sessions_vector[client_index];
- }
- }
-
- return nullptr;
-}
-
-Session* sessions::find(std::uint64_t client_identity)
-{
- const auto it = identity_map.find(client_identity);
-
- if(it != identity_map.cend()) {
- return it->second;
- } else {
- return nullptr;
- }
-}
-
-Session* sessions::find(ENetPeer* peer)
-{
- if(peer != nullptr) {
- return reinterpret_cast<Session*>(peer->data);
- } else {
- return nullptr;
- }
-}
-
-void sessions::destroy(Session* session)
-{
- if(session) {
- if(session->peer) {
- // Make sure we don't leave a mark
- session->peer->data = nullptr;
- }
-
- if(session->dimension) {
- session->dimension->entities.destroy(session->player_entity);
- }
-
- username_map.erase(session->client_username);
- identity_map.erase(session->client_identity);
-
- session->client_index = UINT16_MAX;
- session->client_identity = UINT64_MAX;
- session->client_username = std::string();
- session->player_entity = entt::null;
- session->peer = nullptr;
-
- sessions::num_players -= 1U;
- }
-}
-
-void sessions::broadcast(const Dimension* dimension, ENetPacket* packet)
-{
- for(const auto& session : sessions_vector) {
- if(session.peer && (session.dimension == dimension)) {
- enet_peer_send(session.peer, protocol::CHANNEL, packet);
- }
- }
-}
-
-void sessions::broadcast(const Dimension* dimension, ENetPacket* packet, ENetPeer* except)
-{
- for(const auto& session : sessions_vector) {
- if(session.peer && (session.peer != except)) {
- enet_peer_send(session.peer, protocol::CHANNEL, packet);
- }
- }
-}
-
-void sessions::refresh_scoreboard(void)
-{
- protocol::ScoreboardUpdate packet;
-
- for(std::size_t i = 0; i < sessions::max_players.get_value(); ++i) {
- if(sessions_vector[i].peer) {
- packet.names.push_back(sessions_vector[i].client_username);
- }
- }
-
- protocol::broadcast(globals::server_host, protocol::encode(packet));
-}
diff --git a/game/server/sessions.hh b/game/server/sessions.hh
deleted file mode 100644
index b9a6348..0000000
--- a/game/server/sessions.hh
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef SERVER_SESSIONS_HH
-#define SERVER_SESSIONS_HH 1
-#pragma once
-
-class Dimension;
-
-class ConfigUnsigned;
-
-struct Session final {
- std::uint16_t client_index;
- std::uint64_t client_identity;
- std::string client_username;
- entt::entity player_entity;
- Dimension* dimension;
- ENetPeer* peer;
-};
-
-namespace sessions
-{
-extern ConfigUnsigned max_players;
-extern unsigned int num_players;
-} // namespace sessions
-
-namespace sessions
-{
-void init(void);
-void init_late(void);
-void init_post_universe(void);
-void deinit(void);
-} // namespace sessions
-
-namespace sessions
-{
-Session* create(ENetPeer* peer, const char* client_username);
-Session* find(const char* client_username);
-Session* find(std::uint16_t client_index);
-Session* find(std::uint64_t client_identity);
-Session* find(ENetPeer* peer);
-void destroy(Session* session);
-} // namespace sessions
-
-namespace sessions
-{
-void broadcast(const Dimension* dimension, ENetPacket* packet);
-void broadcast(const Dimension* dimension, ENetPacket* packet, ENetPeer* except);
-} // namespace sessions
-
-namespace sessions
-{
-void refresh_scoreboard(void);
-} // namespace sessions
-
-#endif /* SERVER_SESSIONS_HH */
diff --git a/game/server/status.cc b/game/server/status.cc
deleted file mode 100644
index 6b64719..0000000
--- a/game/server/status.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-#include "server/pch.hh"
-
-#include "server/status.hh"
-
-#include "core/config.hh"
-
-#include "shared/protocol.hh"
-#include "shared/splash.hh"
-
-#include "server/globals.hh"
-#include "server/sessions.hh"
-
-static void on_status_request_packet(const protocol::StatusRequest& packet)
-{
- protocol::StatusResponse response;
- response.version = protocol::VERSION;
- response.max_players = sessions::max_players.get_value();
- response.num_players = sessions::num_players;
- response.motd = splash::get();
- protocol::send(packet.peer, protocol::encode(response));
-}
-
-void status::init(void)
-{
- globals::dispatcher.sink<protocol::StatusRequest>().connect<&on_status_request_packet>();
-}
diff --git a/game/server/status.hh b/game/server/status.hh
deleted file mode 100644
index 5f939f7..0000000
--- a/game/server/status.hh
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef SERVER_STATUS_HH
-#define SERVER_STATUS_HH 1
-#pragma once
-
-namespace status
-{
-void init(void);
-} // namespace status
-
-#endif /* SERVER_STATUS_HH */
diff --git a/game/server/universe.cc b/game/server/universe.cc
deleted file mode 100644
index 96884cf..0000000
--- a/game/server/universe.cc
+++ /dev/null
@@ -1,215 +0,0 @@
-#include "server/pch.hh"
-
-#include "server/universe.hh"
-
-#include "core/buffer.hh"
-#include "core/config.hh"
-#include "core/epoch.hh"
-
-#include "shared/chunk.hh"
-#include "shared/dimension.hh"
-
-#include "server/globals.hh"
-#include "server/inhabited.hh"
-#include "server/overworld.hh"
-
-struct DimensionMetadata final {
- std::string config_path;
- std::string zvox_dir;
- Config config;
-};
-
-static ConfigString universe_name("save");
-
-static Config universe_config;
-static ConfigUnsigned64 universe_config_seed;
-static ConfigString universe_spawn_dimension("world");
-
-static std::string universe_config_path;
-static std::unordered_map<Dimension*, DimensionMetadata*> metadata_map;
-
-static std::string make_chunk_filename(const DimensionMetadata* metadata, const chunk_pos& cpos)
-{
- const auto unsigned_x = static_cast<std::uint32_t>(cpos.x);
- const auto unsigned_y = static_cast<std::uint32_t>(cpos.y);
- const auto unsigned_z = static_cast<std::uint32_t>(cpos.z);
- return std::format("{}/{:08X}-{:08X}-{:08X}.zvox", metadata->zvox_dir, unsigned_x, unsigned_y, unsigned_z);
-}
-
-static void add_new_dimension(Dimension* dimension)
-{
- if(globals::dimensions.count(dimension->get_name())) {
- spdlog::critical("universe: dimension named {} already exists", dimension->get_name());
- std::terminate();
- }
-
- auto dimension_dir = std::format("{}/{}", universe_name.get(), dimension->get_name());
-
- if(!PHYSFS_mkdir(dimension_dir.c_str())) {
- spdlog::critical("universe: {}: {}", dimension_dir, PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
- std::terminate();
- }
-
- auto metadata = new DimensionMetadata;
- metadata->config_path = std::format("{}/dimension.conf", dimension_dir);
- metadata->zvox_dir = std::format("{}/chunk", dimension_dir);
-
- if(!PHYSFS_mkdir(metadata->zvox_dir.c_str())) {
- spdlog::critical("universe: {}: {}", metadata->zvox_dir, PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
- std::terminate();
- }
-
- globals::dimensions.insert_or_assign(dimension->get_name(), dimension);
-
- auto& mapped_metadata = metadata_map.insert_or_assign(dimension, metadata).first->second;
-
- dimension->init(mapped_metadata->config);
-
- mapped_metadata->config.load_file(mapped_metadata->config_path.c_str());
-
- dimension->init_late(universe_config_seed.get_value());
-}
-
-static void internal_save_chunk(const DimensionMetadata* metadata, const Dimension* dimension, const chunk_pos& cpos, const Chunk* chunk)
-{
- auto path = make_chunk_filename(metadata, cpos);
-
- WriteBuffer buffer;
- chunk->get_voxels().serialize(buffer);
-
- if(auto file = buffer.to_file(path.c_str())) {
- PHYSFS_close(file);
- return;
- }
-}
-
-void universe::init(void)
-{
- // If the world is newly created, the seed will
- // be chosed based on the current system's view on UNIX time
- universe_config_seed.set_value(epoch::microseconds());
-
- // We're going to read files from directory named with
- // the value of this config value. Since config is also
- // read from command line, the [--universe <name>] parameter still works
- globals::server_config.add_value("universe", universe_name);
-
- universe_config.add_value("global_seed", universe_config_seed);
- universe_config.add_value("spawn_dimension", universe_spawn_dimension);
-}
-
-void universe::init_late(void)
-{
- const auto universe_dir = std::string(universe_name.get());
-
- if(!PHYSFS_mkdir(universe_dir.c_str())) {
- spdlog::critical("universe: {}: {}", universe_dir, PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
- std::terminate();
- }
-
- universe_config_path = std::format("{}/universe.conf", universe_dir);
- universe_config.load_file(universe_config_path.c_str());
-
- add_new_dimension(new Overworld("world"));
-
- // UNDONE: lua scripts to setup dimensions
- if(globals::dimensions.empty()) {
- spdlog::critical("universe: no dimensions");
- std::terminate();
- }
-
- auto spawn_dimension = globals::dimensions.find(universe_spawn_dimension.get());
-
- if(spawn_dimension == globals::dimensions.cend()) {
- spdlog::critical("universe: {} is not a valid dimension name", universe_spawn_dimension.get());
- std::terminate();
- }
-
- globals::spawn_dimension = spawn_dimension->second;
-}
-
-void universe::deinit(void)
-{
- for(const auto metadata : metadata_map) {
- metadata.second->config.save_file(metadata.second->config_path.c_str());
- delete metadata.second;
- }
-
- metadata_map.clear();
-
- for(const auto dimension : globals::dimensions) {
- universe::save_all_chunks(dimension.second);
- delete dimension.second;
- }
-
- globals::dimensions.clear();
- globals::spawn_dimension = nullptr;
-
- universe_config.save_file(universe_config_path.c_str());
-}
-
-Chunk* universe::load_chunk(Dimension* dimension, const chunk_pos& cpos)
-{
- if(auto chunk = dimension->find_chunk(cpos)) {
- // Just return the existing chunk which is
- // most probable to be up to date compared to
- // whatever the hell is currently stored on disk
- return chunk;
- }
-
- auto metadata = metadata_map.find(dimension);
-
- if(metadata == metadata_map.cend()) {
- // The dimension is for sure a weird one
- return nullptr;
- }
-
- if(auto file = PHYSFS_openRead(make_chunk_filename(metadata->second, cpos).c_str())) {
- VoxelStorage voxels;
- ReadBuffer buffer(file);
- voxels.deserialize(buffer);
-
- PHYSFS_close(file);
-
- auto chunk = dimension->create_chunk(cpos);
- chunk->set_voxels(voxels);
-
- // Make sure we're going to save it later
- dimension->chunks.emplace_or_replace<InhabitedComponent>(chunk->get_entity());
-
- return chunk;
- }
-
- return nullptr;
-}
-
-void universe::save_chunk(Dimension* dimension, const chunk_pos& cpos)
-{
- auto metadata = metadata_map.find(dimension);
-
- if(metadata == metadata_map.cend()) {
- // Cannot save a chunk in a dimension
- // that doesn't have a metadata struct
- return;
- }
-
- if(auto chunk = dimension->find_chunk(cpos)) {
- internal_save_chunk(metadata->second, dimension, cpos, chunk);
- }
-}
-
-void universe::save_all_chunks(Dimension* dimension)
-{
- auto group = dimension->chunks.group(entt::get<ChunkComponent, InhabitedComponent>);
- auto metadata = metadata_map.find(dimension);
-
- if(metadata == metadata_map.cend()) {
- // Cannot save a chunk in a dimension
- // that doesn't have a metadata struct
- return;
- }
-
- for(auto [entity, chunk] : group.each()) {
- internal_save_chunk(metadata->second, dimension, chunk.cpos, chunk.chunk);
- }
-}
diff --git a/game/server/universe.hh b/game/server/universe.hh
deleted file mode 100644
index 2a16806..0000000
--- a/game/server/universe.hh
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef SERVER_UNIVERSE_HH
-#define SERVER_UNIVERSE_HH 1
-#pragma once
-
-#include "shared/types.hh"
-
-class Chunk;
-class Dimension;
-class Session;
-
-namespace universe
-{
-void init(void);
-void init_late(void);
-void deinit(void);
-} // namespace universe
-
-namespace universe
-{
-Chunk* load_chunk(Dimension* dimension, const chunk_pos& cpos);
-void save_chunk(Dimension* dimension, const chunk_pos& cpos);
-void save_all_chunks(Dimension* dimension);
-} // namespace universe
-
-#endif /* SERVER_UNIVERSE_HH */
diff --git a/game/server/unloader.cc b/game/server/unloader.cc
deleted file mode 100644
index f986a61..0000000
--- a/game/server/unloader.cc
+++ /dev/null
@@ -1,76 +0,0 @@
-#include "server/pch.hh"
-
-#include "server/unloader.hh"
-
-#include "core/config.hh"
-
-#include "shared/chunk.hh"
-#include "shared/chunk_aabb.hh"
-#include "shared/dimension.hh"
-#include "shared/player.hh"
-#include "shared/transform.hh"
-
-#include "server/game.hh"
-#include "server/globals.hh"
-#include "server/inhabited.hh"
-#include "server/universe.hh"
-
-static void on_chunk_update(const ChunkUpdateEvent& event)
-{
- event.dimension->chunks.emplace_or_replace<InhabitedComponent>(event.chunk->get_entity());
-}
-
-static void on_voxel_set(const VoxelSetEvent& event)
-{
- event.dimension->chunks.emplace_or_replace<InhabitedComponent>(event.chunk->get_entity());
-}
-
-void unloader::init(void)
-{
- globals::dispatcher.sink<ChunkUpdateEvent>().connect<&on_chunk_update>();
- globals::dispatcher.sink<VoxelSetEvent>().connect<&on_voxel_set>();
-}
-
-void unloader::init_late(void)
-{
-}
-
-void unloader::fixed_update_late(Dimension* dimension)
-{
- auto group = dimension->entities.group(entt::get<PlayerComponent, TransformComponent>);
- auto boxes = std::vector<ChunkAABB>();
-
- for(const auto [entity, transform] : group.each()) {
- ChunkAABB aabb;
- aabb.min = transform.chunk - static_cast<chunk_pos::value_type>(server_game::view_distance.get_value());
- aabb.max = transform.chunk + static_cast<chunk_pos::value_type>(server_game::view_distance.get_value());
- boxes.push_back(aabb);
- }
-
- auto view = dimension->chunks.view<ChunkComponent>();
- auto chunk_in_view = false;
-
- for(const auto [entity, chunk] : view.each()) {
- chunk_in_view = false;
-
- for(const auto& aabb : boxes) {
- if(aabb.contains(chunk.cpos)) {
- chunk_in_view = true;
- break;
- }
- }
-
- if(chunk_in_view) {
- // The chunk is within view box of at least
- // a single player; we shouldn't unload it now
- continue;
- }
-
- if(dimension->chunks.any_of<InhabitedComponent>(entity)) {
- // Only store inhabited chunks on disk
- universe::save_chunk(dimension, chunk.cpos);
- }
-
- dimension->remove_chunk(entity);
- }
-}
diff --git a/game/server/unloader.hh b/game/server/unloader.hh
deleted file mode 100644
index 414cdc4..0000000
--- a/game/server/unloader.hh
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef SERVER_UNLOADER_HH
-#define SERVER_UNLOADER_HH 1
-#pragma once
-
-class Dimension;
-
-namespace unloader
-{
-void init(void);
-void init_late(void);
-void fixed_update_late(Dimension* dimension);
-} // namespace unloader
-
-#endif /* SERVER_UNLOADER_HH */
diff --git a/game/server/vserver.ico b/game/server/vserver.ico
deleted file mode 100644
index 02ff006..0000000
--- a/game/server/vserver.ico
+++ /dev/null
Binary files differ
diff --git a/game/server/vserver.rc b/game/server/vserver.rc
deleted file mode 100644
index b6828bf..0000000
--- a/game/server/vserver.rc
+++ /dev/null
@@ -1 +0,0 @@
-IDI_ICON1 ICON DISCARDABLE "vserver.ico"
diff --git a/game/server/whitelist.cc b/game/server/whitelist.cc
deleted file mode 100644
index 6635122..0000000
--- a/game/server/whitelist.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-#include "server/pch.hh"
-
-#include "server/whitelist.hh"
-
-#include "core/config.hh"
-#include "core/crc64.hh"
-#include "core/strtools.hh"
-
-#include "server/game.hh"
-#include "server/globals.hh"
-
-constexpr static const char* DEFAULT_FILENAME = "whitelist.txt";
-constexpr static char SEPARATOR_CHAR = ':';
-
-ConfigBoolean whitelist::enabled(false);
-ConfigString whitelist::filename(DEFAULT_FILENAME);
-
-static emhash8::HashMap<std::string, std::uint64_t> whitelist_map;
-
-void whitelist::init(void)
-{
- globals::server_config.add_value("whitelist.enabled", whitelist::enabled);
- globals::server_config.add_value("whitelist.filename", whitelist::filename);
-}
-
-void whitelist::init_late(void)
-{
- whitelist_map.clear();
-
- if(!whitelist::enabled.get_value()) {
- // Not enabled, shouldn't
- // even bother with parsing
- // the whitelist file
- return;
- }
-
- if(strtools::is_whitespace(whitelist::filename.get())) {
- spdlog::warn("whitelist: enabled but filename is empty, using default ({})", DEFAULT_FILENAME);
- whitelist::filename.set(DEFAULT_FILENAME);
- }
-
- PHYSFS_File* file = PHYSFS_openRead(whitelist::filename.get());
-
- if(file == nullptr) {
- spdlog::warn("whitelist: {}: {}", whitelist::filename.get(), PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
- whitelist::enabled.set_value(false);
- return;
- }
-
- auto source = std::string(PHYSFS_fileLength(file), char(0x00));
- PHYSFS_readBytes(file, source.data(), source.size());
- PHYSFS_close(file);
-
- std::istringstream stream(source);
- std::string line;
-
- while(std::getline(stream, line)) {
- const auto location = line.find_last_of(SEPARATOR_CHAR);
-
- if(location == std::string::npos) {
- // Entries that don't define a password field default
- // to the global server password; this allows easier adding
- // of guest accounts which can later be edited to use a better password
- whitelist_map[line] = server_game::password_hash;
- } else {
- const auto username = line.substr(0, location);
- const auto password = line.substr(location + 1);
- whitelist_map[username] = crc64::get(password);
- }
- }
-
- PHYSFS_close(file);
-}
-
-void whitelist::deinit(void)
-{
- // UNDONE: implement saving
-}
-
-bool whitelist::contains(const char* username)
-{
- return whitelist_map.contains(username);
-}
-
-bool whitelist::matches(const char* username, std::uint64_t password_hash)
-{
- const auto it = whitelist_map.find(username);
-
- if(it == whitelist_map.cend()) {
- // Not whitelisted, no match
- return false;
- }
-
- return it->second == password_hash;
-}
diff --git a/game/server/whitelist.hh b/game/server/whitelist.hh
deleted file mode 100644
index fe7656b..0000000
--- a/game/server/whitelist.hh
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef SERVER_WHITELIST_HH
-#define SERVER_WHITELIST_HH 1
-#pragma once
-
-class ConfigBoolean;
-class ConfigString;
-
-namespace whitelist
-{
-extern ConfigBoolean enabled;
-extern ConfigString filename;
-} // namespace whitelist
-
-namespace whitelist
-{
-void init(void);
-void init_late(void);
-void deinit(void);
-} // namespace whitelist
-
-namespace whitelist
-{
-bool contains(const char* username);
-bool matches(const char* username, std::uint64_t password_hash);
-} // namespace whitelist
-
-#endif /* SERVER_WHITELIST_HH */
diff --git a/game/server/worldgen.cc b/game/server/worldgen.cc
deleted file mode 100644
index 5c74d47..0000000
--- a/game/server/worldgen.cc
+++ /dev/null
@@ -1,148 +0,0 @@
-#include "server/pch.hh"
-
-#include "server/worldgen.hh"
-
-#include "core/cmdline.hh"
-
-#include "shared/chunk.hh"
-#include "shared/dimension.hh"
-#include "shared/protocol.hh"
-#include "shared/threading.hh"
-
-#include "server/globals.hh"
-#include "server/inhabited.hh"
-#include "server/sessions.hh"
-
-static bool aggressive_caching;
-
-static emhash8::HashMap<Dimension*, emhash8::HashMap<chunk_pos, std::unordered_set<Session*>>> active_tasks;
-
-class WorldgenTask final : public Task {
-public:
- explicit WorldgenTask(Dimension* dimension, const chunk_pos& cpos);
- virtual ~WorldgenTask(void) = default;
- virtual void process(void) override;
- virtual void finalize(void) override;
-
-private:
- Dimension* m_dimension;
- VoxelStorage m_voxels;
- chunk_pos m_cpos;
-};
-
-WorldgenTask::WorldgenTask(Dimension* dimension, const chunk_pos& cpos)
-{
- m_dimension = dimension;
- m_voxels.fill(rand()); // trolling
- m_cpos = cpos;
-}
-
-void WorldgenTask::process(void)
-{
- if(!m_dimension->generate(m_cpos, m_voxels)) {
- set_status(task_status::CANCELLED);
- }
-}
-
-void WorldgenTask::finalize(void)
-{
- auto dim_tasks = active_tasks.find(m_dimension);
-
- if(dim_tasks == active_tasks.cend()) {
- // Normally this should never happen but
- // one can never be sure about anything
- // when that anything is threaded out
- return;
- }
-
- auto it = dim_tasks->second.find(m_cpos);
-
- if(it == dim_tasks->second.cend()) {
- // Normally this should never happen but
- // one can never be sure about anything
- // when that anything is threaded out
- return;
- }
-
- auto chunk = m_dimension->create_chunk(m_cpos);
- chunk->set_voxels(m_voxels);
-
- if(aggressive_caching) {
- // Marking the chunk with InhabitedComponent makes
- // it so that it is saved regardles of whether it was
- // modified by players or not. This isn't particularly
- // good for server-side disk usage but it might improve performance
- m_dimension->chunks.emplace<InhabitedComponent>(chunk->get_entity());
- }
-
- protocol::ChunkVoxels response;
- response.voxels = m_voxels;
- response.chunk = m_cpos;
-
- auto packet = protocol::encode(response);
-
- for(auto session : it->second) {
- if(session->peer) {
- // Respond with the voxels to every session
- // that has requested this specific chunk for this dimension
- enet_peer_send(session->peer, protocol::CHANNEL, packet);
- }
- }
-
- dim_tasks->second.erase(it);
-
- if(dim_tasks->second.empty()) {
- // There are no more requests
- // to generate a chunk for that
- // dimension, at least for now
- active_tasks.erase(dim_tasks);
- }
-}
-
-void worldgen::init(void)
-{
- aggressive_caching = cmdline::contains("aggressive-caching");
-}
-
-bool worldgen::is_generating(Dimension* dimension, const chunk_pos& cpos)
-{
- auto dim_tasks = active_tasks.find(dimension);
-
- if(dim_tasks == active_tasks.cend()) {
- // No tasks for this dimension
- return false;
- }
-
- auto it = dim_tasks->second.find(cpos);
-
- if(it == dim_tasks->second.cend()) {
- // Not generating this chunk
- return false;
- }
-
- return true;
-}
-
-void worldgen::request_chunk(Session* session, const chunk_pos& cpos)
-{
- if(session->dimension) {
- auto dim_tasks = active_tasks.find(session->dimension);
-
- if(dim_tasks == active_tasks.cend()) {
- dim_tasks = active_tasks.emplace(session->dimension, emhash8::HashMap<chunk_pos, std::unordered_set<Session*>>()).first;
- }
-
- auto it = dim_tasks->second.find(cpos);
-
- if(it == dim_tasks->second.cend()) {
- auto& sessions = dim_tasks->second.insert_or_assign(cpos, std::unordered_set<Session*>()).first->second;
- sessions.insert(session);
-
- threading::submit<WorldgenTask>(session->dimension, cpos);
-
- return;
- }
-
- it->second.insert(session);
- }
-}
diff --git a/game/server/worldgen.hh b/game/server/worldgen.hh
deleted file mode 100644
index b0127e5..0000000
--- a/game/server/worldgen.hh
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef SERVER_WORLDGEN_HH
-#define SERVER_WORLDGEN_HH 1
-#pragma once
-
-#include "shared/types.hh"
-
-class Dimension;
-class Session;
-
-namespace worldgen
-{
-void init(void);
-} // namespace worldgen
-
-namespace worldgen
-{
-bool is_generating(Dimension* dimension, const chunk_pos& cpos);
-void request_chunk(Session* session, const chunk_pos& cpos);
-} // namespace worldgen
-
-#endif /* SERVER_WORLDGEN_HH */
diff --git a/game/shared/CMakeLists.txt b/game/shared/CMakeLists.txt
deleted file mode 100644
index e9d3762..0000000
--- a/game/shared/CMakeLists.txt
+++ /dev/null
@@ -1,57 +0,0 @@
-add_library(shared STATIC
- "${CMAKE_CURRENT_LIST_DIR}/chunk_aabb.cc"
- "${CMAKE_CURRENT_LIST_DIR}/chunk_aabb.hh"
- "${CMAKE_CURRENT_LIST_DIR}/chunk.cc"
- "${CMAKE_CURRENT_LIST_DIR}/chunk.hh"
- "${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt"
- "${CMAKE_CURRENT_LIST_DIR}/collision.cc"
- "${CMAKE_CURRENT_LIST_DIR}/collision.hh"
- "${CMAKE_CURRENT_LIST_DIR}/const.hh"
- "${CMAKE_CURRENT_LIST_DIR}/coord.hh"
- "${CMAKE_CURRENT_LIST_DIR}/dimension.cc"
- "${CMAKE_CURRENT_LIST_DIR}/dimension.hh"
- "${CMAKE_CURRENT_LIST_DIR}/factory.cc"
- "${CMAKE_CURRENT_LIST_DIR}/factory.hh"
- "${CMAKE_CURRENT_LIST_DIR}/feature.cc"
- "${CMAKE_CURRENT_LIST_DIR}/feature.hh"
- "${CMAKE_CURRENT_LIST_DIR}/game_items.cc"
- "${CMAKE_CURRENT_LIST_DIR}/game_items.hh"
- "${CMAKE_CURRENT_LIST_DIR}/game_voxels.cc"
- "${CMAKE_CURRENT_LIST_DIR}/game_voxels.hh"
- "${CMAKE_CURRENT_LIST_DIR}/game.cc"
- "${CMAKE_CURRENT_LIST_DIR}/game.hh"
- "${CMAKE_CURRENT_LIST_DIR}/globals.cc"
- "${CMAKE_CURRENT_LIST_DIR}/globals.hh"
- "${CMAKE_CURRENT_LIST_DIR}/gravity.cc"
- "${CMAKE_CURRENT_LIST_DIR}/gravity.hh"
- "${CMAKE_CURRENT_LIST_DIR}/grounded.hh"
- "${CMAKE_CURRENT_LIST_DIR}/head.hh"
- "${CMAKE_CURRENT_LIST_DIR}/item_registry.cc"
- "${CMAKE_CURRENT_LIST_DIR}/item_registry.hh"
- "${CMAKE_CURRENT_LIST_DIR}/pch.hh"
- "${CMAKE_CURRENT_LIST_DIR}/player.hh"
- "${CMAKE_CURRENT_LIST_DIR}/protocol.cc"
- "${CMAKE_CURRENT_LIST_DIR}/protocol.hh"
- "${CMAKE_CURRENT_LIST_DIR}/ray_dda.cc"
- "${CMAKE_CURRENT_LIST_DIR}/ray_dda.hh"
- "${CMAKE_CURRENT_LIST_DIR}/splash.cc"
- "${CMAKE_CURRENT_LIST_DIR}/splash.hh"
- "${CMAKE_CURRENT_LIST_DIR}/stasis.cc"
- "${CMAKE_CURRENT_LIST_DIR}/stasis.hh"
- "${CMAKE_CURRENT_LIST_DIR}/threading.cc"
- "${CMAKE_CURRENT_LIST_DIR}/threading.hh"
- "${CMAKE_CURRENT_LIST_DIR}/transform.cc"
- "${CMAKE_CURRENT_LIST_DIR}/transform.hh"
- "${CMAKE_CURRENT_LIST_DIR}/types.hh"
- "${CMAKE_CURRENT_LIST_DIR}/velocity.cc"
- "${CMAKE_CURRENT_LIST_DIR}/velocity.hh"
- "${CMAKE_CURRENT_LIST_DIR}/voxel_registry.cc"
- "${CMAKE_CURRENT_LIST_DIR}/voxel_registry.hh"
- "${CMAKE_CURRENT_LIST_DIR}/voxel_storage.cc"
- "${CMAKE_CURRENT_LIST_DIR}/voxel_storage.hh")
-target_compile_features(shared PUBLIC cxx_std_20)
-target_include_directories(shared PUBLIC "${DEPS_INCLUDE_DIR}")
-target_include_directories(shared PRIVATE "${PROJECT_SOURCE_DIR}")
-target_include_directories(shared PRIVATE "${PROJECT_SOURCE_DIR}/game")
-target_precompile_headers(shared PRIVATE "${CMAKE_CURRENT_LIST_DIR}/pch.hh")
-target_link_libraries(shared PUBLIC core enet entt FNL miniz parson thread_pool)
diff --git a/game/shared/chunk.cc b/game/shared/chunk.cc
deleted file mode 100644
index da798fa..0000000
--- a/game/shared/chunk.cc
+++ /dev/null
@@ -1,69 +0,0 @@
-#include "shared/pch.hh"
-
-#include "shared/chunk.hh"
-
-#include "shared/coord.hh"
-
-Chunk::Chunk(entt::entity entity, Dimension* dimension)
-{
- m_entity = entity;
- m_dimension = dimension;
- m_voxels.fill(NULL_VOXEL_ID);
- m_biome = BIOME_VOID;
-}
-
-voxel_id Chunk::get_voxel(const local_pos& lpos) const
-{
- return get_voxel(coord::to_index(lpos));
-}
-
-voxel_id Chunk::get_voxel(const std::size_t index) const
-{
- if(index >= CHUNK_VOLUME) {
- return NULL_VOXEL_ID;
- } else {
- return m_voxels[index];
- }
-}
-
-void Chunk::set_voxel(voxel_id voxel, const local_pos& lpos)
-{
- set_voxel(voxel, coord::to_index(lpos));
-}
-
-void Chunk::set_voxel(voxel_id voxel, const std::size_t index)
-{
- if(index < CHUNK_VOLUME) {
- m_voxels[index] = voxel;
- }
-}
-
-const VoxelStorage& Chunk::get_voxels(void) const
-{
- return m_voxels;
-}
-
-void Chunk::set_voxels(const VoxelStorage& voxels)
-{
- m_voxels = voxels;
-}
-
-unsigned int Chunk::get_biome(void) const
-{
- return m_biome;
-}
-
-void Chunk::set_biome(unsigned int biome)
-{
- m_biome = biome;
-}
-
-entt::entity Chunk::get_entity(void) const
-{
- return m_entity;
-}
-
-Dimension* Chunk::get_dimension(void) const
-{
- return m_dimension;
-}
diff --git a/game/shared/chunk.hh b/game/shared/chunk.hh
deleted file mode 100644
index 67bedae..0000000
--- a/game/shared/chunk.hh
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef SHARED_CHUNK_HH
-#define SHARED_CHUNK_HH 1
-#pragma once
-
-#include "shared/types.hh"
-#include "shared/voxel_storage.hh"
-
-constexpr static unsigned int BIOME_VOID = 0U;
-
-class Dimension;
-
-class Chunk final {
-public:
- explicit Chunk(entt::entity entity, Dimension* dimension);
- virtual ~Chunk(void) = default;
-
- voxel_id get_voxel(const local_pos& lpos) const;
- voxel_id get_voxel(const std::size_t index) const;
-
- void set_voxel(voxel_id voxel, const local_pos& lpos);
- void set_voxel(voxel_id voxel, const std::size_t index);
-
- const VoxelStorage& get_voxels(void) const;
- void set_voxels(const VoxelStorage& voxels);
-
- unsigned int get_biome(void) const;
- void set_biome(unsigned int biome);
-
- entt::entity get_entity(void) const;
- Dimension* get_dimension(void) const;
-
-private:
- entt::entity m_entity;
- Dimension* m_dimension;
- VoxelStorage m_voxels;
- unsigned int m_biome;
-};
-
-#endif /* SHARED_CHUNK_HH */
diff --git a/game/shared/chunk_aabb.cc b/game/shared/chunk_aabb.cc
deleted file mode 100644
index 5f23ea9..0000000
--- a/game/shared/chunk_aabb.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-#include "shared/pch.hh"
-
-#include "shared/chunk_aabb.hh"
-
-void ChunkAABB::set_bounds(const chunk_pos& min, const chunk_pos& max)
-{
- this->min = min;
- this->max = max;
-}
-
-void ChunkAABB::set_offset(const chunk_pos& base, const chunk_pos& size)
-{
- this->min = base;
- this->max = base + size;
-}
-
-bool ChunkAABB::contains(const chunk_pos& point) const
-{
- auto result = true;
- result = result && (point.x >= min.x) && (point.x <= max.x);
- result = result && (point.y >= min.y) && (point.y <= max.y);
- result = result && (point.z >= min.z) && (point.z <= max.z);
- return result;
-}
-
-bool ChunkAABB::intersect(const ChunkAABB& other_box) const
-{
- auto result = true;
- result = result && (min.x < other_box.max.x) && (max.x > other_box.min.x);
- result = result && (min.y < other_box.max.y) && (max.y > other_box.min.y);
- result = result && (min.z < other_box.max.z) && (max.z > other_box.min.z);
- return result;
-}
-
-ChunkAABB ChunkAABB::combine_with(const ChunkAABB& other_box) const
-{
- ChunkAABB result;
- result.set_bounds(min, other_box.max);
- return result;
-}
-
-ChunkAABB ChunkAABB::multiply_with(const ChunkAABB& other_box) const
-{
- ChunkAABB result;
- result.set_bounds(other_box.min, max);
- return result;
-}
-
-ChunkAABB ChunkAABB::push(const chunk_pos& vector) const
-{
- ChunkAABB result;
- result.set_bounds(min + vector, max + vector);
- return result;
-}
diff --git a/game/shared/chunk_aabb.hh b/game/shared/chunk_aabb.hh
deleted file mode 100644
index 7a35dd4..0000000
--- a/game/shared/chunk_aabb.hh
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef SHARED_CHUNK_AABB
-#define SHARED_CHUNK_AABB 1
-#pragma once
-
-#include "core/macros.hh"
-
-#include "shared/types.hh"
-
-class ChunkAABB final {
-public:
- DECLARE_DEFAULT_CONSTRUCTOR(ChunkAABB);
- virtual ~ChunkAABB(void) = default;
-
- void set_bounds(const chunk_pos& min, const chunk_pos& max);
- void set_offset(const chunk_pos& base, const chunk_pos& size);
-
- const chunk_pos& get_min(void) const;
- const chunk_pos& get_max(void) const;
-
- bool contains(const chunk_pos& point) const;
- bool intersect(const ChunkAABB& other_box) const;
-
- ChunkAABB combine_with(const ChunkAABB& other_box) const;
- ChunkAABB multiply_with(const ChunkAABB& other_box) const;
- ChunkAABB push(const chunk_pos& vector) const;
-
-public:
- chunk_pos min;
- chunk_pos max;
-};
-
-#endif /* SHARED_CHUNK_AABB */
diff --git a/game/shared/collision.cc b/game/shared/collision.cc
deleted file mode 100644
index dd51dd5..0000000
--- a/game/shared/collision.cc
+++ /dev/null
@@ -1,169 +0,0 @@
-#include "shared/pch.hh"
-
-#include "shared/collision.hh"
-
-#include "core/constexpr.hh"
-
-#include "shared/coord.hh"
-#include "shared/dimension.hh"
-#include "shared/globals.hh"
-#include "shared/gravity.hh"
-#include "shared/grounded.hh"
-#include "shared/transform.hh"
-#include "shared/velocity.hh"
-#include "shared/voxel_registry.hh"
-
-static int vgrid_collide(const Dimension* dimension, int d, CollisionComponent& collision, TransformComponent& transform,
- VelocityComponent& velocity, voxel_surface& touch_surface)
-{
- const auto move = globals::fixed_frametime * velocity.value[d];
- const auto move_sign = vx::sign<int>(move);
-
- const auto& ref_aabb = collision.aabb;
- const auto current_aabb = ref_aabb.push(transform.local);
-
- auto next_aabb = AABB(current_aabb);
- next_aabb.min[d] += move;
- next_aabb.max[d] += move;
-
- local_pos lpos_min;
- lpos_min.x = vx::floor<local_pos::value_type>(next_aabb.min.x);
- lpos_min.y = vx::floor<local_pos::value_type>(next_aabb.min.y);
- lpos_min.z = vx::floor<local_pos::value_type>(next_aabb.min.z);
-
- local_pos lpos_max;
- lpos_max.x = vx::ceil<local_pos::value_type>(next_aabb.max.x);
- lpos_max.y = vx::ceil<local_pos::value_type>(next_aabb.max.y);
- lpos_max.z = vx::ceil<local_pos::value_type>(next_aabb.max.z);
-
- // Other axes
- const int u = (d + 1) % 3;
- const int v = (d + 2) % 3;
-
- local_pos::value_type ddir;
- local_pos::value_type dmin;
- local_pos::value_type dmax;
-
- if(move < 0.0f) {
- ddir = local_pos::value_type(+1);
- dmin = lpos_min[d];
- dmax = lpos_max[d];
- } else {
- ddir = local_pos::value_type(-1);
- dmin = lpos_max[d];
- dmax = lpos_min[d];
- }
-
- voxel_touch latch_touch = voxel_touch::NOTHING;
- glm::fvec3 latch_values = glm::fvec3(0.0f, 0.0f, 0.0f);
- voxel_surface latch_surface = voxel_surface::UNKNOWN;
- AABB latch_vbox;
-
- for(auto i = dmin; i != dmax; i += ddir) {
- for(auto j = lpos_min[u]; j < lpos_max[u]; ++j)
- for(auto k = lpos_min[v]; k < lpos_max[v]; ++k) {
- local_pos lpos;
- lpos[d] = i;
- lpos[u] = j;
- lpos[v] = k;
-
- const auto vpos = coord::to_voxel(transform.chunk, lpos);
- const auto info = voxel_registry::find(dimension->get_voxel(vpos));
-
- if(info == nullptr) {
- // Don't collide with something
- // that we assume to be nothing
- continue;
- }
-
- AABB vbox;
- vbox.min = glm::fvec3(lpos);
- vbox.max = glm::fvec3(lpos) + 1.0f;
-
- if(!next_aabb.intersect(vbox)) {
- // No intersection between the voxel
- // and the entity's collision hull
- continue;
- }
-
- if(info->touch_type == voxel_touch::SOLID) {
- // Solid touch type makes a collision
- // response whenever it is encountered
- velocity.value[d] = 0.0f;
- touch_surface = info->surface;
- return move_sign;
- }
-
- // In case of other touch types, they
- // are latched and the last ever touch
- // type is then responded to
- if(info->touch_type != voxel_touch::NOTHING) {
- latch_touch = info->touch_type;
- latch_values = info->touch_values;
- latch_surface = info->surface;
- latch_vbox = vbox;
- continue;
- }
- }
- }
-
- if(latch_touch != voxel_touch::NOTHING) {
- if(latch_touch == voxel_touch::BOUNCE) {
- const auto move_distance = vx::abs(current_aabb.min[d] - next_aabb.min[d]);
- const auto threshold = 2.0f * globals::fixed_frametime;
-
- if(move_distance > threshold) {
- velocity.value[d] *= -latch_values[d];
- } else {
- velocity.value[d] = 0.0f;
- }
-
- touch_surface = latch_surface;
-
- return move_sign;
- }
-
- if(latch_touch == voxel_touch::SINK) {
- velocity.value[d] *= latch_values[d];
- touch_surface = latch_surface;
- return move_sign;
- }
- }
-
- return 0;
-}
-
-void CollisionComponent::fixed_update(Dimension* dimension)
-{
- // FIXME: this isn't particularly accurate considering
- // some voxels might be passable and some other voxels
- // might apply some slowing factor; what I might do in the
- // future is to add a specific value to the voxel registry
- // entries that would specify the amount of force we apply
- // to prevent player movement inside a specific voxel, plus
- // we shouldn't treat all voxels as full cubes if we want
- // to support slabs, stairs and non-full liquid voxels in the future
-
- auto group = dimension->entities.group<CollisionComponent>(entt::get<TransformComponent, VelocityComponent>);
-
- for(auto [entity, collision, transform, velocity] : group.each()) {
- auto surface = voxel_surface::UNKNOWN;
- auto vertical_move = vgrid_collide(dimension, 1, collision, transform, velocity, surface);
-
- if(dimension->entities.any_of<GravityComponent>(entity)) {
- if(vertical_move == vx::sign<int>(dimension->get_gravity())) {
- dimension->entities.emplace_or_replace<GroundedComponent>(entity, GroundedComponent { surface });
- } else {
- dimension->entities.remove<GroundedComponent>(entity);
- }
- } else {
- // The entity cannot be grounded because the component
- // setup of said entity should not let it comprehend the
- // concept of resting on the ground (it flies around)
- dimension->entities.remove<GroundedComponent>(entity);
- }
-
- vgrid_collide(dimension, 0, collision, transform, velocity, surface);
- vgrid_collide(dimension, 2, collision, transform, velocity, surface);
- }
-}
diff --git a/game/shared/collision.hh b/game/shared/collision.hh
deleted file mode 100644
index 641a803..0000000
--- a/game/shared/collision.hh
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef SHARED_COLLISION_HH
-#define SHARED_COLLISION_HH 1
-#pragma once
-
-#include "core/aabb.hh"
-
-class Dimension;
-
-struct CollisionComponent final {
- AABB aabb;
-
-public:
- // NOTE: CollisionComponent::fixed_update must be called
- // before TransformComponent::fixed_update and VelocityComponent::fixed_update
- // because both transform and velocity may be updated internally
- static void fixed_update(Dimension* dimension);
-};
-
-#endif /* SHARED_COLLISION_HH */
diff --git a/game/shared/const.hh b/game/shared/const.hh
deleted file mode 100644
index 4639c4b..0000000
--- a/game/shared/const.hh
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef SHARED_CONST_HH
-#define SHARED_CONST_HH 1
-#pragma once
-
-#include "core/constexpr.hh"
-
-constexpr static unsigned int CHUNK_SIZE = 16;
-constexpr static unsigned int CHUNK_AREA = CHUNK_SIZE * CHUNK_SIZE;
-constexpr static unsigned int CHUNK_VOLUME = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE;
-constexpr static unsigned int CHUNK_BITSHIFT = vx::log2(CHUNK_SIZE);
-
-template<typename T>
-constexpr static glm::vec<3, T> DIR_NORTH = glm::vec<3, T>(0, 0, +1);
-template<typename T>
-constexpr static glm::vec<3, T> DIR_SOUTH = glm::vec<3, T>(0, 0, -1);
-template<typename T>
-constexpr static glm::vec<3, T> DIR_EAST = glm::vec<3, T>(-1, 0, 0);
-template<typename T>
-constexpr static glm::vec<3, T> DIR_WEST = glm::vec<3, T>(+1, 0, 0);
-template<typename T>
-constexpr static glm::vec<3, T> DIR_DOWN = glm::vec<3, T>(0, -1, 0);
-template<typename T>
-constexpr static glm::vec<3, T> DIR_UP = glm::vec<3, T>(0, +1, 0);
-
-template<typename T>
-constexpr static glm::vec<3, T> DIR_FORWARD = glm::vec<3, T>(0, 0, +1);
-template<typename T>
-constexpr static glm::vec<3, T> DIR_BACK = glm::vec<3, T>(0, 0, -1);
-template<typename T>
-constexpr static glm::vec<3, T> DIR_LEFT = glm::vec<3, T>(-1, 0, 0);
-template<typename T>
-constexpr static glm::vec<3, T> DIR_RIGHT = glm::vec<3, T>(+1, 0, 0);
-
-template<typename T>
-constexpr static glm::vec<3, T> UNIT_X = glm::vec<3, T>(1, 0, 0);
-template<typename T>
-constexpr static glm::vec<3, T> UNIT_Y = glm::vec<3, T>(0, 1, 0);
-template<typename T>
-constexpr static glm::vec<3, T> UNIT_Z = glm::vec<3, T>(0, 0, 1);
-
-template<typename T>
-constexpr static glm::vec<2, T> ZERO_VEC2 = glm::vec<2, T>(0, 0);
-
-template<typename T>
-constexpr static glm::vec<3, T> ZERO_VEC3 = glm::vec<3, T>(0, 0, 0);
-
-#endif /* SHARED_CONST_HH */
diff --git a/game/shared/coord.hh b/game/shared/coord.hh
deleted file mode 100644
index f1a2e70..0000000
--- a/game/shared/coord.hh
+++ /dev/null
@@ -1,149 +0,0 @@
-#ifndef SHARED_COORD_HH
-#define SHARED_COORD_HH 1
-#pragma once
-
-#include "shared/const.hh"
-#include "shared/types.hh"
-
-namespace coord
-{
-constexpr chunk_pos to_chunk(const voxel_pos& vpos);
-} // namespace coord
-
-namespace coord
-{
-constexpr local_pos to_local(const voxel_pos& vpos);
-constexpr local_pos to_local(const glm::fvec3& fvec);
-constexpr local_pos to_local(std::size_t index);
-} // namespace coord
-
-namespace coord
-{
-constexpr voxel_pos to_voxel(const chunk_pos& cpos, const local_pos& lpos);
-constexpr voxel_pos to_voxel(const chunk_pos& cpos, const glm::fvec3& fvec);
-} // namespace coord
-
-namespace coord
-{
-constexpr std::size_t to_index(const local_pos& lpos);
-} // namespace coord
-
-namespace coord
-{
-constexpr glm::fvec3 to_relative(const chunk_pos& pivot_cpos, const chunk_pos& cpos, const glm::fvec3& fvec);
-constexpr glm::fvec3 to_relative(const chunk_pos& pivot_cpos, const glm::fvec3& pivot_fvec, const chunk_pos& cpos);
-constexpr glm::fvec3 to_relative(const chunk_pos& pivot_cpos, const glm::fvec3& pivot_fvec, const chunk_pos& cpos, const glm::fvec3& fvec);
-} // namespace coord
-
-namespace coord
-{
-constexpr glm::fvec3 to_fvec3(const chunk_pos& cpos);
-constexpr glm::fvec3 to_fvec3(const chunk_pos& cpos, const glm::fvec3& fpos);
-} // namespace coord
-
-inline constexpr chunk_pos coord::to_chunk(const voxel_pos& vpos)
-{
- return chunk_pos {
- static_cast<chunk_pos::value_type>(vpos.x >> CHUNK_BITSHIFT),
- static_cast<chunk_pos::value_type>(vpos.y >> CHUNK_BITSHIFT),
- static_cast<chunk_pos::value_type>(vpos.z >> CHUNK_BITSHIFT),
- };
-}
-
-inline constexpr local_pos coord::to_local(const voxel_pos& vpos)
-{
- return local_pos {
- static_cast<local_pos::value_type>(vx::mod_signed<voxel_pos::value_type>(vpos.x, CHUNK_SIZE)),
- static_cast<local_pos::value_type>(vx::mod_signed<voxel_pos::value_type>(vpos.y, CHUNK_SIZE)),
- static_cast<local_pos::value_type>(vx::mod_signed<voxel_pos::value_type>(vpos.z, CHUNK_SIZE)),
- };
-}
-
-inline constexpr local_pos coord::to_local(const glm::fvec3& fvec)
-{
- return local_pos {
- static_cast<local_pos::value_type>(fvec.x),
- static_cast<local_pos::value_type>(fvec.y),
- static_cast<local_pos::value_type>(fvec.z),
- };
-}
-
-inline constexpr local_pos coord::to_local(std::size_t index)
-{
- return local_pos {
- static_cast<local_pos::value_type>((index % CHUNK_SIZE)),
- static_cast<local_pos::value_type>((index / CHUNK_SIZE) / CHUNK_SIZE),
- static_cast<local_pos::value_type>((index / CHUNK_SIZE) % CHUNK_SIZE),
- };
-}
-
-inline constexpr voxel_pos coord::to_voxel(const chunk_pos& cpos, const local_pos& lpos)
-{
- return voxel_pos {
- lpos.x + (static_cast<voxel_pos::value_type>(cpos.x) << CHUNK_BITSHIFT),
- lpos.y + (static_cast<voxel_pos::value_type>(cpos.y) << CHUNK_BITSHIFT),
- lpos.z + (static_cast<voxel_pos::value_type>(cpos.z) << CHUNK_BITSHIFT),
- };
-}
-
-inline constexpr voxel_pos coord::to_voxel(const chunk_pos& cpos, const glm::fvec3& fvec)
-{
- return voxel_pos {
- static_cast<voxel_pos::value_type>(fvec.x) + (static_cast<voxel_pos::value_type>(cpos.x) << CHUNK_BITSHIFT),
- static_cast<voxel_pos::value_type>(fvec.y) + (static_cast<voxel_pos::value_type>(cpos.y) << CHUNK_BITSHIFT),
- static_cast<voxel_pos::value_type>(fvec.z) + (static_cast<voxel_pos::value_type>(cpos.z) << CHUNK_BITSHIFT),
- };
-}
-
-inline constexpr std::size_t coord::to_index(const local_pos& lpos)
-{
- return static_cast<std::size_t>((lpos.y * CHUNK_SIZE + lpos.z) * CHUNK_SIZE + lpos.x);
-}
-
-inline constexpr glm::fvec3 coord::to_relative(const chunk_pos& pivot_cpos, const chunk_pos& cpos, const glm::fvec3& fvec)
-{
- return glm::fvec3 {
- static_cast<float>((cpos.x - pivot_cpos.x) << CHUNK_BITSHIFT) + fvec.x,
- static_cast<float>((cpos.y - pivot_cpos.y) << CHUNK_BITSHIFT) + fvec.y,
- static_cast<float>((cpos.z - pivot_cpos.z) << CHUNK_BITSHIFT) + fvec.z,
- };
-}
-
-inline constexpr glm::fvec3 coord::to_relative(const chunk_pos& pivot_cpos, const glm::fvec3& pivot_fvec, const chunk_pos& cpos)
-{
- return glm::fvec3 {
- static_cast<float>((cpos.x - pivot_cpos.x) << CHUNK_BITSHIFT) - pivot_fvec.x,
- static_cast<float>((cpos.y - pivot_cpos.y) << CHUNK_BITSHIFT) - pivot_fvec.y,
- static_cast<float>((cpos.z - pivot_cpos.z) << CHUNK_BITSHIFT) - pivot_fvec.z,
- };
-}
-
-inline constexpr glm::fvec3 coord::to_relative(
- const chunk_pos& pivot_cpos, const glm::fvec3& pivot_fvec, const chunk_pos& cpos, const glm::fvec3& fvec)
-{
- return glm::fvec3 {
- static_cast<float>((cpos.x - pivot_cpos.x) << CHUNK_BITSHIFT) + (fvec.x - pivot_fvec.x),
- static_cast<float>((cpos.y - pivot_cpos.y) << CHUNK_BITSHIFT) + (fvec.y - pivot_fvec.y),
- static_cast<float>((cpos.z - pivot_cpos.z) << CHUNK_BITSHIFT) + (fvec.z - pivot_fvec.z),
- };
-}
-
-inline constexpr glm::fvec3 coord::to_fvec3(const chunk_pos& cpos)
-{
- return glm::fvec3 {
- static_cast<float>(cpos.x << CHUNK_BITSHIFT),
- static_cast<float>(cpos.y << CHUNK_BITSHIFT),
- static_cast<float>(cpos.z << CHUNK_BITSHIFT),
- };
-}
-
-inline constexpr glm::fvec3 coord::to_fvec3(const chunk_pos& cpos, const glm::fvec3& fpos)
-{
- return glm::fvec3 {
- fpos.x + static_cast<float>(cpos.x << CHUNK_BITSHIFT),
- fpos.y + static_cast<float>(cpos.y << CHUNK_BITSHIFT),
- fpos.z + static_cast<float>(cpos.z << CHUNK_BITSHIFT),
- };
-}
-
-#endif /* SHARED_COORD_HH */
diff --git a/game/shared/dimension.cc b/game/shared/dimension.cc
deleted file mode 100644
index a919dc4..0000000
--- a/game/shared/dimension.cc
+++ /dev/null
@@ -1,169 +0,0 @@
-#include "shared/pch.hh"
-
-#include "shared/dimension.hh"
-
-#include "shared/chunk.hh"
-#include "shared/coord.hh"
-#include "shared/globals.hh"
-
-Dimension::Dimension(const char* name, float gravity)
-{
- m_name = name;
- m_gravity = gravity;
-}
-
-Dimension::~Dimension(void)
-{
- for(const auto it : m_chunkmap)
- delete it.second;
- entities.clear();
- chunks.clear();
-}
-
-const char* Dimension::get_name(void) const
-{
- return m_name.c_str();
-}
-
-float Dimension::get_gravity(void) const
-{
- return m_gravity;
-}
-
-Chunk* Dimension::create_chunk(const chunk_pos& cpos)
-{
- auto it = m_chunkmap.find(cpos);
-
- if(it != m_chunkmap.cend()) {
- // Chunk already exists
- return it->second;
- }
-
- auto entity = chunks.create();
- auto chunk = new Chunk(entity, this);
-
- auto& component = chunks.emplace<ChunkComponent>(entity);
- component.chunk = chunk;
- component.cpos = cpos;
-
- ChunkCreateEvent event;
- event.dimension = this;
- event.chunk = chunk;
- event.cpos = cpos;
-
- globals::dispatcher.trigger(event);
-
- return m_chunkmap.insert_or_assign(cpos, std::move(chunk)).first->second;
-}
-
-Chunk* Dimension::find_chunk(entt::entity entity) const
-{
- if(chunks.valid(entity)) {
- return chunks.get<ChunkComponent>(entity).chunk;
- } else {
- return nullptr;
- }
-}
-
-Chunk* Dimension::find_chunk(const chunk_pos& cpos) const
-{
- auto it = m_chunkmap.find(cpos);
-
- if(it != m_chunkmap.cend()) {
- return it->second;
- } else {
- return nullptr;
- }
-}
-
-void Dimension::remove_chunk(entt::entity entity)
-{
- if(chunks.valid(entity)) {
- auto& component = chunks.get<ChunkComponent>(entity);
- m_chunkmap.erase(component.cpos);
- chunks.destroy(entity);
- }
-}
-
-void Dimension::remove_chunk(const chunk_pos& cpos)
-{
- auto it = m_chunkmap.find(cpos);
-
- if(it != m_chunkmap.cend()) {
- chunks.destroy(it->second->get_entity());
- m_chunkmap.erase(it);
- }
-}
-
-void Dimension::remove_chunk(Chunk* chunk)
-{
- if(chunk) {
- const auto& component = chunks.get<ChunkComponent>(chunk->get_entity());
- m_chunkmap.erase(component.cpos);
- chunks.destroy(chunk->get_entity());
- }
-}
-
-voxel_id Dimension::get_voxel(const voxel_pos& vpos) const
-{
- auto cpos = coord::to_chunk(vpos);
- auto lpos = coord::to_local(vpos);
-
- if(auto chunk = find_chunk(cpos)) {
- return chunk->get_voxel(lpos);
- } else {
- return NULL_VOXEL_ID;
- }
-}
-
-voxel_id Dimension::get_voxel(const chunk_pos& cpos, const local_pos& lpos) const
-{
- // This allows accessing get_voxel with negative
- // local coordinates that usually would result in an
- // out-of-range values; this is useful for per-voxel update logic
- return get_voxel(coord::to_voxel(cpos, lpos));
-}
-
-bool Dimension::set_voxel(voxel_id voxel, const voxel_pos& vpos)
-{
- auto cpos = coord::to_chunk(vpos);
- auto lpos = coord::to_local(vpos);
-
- if(auto chunk = find_chunk(cpos)) {
- chunk->set_voxel(voxel, lpos);
-
- VoxelSetEvent event;
- event.dimension = this;
- event.cpos = cpos;
- event.lpos = lpos;
- event.voxel = voxel;
- event.chunk = chunk;
-
- globals::dispatcher.trigger(event);
-
- return true;
- }
-
- return false;
-}
-
-bool Dimension::set_voxel(voxel_id voxel, const chunk_pos& cpos, const local_pos& lpos)
-{
- // This allows accessing set_voxel with negative
- // local coordinates that usually would result in an
- // out-of-range values; this is useful for per-voxel update logic
- return set_voxel(voxel, coord::to_voxel(cpos, lpos));
-}
-
-void Dimension::init(Config& config)
-{
-}
-
-void Dimension::init_late(std::uint64_t global_seed)
-{
-}
-
-bool Dimension::generate(const chunk_pos& cpos, VoxelStorage& voxels)
-{
- return false;
-}
diff --git a/game/shared/dimension.hh b/game/shared/dimension.hh
deleted file mode 100644
index c609a14..0000000
--- a/game/shared/dimension.hh
+++ /dev/null
@@ -1,85 +0,0 @@
-#ifndef SHARED_DIMENSION_HH
-#define SHARED_DIMENSION_HH 1
-#pragma once
-
-#include "shared/const.hh"
-#include "shared/types.hh"
-
-class Chunk;
-class Config;
-class VoxelStorage;
-
-using dimension_entropy_map = std::array<std::uint64_t, CHUNK_AREA>;
-using dimension_height_map = std::array<voxel_pos::value_type, CHUNK_AREA>;
-
-class Dimension {
-public:
- explicit Dimension(const char* name, float gravity);
- virtual ~Dimension(void);
-
- const char* get_name(void) const;
- float get_gravity(void) const;
-
-public:
- Chunk* create_chunk(const chunk_pos& cpos);
- Chunk* find_chunk(entt::entity entity) const;
- Chunk* find_chunk(const chunk_pos& cpos) const;
-
- void remove_chunk(entt::entity entity);
- void remove_chunk(const chunk_pos& cpos);
- void remove_chunk(Chunk* chunk);
-
-public:
- voxel_id get_voxel(const voxel_pos& vpos) const;
- voxel_id get_voxel(const chunk_pos& cpos, const local_pos& lpos) const;
-
- bool set_voxel(voxel_id voxel, const voxel_pos& vpos);
- bool set_voxel(voxel_id voxel, const chunk_pos& cpos, const local_pos& lpos);
-
-public:
- virtual void init(Config& config);
- virtual void init_late(std::uint64_t global_seed);
- virtual bool generate(const chunk_pos& cpos, VoxelStorage& voxels);
-
-public:
- entt::registry chunks;
- entt::registry entities;
-
-private:
- std::string m_name;
- emhash8::HashMap<chunk_pos, Chunk*> m_chunkmap;
- float m_gravity;
-};
-
-struct ChunkComponent final {
- chunk_pos cpos;
- Chunk* chunk;
-};
-
-struct ChunkCreateEvent final {
- Dimension* dimension;
- chunk_pos cpos;
- Chunk* chunk;
-};
-
-struct ChunkDestroyEvent final {
- Dimension* dimension;
- chunk_pos cpos;
- Chunk* chunk;
-};
-
-struct ChunkUpdateEvent final {
- Dimension* dimension;
- chunk_pos cpos;
- Chunk* chunk;
-};
-
-struct VoxelSetEvent final {
- Dimension* dimension;
- chunk_pos cpos;
- local_pos lpos;
- voxel_id voxel;
- Chunk* chunk;
-};
-
-#endif /* SHARED_DIMENSION_HH */
diff --git a/game/shared/factory.cc b/game/shared/factory.cc
deleted file mode 100644
index ad65928..0000000
--- a/game/shared/factory.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-#include "shared/pch.hh"
-
-#include "shared/factory.hh"
-
-#include "shared/collision.hh"
-#include "shared/dimension.hh"
-#include "shared/globals.hh"
-#include "shared/gravity.hh"
-#include "shared/head.hh"
-#include "shared/player.hh"
-#include "shared/transform.hh"
-#include "shared/velocity.hh"
-
-void shared_factory::create_player(Dimension* dimension, entt::entity entity)
-{
- spdlog::debug("factory[{}]: assigning player components to {}", dimension->get_name(), static_cast<std::uint64_t>(entity));
-
- auto& collision = dimension->entities.emplace_or_replace<CollisionComponent>(entity);
- collision.aabb.min = glm::fvec3(-0.4f, -1.6f, -0.4f);
- collision.aabb.max = glm::fvec3(+0.4f, +0.2f, +0.4f);
-
- auto& head = dimension->entities.emplace_or_replace<HeadComponent>(entity);
- head.angles = glm::fvec3(0.0f, 0.0f, 0.0f);
- head.offset = glm::fvec3(0.0f, 0.0f, 0.0f);
-
- dimension->entities.emplace_or_replace<PlayerComponent>(entity);
-
- auto& transform = dimension->entities.emplace_or_replace<TransformComponent>(entity);
- transform.chunk = chunk_pos(0, 2, 0);
- transform.local = glm::fvec3(0.0f, 0.0f, 0.0f);
- transform.angles = glm::fvec3(0.0f, 0.0f, 0.0f);
-
- auto& velocity = dimension->entities.emplace_or_replace<VelocityComponent>(entity);
- velocity.value = glm::fvec3(0.0f, 0.0f, 0.0f);
-}
diff --git a/game/shared/factory.hh b/game/shared/factory.hh
deleted file mode 100644
index c3449dd..0000000
--- a/game/shared/factory.hh
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef SHARED_FACTORY
-#define SHARED_FACTORY 1
-#pragma once
-
-class Dimension;
-
-namespace shared_factory
-{
-void create_player(Dimension* dimension, entt::entity entity);
-} // namespace shared_factory
-
-#endif /* SHARED_FACTORY */
diff --git a/game/shared/feature.cc b/game/shared/feature.cc
deleted file mode 100644
index eb6cceb..0000000
--- a/game/shared/feature.cc
+++ /dev/null
@@ -1,52 +0,0 @@
-#include "shared/pch.hh"
-
-#include "shared/feature.hh"
-
-#include "shared/chunk.hh"
-#include "shared/coord.hh"
-#include "shared/dimension.hh"
-#include "shared/voxel_storage.hh"
-
-void Feature::place(const voxel_pos& vpos, Dimension* dimension) const
-{
- for(const auto [rpos, voxel, overwrite] : (*this)) {
- auto it_vpos = vpos + rpos;
- auto it_cpos = coord::to_chunk(it_vpos);
-
- if(auto chunk = dimension->create_chunk(it_cpos)) {
- auto it_lpos = coord::to_local(it_vpos);
- auto it_index = coord::to_index(it_lpos);
-
- if(chunk->get_voxel(it_index) && !overwrite) {
- // There is something in the way
- // and the called intentionally requested
- // we do not force feature to overwrite voxels
- continue;
- }
-
- chunk->set_voxel(voxel, it_index);
- }
- }
-}
-
-void Feature::place(const voxel_pos& vpos, const chunk_pos& cpos, VoxelStorage& voxels) const
-{
- for(const auto [rpos, voxel, overwrite] : (*this)) {
- auto it_vpos = vpos + rpos;
- auto it_cpos = coord::to_chunk(it_vpos);
-
- if(it_cpos == cpos) {
- auto it_lpos = coord::to_local(it_vpos);
- auto it_index = coord::to_index(it_lpos);
-
- if(voxels[it_index] && !overwrite) {
- // There is something in the way
- // and the called intentionally requested
- // we do not force feature to overwrite voxels
- continue;
- }
-
- voxels[it_index] = voxel;
- }
- }
-}
diff --git a/game/shared/feature.hh b/game/shared/feature.hh
deleted file mode 100644
index 04f38e8..0000000
--- a/game/shared/feature.hh
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef SHARED_FEATURE_HH
-#define SHARED_FEATURE_HH 1
-#pragma once
-
-#include "core/macros.hh"
-
-#include "shared/types.hh"
-
-class Dimension;
-class VoxelStorage;
-
-class Feature final : public std::vector<std::tuple<voxel_pos, voxel_id, bool>> {
-public:
- DECLARE_DEFAULT_CONSTRUCTOR(Feature);
- virtual ~Feature(void) = default;
-
-public:
- void place(const voxel_pos& vpos, Dimension* dimension) const;
- void place(const voxel_pos& vpos, const chunk_pos& cpos, VoxelStorage& voxels) const;
-};
-
-#endif /* SHARED_FEATURE_HH */
diff --git a/game/shared/game.cc b/game/shared/game.cc
deleted file mode 100644
index 73de8b5..0000000
--- a/game/shared/game.cc
+++ /dev/null
@@ -1,121 +0,0 @@
-#include "shared/pch.hh"
-
-#include "shared/game.hh"
-
-#include "core/cmdline.hh"
-
-static std::filesystem::path get_gamepath(void)
-{
- if(auto gamepath = cmdline::get("gamepath")) {
- // Allow users and third-party launchers to override
- // content location. Perhaps this would work to allow
- // for a Minecraft-like versioning approach?
- return std::filesystem::path(gamepath);
- }
-
- return std::filesystem::current_path() / "data";
-}
-
-static std::filesystem::path get_userpath(void)
-{
- if(auto userpath = cmdline::get("userpath")) {
- // Allow users and third-party launchers to override
- // user data location. Perhaps this would work to allow
- // for a Minecraft-like versioning approach?
- return std::filesystem::path(userpath);
- }
-
- if(auto win_appdata = std::getenv("APPDATA")) {
- // On pre-seven Windows systems it's just AppData
- // On post-seven Windows systems it's AppData/Roaming
- return std::filesystem::path(win_appdata) / "voxelius";
- }
-
- if(auto xdg_home = std::getenv("XDG_DATA_HOME")) {
- // Systems with an active X11/Wayland session
- // theoretically should have this defined, and
- // it can be different from ${HOME} (I think).
- return std::filesystem::path(xdg_home) / ".voxelius";
- }
-
- if(auto unix_home = std::getenv("HOME")) {
- // Any spherical UNIX/UNIX-like system in vacuum
- // has this defined for every single user process.
- return std::filesystem::path(unix_home) / ".voxelius";
- }
-
- // Give up and save stuff into CWD
- return std::filesystem::current_path();
-}
-
-void shared_game::init(int argc, char** argv)
-{
- auto logger = spdlog::default_logger();
- auto& logger_sinks = logger->sinks();
-
- logger_sinks.clear();
- logger_sinks.push_back(std::make_shared<spdlog::sinks::stderr_color_sink_mt>());
- logger_sinks.push_back(std::make_shared<spdlog::sinks::basic_file_sink_mt>("voxelius.log", false));
-
-#if defined(NDEBUG)
- constexpr auto default_loglevel = spdlog::level::info;
-#else
- constexpr auto default_loglevel = spdlog::level::trace;
-#endif
-
- if(cmdline::contains("quiet")) {
- logger->set_level(spdlog::level::warn);
- } else if(cmdline::contains("verbose")) {
- logger->set_level(spdlog::level::trace);
- } else {
- logger->set_level(default_loglevel);
- }
-
- logger->set_pattern("%H:%M:%S.%e %^[%L]%$ %v");
- logger->flush();
-
- if(!PHYSFS_init(argv[0])) {
- spdlog::critical("physfs: init failed: {}", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
- std::terminate();
- }
-
- auto gamepath = get_gamepath();
- auto userpath = get_userpath();
-
- spdlog::info("shared_game: set gamepath to {}", gamepath.string());
- spdlog::info("shared_game: set userpath to {}", userpath.string());
-
- std::error_code ignore_error = {};
- std::filesystem::create_directories(gamepath, ignore_error);
- std::filesystem::create_directories(userpath, ignore_error);
-
- if(!PHYSFS_mount(gamepath.string().c_str(), nullptr, false)) {
- spdlog::critical("physfs: mount {} failed: {}", gamepath.string(), PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
- std::terminate();
- }
-
- if(!PHYSFS_mount(userpath.string().c_str(), nullptr, false)) {
- spdlog::critical("physfs: mount {} failed: {}", userpath.string(), PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
- std::terminate();
- }
-
- if(!PHYSFS_setWriteDir(userpath.string().c_str())) {
- spdlog::critical("physfs: setwritedir {} failed: {}", userpath.string(), PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
- std::terminate();
- }
-
- if(enet_initialize()) {
- spdlog::critical("enet: init failed");
- std::terminate();
- }
-}
-
-void shared_game::deinit(void)
-{
- enet_deinitialize();
-
- if(!PHYSFS_deinit()) {
- spdlog::critical("physfs: deinit failed: {}", PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode()));
- std::terminate();
- }
-}
diff --git a/game/shared/game.hh b/game/shared/game.hh
deleted file mode 100644
index 59c5327..0000000
--- a/game/shared/game.hh
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef SHARED_GAME
-#define SHARED_GAME 1
-#pragma once
-
-namespace shared_game
-{
-void init(int argc, char** argv);
-void deinit(void);
-} // namespace shared_game
-
-#endif /* SHARED_GAME */
diff --git a/game/shared/game_items.cc b/game/shared/game_items.cc
deleted file mode 100644
index 95fa6fc..0000000
--- a/game/shared/game_items.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-#include "shared/pch.hh"
-
-#include "shared/game_items.hh"
-
-#include "shared/game_voxels.hh"
-#include "shared/item_registry.hh"
-
-item_id game_items::stone = NULL_ITEM_ID;
-item_id game_items::cobblestone = NULL_ITEM_ID;
-item_id game_items::dirt = NULL_ITEM_ID;
-item_id game_items::grass = NULL_ITEM_ID;
-item_id game_items::oak_leaves = NULL_ITEM_ID;
-item_id game_items::oak_planks = NULL_ITEM_ID;
-item_id game_items::oak_log = NULL_ITEM_ID;
-item_id game_items::glass = NULL_ITEM_ID;
-item_id game_items::slime = NULL_ITEM_ID;
-item_id game_items::mud = NULL_ITEM_ID;
-
-void game_items::populate(void)
-{
- // Stone; a hardened slate rock
- game_items::stone =
- item_registry::construct("stone").set_texture("textures/item/stone.png").set_place_voxel(game_voxels::stone).build();
-
- // Cobblestone; a bunch of small stones
- game_items::cobblestone =
- item_registry::construct("cobblestone")
- .set_texture("textures/item/cobblestone.png")
- .set_place_voxel(game_voxels::cobblestone)
- .build();
-
- // Dirt; it's very dirty
- game_items::dirt = item_registry::construct("dirt").set_texture("textures/item/dirt.png").set_place_voxel(game_voxels::dirt).build();
-
- // Grass; literally just grassy dirt
- game_items::grass =
- item_registry::construct("grass").set_texture("textures/item/grass.png").set_place_voxel(game_voxels::grass).build();
-
- // Oak leaves; they're bushy!
- game_items::oak_leaves =
- item_registry::construct("oak_leaves").set_texture("textures/item/oak_leaves.png").set_place_voxel(game_voxels::oak_leaves).build();
-
- // Oak planks; watch for splinters!
- game_items::oak_planks =
- item_registry::construct("oak_planks").set_texture("textures/item/oak_planks.png").set_place_voxel(game_voxels::oak_planks).build();
-
- // Oak log; a big wad of wood
- game_items::oak_log =
- item_registry::construct("oak_log").set_texture("textures/item/oak_log.png").set_place_voxel(game_voxels::oak_log).build();
-
- // Glass; used for windowing
- game_items::glass =
- item_registry::construct("glass").set_texture("textures/item/glass.png").set_place_voxel(game_voxels::glass).build();
-
- // Slime; it's bouncy!
- game_items::slime =
- item_registry::construct("slime").set_texture("textures/item/slime.png").set_place_voxel(game_voxels::slime).build();
-
- // Mud; you sink in it!
- game_items::mud = item_registry::construct("mud").set_texture("textures/item/mud.png").build();
-}
diff --git a/game/shared/game_items.hh b/game/shared/game_items.hh
deleted file mode 100644
index 4e4eb81..0000000
--- a/game/shared/game_items.hh
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef SHARED_GAME_ITEMS
-#define SHARED_GAME_ITEMS 1
-#pragma once
-
-#include "shared/types.hh"
-
-namespace game_items
-{
-extern item_id stone;
-extern item_id cobblestone;
-extern item_id dirt;
-extern item_id grass;
-extern item_id oak_leaves;
-extern item_id oak_planks;
-extern item_id oak_log;
-extern item_id glass;
-extern item_id slime;
-extern item_id mud;
-} // namespace game_items
-
-namespace game_items
-{
-void populate(void);
-} // namespace game_items
-
-#endif /* SHARED_GAME_ITEMS */
diff --git a/game/shared/game_voxels.cc b/game/shared/game_voxels.cc
deleted file mode 100644
index 0059335..0000000
--- a/game/shared/game_voxels.cc
+++ /dev/null
@@ -1,122 +0,0 @@
-#include "shared/pch.hh"
-
-#include "shared/game_voxels.hh"
-
-#include "shared/voxel_registry.hh"
-
-voxel_id game_voxels::cobblestone = NULL_VOXEL_ID;
-voxel_id game_voxels::dirt = NULL_VOXEL_ID;
-voxel_id game_voxels::grass = NULL_VOXEL_ID;
-voxel_id game_voxels::stone = NULL_VOXEL_ID;
-voxel_id game_voxels::vtest = NULL_VOXEL_ID;
-voxel_id game_voxels::vtest_ck = NULL_VOXEL_ID;
-voxel_id game_voxels::oak_leaves = NULL_VOXEL_ID;
-voxel_id game_voxels::oak_planks = NULL_VOXEL_ID;
-voxel_id game_voxels::oak_log = NULL_VOXEL_ID;
-voxel_id game_voxels::glass = NULL_VOXEL_ID;
-voxel_id game_voxels::slime = NULL_VOXEL_ID;
-voxel_id game_voxels::mud = NULL_VOXEL_ID;
-
-void game_voxels::populate(void)
-{
- // Stone; the backbone of the generated world
- game_voxels::stone =
- voxel_registry::construct("stone", voxel_type::CUBE, false, false)
- .add_texture_default("textures/voxel/stone_01.png")
- .add_texture_default("textures/voxel/stone_02.png")
- .add_texture_default("textures/voxel/stone_03.png")
- .add_texture_default("textures/voxel/stone_04.png")
- .set_surface(voxel_surface::STONE)
- .build();
-
- // Cobblestone; should drop when a stone is broken, might also be present in surface features
- game_voxels::cobblestone =
- voxel_registry::construct("cobblestone", voxel_type::CUBE, false, false)
- .add_texture_default("textures/voxel/cobblestone_01.png")
- .add_texture_default("textures/voxel/cobblestone_02.png")
- .set_surface(voxel_surface::STONE)
- .build();
-
- // Dirt with a grass layer on top; the top layer of plains biome
- game_voxels::grass =
- voxel_registry::construct("grass", voxel_type::CUBE, false, false)
- .add_texture_default("textures/voxel/grass_side_01.png")
- .add_texture_default("textures/voxel/grass_side_02.png")
- .add_texture(voxel_face::CUBE_BOTTOM, "textures/voxel/dirt_01.png")
- .add_texture(voxel_face::CUBE_BOTTOM, "textures/voxel/dirt_02.png")
- .add_texture(voxel_face::CUBE_BOTTOM, "textures/voxel/dirt_03.png")
- .add_texture(voxel_face::CUBE_BOTTOM, "textures/voxel/dirt_04.png")
- .add_texture(voxel_face::CUBE_TOP, "textures/voxel/grass_01.png")
- .add_texture(voxel_face::CUBE_TOP, "textures/voxel/grass_02.png")
- .set_surface(voxel_surface::GRASS)
- .build();
-
- // Dirt; the under-surface layer of some biomes
- game_voxels::dirt =
- voxel_registry::construct("dirt", voxel_type::CUBE, false, false)
- .add_texture_default("textures/voxel/dirt_01.png")
- .add_texture_default("textures/voxel/dirt_02.png")
- .add_texture_default("textures/voxel/dirt_03.png")
- .add_texture_default("textures/voxel/dirt_04.png")
- .set_surface(voxel_surface::DIRT)
- .build();
-
- // VTest; a test voxel to ensure animations work
- game_voxels::vtest =
- voxel_registry::construct("vtest", voxel_type::CUBE, true, false)
- .add_texture_default("textures/voxel/vtest_F1.png")
- .add_texture_default("textures/voxel/vtest_F2.png")
- .add_texture_default("textures/voxel/vtest_F3.png")
- .add_texture_default("textures/voxel/vtest_F4.png")
- .build();
-
- // VTest-CK; a pure blue chromakey I used to make the game's logo
- game_voxels::vtest_ck =
- voxel_registry::construct("vtest_ck", voxel_type::CUBE, false, false).add_texture_default("textures/voxel/chromakey.png").build();
-
- // Oak leaves; greenery. TODO: add trees as surface features
- game_voxels::oak_leaves =
- voxel_registry::construct("oak_leaves", voxel_type::CUBE, false, false)
- .add_texture_default("textures/voxel/oak_leaves.png")
- .set_surface(voxel_surface::GRASS)
- .build();
-
- // Oak planks; the thing that comes out of oak logs
- game_voxels::oak_planks =
- voxel_registry::construct("oak_planks", voxel_type::CUBE, false, false)
- .add_texture_default("textures/voxel/oak_planks_01.png")
- .add_texture_default("textures/voxel/oak_planks_02.png")
- .set_surface(voxel_surface::WOOD)
- .build();
-
- // Oak logs; greenery. TODO: add trees as surface features
- game_voxels::oak_log =
- voxel_registry::construct("oak_log", voxel_type::CUBE, false, false)
- .add_texture_default("textures/voxel/oak_wood_01.png")
- .add_texture_default("textures/voxel/oak_wood_02.png")
- .add_texture(voxel_face::CUBE_BOTTOM, "textures/voxel/oak_wood_top.png")
- .add_texture(voxel_face::CUBE_TOP, "textures/voxel/oak_wood_top.png")
- .set_surface(voxel_surface::WOOD)
- .build();
-
- // Glass; blend rendering test
- game_voxels::glass = voxel_registry::construct("glass", voxel_type::CUBE, false, true)
- .add_texture_default("textures/voxel/glass_01.png")
- .set_surface(voxel_surface::GLASS)
- .build();
-
- // Slime; it's bouncy!
- game_voxels::slime = voxel_registry::construct("slime", voxel_type::CUBE, false, true)
- .set_touch(voxel_touch::BOUNCE, glm::fvec3(0.00f, 0.60f, 0.00f))
- .add_texture_default("textures/voxel/slime_01.png")
- .build();
-
- // Mud; you sink in it
- game_voxels::mud =
- voxel_registry::construct("mud", voxel_type::CUBE, false, false)
- .set_touch(voxel_touch::SINK, glm::fvec3(0.50f, 0.75f, 0.50f))
- .add_texture_default("textures/voxel/mud_01.png")
- .add_texture_default("textures/voxel/mud_02.png")
- .set_surface(voxel_surface::DIRT)
- .build();
-}
diff --git a/game/shared/game_voxels.hh b/game/shared/game_voxels.hh
deleted file mode 100644
index 1b344bf..0000000
--- a/game/shared/game_voxels.hh
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef SHARED_GAME_VOXELS
-#define SHARED_GAME_VOXELS 1
-#pragma once
-
-#include "shared/types.hh"
-
-namespace game_voxels
-{
-extern voxel_id cobblestone;
-extern voxel_id dirt;
-extern voxel_id grass;
-extern voxel_id stone;
-extern voxel_id vtest;
-extern voxel_id vtest_ck;
-extern voxel_id oak_leaves;
-extern voxel_id oak_planks;
-extern voxel_id oak_log;
-extern voxel_id glass;
-extern voxel_id slime;
-extern voxel_id mud;
-} // namespace game_voxels
-
-namespace game_voxels
-{
-void populate(void);
-} // namespace game_voxels
-
-#endif /* SHARED_GAME_VOXELS */
diff --git a/game/shared/globals.cc b/game/shared/globals.cc
deleted file mode 100644
index 8552214..0000000
--- a/game/shared/globals.cc
+++ /dev/null
@@ -1,12 +0,0 @@
-#include "shared/pch.hh"
-
-#include "shared/globals.hh"
-
-entt::dispatcher globals::dispatcher;
-
-float globals::fixed_frametime;
-float globals::fixed_frametime_avg;
-std::uint64_t globals::fixed_frametime_us;
-std::size_t globals::fixed_framecount;
-
-std::uint64_t globals::curtime;
diff --git a/game/shared/globals.hh b/game/shared/globals.hh
deleted file mode 100644
index 216d341..0000000
--- a/game/shared/globals.hh
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef SHARED_GLOBALS_HH
-#define SHARED_GLOBALS_HH 1
-#pragma once
-
-namespace globals
-{
-extern entt::dispatcher dispatcher;
-} // namespace globals
-
-namespace globals
-{
-extern float fixed_frametime;
-extern float fixed_frametime_avg;
-extern std::uint64_t fixed_frametime_us;
-extern std::size_t fixed_framecount;
-} // namespace globals
-
-namespace globals
-{
-extern std::uint64_t curtime;
-} // namespace globals
-
-#endif /* SHARED_GLOBALS_HH */
diff --git a/game/shared/gravity.cc b/game/shared/gravity.cc
deleted file mode 100644
index 068f658..0000000
--- a/game/shared/gravity.cc
+++ /dev/null
@@ -1,18 +0,0 @@
-#include "shared/pch.hh"
-
-#include "shared/gravity.hh"
-
-#include "shared/dimension.hh"
-#include "shared/globals.hh"
-#include "shared/stasis.hh"
-#include "shared/velocity.hh"
-
-void GravityComponent::fixed_update(Dimension* dimension)
-{
- auto fixed_acceleration = globals::fixed_frametime * dimension->get_gravity();
- auto group = dimension->entities.group<GravityComponent>(entt::get<VelocityComponent>, entt::exclude<StasisComponent>);
-
- for(auto [entity, velocity] : group.each()) {
- velocity.value.y += fixed_acceleration;
- }
-}
diff --git a/game/shared/gravity.hh b/game/shared/gravity.hh
deleted file mode 100644
index 53f51b7..0000000
--- a/game/shared/gravity.hh
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef SHARED_GRAVITY_HH
-#define SHARED_GRAVITY_HH 1
-#pragma once
-
-class Dimension;
-
-struct GravityComponent final {
-public:
- static void fixed_update(Dimension* dimension);
-};
-
-#endif /* SHARED_GRAVITY_HH */
diff --git a/game/shared/grounded.hh b/game/shared/grounded.hh
deleted file mode 100644
index 869cca0..0000000
--- a/game/shared/grounded.hh
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef SHARED_GROUNDED
-#define SHARED_GROUNDED 1
-#pragma once
-
-#include "shared/voxel_registry.hh"
-
-// Assigned to entities which are grounded
-// according to the collision and gravity system
-struct GroundedComponent final {
- voxel_surface surface;
-};
-
-#endif /* SHARED_GROUNDED */
diff --git a/game/shared/head.hh b/game/shared/head.hh
deleted file mode 100644
index 57dd445..0000000
--- a/game/shared/head.hh
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef SHARED_HEAD_HH
-#define SHARED_HEAD_HH 1
-#pragma once
-
-struct HeadComponent {
- glm::fvec3 angles;
- glm::fvec3 offset;
-};
-
-// Client-side only - interpolated and previous head
-struct HeadComponentIntr final : public HeadComponent {};
-struct HeadComponentPrev final : public HeadComponent {};
-
-#endif /* SHARED_HEAD_HH */
diff --git a/game/shared/item_registry.cc b/game/shared/item_registry.cc
deleted file mode 100644
index 1263201..0000000
--- a/game/shared/item_registry.cc
+++ /dev/null
@@ -1,103 +0,0 @@
-#include "shared/pch.hh"
-
-#include "shared/item_registry.hh"
-
-#include "core/crc64.hh"
-
-#include "shared/voxel_registry.hh"
-
-std::unordered_map<std::string, ItemInfoBuilder> item_registry::builders = {};
-std::unordered_map<std::string, item_id> item_registry::names = {};
-std::vector<std::shared_ptr<ItemInfo>> item_registry::items = {};
-
-ItemInfoBuilder::ItemInfoBuilder(const char* name)
-{
- prototype.name = name;
- prototype.texture = std::string();
- prototype.place_voxel = NULL_VOXEL_ID;
- prototype.cached_texture = nullptr;
-}
-
-ItemInfoBuilder& ItemInfoBuilder::set_texture(const char* texture)
-{
- prototype.texture = texture;
- prototype.cached_texture = nullptr;
- return *this;
-}
-
-ItemInfoBuilder& ItemInfoBuilder::set_place_voxel(voxel_id place_voxel)
-{
- prototype.place_voxel = place_voxel;
- return *this;
-}
-
-item_id ItemInfoBuilder::build(void) const
-{
- const auto it = item_registry::names.find(prototype.name);
-
- if(it != item_registry::names.cend()) {
- spdlog::warn("item_registry: cannot build {}: name already present", prototype.name);
- return it->second;
- }
-
- auto new_info = std::make_shared<ItemInfo>();
- new_info->name = prototype.name;
- new_info->texture = prototype.texture;
- new_info->place_voxel = prototype.place_voxel;
- new_info->cached_texture = nullptr;
-
- item_registry::items.push_back(new_info);
- item_registry::names.insert_or_assign(prototype.name, static_cast<item_id>(item_registry::items.size()));
-
- return static_cast<item_id>(item_registry::items.size());
-}
-
-ItemInfoBuilder& item_registry::construct(const char* name)
-{
- const auto it = item_registry::builders.find(name);
-
- if(it != item_registry::builders.cend()) {
- return it->second;
- } else {
- return item_registry::builders.emplace(name, ItemInfoBuilder(name)).first->second;
- }
-}
-
-ItemInfo* item_registry::find(const char* name)
-{
- const auto it = item_registry::names.find(name);
-
- if(it != item_registry::names.cend()) {
- return item_registry::find(it->second);
- } else {
- return nullptr;
- }
-}
-
-ItemInfo* item_registry::find(const item_id item)
-{
- if((item != NULL_ITEM_ID) && (item <= item_registry::items.size())) {
- return item_registry::items[item - 1].get();
- } else {
- return nullptr;
- }
-}
-
-void item_registry::purge(void)
-{
- item_registry::builders.clear();
- item_registry::names.clear();
- item_registry::items.clear();
-}
-
-std::uint64_t item_registry::calcualte_checksum(void)
-{
- std::uint64_t result = 0;
-
- for(const auto& info : item_registry::items) {
- result = crc64::get(info->name, result);
- result += static_cast<std::uint64_t>(info->place_voxel);
- }
-
- return result;
-}
diff --git a/game/shared/item_registry.hh b/game/shared/item_registry.hh
deleted file mode 100644
index 17cff9f..0000000
--- a/game/shared/item_registry.hh
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef SHARED_ITEM_REGISTRY_HH
-#define SHARED_ITEM_REGISTRY_HH 1
-#pragma once
-
-#include "core/resource.hh"
-
-#include "shared/types.hh"
-
-// This resource is only defined client-side and
-// resource_ptr<TextureGUI> should remain set to null
-// anywhere else in the shared and server code
-struct TextureGUI;
-
-struct ItemInfo final {
- std::string name;
- std::string texture;
- voxel_id place_voxel;
-
- resource_ptr<TextureGUI> cached_texture; // Client-side only
-};
-
-class ItemInfoBuilder final {
-public:
- explicit ItemInfoBuilder(const char* name);
- virtual ~ItemInfoBuilder(void) = default;
-
-public:
- ItemInfoBuilder& set_texture(const char* texture);
- ItemInfoBuilder& set_place_voxel(voxel_id place_voxel);
-
-public:
- item_id build(void) const;
-
-private:
- ItemInfo prototype;
-};
-
-namespace item_registry
-{
-extern std::unordered_map<std::string, ItemInfoBuilder> builders;
-extern std::unordered_map<std::string, item_id> names;
-extern std::vector<std::shared_ptr<ItemInfo>> items;
-} // namespace item_registry
-
-namespace item_registry
-{
-ItemInfoBuilder& construct(const char* name);
-ItemInfo* find(const char* name);
-ItemInfo* find(const item_id item);
-} // namespace item_registry
-
-namespace item_registry
-{
-void purge(void);
-} // namespace item_registry
-
-namespace item_registry
-{
-std::uint64_t calcualte_checksum(void);
-} // namespace item_registry
-
-#endif /* SHARED_ITEM_REGISTRY_HH */
diff --git a/game/shared/pch.hh b/game/shared/pch.hh
deleted file mode 100644
index 1776f9b..0000000
--- a/game/shared/pch.hh
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef SHARED_PCH_HH
-#define SHARED_PCH_HH 1
-#pragma once
-
-#include <core/pch.hh>
-
-#include <csignal>
-
-#include <BS_thread_pool.hpp>
-
-#include <enet/enet.h>
-
-#include <entt/entity/registry.hpp>
-#include <entt/signal/dispatcher.hpp>
-
-#include <fastnoiselite.h>
-
-#include <miniz.h>
-
-#include <parson.h>
-
-#include <spdlog/sinks/basic_file_sink.h>
-#include <spdlog/sinks/stdout_color_sinks.h>
-
-#endif /* SHARED_PCH_HH */
diff --git a/game/shared/player.hh b/game/shared/player.hh
deleted file mode 100644
index a01b4f2..0000000
--- a/game/shared/player.hh
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef SHARED_PLAYER_HH
-#define SHARED_PLAYER_HH 1
-#pragma once
-
-struct PlayerComponent final {};
-
-#endif /* SHARED_PLAYER_HH */
diff --git a/game/shared/protocol.cc b/game/shared/protocol.cc
deleted file mode 100644
index 0e57fe4..0000000
--- a/game/shared/protocol.cc
+++ /dev/null
@@ -1,491 +0,0 @@
-#include "shared/pch.hh"
-
-#include "shared/protocol.hh"
-
-#include "core/buffer.hh"
-#include "core/floathacks.hh"
-
-#include "shared/chunk.hh"
-#include "shared/dimension.hh"
-#include "shared/globals.hh"
-#include "shared/head.hh"
-#include "shared/player.hh"
-#include "shared/transform.hh"
-#include "shared/velocity.hh"
-
-static ReadBuffer read_buffer;
-static WriteBuffer write_buffer;
-
-ENetPacket* protocol::encode(const protocol::StatusRequest& packet, enet_uint32 flags)
-{
- write_buffer.reset();
- write_buffer.write_UI16(protocol::StatusRequest::ID);
- write_buffer.write_UI32(packet.version);
- return write_buffer.to_packet(flags);
-}
-
-ENetPacket* protocol::encode(const protocol::StatusResponse& packet, enet_uint32 flags)
-{
- write_buffer.reset();
- write_buffer.write_UI16(protocol::StatusResponse::ID);
- write_buffer.write_UI32(packet.version);
- write_buffer.write_UI16(packet.max_players);
- write_buffer.write_UI16(packet.num_players);
- write_buffer.write_string(packet.motd);
- return write_buffer.to_packet(flags);
-}
-
-ENetPacket* protocol::encode(const protocol::LoginRequest& packet, enet_uint32 flags)
-{
- write_buffer.reset();
- write_buffer.write_UI16(protocol::LoginRequest::ID);
- write_buffer.write_UI32(packet.version);
- write_buffer.write_UI64(packet.voxel_registry_checksum);
- write_buffer.write_UI64(packet.item_registry_checksum);
- write_buffer.write_UI64(packet.password_hash);
- write_buffer.write_string(packet.username.substr(0, protocol::MAX_USERNAME));
- return write_buffer.to_packet(flags);
-}
-
-ENetPacket* protocol::encode(const protocol::LoginResponse& packet, enet_uint32 flags)
-{
- write_buffer.reset();
- write_buffer.write_UI16(protocol::LoginResponse::ID);
- write_buffer.write_UI16(packet.client_index);
- write_buffer.write_UI64(packet.client_identity);
- write_buffer.write_UI16(packet.server_tickrate);
- return write_buffer.to_packet(flags);
-}
-
-ENetPacket* protocol::encode(const protocol::Disconnect& packet, enet_uint32 flags)
-{
- write_buffer.reset();
- write_buffer.write_UI16(protocol::Disconnect::ID);
- write_buffer.write_string(packet.reason);
- return write_buffer.to_packet(flags);
-}
-
-ENetPacket* protocol::encode(const protocol::ChunkVoxels& packet, enet_uint32 flags)
-{
- write_buffer.reset();
- write_buffer.write_UI16(protocol::ChunkVoxels::ID);
- write_buffer.write_I32(packet.chunk.x);
- write_buffer.write_I32(packet.chunk.y);
- write_buffer.write_I32(packet.chunk.z);
- packet.voxels.serialize(write_buffer);
- return write_buffer.to_packet(flags);
-}
-
-ENetPacket* protocol::encode(const protocol::EntityTransform& packet, enet_uint32 flags)
-{
- write_buffer.reset();
- write_buffer.write_UI16(protocol::EntityTransform::ID);
- write_buffer.write_UI64(static_cast<std::uint64_t>(packet.entity));
- write_buffer.write_I32(packet.chunk.x);
- write_buffer.write_I32(packet.chunk.y);
- write_buffer.write_I32(packet.chunk.z);
- write_buffer.write_FP32(packet.local.x);
- write_buffer.write_FP32(packet.local.y);
- write_buffer.write_FP32(packet.local.z);
- write_buffer.write_FP32(packet.angles.x);
- write_buffer.write_FP32(packet.angles.y);
- write_buffer.write_FP32(packet.angles.z);
- return write_buffer.to_packet(flags);
-}
-
-ENetPacket* protocol::encode(const protocol::EntityHead& packet, enet_uint32 flags)
-{
- write_buffer.reset();
- write_buffer.write_UI16(protocol::EntityHead::ID);
- write_buffer.write_UI64(static_cast<std::uint64_t>(packet.entity));
- write_buffer.write_FP32(packet.angles.x);
- write_buffer.write_FP32(packet.angles.y);
- write_buffer.write_FP32(packet.angles.z);
- return write_buffer.to_packet(flags);
-}
-
-ENetPacket* protocol::encode(const protocol::EntityVelocity& packet, enet_uint32 flags)
-{
- write_buffer.reset();
- write_buffer.write_UI16(protocol::EntityVelocity::ID);
- write_buffer.write_UI64(static_cast<std::uint64_t>(packet.entity));
- write_buffer.write_FP32(packet.value.x);
- write_buffer.write_FP32(packet.value.y);
- write_buffer.write_FP32(packet.value.z);
- return write_buffer.to_packet(flags);
-}
-
-ENetPacket* protocol::encode(const protocol::SpawnPlayer& packet, enet_uint32 flags)
-{
- write_buffer.reset();
- write_buffer.write_UI16(protocol::SpawnPlayer::ID);
- write_buffer.write_UI64(static_cast<std::uint64_t>(packet.entity));
- return write_buffer.to_packet(flags);
-}
-
-ENetPacket* protocol::encode(const protocol::ChatMessage& packet, enet_uint32 flags)
-{
- write_buffer.reset();
- write_buffer.write_UI16(protocol::ChatMessage::ID);
- write_buffer.write_UI16(packet.type);
- write_buffer.write_string(packet.sender.substr(0, protocol::MAX_USERNAME));
- write_buffer.write_string(packet.message.substr(0, protocol::MAX_CHAT));
- return write_buffer.to_packet(flags);
-}
-
-ENetPacket* protocol::encode(const protocol::SetVoxel& packet, enet_uint32 flags)
-{
- write_buffer.reset();
- write_buffer.write_UI16(protocol::SetVoxel::ID);
- write_buffer.write_I64(packet.vpos.x);
- write_buffer.write_I64(packet.vpos.y);
- write_buffer.write_I64(packet.vpos.z);
- write_buffer.write_UI16(packet.voxel);
- write_buffer.write_UI16(packet.flags);
- return write_buffer.to_packet(flags);
-}
-
-ENetPacket* protocol::encode(const protocol::RemoveEntity& packet, enet_uint32 flags)
-{
- write_buffer.reset();
- write_buffer.write_UI16(protocol::RemoveEntity::ID);
- write_buffer.write_UI64(static_cast<std::uint64_t>(packet.entity));
- return write_buffer.to_packet(flags);
-}
-
-ENetPacket* protocol::encode(const protocol::EntityPlayer& packet, enet_uint32 flags)
-{
- write_buffer.reset();
- write_buffer.write_UI16(protocol::EntityPlayer::ID);
- write_buffer.write_UI64(static_cast<std::uint64_t>(packet.entity));
- return write_buffer.to_packet(flags);
-}
-
-ENetPacket* protocol::encode(const protocol::ScoreboardUpdate& packet, enet_uint32 flags)
-{
- write_buffer.reset();
- write_buffer.write_UI16(protocol::ScoreboardUpdate::ID);
- write_buffer.write_UI16(static_cast<std::uint16_t>(packet.names.size()));
- for(const std::string& username : packet.names)
- write_buffer.write_string(username.substr(0, protocol::MAX_USERNAME));
- return write_buffer.to_packet(flags);
-}
-
-ENetPacket* protocol::encode(const protocol::RequestChunk& packet, enet_uint32 flags)
-{
- write_buffer.reset();
- write_buffer.write_UI16(protocol::RequestChunk::ID);
- write_buffer.write_I32(packet.cpos.x);
- write_buffer.write_I32(packet.cpos.y);
- write_buffer.write_I32(packet.cpos.z);
- return write_buffer.to_packet(flags);
-}
-
-ENetPacket* protocol::encode(const protocol::GenericSound& packet, enet_uint32 flags)
-{
- write_buffer.reset();
- write_buffer.write_UI16(protocol::GenericSound::ID);
- write_buffer.write_string(packet.sound.substr(0, protocol::MAX_SOUNDNAME));
- write_buffer.write_UI8(packet.looping);
- write_buffer.write_FP32(packet.pitch);
- return write_buffer.to_packet(flags);
-}
-
-ENetPacket* protocol::encode(const protocol::EntitySound& packet, enet_uint32 flags)
-{
- write_buffer.reset();
- write_buffer.write_UI16(protocol::EntitySound::ID);
- write_buffer.write_UI64(static_cast<std::uint64_t>(packet.entity));
- write_buffer.write_string(packet.sound.substr(0, protocol::MAX_SOUNDNAME));
- write_buffer.write_UI8(packet.looping);
- write_buffer.write_FP32(packet.pitch);
- return write_buffer.to_packet(flags);
-}
-
-ENetPacket* protocol::encode(const protocol::DimensionInfo& packet, enet_uint32 flags)
-{
- write_buffer.reset();
- write_buffer.write_UI16(protocol::DimensionInfo::ID);
- write_buffer.write_string(packet.name);
- write_buffer.write_FP32(packet.gravity);
- return write_buffer.to_packet(flags);
-}
-
-void protocol::broadcast(ENetHost* host, ENetPacket* packet)
-{
- if(packet) {
- enet_host_broadcast(host, protocol::CHANNEL, packet);
- }
-}
-
-void protocol::broadcast(ENetHost* host, ENetPacket* packet, ENetPeer* except)
-{
- if(packet) {
- for(unsigned int i = 0U; i < host->peerCount; ++i) {
- if(host->peers[i].state == ENET_PEER_STATE_CONNECTED) {
- if(&host->peers[i] != except) {
- enet_peer_send(&host->peers[i], protocol::CHANNEL, packet);
- }
- }
- }
- }
-}
-
-void protocol::send(ENetPeer* peer, ENetPacket* packet)
-{
- if(packet) {
- enet_peer_send(peer, protocol::CHANNEL, packet);
- }
-}
-
-void protocol::decode(entt::dispatcher& dispatcher, const ENetPacket* packet, ENetPeer* peer)
-{
- read_buffer.reset(packet);
-
- protocol::StatusRequest status_request;
- protocol::StatusResponse status_response;
- protocol::LoginRequest login_request;
- protocol::LoginResponse login_response;
- protocol::Disconnect disconnect;
- protocol::ChunkVoxels chunk_voxels;
- protocol::EntityTransform entity_transform;
- protocol::EntityHead entity_head;
- protocol::EntityVelocity entity_velocity;
- protocol::SpawnPlayer spawn_player;
- protocol::ChatMessage chat_message;
- protocol::SetVoxel set_voxel;
- protocol::RemoveEntity remove_entity;
- protocol::EntityPlayer entity_player;
- protocol::ScoreboardUpdate scoreboard_update;
- protocol::RequestChunk request_chunk;
- protocol::GenericSound generic_sound;
- protocol::EntitySound entity_sound;
- protocol::DimensionInfo dimension_info;
-
- auto id = read_buffer.read_UI16();
-
- switch(id) {
- case protocol::StatusRequest::ID:
- status_request.peer = peer;
- status_request.version = read_buffer.read_UI32();
- dispatcher.trigger(status_request);
- break;
- case protocol::StatusResponse::ID:
- status_response.peer = peer;
- status_response.version = read_buffer.read_UI32();
- status_response.max_players = read_buffer.read_UI16();
- status_response.num_players = read_buffer.read_UI16();
- status_response.motd = read_buffer.read_string();
- dispatcher.trigger(status_response);
- break;
- case protocol::LoginRequest::ID:
- login_request.peer = peer;
- login_request.version = read_buffer.read_UI32();
- login_request.voxel_registry_checksum = read_buffer.read_UI64();
- login_request.item_registry_checksum = read_buffer.read_UI64();
- login_request.password_hash = read_buffer.read_UI64();
- login_request.username = read_buffer.read_string();
- dispatcher.trigger(login_request);
- break;
- case protocol::LoginResponse::ID:
- login_response.peer = peer;
- login_response.client_index = read_buffer.read_UI16();
- login_response.client_identity = read_buffer.read_UI64();
- login_response.server_tickrate = read_buffer.read_UI16();
- dispatcher.trigger(login_response);
- break;
- case protocol::Disconnect::ID:
- disconnect.peer = peer;
- disconnect.reason = read_buffer.read_string();
- dispatcher.trigger(disconnect);
- break;
- case protocol::ChunkVoxels::ID:
- chunk_voxels.peer = peer;
- chunk_voxels.chunk.x = read_buffer.read_I32();
- chunk_voxels.chunk.y = read_buffer.read_I32();
- chunk_voxels.chunk.z = read_buffer.read_I32();
- chunk_voxels.voxels.deserialize(read_buffer);
- dispatcher.trigger(chunk_voxels);
- break;
- case protocol::EntityTransform::ID:
- entity_transform.peer = peer;
- entity_transform.entity = static_cast<entt::entity>(read_buffer.read_UI64());
- entity_transform.chunk.x = read_buffer.read_I32();
- entity_transform.chunk.y = read_buffer.read_I32();
- entity_transform.chunk.z = read_buffer.read_I32();
- entity_transform.local.x = read_buffer.read_FP32();
- entity_transform.local.y = read_buffer.read_FP32();
- entity_transform.local.z = read_buffer.read_FP32();
- entity_transform.angles.x = read_buffer.read_FP32();
- entity_transform.angles.y = read_buffer.read_FP32();
- entity_transform.angles.z = read_buffer.read_FP32();
- dispatcher.trigger(entity_transform);
- break;
- case protocol::EntityHead::ID:
- entity_head.peer = peer;
- entity_head.entity = static_cast<entt::entity>(read_buffer.read_UI64());
- entity_head.angles[0] = read_buffer.read_FP32();
- entity_head.angles[1] = read_buffer.read_FP32();
- entity_head.angles[2] = read_buffer.read_FP32();
- dispatcher.trigger(entity_head);
- break;
- case protocol::EntityVelocity::ID:
- entity_velocity.peer = peer;
- entity_velocity.entity = static_cast<entt::entity>(read_buffer.read_UI64());
- entity_velocity.value.x = read_buffer.read_FP32();
- entity_velocity.value.y = read_buffer.read_FP32();
- entity_velocity.value.z = read_buffer.read_FP32();
- dispatcher.trigger(entity_velocity);
- break;
- case protocol::SpawnPlayer::ID:
- spawn_player.peer = peer;
- spawn_player.entity = static_cast<entt::entity>(read_buffer.read_UI64());
- dispatcher.trigger(spawn_player);
- break;
- case protocol::ChatMessage::ID:
- chat_message.peer = peer;
- chat_message.type = read_buffer.read_UI16();
- chat_message.sender = read_buffer.read_string();
- chat_message.message = read_buffer.read_string();
- dispatcher.trigger(chat_message);
- break;
- case protocol::SetVoxel::ID:
- set_voxel.peer = peer;
- set_voxel.vpos.x = read_buffer.read_I64();
- set_voxel.vpos.y = read_buffer.read_I64();
- set_voxel.vpos.z = read_buffer.read_I64();
- set_voxel.voxel = read_buffer.read_UI16();
- set_voxel.flags = read_buffer.read_UI16();
- dispatcher.trigger(set_voxel);
- break;
- case protocol::RemoveEntity::ID:
- remove_entity.peer = peer;
- remove_entity.entity = static_cast<entt::entity>(read_buffer.read_UI64());
- dispatcher.trigger(remove_entity);
- break;
- case protocol::EntityPlayer::ID:
- entity_player.peer = peer;
- entity_player.entity = static_cast<entt::entity>(read_buffer.read_UI64());
- dispatcher.trigger(entity_player);
- break;
- case protocol::ScoreboardUpdate::ID:
- scoreboard_update.peer = peer;
- scoreboard_update.names.resize(read_buffer.read_UI16());
- for(std::size_t i = 0; i < scoreboard_update.names.size(); ++i)
- scoreboard_update.names[i] = read_buffer.read_string();
- dispatcher.trigger(scoreboard_update);
- break;
- case protocol::RequestChunk::ID:
- request_chunk.peer = peer;
- request_chunk.cpos.x = read_buffer.read_UI32();
- request_chunk.cpos.y = read_buffer.read_UI32();
- request_chunk.cpos.z = read_buffer.read_UI32();
- dispatcher.trigger(request_chunk);
- break;
- case protocol::GenericSound::ID:
- generic_sound.peer = peer;
- generic_sound.sound = read_buffer.read_string();
- generic_sound.looping = read_buffer.read_UI8();
- generic_sound.pitch = read_buffer.read_FP32();
- dispatcher.trigger(generic_sound);
- break;
- case protocol::EntitySound::ID:
- entity_sound.peer = peer;
- entity_sound.entity = static_cast<entt::entity>(read_buffer.read_UI64());
- entity_sound.sound = read_buffer.read_string();
- entity_sound.looping = read_buffer.read_UI8();
- entity_sound.pitch = read_buffer.read_FP32();
- dispatcher.trigger(entity_sound);
- break;
- case protocol::DimensionInfo::ID:
- dimension_info.peer = peer;
- dimension_info.name = read_buffer.read_string();
- dimension_info.gravity = read_buffer.read_FP32();
- dispatcher.trigger(dimension_info);
- break;
- }
-}
-
-ENetPacket* protocol::utils::make_disconnect(const char* reason, enet_uint32 flags)
-{
- protocol::Disconnect packet;
- packet.reason = std::string(reason);
- return protocol::encode(packet, flags);
-}
-
-ENetPacket* protocol::utils::make_chat_message(const char* message, enet_uint32 flags)
-{
- protocol::ChatMessage packet;
- packet.type = protocol::ChatMessage::TEXT_MESSAGE;
- packet.message = std::string(message);
- return protocol::encode(packet, flags);
-}
-
-ENetPacket* protocol::utils::make_chunk_voxels(Dimension* dimension, entt::entity entity, enet_uint32 flags)
-{
- if(auto component = dimension->chunks.try_get<ChunkComponent>(entity)) {
- protocol::ChunkVoxels packet;
- packet.chunk = component->cpos;
- packet.voxels = component->chunk->get_voxels();
- return protocol::encode(packet, flags);
- }
-
- return nullptr;
-}
-
-ENetPacket* protocol::utils::make_entity_head(Dimension* dimension, entt::entity entity, enet_uint32 flags)
-{
- if(auto component = dimension->entities.try_get<HeadComponent>(entity)) {
- protocol::EntityHead packet;
- packet.entity = entity;
- packet.angles = component->angles;
- return protocol::encode(packet, flags);
- }
-
- return nullptr;
-}
-
-ENetPacket* protocol::utils::make_entity_transform(Dimension* dimension, entt::entity entity, enet_uint32 flags)
-{
- if(auto component = dimension->entities.try_get<TransformComponent>(entity)) {
- protocol::EntityTransform packet;
- packet.entity = entity;
- packet.chunk = component->chunk;
- packet.local = component->local;
- packet.angles = component->angles;
- return protocol::encode(packet, flags);
- }
-
- return nullptr;
-}
-
-ENetPacket* protocol::utils::make_entity_velocity(Dimension* dimension, entt::entity entity, enet_uint32 flags)
-{
- if(auto component = dimension->entities.try_get<VelocityComponent>(entity)) {
- protocol::EntityVelocity packet;
- packet.entity = entity;
- packet.value = component->value;
- return protocol::encode(packet, flags);
- }
-
- return nullptr;
-}
-
-ENetPacket* protocol::utils::make_entity_player(Dimension* dimension, entt::entity entity, enet_uint32 flags)
-{
- if(dimension->entities.any_of<PlayerComponent>(entity)) {
- protocol::EntityPlayer packet;
- packet.entity = entity;
- return protocol::encode(packet, flags);
- }
-
- return nullptr;
-}
-
-ENetPacket* protocol::utils::make_dimension_info(const Dimension* dimension)
-{
- protocol::DimensionInfo packet;
- packet.name = dimension->get_name();
- packet.gravity = dimension->get_gravity();
- return protocol::encode(packet, ENET_PACKET_FLAG_RELIABLE);
-}
diff --git a/game/shared/protocol.hh b/game/shared/protocol.hh
deleted file mode 100644
index 5b25628..0000000
--- a/game/shared/protocol.hh
+++ /dev/null
@@ -1,213 +0,0 @@
-#ifndef SHARED_PROTOCOL_HH
-#define SHARED_PROTOCOL_HH 1
-#pragma once
-
-#include "shared/chunk.hh"
-
-class Dimension;
-
-namespace protocol
-{
-constexpr static std::size_t MAX_CHAT = 16384;
-constexpr static std::size_t MAX_USERNAME = 64;
-constexpr static std::size_t MAX_SOUNDNAME = 1024;
-constexpr static std::uint16_t TICKRATE = 60;
-constexpr static std::uint16_t PORT = 43103;
-constexpr static std::uint32_t VERSION = 15;
-constexpr static std::uint8_t CHANNEL = 0;
-} // namespace protocol
-
-namespace protocol
-{
-template<std::uint16_t packet_id>
-struct Base {
- constexpr static std::uint16_t ID = packet_id;
- virtual ~Base(void) = default;
- ENetPeer* peer { nullptr };
-};
-} // namespace protocol
-
-namespace protocol
-{
-struct StatusRequest;
-struct StatusResponse;
-struct LoginRequest;
-struct LoginResponse;
-struct Disconnect;
-struct ChunkVoxels;
-struct EntityTransform;
-struct EntityHead;
-struct EntityVelocity;
-struct SpawnPlayer;
-struct ChatMessage;
-struct SetVoxel;
-struct RemoveEntity;
-struct EntityPlayer;
-struct ScoreboardUpdate;
-struct RequestChunk;
-struct GenericSound;
-struct EntitySound;
-struct DimensionInfo;
-} // namespace protocol
-
-namespace protocol
-{
-ENetPacket* encode(const StatusRequest& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
-ENetPacket* encode(const StatusResponse& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
-ENetPacket* encode(const LoginRequest& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
-ENetPacket* encode(const LoginResponse& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
-ENetPacket* encode(const Disconnect& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
-ENetPacket* encode(const ChunkVoxels& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
-ENetPacket* encode(const EntityTransform& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
-ENetPacket* encode(const EntityHead& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
-ENetPacket* encode(const EntityVelocity& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
-ENetPacket* encode(const SpawnPlayer& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
-ENetPacket* encode(const ChatMessage& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
-ENetPacket* encode(const SetVoxel& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
-ENetPacket* encode(const RemoveEntity& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
-ENetPacket* encode(const EntityPlayer& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
-ENetPacket* encode(const ScoreboardUpdate& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
-ENetPacket* encode(const RequestChunk& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
-ENetPacket* encode(const GenericSound& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
-ENetPacket* encode(const EntitySound& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
-ENetPacket* encode(const DimensionInfo& packet, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
-} // namespace protocol
-
-namespace protocol
-{
-void broadcast(ENetHost* host, ENetPacket* packet);
-void broadcast(ENetHost* host, ENetPacket* packet, ENetPeer* except);
-void send(ENetPeer* peer, ENetPacket* packet);
-} // namespace protocol
-
-namespace protocol
-{
-void decode(entt::dispatcher& dispatcher, const ENetPacket* packet, ENetPeer* peer);
-} // namespace protocol
-
-namespace protocol::utils
-{
-ENetPacket* make_disconnect(const char* reason, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
-ENetPacket* make_chat_message(const char* message, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
-} // namespace protocol::utils
-
-namespace protocol::utils
-{
-ENetPacket* make_chunk_voxels(Dimension* dimension, entt::entity entity, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
-} // namespace protocol::utils
-
-namespace protocol::utils
-{
-ENetPacket* make_entity_head(Dimension* dimension, entt::entity entity, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
-ENetPacket* make_entity_transform(Dimension* dimension, entt::entity entity, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
-ENetPacket* make_entity_velocity(Dimension* dimension, entt::entity entity, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
-ENetPacket* make_entity_player(Dimension* dimension, entt::entity entity, enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE);
-ENetPacket* make_dimension_info(const Dimension* dimension);
-} // namespace protocol::utils
-
-struct protocol::StatusRequest final : public protocol::Base<0x0000> {
- std::uint32_t version;
-};
-
-struct protocol::StatusResponse final : public protocol::Base<0x0001> {
- std::uint32_t version;
- std::uint16_t max_players;
- std::uint16_t num_players;
- std::string motd;
-};
-
-struct protocol::LoginRequest final : public protocol::Base<0x0002> {
- std::uint32_t version;
- std::uint64_t voxel_registry_checksum;
- std::uint64_t item_registry_checksum;
- std::uint64_t password_hash;
- std::string username;
-};
-
-struct protocol::LoginResponse final : public protocol::Base<0x0003> {
- std::uint16_t client_index;
- std::uint64_t client_identity;
- std::uint16_t server_tickrate;
-};
-
-struct protocol::Disconnect final : public protocol::Base<0x0004> {
- std::string reason;
-};
-
-struct protocol::ChunkVoxels final : public protocol::Base<0x0005> {
- chunk_pos chunk;
- VoxelStorage voxels;
-};
-
-struct protocol::EntityTransform final : public protocol::Base<0x0006> {
- entt::entity entity;
- chunk_pos chunk;
- glm::fvec3 local;
- glm::fvec3 angles;
-};
-
-struct protocol::EntityHead final : public protocol::Base<0x0007> {
- entt::entity entity;
- glm::fvec3 angles;
-};
-
-struct protocol::EntityVelocity final : public protocol::Base<0x0008> {
- entt::entity entity;
- glm::fvec3 value;
-};
-
-struct protocol::SpawnPlayer final : public protocol::Base<0x0009> {
- entt::entity entity;
-};
-
-struct protocol::ChatMessage final : public protocol::Base<0x000A> {
- constexpr static std::uint16_t TEXT_MESSAGE = 0x0000;
- constexpr static std::uint16_t PLAYER_JOIN = 0x0001;
- constexpr static std::uint16_t PLAYER_LEAVE = 0x0002;
-
- std::uint16_t type;
- std::string sender;
- std::string message;
-};
-
-struct protocol::SetVoxel final : public protocol::Base<0x000B> {
- voxel_pos vpos;
- voxel_id voxel;
- std::uint16_t flags;
-};
-
-struct protocol::RemoveEntity final : public protocol::Base<0x000C> {
- entt::entity entity;
-};
-
-struct protocol::EntityPlayer final : public protocol::Base<0x000D> {
- entt::entity entity;
-};
-
-struct protocol::ScoreboardUpdate final : public protocol::Base<0x000E> {
- std::vector<std::string> names;
-};
-
-struct protocol::RequestChunk final : public protocol::Base<0x000F> {
- chunk_pos cpos;
-};
-
-struct protocol::GenericSound final : public protocol::Base<0x0010> {
- std::string sound;
- bool looping;
- float pitch;
-};
-
-struct protocol::EntitySound final : public protocol::Base<0x0011> {
- entt::entity entity;
- std::string sound;
- bool looping;
- float pitch;
-};
-
-struct protocol::DimensionInfo final : public protocol::Base<0x0012> {
- std::string name;
- float gravity;
-};
-
-#endif /* SHARED_PROTOCOL_HH */
diff --git a/game/shared/ray_dda.cc b/game/shared/ray_dda.cc
deleted file mode 100644
index 75d4386..0000000
--- a/game/shared/ray_dda.cc
+++ /dev/null
@@ -1,96 +0,0 @@
-#include "shared/pch.hh"
-
-#include "shared/ray_dda.hh"
-
-#include "shared/coord.hh"
-#include "shared/dimension.hh"
-
-RayDDA::RayDDA(const Dimension* dimension, const chunk_pos& start_chunk, const glm::fvec3& start_fpos, const glm::fvec3& direction)
-{
- reset(dimension, start_chunk, start_fpos, direction);
-}
-
-RayDDA::RayDDA(const Dimension& dimension, const chunk_pos& start_chunk, const glm::fvec3& start_fpos, const glm::fvec3& direction)
-{
- reset(dimension, start_chunk, start_fpos, direction);
-}
-
-void RayDDA::reset(const Dimension* dimension, const chunk_pos& start_chunk, const glm::fvec3& start_fpos, const glm::fvec3& direction)
-{
- this->dimension = dimension;
- this->start_chunk = start_chunk;
- this->start_fpos = start_fpos;
- this->direction = direction;
-
- this->delta_dist.x = direction.x ? vx::abs(1.0f / direction.x) : std::numeric_limits<float>::max();
- this->delta_dist.y = direction.y ? vx::abs(1.0f / direction.y) : std::numeric_limits<float>::max();
- this->delta_dist.z = direction.z ? vx::abs(1.0f / direction.z) : std::numeric_limits<float>::max();
-
- this->distance = 0.0f;
- this->vpos = coord::to_voxel(start_chunk, start_fpos);
- this->vnormal = voxel_pos(0, 0, 0);
-
- // Need this for initial direction calculations
- auto lpos = coord::to_local(start_fpos);
-
- if(direction.x < 0.0f) {
- this->side_dist.x = this->delta_dist.x * (start_fpos.x - lpos.x);
- this->vstep.x = voxel_pos::value_type(-1);
- } else {
- this->side_dist.x = this->delta_dist.x * (lpos.x + 1.0f - start_fpos.x);
- this->vstep.x = voxel_pos::value_type(+1);
- }
-
- if(direction.y < 0.0f) {
- this->side_dist.y = this->delta_dist.y * (start_fpos.y - lpos.y);
- this->vstep.y = voxel_pos::value_type(-1);
- } else {
- this->side_dist.y = this->delta_dist.y * (lpos.y + 1.0f - start_fpos.y);
- this->vstep.y = voxel_pos::value_type(+1);
- }
-
- if(direction.z < 0.0f) {
- this->side_dist.z = this->delta_dist.z * (start_fpos.z - lpos.z);
- this->vstep.z = voxel_pos::value_type(-1);
- } else {
- this->side_dist.z = this->delta_dist.z * (lpos.z + 1.0f - start_fpos.z);
- this->vstep.z = voxel_pos::value_type(+1);
- }
-}
-
-void RayDDA::reset(const Dimension& dimension, const chunk_pos& start_chunk, const glm::fvec3& start_fpos, const glm::fvec3& direction)
-{
- reset(&dimension, start_chunk, start_fpos, direction);
-}
-
-voxel_id RayDDA::step(void)
-{
- if(side_dist.x < side_dist.z) {
- if(side_dist.x < side_dist.y) {
- vnormal = voxel_pos(-vstep.x, 0, 0);
- distance = side_dist.x;
- side_dist.x += delta_dist.x;
- vpos.x += vstep.x;
- } else {
- vnormal = voxel_pos(0, -vstep.y, 0);
- distance = side_dist.y;
- side_dist.y += delta_dist.y;
- vpos.y += vstep.y;
- }
- } else {
- if(side_dist.z < side_dist.y) {
- vnormal = voxel_pos(0, 0, -vstep.z);
- distance = side_dist.z;
- side_dist.z += delta_dist.z;
- vpos.z += vstep.z;
- } else {
- vnormal = voxel_pos(0, -vstep.y, 0);
- distance = side_dist.y;
- side_dist.y += delta_dist.y;
- vpos.y += vstep.y;
- }
- }
-
- // This is slower than I want it to be
- return dimension->get_voxel(vpos);
-}
diff --git a/game/shared/ray_dda.hh b/game/shared/ray_dda.hh
deleted file mode 100644
index 91eb462..0000000
--- a/game/shared/ray_dda.hh
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef SHARED_RAY_DDA
-#define SHARED_RAY_DDA 1
-#pragma once
-
-#include "core/macros.hh"
-
-#include "shared/types.hh"
-
-class Dimension;
-
-class RayDDA final {
-public:
- DECLARE_DEFAULT_CONSTRUCTOR(RayDDA);
- explicit RayDDA(const Dimension* dimension, const chunk_pos& start_chunk, const glm::fvec3& start_fpos, const glm::fvec3& direction);
- explicit RayDDA(const Dimension& dimension, const chunk_pos& start_chunk, const glm::fvec3& start_fpos, const glm::fvec3& direction);
-
- void reset(const Dimension* dimension, const chunk_pos& start_chunk, const glm::fvec3& start_fpos, const glm::fvec3& direction);
- void reset(const Dimension& dimension, const chunk_pos& start_chunk, const glm::fvec3& start_fpos, const glm::fvec3& direction);
-
- voxel_id step(void);
-
-public:
- const Dimension* dimension;
- chunk_pos start_chunk;
- glm::fvec3 start_fpos;
- glm::fvec3 direction;
-
- glm::fvec3 delta_dist;
- glm::fvec3 side_dist;
- voxel_pos vstep;
-
- double distance;
- voxel_pos vnormal;
- voxel_pos vpos;
-};
-
-#endif /* SHARED_RAY_DDA */
diff --git a/game/shared/splash.cc b/game/shared/splash.cc
deleted file mode 100644
index 0cd5f50..0000000
--- a/game/shared/splash.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-#include "shared/pch.hh"
-
-#include "shared/splash.hh"
-
-constexpr static const char* SPLASHES_FILENAME_CLIENT = "misc/splashes_client.txt";
-constexpr static const char* SPLASHES_FILENAME_SERVER = "misc/splashes_server.txt";
-constexpr static std::size_t SPLASH_SERVER_MAX_LENGTH = 32;
-
-static std::mt19937_64 splash_random;
-static std::vector<std::string> splash_lines;
-
-static std::string sanitize_line(const std::string& line)
-{
- std::string result;
-
- for(auto chr : line) {
- if(chr != '\r' && chr != '\n') {
- result.push_back(chr);
- }
- }
-
- return result;
-}
-
-static void splash_init_filename(const char* filename)
-{
- if(auto file = PHYSFS_openRead(filename)) {
- auto source = std::string(PHYSFS_fileLength(file), char(0x00));
- PHYSFS_readBytes(file, source.data(), source.size());
- PHYSFS_close(file);
-
- std::string line;
- std::istringstream stream(source);
-
- while(std::getline(stream, line))
- splash_lines.push_back(sanitize_line(line));
- splash_random.seed(std::random_device()());
- } else {
- splash_lines.push_back(std::format("{}: {}", filename, PHYSFS_getErrorByCode(PHYSFS_getLastErrorCode())));
- splash_random.seed(std::random_device()());
- }
-}
-
-void splash::init_client(void)
-{
- splash_init_filename(SPLASHES_FILENAME_CLIENT);
-}
-
-void splash::init_server(void)
-{
- splash_init_filename(SPLASHES_FILENAME_SERVER);
-
- // Server browser GUI should be able to display
- // these splash messages without text clipping over
- for(int i = 0; i < splash_lines.size(); i++) {
- splash_lines[i] = splash_lines[i].substr(0, SPLASH_SERVER_MAX_LENGTH);
- }
-}
-
-const char* splash::get(void)
-{
- std::uniform_int_distribution<std::size_t> dist(0, splash_lines.size() - 1);
- return splash_lines.at(dist(splash_random)).c_str();
-}
diff --git a/game/shared/splash.hh b/game/shared/splash.hh
deleted file mode 100644
index 9510d35..0000000
--- a/game/shared/splash.hh
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef SHARED_SPLASH_HH
-#define SHARED_SPLASH_HH 1
-#pragma once
-
-namespace splash
-{
-void init_client(void);
-void init_server(void);
-const char* get(void);
-} // namespace splash
-
-#endif /* SHARED_SPLASH_HH */
diff --git a/game/shared/stasis.cc b/game/shared/stasis.cc
deleted file mode 100644
index 462871d..0000000
--- a/game/shared/stasis.cc
+++ /dev/null
@@ -1,19 +0,0 @@
-#include "shared/pch.hh"
-
-#include "shared/stasis.hh"
-
-#include "shared/dimension.hh"
-#include "shared/transform.hh"
-
-void StasisComponent::fixed_update(Dimension* dimension)
-{
- auto view = dimension->entities.view<TransformComponent>();
-
- for(auto [entity, transform] : view.each()) {
- if(dimension->find_chunk(transform.chunk)) {
- dimension->entities.remove<StasisComponent>(entity);
- } else {
- dimension->entities.emplace_or_replace<StasisComponent>(entity);
- }
- }
-}
diff --git a/game/shared/stasis.hh b/game/shared/stasis.hh
deleted file mode 100644
index bd06d4e..0000000
--- a/game/shared/stasis.hh
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef SHARED_STASIS_HH
-#define SHARED_STASIS_HH 1
-#pragma once
-
-class Dimension;
-
-// Attached to entities with transform values
-// out of bounds in a specific dimension
-struct StasisComponent final {
-public:
- static void fixed_update(Dimension* dimension);
-};
-
-#endif /* SHARED_STASIS_HH */
diff --git a/game/shared/threading.cc b/game/shared/threading.cc
deleted file mode 100644
index 9e46d17..0000000
--- a/game/shared/threading.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-#include "shared/pch.hh"
-
-#include "shared/threading.hh"
-
-#include "core/cmdline.hh"
-#include "core/constexpr.hh"
-
-constexpr static const char* DEFAULT_POOL_SIZE_ARG = "4";
-
-static BS::light_thread_pool* thread_pool;
-static std::deque<Task*> task_deque;
-
-static void task_process(Task* task)
-{
- task->set_status(task_status::PROCESSING);
- task->process();
-
- if(task->get_status() == task_status::PROCESSING) {
- // If the task status is still PROCESSING
- // it can be deduced it hasn't been cancelled
- task->set_status(task_status::COMPLETED);
- }
-}
-
-task_status Task::get_status(void) const
-{
- return m_status;
-}
-
-void Task::set_status(task_status status)
-{
- m_status = status;
-}
-
-void threading::init(void)
-{
- auto argument = cmdline::get("threads", DEFAULT_POOL_SIZE_ARG);
- auto num_concurrent_threads = std::thread::hardware_concurrency();
- unsigned int thread_pool_size;
-
- if(num_concurrent_threads && !std::strcmp(argument, "max")) {
- // Use the maximum available number of concurrent
- // hardware threads provided by the implementation
- thread_pool_size = num_concurrent_threads;
- } else {
- if(num_concurrent_threads) {
- thread_pool_size = vx::clamp<unsigned int>(std::strtoul(argument, nullptr, 10), 1U, num_concurrent_threads);
- } else {
- thread_pool_size = vx::max<unsigned int>(std::strtoul(argument, nullptr, 10), 1U);
- }
- }
-
- spdlog::info("threading: using {} threads for pooling tasks", thread_pool_size);
-
- thread_pool = new BS::light_thread_pool(thread_pool_size);
-
- task_deque.clear();
-}
-
-void threading::deinit(void)
-{
- for(auto task : task_deque) {
- auto status = task->get_status();
- if((status != task_status::CANCELLED) || (status != task_status::COMPLETED)) {
- task->set_status(task_status::CANCELLED);
- }
- }
-
- thread_pool->purge();
- thread_pool->wait();
-
- for(auto task : task_deque)
- delete task;
- task_deque.clear();
-
- delete thread_pool;
-}
-
-void threading::update(void)
-{
- auto task_iter = task_deque.cbegin();
-
- while(task_iter != task_deque.cend()) {
- auto task_ptr = *task_iter;
- auto status = task_ptr->get_status();
-
- if(status == task_status::CANCELLED) {
- delete task_ptr;
- task_iter = task_deque.erase(task_iter);
- continue;
- }
-
- if(status == task_status::COMPLETED) {
- task_ptr->finalize();
- delete task_ptr;
- task_iter = task_deque.erase(task_iter);
- continue;
- }
-
- task_iter = std::next(task_iter);
- }
-}
-
-void threading::detail::submit_new(Task* task)
-{
- task->set_status(task_status::ENQUEUED);
-
- static_cast<void>(thread_pool->submit_task(std::bind(&task_process, task)));
-
- task_deque.push_back(task);
-}
diff --git a/game/shared/threading.hh b/game/shared/threading.hh
deleted file mode 100644
index bce4811..0000000
--- a/game/shared/threading.hh
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef SHARED_THREADING_HH
-#define SHARED_THREADING_HH 1
-#pragma once
-
-enum class task_status : unsigned int {
- ENQUEUED = 0x0000U,
- PROCESSING = 0x0001U,
- COMPLETED = 0x0002U,
- CANCELLED = 0x0004U,
-};
-
-class Task {
-public:
- virtual ~Task(void) = default;
- virtual void process(void) = 0;
- virtual void finalize(void) = 0;
-
- task_status get_status(void) const;
- void set_status(task_status status);
-
-protected:
- std::atomic<task_status> m_status;
- std::future<void> m_future;
-};
-
-namespace threading
-{
-void init(void);
-void deinit(void);
-void update(void);
-} // namespace threading
-
-namespace threading::detail
-{
-void submit_new(Task* task);
-} // namespace threading::detail
-
-namespace threading
-{
-template<typename T, typename... AT>
-void submit(AT&&... args);
-} // namespace threading
-
-template<typename T, typename... AT>
-inline void threading::submit(AT&&... args)
-{
- threading::detail::submit_new(new T(args...));
-}
-
-#endif /* SHARED_THREADING_HH */
diff --git a/game/shared/transform.cc b/game/shared/transform.cc
deleted file mode 100644
index f4b661c..0000000
--- a/game/shared/transform.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-#include "shared/pch.hh"
-
-#include "shared/transform.hh"
-
-#include "shared/const.hh"
-#include "shared/dimension.hh"
-
-constexpr inline static void update_component(unsigned int dim, TransformComponent& component)
-{
- if(component.local[dim] >= CHUNK_SIZE) {
- component.local[dim] -= CHUNK_SIZE;
- component.chunk[dim] += 1;
- return;
- }
-
- if(component.local[dim] < 0.0f) {
- component.local[dim] += CHUNK_SIZE;
- component.chunk[dim] -= 1;
- return;
- }
-}
-
-void TransformComponent::fixed_update(Dimension* dimension)
-{
- auto view = dimension->entities.view<TransformComponent>();
-
- for(auto [entity, transform] : view.each()) {
- update_component(0U, transform);
- update_component(1U, transform);
- update_component(2U, transform);
- }
-}
diff --git a/game/shared/transform.hh b/game/shared/transform.hh
deleted file mode 100644
index f9c5f47..0000000
--- a/game/shared/transform.hh
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef SHARED_TRANSFORM_HH
-#define SHARED_TRANSFORM_HH 1
-#pragma once
-
-#include "shared/types.hh"
-
-class Dimension;
-
-struct TransformComponent {
- chunk_pos chunk;
- glm::fvec3 local;
- glm::fvec3 angles;
-
-public:
- // Updates TransformComponent values so that
- // the local translation field is always within
- // local coodrinates; [floating-point precision]
- static void fixed_update(Dimension* dimension);
-};
-
-// Client-side only - interpolated and previous transform
-struct TransformComponentIntr final : public TransformComponent {};
-struct TransformComponentPrev final : public TransformComponent {};
-
-#endif /* SHARED_TRANSFORM_HH */
diff --git a/game/shared/types.hh b/game/shared/types.hh
deleted file mode 100644
index 85fbd19..0000000
--- a/game/shared/types.hh
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef SHARED_TYPES_HH
-#define SHARED_TYPES_HH 1
-#pragma once
-
-using item_id = std::uint32_t;
-constexpr static item_id NULL_ITEM_ID = UINT32_C(0x00000000);
-constexpr static item_id MAX_ITEM_ID = UINT32_C(0xFFFFFFFF);
-
-using voxel_id = std::uint16_t;
-constexpr static voxel_id NULL_VOXEL_ID = UINT16_C(0x0000);
-constexpr static voxel_id MAX_VOXEL_ID = UINT16_C(0xFFFF);
-
-using chunk_pos = glm::vec<3, std::int32_t>;
-using local_pos = glm::vec<3, std::int16_t>;
-using voxel_pos = glm::vec<3, std::int64_t>;
-
-using chunk_pos_xz = glm::vec<2, chunk_pos::value_type>;
-using local_pos_xz = glm::vec<2, local_pos::value_type>;
-using voxel_pos_xz = glm::vec<2, local_pos::value_type>;
-
-template<>
-struct std::hash<chunk_pos> final {
- constexpr inline std::size_t operator()(const chunk_pos& cpos) const
- {
- std::size_t value = 0;
- value ^= cpos.x * 73856093;
- value ^= cpos.y * 19349663;
- value ^= cpos.z * 83492791;
- return value;
- }
-};
-
-template<>
-struct std::hash<chunk_pos_xz> final {
- constexpr inline std::size_t operator()(const chunk_pos_xz& cwpos) const
- {
- std::size_t value = 0;
- value ^= cwpos.x * 73856093;
- value ^= cwpos.y * 19349663;
- return value;
- }
-};
-
-#endif /* SHARED_TYPES_HH */
diff --git a/game/shared/velocity.cc b/game/shared/velocity.cc
deleted file mode 100644
index 329dc91..0000000
--- a/game/shared/velocity.cc
+++ /dev/null
@@ -1,17 +0,0 @@
-#include "shared/pch.hh"
-
-#include "shared/velocity.hh"
-
-#include "shared/dimension.hh"
-#include "shared/globals.hh"
-#include "shared/stasis.hh"
-#include "shared/transform.hh"
-
-void VelocityComponent::fixed_update(Dimension* dimension)
-{
- auto group = dimension->entities.group<VelocityComponent>(entt::get<TransformComponent>, entt::exclude<StasisComponent>);
-
- for(auto [entity, velocity, transform] : group.each()) {
- transform.local += velocity.value * globals::fixed_frametime;
- }
-}
diff --git a/game/shared/velocity.hh b/game/shared/velocity.hh
deleted file mode 100644
index 45a2858..0000000
--- a/game/shared/velocity.hh
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef SHARED_VELOCITY_HH
-#define SHARED_VELOCITY_HH 1
-#pragma once
-
-class Dimension;
-
-struct VelocityComponent final {
- glm::fvec3 value;
-
-public:
- // Updates entities TransformComponent values
- // according to velocities multiplied by fixed_frametime.
- // NOTE: This system was previously called inertial
- static void fixed_update(Dimension* dimension);
-};
-
-#endif /* SHARED_VELOCITY_HH */
diff --git a/game/shared/voxel_registry.cc b/game/shared/voxel_registry.cc
deleted file mode 100644
index cb3c724..0000000
--- a/game/shared/voxel_registry.cc
+++ /dev/null
@@ -1,192 +0,0 @@
-#include "shared/pch.hh"
-
-#include "shared/voxel_registry.hh"
-
-#include "core/crc64.hh"
-
-std::unordered_map<std::string, VoxelInfoBuilder> voxel_registry::builders = {};
-std::unordered_map<std::string, voxel_id> voxel_registry::names = {};
-std::vector<std::shared_ptr<VoxelInfo>> voxel_registry::voxels = {};
-
-VoxelInfoBuilder::VoxelInfoBuilder(const char* name, voxel_type type, bool animated, bool blending)
-{
- prototype.name = name;
- prototype.type = type;
- prototype.animated = animated;
- prototype.blending = blending;
-
- switch(type) {
- case voxel_type::CUBE:
- prototype.textures.resize(static_cast<std::size_t>(voxel_face::CUBE__NR));
- break;
- case voxel_type::CROSS:
- prototype.textures.resize(static_cast<std::size_t>(voxel_face::CROSS__NR));
- break;
- case voxel_type::MODEL:
- // Custom models should use a different texture
- // resource management that is not a voxel atlas
- // TODO: actually implement custom models lol
- prototype.textures.resize(0);
- break;
- default:
- // Something really bad should happen if we end up here.
- // The outside code would static_cast an int to VoxelType
- // and possibly fuck a lot of things up to cause this
- spdlog::critical("voxel_registry: {}: unknown voxel type {}", name, static_cast<int>(type));
- std::terminate();
- }
-
- // Physics properties
- prototype.touch_type = voxel_touch::SOLID;
- prototype.touch_values = glm::fvec3(0.0f, 0.0f, 0.0f);
- prototype.surface = voxel_surface::DEFAULT;
-
- // Things set in future by item_def
- prototype.item_pick = NULL_ITEM_ID;
-}
-
-VoxelInfoBuilder& VoxelInfoBuilder::add_texture_default(const char* texture)
-{
- default_texture.paths.push_back(texture);
- return *this;
-}
-
-VoxelInfoBuilder& VoxelInfoBuilder::add_texture(voxel_face face, const char* texture)
-{
- const auto index = static_cast<std::size_t>(face);
- prototype.textures[index].paths.push_back(texture);
- return *this;
-}
-
-VoxelInfoBuilder& VoxelInfoBuilder::set_touch(voxel_touch type, const glm::fvec3& values)
-{
- prototype.touch_type = type;
- prototype.touch_values = values;
- return *this;
-}
-
-VoxelInfoBuilder& VoxelInfoBuilder::set_surface(voxel_surface surface)
-{
- prototype.surface = surface;
- return *this;
-}
-
-voxel_id VoxelInfoBuilder::build(void) const
-{
- const auto it = voxel_registry::names.find(prototype.name);
-
- if(it != voxel_registry::names.cend()) {
- spdlog::warn("voxel_registry: cannot build {}: name already present", prototype.name);
- return it->second;
- }
-
- std::size_t state_count;
-
- switch(prototype.type) {
- case voxel_type::CUBE:
- case voxel_type::CROSS:
- case voxel_type::MODEL:
- state_count = 1;
- break;
- default:
- // Something really bad should happen if we end up here.
- // The outside code would static_cast an int to VoxelType
- // and possibly fuck a lot of things up to cause this
- spdlog::critical("voxel_registry: {}: unknown voxel type {}", prototype.name, static_cast<int>(prototype.type));
- std::terminate();
- }
-
- if((voxel_registry::voxels.size() + state_count) >= MAX_VOXEL_ID) {
- spdlog::critical("voxel_registry: voxel registry overflow");
- std::terminate();
- }
-
- auto new_info = std::make_shared<VoxelInfo>();
- new_info->name = prototype.name;
- new_info->type = prototype.type;
- new_info->animated = prototype.animated;
- new_info->blending = prototype.blending;
-
- new_info->textures.resize(prototype.textures.size());
-
- for(std::size_t i = 0; i < prototype.textures.size(); ++i) {
- if(prototype.textures[i].paths.empty()) {
- new_info->textures[i].paths = default_texture.paths;
- new_info->textures[i].cached_offset = SIZE_MAX;
- new_info->textures[i].cached_plane = SIZE_MAX;
- } else {
- new_info->textures[i].paths = prototype.textures[i].paths;
- new_info->textures[i].cached_offset = SIZE_MAX;
- new_info->textures[i].cached_plane = SIZE_MAX;
- }
- }
-
- // Physics properties
- new_info->touch_type = prototype.touch_type;
- new_info->touch_values = prototype.touch_values;
- new_info->surface = prototype.surface;
-
- // Things set in future by item_def
- new_info->item_pick = prototype.item_pick;
-
- // Base voxel identifier offset
- new_info->base_voxel = voxel_registry::voxels.size() + 1;
-
- for(std::size_t i = 0; i < state_count; ++i)
- voxel_registry::voxels.push_back(new_info);
- voxel_registry::names.insert_or_assign(new_info->name, new_info->base_voxel);
-
- return new_info->base_voxel;
-}
-
-VoxelInfoBuilder& voxel_registry::construct(const char* name, voxel_type type, bool animated, bool blending)
-{
- const auto it = voxel_registry::builders.find(name);
-
- if(it != voxel_registry::builders.cend()) {
- return it->second;
- } else {
- return voxel_registry::builders.emplace(name, VoxelInfoBuilder(name, type, animated, blending)).first->second;
- }
-}
-
-VoxelInfo* voxel_registry::find(const char* name)
-{
- const auto it = voxel_registry::names.find(name);
-
- if(it != voxel_registry::names.cend()) {
- return voxel_registry::find(it->second);
- } else {
- return nullptr;
- }
-}
-
-VoxelInfo* voxel_registry::find(const voxel_id voxel)
-{
- if((voxel != NULL_VOXEL_ID) && (voxel <= voxel_registry::voxels.size())) {
- return voxel_registry::voxels[voxel - 1].get();
- } else {
- return nullptr;
- }
-}
-
-void voxel_registry::purge(void)
-{
- voxel_registry::builders.clear();
- voxel_registry::names.clear();
- voxel_registry::voxels.clear();
-}
-
-std::uint64_t voxel_registry::calcualte_checksum(void)
-{
- std::uint64_t result = 0;
-
- for(const std::shared_ptr<VoxelInfo>& info : voxel_registry::voxels) {
- result = crc64::get(info->name, result);
- result += static_cast<std::uint64_t>(info->type);
- result += static_cast<std::uint64_t>(info->base_voxel);
- result += info->blending ? 256 : 1;
- }
-
- return result;
-}
diff --git a/game/shared/voxel_registry.hh b/game/shared/voxel_registry.hh
deleted file mode 100644
index 5f7963f..0000000
--- a/game/shared/voxel_registry.hh
+++ /dev/null
@@ -1,144 +0,0 @@
-#ifndef SHARED_VOXEL_REGISTRY_HH
-#define SHARED_VOXEL_REGISTRY_HH 1
-#pragma once
-
-#include "shared/types.hh"
-
-enum class voxel_face : unsigned short {
- CUBE_NORTH = 0x0000,
- CUBE_SOUTH = 0x0001,
- CUBE_EAST = 0x0002,
- CUBE_WEST = 0x0003,
- CUBE_TOP = 0x0004,
- CUBE_BOTTOM = 0x0005,
- CUBE__NR = 0x0006,
-
- CROSS_NESW = 0x0000,
- CROSS_NWSE = 0x0001,
- CROSS__NR = 0x0002,
-};
-
-enum class voxel_type : unsigned short {
- CUBE = 0x0000,
- CROSS = 0x0001, // TODO
- MODEL = 0x0002, // TODO
-};
-
-enum class voxel_facing : unsigned short {
- NORTH = 0x0000,
- SOUTH = 0x0001,
- EAST = 0x0002,
- WEST = 0x0003,
- UP = 0x0004,
- DOWN = 0x0005,
- NESW = 0x0006,
- NWSE = 0x0007,
-};
-
-enum class voxel_touch : unsigned short {
- SOLID = 0x0000, // The entity is stopped in its tracks
- BOUNCE = 0x0001, // The entity bounces back with some energy loss
- SINK = 0x0002, // The entity phases/sinks through the voxel
- NOTHING = 0xFFFF,
-};
-
-enum class voxel_surface : unsigned short {
- DEFAULT = 0x0000,
- STONE = 0x0001,
- DIRT = 0x0002,
- GLASS = 0x0003,
- GRASS = 0x0004,
- GRAVEL = 0x0005,
- METAL = 0x0006,
- SAND = 0x0007,
- WOOD = 0x0008,
- SLOSH = 0x0009,
- COUNT = 0x000A,
- UNKNOWN = 0xFFFF,
-};
-
-using voxel_vis = unsigned short;
-constexpr static voxel_vis VIS_NORTH = 1 << static_cast<unsigned int>(voxel_facing::NORTH);
-constexpr static voxel_vis VIS_SOUTH = 1 << static_cast<unsigned int>(voxel_facing::SOUTH);
-constexpr static voxel_vis VIS_EAST = 1 << static_cast<unsigned int>(voxel_facing::EAST);
-constexpr static voxel_vis VIS_WEST = 1 << static_cast<unsigned int>(voxel_facing::WEST);
-constexpr static voxel_vis VIS_UP = 1 << static_cast<unsigned int>(voxel_facing::UP);
-constexpr static voxel_vis VIS_DOWN = 1 << static_cast<unsigned int>(voxel_facing::DOWN);
-
-struct VoxelTexture final {
- std::vector<std::string> paths;
- std::size_t cached_offset; // client-side only
- std::size_t cached_plane; // client-side only
-};
-
-struct VoxelInfo final {
- std::string name;
- voxel_type type;
- bool animated;
- bool blending;
-
- std::vector<VoxelTexture> textures;
-
- // Physics properties go here
- // TODO: player_move friction modifiers
- // that would make the voxel very sticky or
- // very slippery to walk on
- voxel_touch touch_type;
- glm::fvec3 touch_values;
- voxel_surface surface;
-
- // Some voxel types might occupy multiple voxel_id
- // values that reference to the exact same VoxelInfo
- // structure; the actual numeric state is figured out by
- // subtracting base_voxel from the checking voxel_id
- voxel_id base_voxel;
-
- // These will be set by item_registry
- // and by default set to NULL_ITEM_ID
- item_id item_pick;
-};
-
-class VoxelInfoBuilder final {
-public:
- explicit VoxelInfoBuilder(const char* name, voxel_type type, bool animated, bool blending);
- virtual ~VoxelInfoBuilder(void) = default;
-
-public:
- VoxelInfoBuilder& add_texture_default(const char* texture);
- VoxelInfoBuilder& add_texture(voxel_face face, const char* texture);
- VoxelInfoBuilder& set_touch(voxel_touch type, const glm::fvec3& values);
- VoxelInfoBuilder& set_surface(voxel_surface surface);
-
-public:
- voxel_id build(void) const;
-
-private:
- VoxelTexture default_texture;
- VoxelInfo prototype;
-};
-
-namespace voxel_registry
-{
-extern std::unordered_map<std::string, VoxelInfoBuilder> builders;
-extern std::unordered_map<std::string, voxel_id> names;
-extern std::vector<std::shared_ptr<VoxelInfo>> voxels;
-} // namespace voxel_registry
-
-namespace voxel_registry
-{
-VoxelInfoBuilder& construct(const char* name, voxel_type type, bool animated, bool blending);
-VoxelInfo* find(const char* name);
-VoxelInfo* find(const voxel_id voxel);
-} // namespace voxel_registry
-
-namespace voxel_registry
-{
-void purge(void);
-} // namespace voxel_registry
-
-namespace voxel_registry
-{
-std::uint64_t calcualte_checksum(void);
-} // namespace voxel_registry
-
-#endif /* SHARED_VOXEL_REGISTRY_HH */
diff --git a/game/shared/voxel_storage.cc b/game/shared/voxel_storage.cc
deleted file mode 100644
index f2c4d42..0000000
--- a/game/shared/voxel_storage.cc
+++ /dev/null
@@ -1,46 +0,0 @@
-#include "shared/pch.hh"
-
-#include "shared/voxel_storage.hh"
-
-#include "core/buffer.hh"
-
-void VoxelStorage::serialize(WriteBuffer& buffer) const
-{
- auto bound = mz_compressBound(sizeof(VoxelStorage));
- auto zdata = std::vector<unsigned char>(bound);
-
- VoxelStorage net_storage;
-
- for(std::size_t i = 0; i < CHUNK_VOLUME; ++i) {
- // Convert voxel indices into network byte order;
- // We're going to compress them but we still want
- // the order to be consistent across all the platforms
- net_storage[i] = ENET_HOST_TO_NET_16(at(i));
- }
-
- mz_compress(zdata.data(), &bound, reinterpret_cast<unsigned char*>(net_storage.data()), sizeof(VoxelStorage));
-
- buffer.write_UI64(bound);
-
- // Write all the compressed data into the buffer
- for(std::size_t i = 0; i < bound; buffer.write_UI8(zdata[i++]))
- ;
-}
-
-void VoxelStorage::deserialize(ReadBuffer& buffer)
-{
- auto size = static_cast<mz_ulong>(sizeof(VoxelStorage));
- auto bound = static_cast<mz_ulong>(buffer.read_UI64());
- auto zdata = std::vector<unsigned char>(bound);
-
- // Read all the compressed data from the buffer
- for(std::size_t i = 0; i < bound; zdata[i++] = buffer.read_UI8())
- ;
-
- mz_uncompress(reinterpret_cast<unsigned char*>(data()), &size, zdata.data(), bound);
-
- for(std::size_t i = 0; i < CHUNK_VOLUME; ++i) {
- // Convert voxel indices back into the host byte order
- at(i) = ENET_NET_TO_HOST_16(at(i));
- }
-}
diff --git a/game/shared/voxel_storage.hh b/game/shared/voxel_storage.hh
deleted file mode 100644
index a31cf3e..0000000
--- a/game/shared/voxel_storage.hh
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef SHARED_VOXEL_STORAGE_HH
-#define SHARED_VOXEL_STORAGE_HH 1
-#pragma once
-
-#include "shared/const.hh"
-#include "shared/types.hh"
-
-class ReadBuffer;
-class WriteBuffer;
-
-class VoxelStorage final : public std::array<voxel_id, CHUNK_VOLUME> {
-public:
- using std::array<voxel_id, CHUNK_VOLUME>::array;
- void serialize(WriteBuffer& buffer) const;
- void deserialize(ReadBuffer& buffer);
-};
-
-#endif /* SHARED_VOXEL_STORAGE_HH */