diff --git a/Code/client/Services/Generic/TransportService.cpp b/Code/client/Services/Generic/TransportService.cpp index 237fa707a..0f3f684dc 100644 --- a/Code/client/Services/Generic/TransportService.cpp +++ b/Code/client/Services/Generic/TransportService.cpp @@ -37,7 +37,8 @@ TransportService::TransportService(World& aWorld, entt::dispatcher& aDispatcher) { m_updateConnection = m_dispatcher.sink().connect<&TransportService::HandleUpdate>(this); m_settingsChangeConnection = m_dispatcher.sink().connect<&TransportService::HandleNotifySettingsChange>(this); - m_connectedConnection = m_dispatcher.sink().connect<&TransportService::HandleConnect>(this); + m_connectedConnection = m_dispatcher.sink().connect<&TransportService::HandleConnected>(this); + m_disconnectedConnection = m_dispatcher.sink().connect<&TransportService::HandleDisconnected>(this); m_connected = false; @@ -182,11 +183,16 @@ void TransportService::HandleUpdate(const UpdateEvent& acEvent) noexcept Update(); } -void TransportService::HandleConnect(const ConnectedEvent& acEvent) noexcept +void TransportService::HandleConnected(const ConnectedEvent& acEvent) noexcept { m_localPlayerId = acEvent.PlayerId; } +void TransportService::HandleDisconnected(const DisconnectedEvent& acEvent) noexcept +{ + m_localPlayerId = NULL; +} + void TransportService::HandleAuthenticationResponse(const AuthenticationResponse& acMessage) noexcept { using AR = AuthenticationResponse::ResponseType; diff --git a/Code/client/Services/TransportService.h b/Code/client/Services/TransportService.h index 2cb781427..8f2c3503e 100644 --- a/Code/client/Services/TransportService.h +++ b/Code/client/Services/TransportService.h @@ -1,6 +1,7 @@ #pragma once #include "Events/ConnectedEvent.h" +#include "Events/DisconnectedEvent.h" #include #include @@ -39,7 +40,8 @@ struct TransportService : Client protected: // Event handlers void HandleUpdate(const UpdateEvent& acEvent) noexcept; - void HandleConnect(const ConnectedEvent& acEvent) noexcept; + void HandleConnected(const ConnectedEvent& acEvent) noexcept; + void HandleDisconnected(const DisconnectedEvent& acEvent) noexcept; // Packet handlers void HandleAuthenticationResponse(const AuthenticationResponse& acMessage) noexcept; @@ -56,5 +58,6 @@ struct TransportService : Client entt::scoped_connection m_sendServerMessageConnection; entt::scoped_connection m_settingsChangeConnection; entt::scoped_connection m_connectedConnection; + entt::scoped_connection m_disconnectedConnection; std::function&)> m_messageHandlers[kServerOpcodeMax]; }; diff --git a/Code/server/Game/PlayerManager.cpp b/Code/server/Game/PlayerManager.cpp index 7ab3f6f1b..3c3380942 100644 --- a/Code/server/Game/PlayerManager.cpp +++ b/Code/server/Game/PlayerManager.cpp @@ -90,6 +90,31 @@ Player const* PlayerManager::GetById(uint32_t aId) const noexcept return nullptr; } +Player* PlayerManager::GetByUsername(const String& acUsername) const noexcept +{ + auto itor = std::begin(m_players); + const auto end = std::end(m_players); + + for (; itor != end; ++itor) + if (itor.value()->GetUsername() == acUsername) + return itor.value().get(); + + return nullptr; +} + + +Player const* PlayerManager::GetByUsername(const String& acUsername) noexcept +{ + auto itor = std::begin(m_players); + const auto end = std::end(m_players); + + for (; itor != end; ++itor) + if (itor.value()->GetUsername() == acUsername) + return itor.value().get(); + + return nullptr; +} + uint32_t PlayerManager::Count() const noexcept { return static_cast(m_players.size()); diff --git a/Code/server/Game/PlayerManager.h b/Code/server/Game/PlayerManager.h index d5f50efe7..0fb988b1a 100644 --- a/Code/server/Game/PlayerManager.h +++ b/Code/server/Game/PlayerManager.h @@ -44,6 +44,9 @@ struct PlayerManager Player* GetById(uint32_t aId) noexcept; Player const* GetById(uint32_t aId) const noexcept; + Player* GetByUsername(const String& acUsername) const noexcept; + Player const* GetByUsername(const String& acUsername) noexcept; + uint32_t Count() const noexcept; template void ForEach(const T& acFunctor) noexcept diff --git a/Code/server/GameServer.cpp b/Code/server/GameServer.cpp index e5cdd8606..7127d6b93 100644 --- a/Code/server/GameServer.cpp +++ b/Code/server/GameServer.cpp @@ -222,14 +222,6 @@ void GameServer::Kill() m_requestStop = true; } -void GameServer::RemoveAdminSession(ConnectionId_t acSession) noexcept -{ - if (m_adminSessions.contains(acSession)) - { - m_adminSessions.erase(acSession); - } -} - bool GameServer::CheckMoPo() { if (!bEnableModCheck) @@ -393,48 +385,37 @@ void GameServer::BindServerCommands() }); m_commands.RegisterCommand( - "AddAdmin", "Add admin privileges from player", [&](Console::ArgStack& aStack) { + "AddAdmin", "Add admin privileges to player", [&](Console::ArgStack& aStack) { auto out = spdlog::get("ConOut"); const auto& cUsername = aStack.Pop(); + if (GetAdminByUsername(cUsername)) + { + out->info("{} is already an admin", cUsername.c_str()); + return; + } - bool playerFound = false; + auto* pPlayer = PlayerManager::Get()->GetByUsername(cUsername); + if (pPlayer) + { + AddAdminSession(pPlayer->GetConnectionId()); + out->info("{} admin privileges added", cUsername.c_str()); + } + else + { + // retry after sanitizing username + String backupUsername = SanitizeUsername(cUsername); + pPlayer = PlayerManager::Get()->GetByUsername(backupUsername); - PlayerManager::Get()->ForEach([&](const Player* apPlayer) { - if (apPlayer->GetUsername() == cUsername) + if (pPlayer) { - AddAdminSession(apPlayer->GetConnectionId()); + AddAdminSession(pPlayer->GetConnectionId()); out->info("{} admin privileges added", cUsername.c_str()); - playerFound = true; - return; } - }); - - if (!playerFound) - { - // space in username handling - String backupUsername = cUsername; - if (cUsername.find('_') != std::string::npos) + else { - - while (backupUsername.find('_') != std::string::npos) - { - std::ranges::replace(backupUsername, '_', ' '); - } - - PlayerManager::Get()->ForEach([&](const Player* apPlayer) { - if (apPlayer->GetUsername() == backupUsername) - { - AddAdminSession(apPlayer->GetConnectionId()); - out->info("{} admin privileges added", backupUsername.c_str()); - playerFound = true; - return; - } - }); - + out->warn("{} is not a valid player", backupUsername.c_str()); } - if (!playerFound) - out->warn("{} is not an admin", backupUsername.c_str()); } }); m_commands.RegisterCommand( @@ -442,47 +423,28 @@ void GameServer::BindServerCommands() auto out = spdlog::get("ConOut"); const auto& cUsername = aStack.Pop(); - bool playerFound = false; + auto* pPlayer = GetAdminByUsername(cUsername); - for (const auto& cAdmin : m_adminSessions) + if (pPlayer) + { + RemoveAdminSession(pPlayer->GetConnectionId()); + out->info("{} admin privileges revoked", cUsername.c_str()); + } + else { - Player* pPlayer = PlayerManager::Get()->GetByConnectionId(cAdmin); - if (pPlayer->GetUsername() == cUsername) + // retry after sanitizing username + String backupUsername = SanitizeUsername(cUsername); + pPlayer = GetAdminByUsername(backupUsername); + + if (pPlayer) { RemoveAdminSession(pPlayer->GetConnectionId()); out->info("{} admin privileges revoked", cUsername.c_str()); - playerFound = true; - break; } - } - - if (!playerFound) - { - // space in username handling - String backupUsername = cUsername; - if (cUsername.find('_') != std::string::npos) + else { - - while (backupUsername.find('_') != std::string::npos) - { - std::ranges::replace(backupUsername, '_', ' '); - } - - for (const auto& cAdmin : m_adminSessions) - { - Player* pPlayer = PlayerManager::Get()->GetByConnectionId(cAdmin); - if (pPlayer->GetUsername() == backupUsername) - { - RemoveAdminSession(pPlayer->GetConnectionId()); - out->info("{} admin privileges revoked", backupUsername.c_str()); - playerFound = true; - break; - } - } - - } - if (!playerFound) out->warn("{} is not an admin", backupUsername.c_str()); + } } }); m_commands.RegisterCommand<>( @@ -497,9 +459,17 @@ void GameServer::BindServerCommands() String output = "Admins: "; bool _first = true; - for (const auto& cAdmin : m_adminSessions) + for (const auto& cAdminSession : m_adminSessions) { - const auto& cUsername = PlayerManager::Get()->GetByConnectionId(cAdmin)->GetUsername(); + auto* pPlayer = PlayerManager::Get()->GetByConnectionId(cAdminSession); + + if (!pPlayer) + { + out->error("Admin session not found: {}", cAdminSession); + continue; + } + + const auto& cUsername = pPlayer->GetUsername(); if (_first) { @@ -1070,3 +1040,41 @@ void GameServer::UpdateTitle() const std::cout << "\033]0;" << title << "\007"; #endif } + +Player* GameServer::GetAdminByUsername(const String& acUsername) const noexcept +{ + for (auto session : m_adminSessions) + { + if (auto* pPlayer = PlayerManager::Get()->GetByConnectionId(session)) + { + if (pPlayer->GetUsername() == acUsername) + return pPlayer; + } + } + + return nullptr; +} + +Player const* GameServer::GetAdminByUsername(const String& acUsername) noexcept +{ + for (auto session : m_adminSessions) + { + if (auto const* pPlayer = PlayerManager::Get()->GetByConnectionId(session)) + { + if (pPlayer->GetUsername() == acUsername) + return pPlayer; + } + } + + return nullptr; +} + +String GameServer::SanitizeUsername(const String& acUsername) const noexcept +{ + String username = acUsername; + + // space in username handling | "_" -> space + std::ranges::replace(username, '_', ' '); + + return username; +} diff --git a/Code/server/GameServer.h b/Code/server/GameServer.h index 1d7e3621a..799be34b1 100644 --- a/Code/server/GameServer.h +++ b/Code/server/GameServer.h @@ -78,11 +78,7 @@ struct GameServer final : Server { return m_isPasswordProtected; } - void SetPublic(bool aIsPublic) noexcept - { - m_isPublic = aIsPublic; - } - bool IsPublic() const noexcept + [[nodiscard]] bool IsPublic() const noexcept { return m_isPublic; } @@ -117,7 +113,13 @@ struct GameServer final : Server m_adminSessions.insert(acSession); } - void RemoveAdminSession(ConnectionId_t acSession) noexcept; + void RemoveAdminSession(ConnectionId_t acSession) noexcept + { + m_adminSessions.erase(acSession); + } + + Player* GetAdminByUsername(const String& acUsername) const noexcept; + Player const* GetAdminByUsername(const String& acUsername) noexcept; protected: bool ValidateAuthParams(ConnectionId_t aConnectionId, const UniquePtr& acRequest); @@ -131,6 +133,7 @@ struct GameServer final : Server private: void UpdateTitle() const; + String SanitizeUsername(const String& acUsername) const noexcept; private: std::chrono::high_resolution_clock::time_point m_startTime; diff --git a/Code/server/Services/ServerListService.cpp b/Code/server/Services/ServerListService.cpp index a926ad105..210333b09 100644 --- a/Code/server/Services/ServerListService.cpp +++ b/Code/server/Services/ServerListService.cpp @@ -30,8 +30,6 @@ ServerListService::ServerListService(World& aWorld, entt::dispatcher& aDispatche if (!bAnnounceServer) spdlog::warn("bAnnounceServer is set to false. The server will not show up as a public server. " "If you are just playing with friends, this is probably what you want."); - - GameServer::Get()->SetPublic(bAnnounceServer); } void ServerListService::OnUpdate(const UpdateEvent& acEvent) noexcept