summaryrefslogtreecommitdiffstats
path: root/src/game/server
diff options
context:
space:
mode:
authoruntodesu <kirill@untode.su>2025-07-01 03:08:39 +0500
committeruntodesu <kirill@untode.su>2025-07-01 03:08:39 +0500
commit458e0005690ea9d579588a0a12368fc2c2c9a93a (patch)
tree588a9ca6cb3c76d9193b5bd4601d64f0e50e8c8c /src/game/server
parentc7b0c8e0286a1b2bb7ec55e579137dfc3b22eeb9 (diff)
downloadvoxelius-458e0005690ea9d579588a0a12368fc2c2c9a93a.tar.bz2
voxelius-458e0005690ea9d579588a0a12368fc2c2c9a93a.zip
I hyper-focued on refactoring again
- I put a cool-sounding "we are number one" remix on repeat and straight up grinded the entire repository to a better state until 03:09 AM. I guess I have something wrong in my brain that makes me do this shit
Diffstat (limited to 'src/game/server')
-rw-r--r--src/game/server/CMakeLists.txt39
-rw-r--r--src/game/server/chat.cc54
-rw-r--r--src/game/server/chat.hh16
-rw-r--r--src/game/server/game.cc148
-rw-r--r--src/game/server/game.hh26
-rw-r--r--src/game/server/globals.cc18
-rw-r--r--src/game/server/globals.hh25
-rw-r--r--src/game/server/inhabited.hh7
-rw-r--r--src/game/server/main.cc103
-rw-r--r--src/game/server/overworld.cc380
-rw-r--r--src/game/server/overworld.hh63
-rw-r--r--src/game/server/pch.hh7
-rw-r--r--src/game/server/receive.cc170
-rw-r--r--src/game/server/receive.hh10
-rw-r--r--src/game/server/sessions.cc419
-rw-r--r--src/game/server/sessions.hh53
-rw-r--r--src/game/server/status.cc26
-rw-r--r--src/game/server/status.hh10
-rw-r--r--src/game/server/universe.cc215
-rw-r--r--src/game/server/universe.hh25
-rw-r--r--src/game/server/unloader.cc76
-rw-r--r--src/game/server/unloader.hh14
-rw-r--r--src/game/server/vserver.icobin60201 -> 0 bytes
-rw-r--r--src/game/server/vserver.rc1
-rw-r--r--src/game/server/whitelist.cc95
-rw-r--r--src/game/server/whitelist.hh27
-rw-r--r--src/game/server/worldgen.cc148
-rw-r--r--src/game/server/worldgen.hh21
28 files changed, 0 insertions, 2196 deletions
diff --git a/src/game/server/CMakeLists.txt b/src/game/server/CMakeLists.txt
deleted file mode 100644
index bd0eff3..0000000
--- a/src/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}/src")
-target_include_directories(vserver PRIVATE "${PROJECT_SOURCE_DIR}/src/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/src/game/server/chat.cc b/src/game/server/chat.cc
deleted file mode 100644
index 1634c59..0000000
--- a/src/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/src/game/server/chat.hh b/src/game/server/chat.hh
deleted file mode 100644
index 524ea78..0000000
--- a/src/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/src/game/server/game.cc b/src/game/server/game.cc
deleted file mode 100644
index cdf1459..0000000
--- a/src/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::shutdown(void)
-{
- protocol::Disconnect packet;
- packet.reason = "protocol.server_shutdown";
- protocol::broadcast(globals::server_host, protocol::encode(packet));
-
- whitelist::shutdown();
-
- sessions::shutdown();
-
- enet_host_flush(globals::server_host);
- enet_host_service(globals::server_host, nullptr, 500);
- enet_host_destroy(globals::server_host);
-
- universe::shutdown();
-}
-
-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/src/game/server/game.hh b/src/game/server/game.hh
deleted file mode 100644
index 9ff21d9..0000000
--- a/src/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 shutdown(void);
-void fixed_update(void);
-void fixed_update_late(void);
-} // namespace server_game
-
-#endif // SERVER_GAME_HH
diff --git a/src/game/server/globals.cc b/src/game/server/globals.cc
deleted file mode 100644
index 883588b..0000000
--- a/src/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/src/game/server/globals.hh b/src/game/server/globals.hh
deleted file mode 100644
index 3ae2226..0000000
--- a/src/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/src/game/server/inhabited.hh b/src/game/server/inhabited.hh
deleted file mode 100644
index 982fe5d..0000000
--- a/src/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/src/game/server/main.cc b/src/game/server/main.cc
deleted file mode 100644
index 535982a..0000000
--- a/src/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::shutdown();
-
- resource::hard_cleanup<BinFile>();
- resource::hard_cleanup<Image>();
-
- threading::shutdown();
-
- 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::shutdown();
-
- return EXIT_SUCCESS;
-}
diff --git a/src/game/server/overworld.cc b/src/game/server/overworld.cc
deleted file mode 100644
index a280e06..0000000
--- a/src/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/src/game/server/overworld.hh b/src/game/server/overworld.hh
deleted file mode 100644
index fa3eb42..0000000
--- a/src/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/src/game/server/pch.hh b/src/game/server/pch.hh
deleted file mode 100644
index 810a7e4..0000000
--- a/src/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/src/game/server/receive.cc b/src/game/server/receive.cc
deleted file mode 100644
index 7674122..0000000
--- a/src/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/src/game/server/receive.hh b/src/game/server/receive.hh
deleted file mode 100644
index 17333d0..0000000
--- a/src/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/src/game/server/sessions.cc b/src/game/server/sessions.cc
deleted file mode 100644
index 3024939..0000000
--- a/src/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::shutdown(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/src/game/server/sessions.hh b/src/game/server/sessions.hh
deleted file mode 100644
index 2eee256..0000000
--- a/src/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 shutdown(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/src/game/server/status.cc b/src/game/server/status.cc
deleted file mode 100644
index 6b64719..0000000
--- a/src/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/src/game/server/status.hh b/src/game/server/status.hh
deleted file mode 100644
index 218eab0..0000000
--- a/src/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/src/game/server/universe.cc b/src/game/server/universe.cc
deleted file mode 100644
index 91d8469..0000000
--- a/src/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::shutdown(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/src/game/server/universe.hh b/src/game/server/universe.hh
deleted file mode 100644
index 0313437..0000000
--- a/src/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 shutdown(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/src/game/server/unloader.cc b/src/game/server/unloader.cc
deleted file mode 100644
index f986a61..0000000
--- a/src/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/src/game/server/unloader.hh b/src/game/server/unloader.hh
deleted file mode 100644
index 6648a1f..0000000
--- a/src/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/src/game/server/vserver.ico b/src/game/server/vserver.ico
deleted file mode 100644
index 02ff006..0000000
--- a/src/game/server/vserver.ico
+++ /dev/null
Binary files differ
diff --git a/src/game/server/vserver.rc b/src/game/server/vserver.rc
deleted file mode 100644
index b6828bf..0000000
--- a/src/game/server/vserver.rc
+++ /dev/null
@@ -1 +0,0 @@
-IDI_ICON1 ICON DISCARDABLE "vserver.ico"
diff --git a/src/game/server/whitelist.cc b/src/game/server/whitelist.cc
deleted file mode 100644
index 69ac5a8..0000000
--- a/src/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::shutdown(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/src/game/server/whitelist.hh b/src/game/server/whitelist.hh
deleted file mode 100644
index b9008aa..0000000
--- a/src/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 shutdown(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/src/game/server/worldgen.cc b/src/game/server/worldgen.cc
deleted file mode 100644
index 5c74d47..0000000
--- a/src/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/src/game/server/worldgen.hh b/src/game/server/worldgen.hh
deleted file mode 100644
index e355ab9..0000000
--- a/src/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