diff options
| author | untodesu <kirill@untode.su> | 2025-06-29 22:24:42 +0500 |
|---|---|---|
| committer | untodesu <kirill@untode.su> | 2025-06-29 22:24:42 +0500 |
| commit | 6cd00aacfa22fed6a54a9b812f6b069ad16feec0 (patch) | |
| tree | b77f4e665da3dd235cdb01e7e6ea78c1c02ecf2e /game/server/sessions.cc | |
| parent | f440914e1ae453768d09383f332bc7844e0a700e (diff) | |
| download | voxelius-6cd00aacfa22fed6a54a9b812f6b069ad16feec0.tar.bz2 voxelius-6cd00aacfa22fed6a54a9b812f6b069ad16feec0.zip | |
Move game sources into src subdirectory
Diffstat (limited to 'game/server/sessions.cc')
| -rw-r--r-- | game/server/sessions.cc | 419 |
1 files changed, 0 insertions, 419 deletions
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)); -} |
