From 9abba39d69248f39421998f0b686515bb0ad1045 Mon Sep 17 00:00:00 2001 From: Edo Date: Thu, 29 Dec 2022 12:34:43 +0100 Subject: [PATCH] [ServerList]: Display warning message for recoverable error (#682) --- src/Components/Modules/Logger.cpp | 2 +- src/Components/Modules/Party.cpp | 2 +- src/Components/Modules/Playlist.cpp | 2 +- src/Components/Modules/ServerInfo.cpp | 13 +- src/Components/Modules/ServerList.cpp | 402 +++++++++++++------------- src/Components/Modules/ServerList.hpp | 8 +- src/Game/Dvars.cpp | 11 + src/Game/Dvars.hpp | 5 + src/Game/Functions.cpp | 8 - src/Utils/InfoString.cpp | 3 +- 10 files changed, 237 insertions(+), 219 deletions(-) diff --git a/src/Components/Modules/Logger.cpp b/src/Components/Modules/Logger.cpp index e355a95e..c1e446b7 100644 --- a/src/Components/Modules/Logger.cpp +++ b/src/Components/Modules/Logger.cpp @@ -20,7 +20,7 @@ namespace Components va_list va; va_start(va, message); - _vsnprintf_s(buf, _TRUNCATE, message, va); + vsnprintf_s(buf, _TRUNCATE, message, va); va_end(va); MessagePrint(channel, {buf}); diff --git a/src/Components/Modules/Party.cpp b/src/Components/Modules/Party.cpp index 7798c760..4126726f 100644 --- a/src/Components/Modules/Party.cpp +++ b/src/Components/Modules/Party.cpp @@ -324,7 +324,7 @@ namespace Components auto clientCount = 0; auto maxClientCount = *Game::svs_clientCount; const auto securityLevel = Dvar::Var("sv_securityLevel").get(); - const auto* password = (*Game::g_password)->current.string; + const auto* password = *Game::g_password ? (*Game::g_password)->current.string : ""; if (maxClientCount) { diff --git a/src/Components/Modules/Playlist.cpp b/src/Components/Modules/Playlist.cpp index 1b355aa4..52aa12b5 100644 --- a/src/Components/Modules/Playlist.cpp +++ b/src/Components/Modules/Playlist.cpp @@ -46,7 +46,7 @@ namespace Components void Playlist::PlaylistRequest(const Network::Address& address, [[maybe_unused]] const std::string& data) { - const auto* password = (*Game::g_password)->current.string; + const auto* password = *Game::g_password ? (*Game::g_password)->current.string : ""; if (*password) { diff --git a/src/Components/Modules/ServerInfo.cpp b/src/Components/Modules/ServerInfo.cpp index 4114f2df..1dfcba0c 100644 --- a/src/Components/Modules/ServerInfo.cpp +++ b/src/Components/Modules/ServerInfo.cpp @@ -136,7 +136,7 @@ namespace Components Utils::InfoString ServerInfo::GetInfo() { auto maxClientCount = *Game::svs_clientCount; - const auto* password = (*Game::g_password)->current.string; + const auto* password = *Game::g_password ? (*Game::g_password)->current.string : ""; if (!maxClientCount) { @@ -151,7 +151,7 @@ namespace Components info.set("version", (*Game::version)->current.string); info.set("mapname", (*Game::sv_mapname)->current.string); info.set("isPrivate", *password ? "1" : "0"); - info.set("checksum", Utils::String::VA("%X", Utils::Cryptography::JenkinsOneAtATime::Compute(Utils::String::VA("%u", Game::Sys_Milliseconds())))); + info.set("checksum", Utils::String::VA("%X", Utils::Cryptography::JenkinsOneAtATime::Compute(std::to_string(Game::Sys_Milliseconds())))); info.set("aimAssist", (Gamepad::sv_allowAimAssist.get() ? "1" : "0")); info.set("voiceChat", (Voice::SV_VoiceEnabled() ? "1" : "0")); @@ -260,7 +260,7 @@ namespace Components Dvar::Var("uiSi_aimAssist").set(info.get("aimAssist") == "0" ? "@MENU_DISABLED" : "@MENU_ENABLED"); Dvar::Var("uiSi_voiceChat").set(info.get("voiceChat") == "0" ? "@MENU_DISABLED" : "@MENU_ENABLED"); - switch (atoi(info.get("scr_team_fftype").data())) + switch (std::strtol(info.get("scr_team_fftype").data(), nullptr, 10)) { default: Dvar::Var("uiSi_ffType").set("@MENU_DISABLED"); @@ -276,12 +276,13 @@ namespace Components break; } - if (info.get("fs_game").size() > 5) + if (Utils::String::StartsWith(info.get("fs_game"), "mods/")) { - Dvar::Var("uiSi_ModName").set(info.get("fs_game").data() + 5); + auto mod = info.get("fs_game"); + Dvar::Var("uiSi_ModName").set(mod.substr(5)); } - auto lines = Utils::String::Split(data, '\n'); + const auto lines = Utils::String::Split(data, '\n'); if (lines.size() <= 1) return; diff --git a/src/Components/Modules/ServerList.cpp b/src/Components/Modules/ServerList.cpp index bb39ae5d..e50011bc 100644 --- a/src/Components/Modules/ServerList.cpp +++ b/src/Components/Modules/ServerList.cpp @@ -8,7 +8,7 @@ namespace Components { bool ServerList::SortAsc = true; - int ServerList::SortKey = ServerList::Column::Ping; + int ServerList::SortKey = static_cast>(Column::Ping); unsigned int ServerList::CurrentServer = 0; ServerList::Container ServerList::RefreshContainer; @@ -28,17 +28,19 @@ namespace Components std::vector* ServerList::GetList() { - if (ServerList::IsOnlineList()) + if (IsOnlineList()) { - return &ServerList::OnlineList; + return &OnlineList; } - if (ServerList::IsOfflineList()) + + if (IsOfflineList()) { - return &ServerList::OfflineList; + return &OfflineList; } - if (ServerList::IsFavouriteList()) + + if (IsFavouriteList()) { - return &ServerList::FavouriteList; + return &FavouriteList; } return nullptr; @@ -46,41 +48,41 @@ namespace Components bool ServerList::IsFavouriteList() { - return (Dvar::Var("ui_netSource").get() == 2); + return (*Game::ui_netSource)->current.integer == 2; } bool ServerList::IsOfflineList() { - return (Dvar::Var("ui_netSource").get() == 0); + return (*Game::ui_netSource)->current.integer == 0; } bool ServerList::IsOnlineList() { - return (Dvar::Var("ui_netSource").get() == 1); + return (*Game::ui_netSource)->current.integer == 1; } unsigned int ServerList::GetServerCount() { - return ServerList::VisibleList.size(); + return VisibleList.size(); } const char* ServerList::GetServerText(unsigned int index, int column) { - ServerList::ServerInfo* info = ServerList::GetServer(index); + auto* info = GetServer(index); if (info) { - return ServerList::GetServerInfoText(info, column); + return GetServerInfoText(info, column); } return ""; } - const char* ServerList::GetServerInfoText(ServerList::ServerInfo* server, int column, bool sorting) + const char* ServerList::GetServerInfoText(ServerInfo* server, int column, bool sorting) { if (!server) return ""; - switch (column) + switch (static_cast(column)) { case Column::Password: { @@ -115,12 +117,11 @@ namespace Components { return Utils::String::VA("^1%s", Game::UI_LocalizeMapName(server->mapname.data())); } + return Game::UI_LocalizeMapName(server->mapname.data()); } - else - { - return Utils::String::VA("^3%s", Game::UI_LocalizeMapName(server->mapname.data())); - } + + return Utils::String::VA("^3%s", Game::UI_LocalizeMapName(server->mapname.data())); } case Column::Players: @@ -135,8 +136,9 @@ namespace Components case Column::Mod: { - if (server->mod != "") + if (Utils::String::StartsWith(server->mod, "mods/")) { + // Can point to '\0' which is fine return (server->mod.data() + 5); } @@ -149,20 +151,18 @@ namespace Components { return Utils::String::VA("^2%i", server->ping); } - else if (server->ping < 150) // Below this is a medium ping + + if (server->ping < 150) // Below this is a medium ping { return Utils::String::VA("^3%i", server->ping); } - else - { - return Utils::String::VA("^1%i", server->ping); - } - } + return Utils::String::VA("^1%i", server->ping); + } default: { break; - }; + } } return ""; @@ -170,75 +170,75 @@ namespace Components void ServerList::SelectServer(unsigned int index) { - ServerList::CurrentServer = index; + CurrentServer = index; - ServerList::ServerInfo* info = ServerList::GetCurrentServer(); + auto* info = GetCurrentServer(); if (info) { - ServerList::UIServerSelected.set(true); - ServerList::UIServerSelectedMap.set(info->mapname); + UIServerSelected.set(true); + UIServerSelectedMap.set(info->mapname); Dvar::Var("ui_serverSelectedGametype").set(info->gametype); } else { - ServerList::UIServerSelected.set(false); + UIServerSelected.set(false); } } void ServerList::UpdateVisibleList([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { - auto list = ServerList::GetList(); + auto* list = GetList(); if (!list) return; - std::vector tempList(*list); + std::vector tempList(*list); if (tempList.empty()) { - ServerList::Refresh(UIScript::Token(), info); + Refresh(UIScript::Token(), info); } else { list->clear(); - std::lock_guard _(ServerList::RefreshContainer.mutex); + std::lock_guard _(RefreshContainer.mutex); - ServerList::RefreshContainer.sendCount = 0; - ServerList::RefreshContainer.sentCount = 0; + RefreshContainer.sendCount = 0; + RefreshContainer.sentCount = 0; for (auto& server : tempList) { - ServerList::InsertRequest(server.addr); + InsertRequest(server.addr); } } } void ServerList::RefreshVisibleList([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { - ServerList::RefreshVisibleListInternal(UIScript::Token(), info); + RefreshVisibleListInternal(UIScript::Token(), info); } void ServerList::RefreshVisibleListInternal([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info, bool refresh) { - Dvar::Var("ui_serverSelected").set(false); + Game::Dvar_SetBoolByName("ui_serverSelected", false); - ServerList::VisibleList.clear(); + VisibleList.clear(); - auto list = ServerList::GetList(); + auto* list = GetList(); if (!list) return; if (refresh) { - ServerList::Refresh(UIScript::Token(), info); + Refresh(UIScript::Token(), info); return; } - auto ui_browserShowFull = Dvar::Var("ui_browserShowFull").get(); - auto ui_browserShowEmpty = Dvar::Var("ui_browserShowEmpty").get(); - auto ui_browserShowHardcore = Dvar::Var("ui_browserKillcam").get(); - auto ui_browserShowPassword = Dvar::Var("ui_browserShowPassword").get(); - auto ui_browserMod = Dvar::Var("ui_browserMod").get(); - auto ui_joinGametype = Dvar::Var("ui_joinGametype").get(); + auto ui_browserShowFull = Dvar::Var("ui_browserShowFull").get(); + auto ui_browserShowEmpty = Dvar::Var("ui_browserShowEmpty").get(); + auto ui_browserShowHardcore = Dvar::Var("ui_browserKillcam").get(); + auto ui_browserShowPassword = Dvar::Var("ui_browserShowPassword").get(); + auto ui_browserMod = Dvar::Var("ui_browserMod").get(); + auto ui_joinGametype = (*Game::ui_joinGametype)->current.integer; for (unsigned int i = 0; i < list->size(); ++i) { @@ -257,15 +257,15 @@ namespace Components if ((ui_browserShowPassword == 0 && serverInfo->password) || (ui_browserShowPassword == 1 && !serverInfo->password)) continue; // Don't show modded servers - if ((ui_browserMod == 0 && serverInfo->mod.size()) || (ui_browserMod == 1 && !serverInfo->mod.size())) continue; + if ((ui_browserMod == 0 && static_cast(serverInfo->mod.size())) || (ui_browserMod == 1 && serverInfo->mod.empty())) continue; // Filter by gametype if (ui_joinGametype > 0 && (ui_joinGametype - 1) < *Game::gameTypeCount && Game::gameTypes[(ui_joinGametype - 1)].gameType != serverInfo->gametype) continue; - ServerList::VisibleList.push_back(i); + VisibleList.push_back(i); } - ServerList::SortList(); + SortList(); } void ServerList::Refresh([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) @@ -273,37 +273,38 @@ namespace Components Dvar::Var("ui_serverSelected").set(false); //Localization::Set("MPUI_SERVERQUERIED", "Sent requests: 0/0"); -// ServerList::OnlineList.clear(); -// ServerList::OfflineList.clear(); -// ServerList::FavouriteList.clear(); - - auto list = ServerList::GetList(); +#if 0 + OnlineList.clear(); + OfflineList.clear(); + FavouriteList.clear(); +#endif + auto* list = GetList(); if (list) list->clear(); - ServerList::VisibleList.clear(); + VisibleList.clear(); { - std::lock_guard _(ServerList::RefreshContainer.mutex); - ServerList::RefreshContainer.servers.clear(); - ServerList::RefreshContainer.sendCount = 0; - ServerList::RefreshContainer.sentCount = 0; + std::lock_guard _(RefreshContainer.mutex); + RefreshContainer.servers.clear(); + RefreshContainer.sendCount = 0; + RefreshContainer.sentCount = 0; } - if (ServerList::IsOfflineList()) + if (IsOfflineList()) { Discovery::Perform(); } - else if (ServerList::IsOnlineList()) + else if (IsOnlineList()) { const auto masterPort = Dvar::Var("masterPort").get(); const auto masterServerName = Dvar::Var("masterServerName").get(); // Check if our dvars can properly convert to a address Game::netadr_t masterServerAddr; - if (!ServerList::GetMasterServer(masterServerName, masterPort, masterServerAddr)) + if (!GetMasterServer(masterServerName, masterPort, masterServerAddr)) { Logger::Print("Could not resolve address for {}:{}", masterServerName, masterPort); - Toast::Show("cardicon_headshot", "^1Error", Utils::String::VA("Could not resolve address for %s:%u", masterServerName, masterPort), 5000); + Toast::Show("cardicon_headshot", "^1Error", Utils::String::VA("Could not resolve address for %s:%i", masterServerName, masterPort), 5000); UseMasterServer = false; return; } @@ -312,16 +313,16 @@ namespace Components UseMasterServer = true; - ServerList::RefreshContainer.awatingList = true; - ServerList::RefreshContainer.awaitTime = Game::Sys_Milliseconds(); - ServerList::RefreshContainer.host = Network::Address(Utils::String::VA("%s:%u", masterServerName, masterPort)); + RefreshContainer.awatingList = true; + RefreshContainer.awaitTime = Game::Sys_Milliseconds(); + RefreshContainer.host = Network::Address(Utils::String::VA("%s:%u", masterServerName, masterPort)); Logger::Print("Sending serverlist request to master\n"); - Network::SendCommand(ServerList::RefreshContainer.host, "getservers", Utils::String::VA("IW4 %i full empty", PROTOCOL)); + Network::SendCommand(RefreshContainer.host, "getservers", Utils::String::VA("IW4 %i full empty", PROTOCOL)); } - else if (ServerList::IsFavouriteList()) + else if (IsFavouriteList()) { - ServerList::LoadFavourties(); + LoadFavourties(); } } @@ -409,22 +410,22 @@ namespace Components const auto data = nlohmann::json(servers); Utils::IO::WriteFile(FavouriteFile, data.dump()); - auto list = ServerList::GetList(); + auto* list = GetList(); if (list) list->clear(); - ServerList::RefreshVisibleListInternal(UIScript::Token(), nullptr); + RefreshVisibleListInternal(UIScript::Token(), nullptr); Game::ShowMessageBox("Server removed from favourites.", "Success"); } void ServerList::LoadFavourties() { - if (!ServerList::IsFavouriteList()) + if (!IsFavouriteList()) { return; } - auto list = ServerList::GetList(); + auto* list = GetList(); if (list) list->clear(); const auto parseData = Utils::IO::ReadFile(FavouriteFile); @@ -455,20 +456,20 @@ namespace Components for (const auto& server : servers) { if (!server.is_string()) continue; - ServerList::InsertRequest(server.get()); + InsertRequest(server.get()); } } void ServerList::InsertRequest(Network::Address address) { - std::lock_guard _(ServerList::RefreshContainer.mutex); + std::lock_guard _(RefreshContainer.mutex); - ServerList::Container::ServerContainer container; + Container::ServerContainer container; container.sent = false; container.target = address; bool alreadyInserted = false; - for (auto &server : ServerList::RefreshContainer.servers) + for (auto &server : RefreshContainer.servers) { if (server.target == container.target) { @@ -479,34 +480,34 @@ namespace Components if (!alreadyInserted) { - ServerList::RefreshContainer.servers.push_back(container); + RefreshContainer.servers.push_back(container); - auto list = ServerList::GetList(); + auto* list = GetList(); if (list) { for (auto& server : *list) { if (server.addr == container.target) { - --ServerList::RefreshContainer.sendCount; - --ServerList::RefreshContainer.sentCount; + --RefreshContainer.sendCount; + --RefreshContainer.sentCount; break; } } } - ++ServerList::RefreshContainer.sendCount; + ++RefreshContainer.sendCount; } } void ServerList::Insert(const Network::Address& address, const Utils::InfoString& info) { - std::lock_guard _(ServerList::RefreshContainer.mutex); + std::lock_guard _(RefreshContainer.mutex); - for (auto i = ServerList::RefreshContainer.servers.begin(); i != ServerList::RefreshContainer.servers.end();) + for (auto i = RefreshContainer.servers.begin(); i != RefreshContainer.servers.end();) { // Our desired server - if (i->target == address && i->sent) + if ((i->target == address) && i->sent) { // Challenge did not match if (i->challenge != info.get("challenge")) @@ -523,16 +524,16 @@ namespace Components server.gametype = info.get("gametype"); server.shortversion = info.get("shortversion"); server.mod = info.get("fs_game"); - server.matchType = atoi(info.get("matchtype").data()); - server.clients = atoi(info.get("clients").data()); - server.bots = atoi(info.get("bots").data()); - server.securityLevel = atoi(info.get("securityLevel").data()); - server.maxClients = atoi(info.get("sv_maxclients").data()); - server.password = (atoi(info.get("isPrivate").data()) != 0); - server.aimassist = (atoi(info.get("aimAssist").data()) != 0); - server.voice = (atoi(info.get("voiceChat").data()) != 0); - server.hardcore = (atoi(info.get("hc").data()) != 0); - server.svRunning = (atoi(info.get("sv_running").data()) != 0); + server.matchType = std::strtol(info.get("matchtype").data(), nullptr, 10); + server.clients = std::strtol(info.get("clients").data(), nullptr, 10); + server.bots = std::strtol(info.get("bots").data(), nullptr, 10); + server.securityLevel = std::strtol(info.get("securityLevel").data(), nullptr, 10); + server.maxClients = std::strtol(info.get("sv_maxclients").data(), nullptr, 10); + server.password = info.get("isPrivate") == "1"s; + server.aimassist = info.get("aimAssist") == "1"; + server.voice = info.get("voiceChat") == "1"s; + server.hardcore = info.get("hc") == "1"s; + server.svRunning = info.get("sv_running") == "1"s; server.ping = (Game::Sys_Milliseconds() - i->sendTime); server.addr = address; @@ -542,18 +543,20 @@ namespace Components server.mod = TextRenderer::StripMaterialTextIcons(server.mod); // Remove server from queue - i = ServerList::RefreshContainer.servers.erase(i); + i = RefreshContainer.servers.erase(i); // Servers with more than 18 players or less than 0 players are faking for sure // So lets ignore those if (server.clients > 18 || server.maxClients > 18 || server.clients < 0 || server.maxClients < 0) + { return; + } // Check if already inserted and remove - auto list = ServerList::GetList(); + auto* list = GetList(); if (!list) return; - unsigned int k = 0; + std::size_t k = 0; for (auto j = list->begin(); j != list->end(); ++k) { if (j->addr == address) @@ -567,11 +570,11 @@ namespace Components } // Also remove from visible list - for (auto j = ServerList::VisibleList.begin(); j != ServerList::VisibleList.end();) + for (auto j = VisibleList.begin(); j != VisibleList.end();) { if (*j == k) { - j = ServerList::VisibleList.erase(j); + j = VisibleList.erase(j); } else { @@ -581,15 +584,15 @@ namespace Components if (info.get("gamename") == "IW4"s && server.matchType #if !defined(DEBUG) && defined(VERSION_FILTER) - && ServerList::CompareVersion(server.shortversion, SHORTVERSION) + && CompareVersion(server.shortversion, SHORTVERSION) #endif ) { - auto lList = ServerList::GetList(); + auto* lList = GetList(); if (lList) { lList->push_back(server); - ServerList::RefreshVisibleListInternal(UIScript::Token(), nullptr); + RefreshVisibleListInternal(UIScript::Token(), nullptr); } } } @@ -609,10 +612,18 @@ namespace Components while (subVersions2.size() >= 3) subVersions2.pop_back(); if (subVersions1.size() != subVersions2.size()) return false; - for (unsigned int i = 0; i < subVersions1.size(); ++i) + for (std::size_t i = 0; i < subVersions1.size(); ++i) { - if (atoi(subVersions1[i].data()) != atoi(subVersions2[i].data())) + try { + if (std::stoi(subVersions1[i]) != std::stoi(subVersions2[i])) + { + return false; + } + } + catch (const std::exception& ex) + { + Logger::Warning(Game::CON_CHANNEL_CONSOLEONLY, "{} while performing numeric comparison between {} and {}\n", ex.what(), subVersions1[i], subVersions2[i]); return false; } } @@ -622,20 +633,20 @@ namespace Components ServerList::ServerInfo* ServerList::GetCurrentServer() { - return ServerList::GetServer(ServerList::CurrentServer); + return GetServer(CurrentServer); } void ServerList::SortList() { // Only sort when the serverlist is open - if (!ServerList::IsServerListOpen()) return; + if (!IsServerListOpen()) return; - std::stable_sort(ServerList::VisibleList.begin(), ServerList::VisibleList.end(), [](const unsigned int &server1, const unsigned int &server2) -> bool + std::ranges::stable_sort(VisibleList, [](const unsigned int& server1, const unsigned int& server2) -> bool { ServerInfo* info1 = nullptr; ServerInfo* info2 = nullptr; - auto list = ServerList::GetList(); + auto* list = GetList(); if (!list) return false; if (list->size() > server1) info1 = &(*list)[server1]; @@ -645,35 +656,36 @@ namespace Components if (!info2) return false; // Numerical comparisons - if (ServerList::SortKey == ServerList::Column::Ping) + if (SortKey == static_cast>(Column::Ping)) { return info1->ping < info2->ping; } - else if (ServerList::SortKey == ServerList::Column::Players) + + if (SortKey == static_cast>(Column::Players)) { return info1->clients < info2->clients; } - std::string text1 = Utils::String::ToLower(TextRenderer::StripColors(ServerList::GetServerInfoText(info1, ServerList::SortKey, true))); - std::string text2 = Utils::String::ToLower(TextRenderer::StripColors(ServerList::GetServerInfoText(info2, ServerList::SortKey, true))); + auto text1 = Utils::String::ToLower(TextRenderer::StripColors(GetServerInfoText(info1, SortKey, true))); + auto text2 = Utils::String::ToLower(TextRenderer::StripColors(GetServerInfoText(info2, SortKey, true))); // ASCII-based comparison return text1.compare(text2) < 0; }); - if (!ServerList::SortAsc) std::reverse(ServerList::VisibleList.begin(), ServerList::VisibleList.end()); + if (!SortAsc) std::ranges::reverse(VisibleList); } ServerList::ServerInfo* ServerList::GetServer(unsigned int index) { - if (ServerList::VisibleList.size() > index) + if (VisibleList.size() > index) { - auto list = ServerList::GetList(); + auto* list = GetList(); if (!list) return nullptr; - if (list->size() > ServerList::VisibleList[index]) + if (list->size() > VisibleList[index]) { - return &(*list)[ServerList::VisibleList[index]]; + return &(*list)[VisibleList[index]]; } } @@ -683,40 +695,42 @@ namespace Components void ServerList::Frame() { static Utils::Time::Interval frameLimit; - const auto interval = static_cast(1000.0f / ServerList::NETServerFrames.get()); + const auto interval = static_cast(1000.0f / static_cast(NETServerFrames.get())); if (!frameLimit.elapsed(std::chrono::milliseconds(interval))) + { return; + } frameLimit.update(); - std::lock_guard _(ServerList::RefreshContainer.mutex); + std::lock_guard _(RefreshContainer.mutex); - if (ServerList::RefreshContainer.awatingList) + if (RefreshContainer.awatingList) { // Stop counting if we are out of the server browser menu - if (!ServerList::IsServerListOpen()) + if (!IsServerListOpen()) { - ServerList::RefreshContainer.awatingList = false; + RefreshContainer.awatingList = false; } // Check if we haven't got a response within 5 seconds - if (Game::Sys_Milliseconds() - ServerList::RefreshContainer.awaitTime > 5000) + if (Game::Sys_Milliseconds() - RefreshContainer.awaitTime > 5000) { - ServerList::RefreshContainer.awatingList = false; + RefreshContainer.awatingList = false; - Logger::Print("We haven't received a response from the master within {} seconds!\n", (Game::Sys_Milliseconds() - ServerList::RefreshContainer.awaitTime) / 1000); - Toast::Show("cardicon_headshot", "^1Error", "Failed to reach master server, using node servers instead.", 5000); + Logger::Print("We haven't received a response from the master within {} seconds!\n", (Game::Sys_Milliseconds() - RefreshContainer.awaitTime) / 1000); + Toast::Show("cardicon_headshot", "^3Warning", "Failed to reach master server. Using node system instead.", 5000); UseMasterServer = false; Node::Synchronize(); } } - auto requestLimit = ServerList::NETServerQueryLimit.get(); - for (unsigned int i = 0; i < ServerList::RefreshContainer.servers.size() && requestLimit > 0; ++i) + auto requestLimit = NETServerQueryLimit.get(); + for (std::size_t i = 0; i < RefreshContainer.servers.size() && requestLimit > 0; ++i) { - ServerList::Container::ServerContainer* server = &ServerList::RefreshContainer.servers[i]; + auto* server = &RefreshContainer.servers[i]; if (server->sent) continue; // Found server we can send a request to @@ -726,47 +740,43 @@ namespace Components server->sendTime = Game::Sys_Milliseconds(); server->challenge = Utils::Cryptography::Rand::GenerateChallenge(); - ++ServerList::RefreshContainer.sentCount; + ++RefreshContainer.sentCount; Network::SendCommand(server->target, "getinfo", server->challenge); - // Display in the menu, like in COD4 + // Display in the menu, like in CoD4 - Disabled to avoid spamming? //Localization::Set("MPUI_SERVERQUERIED", Utils::String::VA("Sent requests: %d/%d", ServerList::RefreshContainer.sentCount, ServerList::RefreshContainer.sendCount)); } - ServerList::UpdateVisibleInfo(); + UpdateVisibleInfo(); } void ServerList::UpdateSource() { - Dvar::Var netSource("ui_netSource"); + auto source = (*Game::ui_netSource)->current.integer; - int source = netSource.get(); - - if (++source > netSource.get()->domain.integer.max) + if (++source > (*Game::ui_netSource)->domain.integer.max) { source = 0; } - netSource.set(source); + Game::Dvar_SetInt(*Game::ui_netSource, source); - ServerList::RefreshVisibleListInternal(UIScript::Token(), nullptr, true); + RefreshVisibleListInternal(UIScript::Token(), nullptr, true); } void ServerList::UpdateGameType() { - Dvar::Var joinGametype("ui_joinGametype"); - - int gametype = joinGametype.get(); + auto gametype = (*Game::ui_joinGametype)->current.integer; if (++gametype > *Game::gameTypeCount) { gametype = 0; } - joinGametype.set(gametype); + Game::Dvar_SetInt(*Game::ui_joinGametype, gametype); - ServerList::RefreshVisibleListInternal(UIScript::Token(), nullptr); + RefreshVisibleListInternal(UIScript::Token(), nullptr); } void ServerList::UpdateVisibleInfo() @@ -775,7 +785,7 @@ namespace Components static int players = 0; static int bots = 0; - auto list = ServerList::GetList(); + auto list = GetList(); if (list) { @@ -783,7 +793,7 @@ namespace Components int newPlayers = 0; int newBots = 0; - for (unsigned int i = 0; i < list->size(); ++i) + for (std::size_t i = 0; i < list->size(); ++i) { newPlayers += list->at(i).clients; newBots += list->at(i).bots; @@ -816,47 +826,45 @@ namespace Components ServerList::ServerList() { - ServerList::OnlineList.clear(); - ServerList::OfflineList.clear(); - ServerList::FavouriteList.clear(); - ServerList::VisibleList.clear(); + OnlineList.clear(); + OfflineList.clear(); + FavouriteList.clear(); + VisibleList.clear(); Scheduler::Once([] { - ServerList::UIServerSelected = Dvar::Register("ui_serverSelected", false, + UIServerSelected = Dvar::Register("ui_serverSelected", false, Game::DVAR_NONE, "Whether a server has been selected in the serverlist"); - ServerList::UIServerSelectedMap = Dvar::Register("ui_serverSelectedMap", "mp_afghan", + UIServerSelectedMap = Dvar::Register("ui_serverSelectedMap", "mp_afghan", Game::DVAR_NONE, "Map of the selected server"); - ServerList::NETServerQueryLimit = Dvar::Register("net_serverQueryLimit", 1, + NETServerQueryLimit = Dvar::Register("net_serverQueryLimit", 1, 1, 10, Dedicated::IsEnabled() ? Game::DVAR_NONE : Game::DVAR_ARCHIVE, "Amount of server queries per frame"); - ServerList::NETServerFrames = Dvar::Register("net_serverFrames", 30, + NETServerFrames = Dvar::Register("net_serverFrames", 30, 1, 60, Dedicated::IsEnabled() ? Game::DVAR_NONE : Game::DVAR_ARCHIVE, "Amount of server query frames per second"); }, Scheduler::Pipeline::MAIN); // Fix ui_netsource dvar Utils::Hook::Nop(0x4CDEEC, 5); // Don't reset the netsource when gametypes aren't loaded - Dvar::Register("ui_netSource", 1, 0, 2, Game::DVAR_ARCHIVE, reinterpret_cast(0x6D9F08)); - //Localization::Set("MPUI_SERVERQUERIED", "Sent requests: 0/0"); Localization::Set("MPUI_SERVERQUERIED", "Servers: 0\nPlayers: 0 (0)"); Network::OnClientPacket("getServersResponse", [](const Network::Address& address, [[maybe_unused]] const std::string& data) { - if (ServerList::RefreshContainer.host != address) return; // Only parse from host we sent to + if (RefreshContainer.host != address) return; // Only parse from host we sent to - ServerList::RefreshContainer.awatingList = false; + RefreshContainer.awatingList = false; - std::lock_guard _(ServerList::RefreshContainer.mutex); + std::lock_guard _(RefreshContainer.mutex); int offset = 0; - int count = ServerList::RefreshContainer.servers.size(); - ServerList::MasterEntry* entry = nullptr; + auto count = RefreshContainer.servers.size(); + MasterEntry* entry = nullptr; // Find first entry do { - entry = reinterpret_cast(const_cast(data.data()) + offset++); + entry = reinterpret_cast(const_cast(data.data()) + offset++); } while (!entry->HasSeparator() && !entry->IsEndToken()); for (int i = 0; !entry[i].IsEndToken() && entry[i].HasSeparator(); ++i) @@ -866,29 +874,29 @@ namespace Components serverAddr.setPort(ntohs(entry[i].port)); serverAddr.setType(Game::NA_IP); - ServerList::InsertRequest(serverAddr); + InsertRequest(serverAddr); } - Logger::Print("Parsed {} servers from master\n", ServerList::RefreshContainer.servers.size() - count); + Logger::Print("Parsed {} servers from master\n", RefreshContainer.servers.size() - count); }); // Set default masterServerName + port and save it Utils::Hook::Set(0x60AD92, "master.xlabs.dev"); - Utils::Hook::Set(0x60AD90, Game::DVAR_NONE); // masterServerName - Utils::Hook::Set(0x60ADC6, Game::DVAR_NONE); // masterPort + Utils::Hook::Set(0x60AD90, Game::DVAR_NONE); // masterServerName + Utils::Hook::Set(0x60ADC6, Game::DVAR_NONE); // masterPort // Add server list feeder - UIFeeder::Add(2.0f, ServerList::GetServerCount, ServerList::GetServerText, ServerList::SelectServer); + UIFeeder::Add(2.0f, GetServerCount, GetServerText, SelectServer); // Add required UIScripts - UIScript::Add("UpdateFilter", ServerList::RefreshVisibleList); - UIScript::Add("RefreshFilter", ServerList::UpdateVisibleList); + UIScript::Add("UpdateFilter", RefreshVisibleList); + UIScript::Add("RefreshFilter", UpdateVisibleList); - UIScript::Add("RefreshServers", ServerList::Refresh); + UIScript::Add("RefreshServers", Refresh); UIScript::Add("JoinServer", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { - auto* serverInfo = ServerList::GetServer(ServerList::CurrentServer); + auto* serverInfo = GetServer(CurrentServer); if (serverInfo) { Party::Connect(serverInfo->addr); @@ -897,53 +905,53 @@ namespace Components UIScript::Add("ServerSort", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { - auto key = token.get(); - if (ServerList::SortKey == key) + const auto key = token.get(); + if (SortKey == key) { - ServerList::SortAsc = !ServerList::SortAsc; + SortAsc = !SortAsc; } else { - ServerList::SortKey = key; - ServerList::SortAsc = true; + SortKey = key; + SortAsc = true; } - Logger::Print("Sorting server list by token: {}\n", ServerList::SortKey); - ServerList::SortList(); + Logger::Print("Sorting server list by token: {}\n", SortKey); + SortList(); }); UIScript::Add("CreateListFavorite", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { - auto* serverInfo = ServerList::GetCurrentServer(); + auto* serverInfo = GetCurrentServer(); if (info) { - ServerList::StoreFavourite(serverInfo->addr.getString()); + StoreFavourite(serverInfo->addr.getString()); } }); UIScript::Add("CreateFavorite", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { - ServerList::StoreFavourite(Dvar::Var("ui_favoriteAddress").get()); + StoreFavourite(Dvar::Var("ui_favoriteAddress").get()); }); UIScript::Add("CreateCurrentServerFavorite", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { if (Game::CL_IsCgameInitialized()) { - std::string addressText = Network::Address(*Game::connectedHost).getString(); - if (addressText != "0.0.0.0:0" && addressText != "loopback") + const auto addressText = Network::Address(*Game::connectedHost).getString(); + if (addressText != "0.0.0.0:0"s && addressText != "loopback"s) { - ServerList::StoreFavourite(addressText); + StoreFavourite(addressText); } } }); UIScript::Add("DeleteFavorite", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { - auto* serverInfo = ServerList::GetCurrentServer(); + auto* serverInfo = GetCurrentServer(); if (serverInfo) { - ServerList::RemoveFavourite(serverInfo->addr.getString()); + RemoveFavourite(serverInfo->addr.getString()); } }); @@ -951,7 +959,7 @@ namespace Components Command::Add("playerCount", [](Command::Params*) { auto count = 0; - for (const auto& server : ServerList::OnlineList) + for (const auto& server : OnlineList) { count += server.clients; } @@ -960,17 +968,17 @@ namespace Components }); #endif // Add required ownerDraws - UIScript::AddOwnerDraw(220, ServerList::UpdateSource); - UIScript::AddOwnerDraw(253, ServerList::UpdateGameType); + UIScript::AddOwnerDraw(220, UpdateSource); + UIScript::AddOwnerDraw(253, UpdateGameType); // Add frame callback - Scheduler::Loop(ServerList::Frame, Scheduler::Pipeline::CLIENT); + Scheduler::Loop(Frame, Scheduler::Pipeline::CLIENT); } ServerList::~ServerList() { - std::lock_guard _(ServerList::RefreshContainer.mutex); - ServerList::RefreshContainer.awatingList = false; - ServerList::RefreshContainer.servers.clear(); + std::lock_guard _(RefreshContainer.mutex); + RefreshContainer.awatingList = false; + RefreshContainer.servers.clear(); } } diff --git a/src/Components/Modules/ServerList.hpp b/src/Components/Modules/ServerList.hpp index b65036e0..834f90e5 100644 --- a/src/Components/Modules/ServerList.hpp +++ b/src/Components/Modules/ServerList.hpp @@ -57,7 +57,7 @@ namespace Components static bool UseMasterServer; private: - enum Column + enum class Column : int { Password, Matchtype, @@ -69,6 +69,8 @@ namespace Components Gametype, Mod, Ping, + + Count }; static constexpr auto* FavouriteFile = "players/favourites.json"; @@ -83,13 +85,13 @@ namespace Components uint16_t port; }; - bool IsEndToken() + bool IsEndToken() const { // End of transmission or file token return (token[0] == 'E' && token[1] == 'O' && (token[2] == 'T' || token[2] == 'F')); } - bool HasSeparator() + bool HasSeparator() const { return (token[6] == '\\'); } diff --git a/src/Game/Dvars.cpp b/src/Game/Dvars.cpp index 038308e0..be172a8a 100644 --- a/src/Game/Dvars.cpp +++ b/src/Game/Dvars.cpp @@ -22,6 +22,15 @@ namespace Game Dvar_DisplayableValue_t Dvar_DisplayableValue = Dvar_DisplayableValue_t(0x4B5530); Dvar_Reset_t Dvar_Reset = Dvar_Reset_t(0x4FEFD0); + Dvar_SetFromStringByName_t Dvar_SetFromStringByName = Dvar_SetFromStringByName_t(0x4F52E0); + Dvar_SetFromStringByNameFromSource_t Dvar_SetFromStringByNameFromSource = Dvar_SetFromStringByNameFromSource_t(0x4FC770); + Dvar_SetStringByName_t Dvar_SetStringByName = Dvar_SetStringByName_t(0x44F060); + Dvar_SetString_t Dvar_SetString = Dvar_SetString_t(0x4A9580); + Dvar_SetBool_t Dvar_SetBool = Dvar_SetBool_t(0x4A9510); + Dvar_SetBoolByName_t Dvar_SetBoolByName = Dvar_SetBoolByName_t(0x45C4D0); + Dvar_SetFloat_t Dvar_SetFloat = Dvar_SetFloat_t(0x40BB20); + Dvar_SetInt_t Dvar_SetInt = Dvar_SetInt_t(0x421DA0); + const dvar_t** com_developer = reinterpret_cast(0x1AD78E8); const dvar_t** com_developer_script = reinterpret_cast(0x1AD8F10); const dvar_t** com_timescale = reinterpret_cast(0x1AD7920); @@ -61,7 +70,9 @@ namespace Game const dvar_t** ui_currentMap = reinterpret_cast(0x62E2834); const dvar_t** ui_gametype = reinterpret_cast(0x62E2828); const dvar_t** ui_mapname = reinterpret_cast(0x62E279C); + const dvar_t** ui_joinGametype = reinterpret_cast(0x62E2840); const dvar_t** ui_netGameType = reinterpret_cast(0x62E2838); + const dvar_t** ui_netSource = reinterpret_cast(0x62E27E8); const dvar_t** loc_warnings = reinterpret_cast(0x62C8700); const dvar_t** loc_warningsAsErrors = reinterpret_cast(0x62C86FC); diff --git a/src/Game/Dvars.hpp b/src/Game/Dvars.hpp index b3397ebd..f54eaba7 100644 --- a/src/Game/Dvars.hpp +++ b/src/Game/Dvars.hpp @@ -48,6 +48,9 @@ namespace Game typedef void(*Dvar_SetBool_t)(const dvar_t* dvar, bool enabled); extern Dvar_SetBool_t Dvar_SetBool; + typedef void(*Dvar_SetBoolByName_t)(const char* dvarName, bool value); + extern Dvar_SetBoolByName_t Dvar_SetBoolByName; + typedef void(*Dvar_SetFloat_t)(const dvar_t* dvar, float value); extern Dvar_SetFloat_t Dvar_SetFloat; @@ -117,7 +120,9 @@ namespace Game extern const dvar_t** ui_currentMap; extern const dvar_t** ui_gametype; extern const dvar_t** ui_mapname; + extern const dvar_t** ui_joinGametype; extern const dvar_t** ui_netGameType; + extern const dvar_t** ui_netSource; extern const dvar_t** loc_warnings; extern const dvar_t** loc_warningsAsErrors; diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index c641e670..ed6f44c8 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -164,14 +164,6 @@ namespace Game SEH_ReadCharFromString_t SEH_ReadCharFromString = SEH_ReadCharFromString_t(0x486560); SEH_GetCurrentLanguage_t SEH_GetCurrentLanguage = SEH_GetCurrentLanguage_t(0x4F6110); - Dvar_SetFromStringByName_t Dvar_SetFromStringByName = Dvar_SetFromStringByName_t(0x4F52E0); - Dvar_SetFromStringByNameFromSource_t Dvar_SetFromStringByNameFromSource = Dvar_SetFromStringByNameFromSource_t(0x4FC770); - Dvar_SetStringByName_t Dvar_SetStringByName = Dvar_SetStringByName_t(0x44F060); - Dvar_SetString_t Dvar_SetString = Dvar_SetString_t(0x4A9580); - Dvar_SetBool_t Dvar_SetBool = Dvar_SetBool_t(0x4A9510); - Dvar_SetFloat_t Dvar_SetFloat = Dvar_SetFloat_t(0x40BB20); - Dvar_SetInt_t Dvar_SetInt = Dvar_SetInt_t(0x421DA0); - SND_Init_t SND_Init = SND_Init_t(0x46A630); SND_InitDriver_t SND_InitDriver = SND_InitDriver_t(0x4F5090); diff --git a/src/Utils/InfoString.cpp b/src/Utils/InfoString.cpp index 9eb8c37b..bfefdff2 100644 --- a/src/Utils/InfoString.cpp +++ b/src/Utils/InfoString.cpp @@ -19,8 +19,7 @@ namespace Utils std::string InfoString::get(const std::string& key) const { - const auto value = this->keyValuePairs.find(key); - if (value != this->keyValuePairs.end()) + if (const auto value = this->keyValuePairs.find(key); value != this->keyValuePairs.end()) { return value->second; }