[ServerList]: Display warning message for recoverable error (#682)

This commit is contained in:
Edo 2022-12-29 12:34:43 +01:00 committed by GitHub
parent 667cdd6815
commit 9abba39d69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 237 additions and 219 deletions

View File

@ -20,7 +20,7 @@ namespace Components
va_list va; va_list va;
va_start(va, message); va_start(va, message);
_vsnprintf_s(buf, _TRUNCATE, message, va); vsnprintf_s(buf, _TRUNCATE, message, va);
va_end(va); va_end(va);
MessagePrint(channel, {buf}); MessagePrint(channel, {buf});

View File

@ -324,7 +324,7 @@ namespace Components
auto clientCount = 0; auto clientCount = 0;
auto maxClientCount = *Game::svs_clientCount; auto maxClientCount = *Game::svs_clientCount;
const auto securityLevel = Dvar::Var("sv_securityLevel").get<int>(); const auto securityLevel = Dvar::Var("sv_securityLevel").get<int>();
const auto* password = (*Game::g_password)->current.string; const auto* password = *Game::g_password ? (*Game::g_password)->current.string : "";
if (maxClientCount) if (maxClientCount)
{ {

View File

@ -46,7 +46,7 @@ namespace Components
void Playlist::PlaylistRequest(const Network::Address& address, [[maybe_unused]] const std::string& data) 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) if (*password)
{ {

View File

@ -136,7 +136,7 @@ namespace Components
Utils::InfoString ServerInfo::GetInfo() Utils::InfoString ServerInfo::GetInfo()
{ {
auto maxClientCount = *Game::svs_clientCount; 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) if (!maxClientCount)
{ {
@ -151,7 +151,7 @@ namespace Components
info.set("version", (*Game::version)->current.string); info.set("version", (*Game::version)->current.string);
info.set("mapname", (*Game::sv_mapname)->current.string); info.set("mapname", (*Game::sv_mapname)->current.string);
info.set("isPrivate", *password ? "1" : "0"); 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<bool>() ? "1" : "0")); info.set("aimAssist", (Gamepad::sv_allowAimAssist.get<bool>() ? "1" : "0"));
info.set("voiceChat", (Voice::SV_VoiceEnabled() ? "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_aimAssist").set(info.get("aimAssist") == "0" ? "@MENU_DISABLED" : "@MENU_ENABLED");
Dvar::Var("uiSi_voiceChat").set(info.get("voiceChat") == "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: default:
Dvar::Var("uiSi_ffType").set("@MENU_DISABLED"); Dvar::Var("uiSi_ffType").set("@MENU_DISABLED");
@ -276,12 +276,13 @@ namespace Components
break; 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; if (lines.size() <= 1) return;

View File

@ -8,7 +8,7 @@
namespace Components namespace Components
{ {
bool ServerList::SortAsc = true; bool ServerList::SortAsc = true;
int ServerList::SortKey = ServerList::Column::Ping; int ServerList::SortKey = static_cast<std::underlying_type_t<Column>>(Column::Ping);
unsigned int ServerList::CurrentServer = 0; unsigned int ServerList::CurrentServer = 0;
ServerList::Container ServerList::RefreshContainer; ServerList::Container ServerList::RefreshContainer;
@ -28,17 +28,19 @@ namespace Components
std::vector<ServerList::ServerInfo>* ServerList::GetList() std::vector<ServerList::ServerInfo>* 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; return nullptr;
@ -46,41 +48,41 @@ namespace Components
bool ServerList::IsFavouriteList() bool ServerList::IsFavouriteList()
{ {
return (Dvar::Var("ui_netSource").get<int>() == 2); return (*Game::ui_netSource)->current.integer == 2;
} }
bool ServerList::IsOfflineList() bool ServerList::IsOfflineList()
{ {
return (Dvar::Var("ui_netSource").get<int>() == 0); return (*Game::ui_netSource)->current.integer == 0;
} }
bool ServerList::IsOnlineList() bool ServerList::IsOnlineList()
{ {
return (Dvar::Var("ui_netSource").get<int>() == 1); return (*Game::ui_netSource)->current.integer == 1;
} }
unsigned int ServerList::GetServerCount() unsigned int ServerList::GetServerCount()
{ {
return ServerList::VisibleList.size(); return VisibleList.size();
} }
const char* ServerList::GetServerText(unsigned int index, int column) const char* ServerList::GetServerText(unsigned int index, int column)
{ {
ServerList::ServerInfo* info = ServerList::GetServer(index); auto* info = GetServer(index);
if (info) if (info)
{ {
return ServerList::GetServerInfoText(info, column); return GetServerInfoText(info, column);
} }
return ""; 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 ""; if (!server) return "";
switch (column) switch (static_cast<Column>(column))
{ {
case Column::Password: case Column::Password:
{ {
@ -115,12 +117,11 @@ namespace Components
{ {
return Utils::String::VA("^1%s", Game::UI_LocalizeMapName(server->mapname.data())); return Utils::String::VA("^1%s", Game::UI_LocalizeMapName(server->mapname.data()));
} }
return 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: case Column::Players:
@ -135,8 +136,9 @@ namespace Components
case Column::Mod: 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); return (server->mod.data() + 5);
} }
@ -149,20 +151,18 @@ namespace Components
{ {
return Utils::String::VA("^2%i", server->ping); 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); 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: default:
{ {
break; break;
}; }
} }
return ""; return "";
@ -170,75 +170,75 @@ namespace Components
void ServerList::SelectServer(unsigned int index) void ServerList::SelectServer(unsigned int index)
{ {
ServerList::CurrentServer = index; CurrentServer = index;
ServerList::ServerInfo* info = ServerList::GetCurrentServer(); auto* info = GetCurrentServer();
if (info) if (info)
{ {
ServerList::UIServerSelected.set(true); UIServerSelected.set(true);
ServerList::UIServerSelectedMap.set(info->mapname); UIServerSelectedMap.set(info->mapname);
Dvar::Var("ui_serverSelectedGametype").set(info->gametype); Dvar::Var("ui_serverSelectedGametype").set(info->gametype);
} }
else else
{ {
ServerList::UIServerSelected.set(false); UIServerSelected.set(false);
} }
} }
void ServerList::UpdateVisibleList([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) 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; if (!list) return;
std::vector<ServerList::ServerInfo> tempList(*list); std::vector tempList(*list);
if (tempList.empty()) if (tempList.empty())
{ {
ServerList::Refresh(UIScript::Token(), info); Refresh(UIScript::Token(), info);
} }
else else
{ {
list->clear(); list->clear();
std::lock_guard<std::recursive_mutex> _(ServerList::RefreshContainer.mutex); std::lock_guard _(RefreshContainer.mutex);
ServerList::RefreshContainer.sendCount = 0; RefreshContainer.sendCount = 0;
ServerList::RefreshContainer.sentCount = 0; RefreshContainer.sentCount = 0;
for (auto& server : tempList) 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) 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) 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 (!list) return;
if (refresh) if (refresh)
{ {
ServerList::Refresh(UIScript::Token(), info); Refresh(UIScript::Token(), info);
return; return;
} }
auto ui_browserShowFull = Dvar::Var("ui_browserShowFull").get<bool>(); auto ui_browserShowFull = Dvar::Var("ui_browserShowFull").get<bool>();
auto ui_browserShowEmpty = Dvar::Var("ui_browserShowEmpty").get<bool>(); auto ui_browserShowEmpty = Dvar::Var("ui_browserShowEmpty").get<bool>();
auto ui_browserShowHardcore = Dvar::Var("ui_browserKillcam").get<int>(); auto ui_browserShowHardcore = Dvar::Var("ui_browserKillcam").get<int>();
auto ui_browserShowPassword = Dvar::Var("ui_browserShowPassword").get<int>(); auto ui_browserShowPassword = Dvar::Var("ui_browserShowPassword").get<int>();
auto ui_browserMod = Dvar::Var("ui_browserMod").get<int>(); auto ui_browserMod = Dvar::Var("ui_browserMod").get<int>();
auto ui_joinGametype = Dvar::Var("ui_joinGametype").get<int>(); auto ui_joinGametype = (*Game::ui_joinGametype)->current.integer;
for (unsigned int i = 0; i < list->size(); ++i) 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; if ((ui_browserShowPassword == 0 && serverInfo->password) || (ui_browserShowPassword == 1 && !serverInfo->password)) continue;
// Don't show modded servers // 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<int>(serverInfo->mod.size())) || (ui_browserMod == 1 && serverInfo->mod.empty())) continue;
// Filter by gametype // Filter by gametype
if (ui_joinGametype > 0 && (ui_joinGametype - 1) < *Game::gameTypeCount && Game::gameTypes[(ui_joinGametype - 1)].gameType != serverInfo->gametype) continue; 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) 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); Dvar::Var("ui_serverSelected").set(false);
//Localization::Set("MPUI_SERVERQUERIED", "Sent requests: 0/0"); //Localization::Set("MPUI_SERVERQUERIED", "Sent requests: 0/0");
// ServerList::OnlineList.clear(); #if 0
// ServerList::OfflineList.clear(); OnlineList.clear();
// ServerList::FavouriteList.clear(); OfflineList.clear();
FavouriteList.clear();
auto list = ServerList::GetList(); #endif
auto* list = GetList();
if (list) list->clear(); if (list) list->clear();
ServerList::VisibleList.clear(); VisibleList.clear();
{ {
std::lock_guard<std::recursive_mutex> _(ServerList::RefreshContainer.mutex); std::lock_guard _(RefreshContainer.mutex);
ServerList::RefreshContainer.servers.clear(); RefreshContainer.servers.clear();
ServerList::RefreshContainer.sendCount = 0; RefreshContainer.sendCount = 0;
ServerList::RefreshContainer.sentCount = 0; RefreshContainer.sentCount = 0;
} }
if (ServerList::IsOfflineList()) if (IsOfflineList())
{ {
Discovery::Perform(); Discovery::Perform();
} }
else if (ServerList::IsOnlineList()) else if (IsOnlineList())
{ {
const auto masterPort = Dvar::Var("masterPort").get<int>(); const auto masterPort = Dvar::Var("masterPort").get<int>();
const auto masterServerName = Dvar::Var("masterServerName").get<const char*>(); const auto masterServerName = Dvar::Var("masterServerName").get<const char*>();
// Check if our dvars can properly convert to a address // Check if our dvars can properly convert to a address
Game::netadr_t masterServerAddr; Game::netadr_t masterServerAddr;
if (!ServerList::GetMasterServer(masterServerName, masterPort, masterServerAddr)) if (!GetMasterServer(masterServerName, masterPort, masterServerAddr))
{ {
Logger::Print("Could not resolve address for {}:{}", masterServerName, masterPort); 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; UseMasterServer = false;
return; return;
} }
@ -312,16 +313,16 @@ namespace Components
UseMasterServer = true; UseMasterServer = true;
ServerList::RefreshContainer.awatingList = true; RefreshContainer.awatingList = true;
ServerList::RefreshContainer.awaitTime = Game::Sys_Milliseconds(); RefreshContainer.awaitTime = Game::Sys_Milliseconds();
ServerList::RefreshContainer.host = Network::Address(Utils::String::VA("%s:%u", masterServerName, masterPort)); RefreshContainer.host = Network::Address(Utils::String::VA("%s:%u", masterServerName, masterPort));
Logger::Print("Sending serverlist request to master\n"); 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); const auto data = nlohmann::json(servers);
Utils::IO::WriteFile(FavouriteFile, data.dump()); Utils::IO::WriteFile(FavouriteFile, data.dump());
auto list = ServerList::GetList(); auto* list = GetList();
if (list) list->clear(); if (list) list->clear();
ServerList::RefreshVisibleListInternal(UIScript::Token(), nullptr); RefreshVisibleListInternal(UIScript::Token(), nullptr);
Game::ShowMessageBox("Server removed from favourites.", "Success"); Game::ShowMessageBox("Server removed from favourites.", "Success");
} }
void ServerList::LoadFavourties() void ServerList::LoadFavourties()
{ {
if (!ServerList::IsFavouriteList()) if (!IsFavouriteList())
{ {
return; return;
} }
auto list = ServerList::GetList(); auto* list = GetList();
if (list) list->clear(); if (list) list->clear();
const auto parseData = Utils::IO::ReadFile(FavouriteFile); const auto parseData = Utils::IO::ReadFile(FavouriteFile);
@ -455,20 +456,20 @@ namespace Components
for (const auto& server : servers) for (const auto& server : servers)
{ {
if (!server.is_string()) continue; if (!server.is_string()) continue;
ServerList::InsertRequest(server.get<std::string>()); InsertRequest(server.get<std::string>());
} }
} }
void ServerList::InsertRequest(Network::Address address) void ServerList::InsertRequest(Network::Address address)
{ {
std::lock_guard<std::recursive_mutex> _(ServerList::RefreshContainer.mutex); std::lock_guard _(RefreshContainer.mutex);
ServerList::Container::ServerContainer container; Container::ServerContainer container;
container.sent = false; container.sent = false;
container.target = address; container.target = address;
bool alreadyInserted = false; bool alreadyInserted = false;
for (auto &server : ServerList::RefreshContainer.servers) for (auto &server : RefreshContainer.servers)
{ {
if (server.target == container.target) if (server.target == container.target)
{ {
@ -479,34 +480,34 @@ namespace Components
if (!alreadyInserted) if (!alreadyInserted)
{ {
ServerList::RefreshContainer.servers.push_back(container); RefreshContainer.servers.push_back(container);
auto list = ServerList::GetList(); auto* list = GetList();
if (list) if (list)
{ {
for (auto& server : *list) for (auto& server : *list)
{ {
if (server.addr == container.target) if (server.addr == container.target)
{ {
--ServerList::RefreshContainer.sendCount; --RefreshContainer.sendCount;
--ServerList::RefreshContainer.sentCount; --RefreshContainer.sentCount;
break; break;
} }
} }
} }
++ServerList::RefreshContainer.sendCount; ++RefreshContainer.sendCount;
} }
} }
void ServerList::Insert(const Network::Address& address, const Utils::InfoString& info) void ServerList::Insert(const Network::Address& address, const Utils::InfoString& info)
{ {
std::lock_guard<std::recursive_mutex> _(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 // Our desired server
if (i->target == address && i->sent) if ((i->target == address) && i->sent)
{ {
// Challenge did not match // Challenge did not match
if (i->challenge != info.get("challenge")) if (i->challenge != info.get("challenge"))
@ -523,16 +524,16 @@ namespace Components
server.gametype = info.get("gametype"); server.gametype = info.get("gametype");
server.shortversion = info.get("shortversion"); server.shortversion = info.get("shortversion");
server.mod = info.get("fs_game"); server.mod = info.get("fs_game");
server.matchType = atoi(info.get("matchtype").data()); server.matchType = std::strtol(info.get("matchtype").data(), nullptr, 10);
server.clients = atoi(info.get("clients").data()); server.clients = std::strtol(info.get("clients").data(), nullptr, 10);
server.bots = atoi(info.get("bots").data()); server.bots = std::strtol(info.get("bots").data(), nullptr, 10);
server.securityLevel = atoi(info.get("securityLevel").data()); server.securityLevel = std::strtol(info.get("securityLevel").data(), nullptr, 10);
server.maxClients = atoi(info.get("sv_maxclients").data()); server.maxClients = std::strtol(info.get("sv_maxclients").data(), nullptr, 10);
server.password = (atoi(info.get("isPrivate").data()) != 0); server.password = info.get("isPrivate") == "1"s;
server.aimassist = (atoi(info.get("aimAssist").data()) != 0); server.aimassist = info.get("aimAssist") == "1";
server.voice = (atoi(info.get("voiceChat").data()) != 0); server.voice = info.get("voiceChat") == "1"s;
server.hardcore = (atoi(info.get("hc").data()) != 0); server.hardcore = info.get("hc") == "1"s;
server.svRunning = (atoi(info.get("sv_running").data()) != 0); server.svRunning = info.get("sv_running") == "1"s;
server.ping = (Game::Sys_Milliseconds() - i->sendTime); server.ping = (Game::Sys_Milliseconds() - i->sendTime);
server.addr = address; server.addr = address;
@ -542,18 +543,20 @@ namespace Components
server.mod = TextRenderer::StripMaterialTextIcons(server.mod); server.mod = TextRenderer::StripMaterialTextIcons(server.mod);
// Remove server from queue // 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 // Servers with more than 18 players or less than 0 players are faking for sure
// So lets ignore those // So lets ignore those
if (server.clients > 18 || server.maxClients > 18 || server.clients < 0 || server.maxClients < 0) if (server.clients > 18 || server.maxClients > 18 || server.clients < 0 || server.maxClients < 0)
{
return; return;
}
// Check if already inserted and remove // Check if already inserted and remove
auto list = ServerList::GetList(); auto* list = GetList();
if (!list) return; if (!list) return;
unsigned int k = 0; std::size_t k = 0;
for (auto j = list->begin(); j != list->end(); ++k) for (auto j = list->begin(); j != list->end(); ++k)
{ {
if (j->addr == address) if (j->addr == address)
@ -567,11 +570,11 @@ namespace Components
} }
// Also remove from visible list // 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) if (*j == k)
{ {
j = ServerList::VisibleList.erase(j); j = VisibleList.erase(j);
} }
else else
{ {
@ -581,15 +584,15 @@ namespace Components
if (info.get("gamename") == "IW4"s && server.matchType if (info.get("gamename") == "IW4"s && server.matchType
#if !defined(DEBUG) && defined(VERSION_FILTER) #if !defined(DEBUG) && defined(VERSION_FILTER)
&& ServerList::CompareVersion(server.shortversion, SHORTVERSION) && CompareVersion(server.shortversion, SHORTVERSION)
#endif #endif
) )
{ {
auto lList = ServerList::GetList(); auto* lList = GetList();
if (lList) if (lList)
{ {
lList->push_back(server); 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(); while (subVersions2.size() >= 3) subVersions2.pop_back();
if (subVersions1.size() != subVersions2.size()) return false; 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; return false;
} }
} }
@ -622,20 +633,20 @@ namespace Components
ServerList::ServerInfo* ServerList::GetCurrentServer() ServerList::ServerInfo* ServerList::GetCurrentServer()
{ {
return ServerList::GetServer(ServerList::CurrentServer); return GetServer(CurrentServer);
} }
void ServerList::SortList() void ServerList::SortList()
{ {
// Only sort when the serverlist is open // 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* info1 = nullptr;
ServerInfo* info2 = nullptr; ServerInfo* info2 = nullptr;
auto list = ServerList::GetList(); auto* list = GetList();
if (!list) return false; if (!list) return false;
if (list->size() > server1) info1 = &(*list)[server1]; if (list->size() > server1) info1 = &(*list)[server1];
@ -645,35 +656,36 @@ namespace Components
if (!info2) return false; if (!info2) return false;
// Numerical comparisons // Numerical comparisons
if (ServerList::SortKey == ServerList::Column::Ping) if (SortKey == static_cast<std::underlying_type_t<Column>>(Column::Ping))
{ {
return info1->ping < info2->ping; return info1->ping < info2->ping;
} }
else if (ServerList::SortKey == ServerList::Column::Players)
if (SortKey == static_cast<std::underlying_type_t<Column>>(Column::Players))
{ {
return info1->clients < info2->clients; return info1->clients < info2->clients;
} }
std::string text1 = Utils::String::ToLower(TextRenderer::StripColors(ServerList::GetServerInfoText(info1, ServerList::SortKey, true))); auto text1 = Utils::String::ToLower(TextRenderer::StripColors(GetServerInfoText(info1, SortKey, true)));
std::string text2 = Utils::String::ToLower(TextRenderer::StripColors(ServerList::GetServerInfoText(info2, ServerList::SortKey, true))); auto text2 = Utils::String::ToLower(TextRenderer::StripColors(GetServerInfoText(info2, SortKey, true)));
// ASCII-based comparison // ASCII-based comparison
return text1.compare(text2) < 0; 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) 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) 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() void ServerList::Frame()
{ {
static Utils::Time::Interval frameLimit; static Utils::Time::Interval frameLimit;
const auto interval = static_cast<int>(1000.0f / ServerList::NETServerFrames.get<int>()); const auto interval = static_cast<int>(1000.0f / static_cast<float>(NETServerFrames.get<int>()));
if (!frameLimit.elapsed(std::chrono::milliseconds(interval))) if (!frameLimit.elapsed(std::chrono::milliseconds(interval)))
{
return; return;
}
frameLimit.update(); frameLimit.update();
std::lock_guard<std::recursive_mutex> _(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 // 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 // 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); Logger::Print("We haven't received a response from the master within {} seconds!\n", (Game::Sys_Milliseconds() - RefreshContainer.awaitTime) / 1000);
Toast::Show("cardicon_headshot", "^1Error", "Failed to reach master server, using node servers instead.", 5000); Toast::Show("cardicon_headshot", "^3Warning", "Failed to reach master server. Using node system instead.", 5000);
UseMasterServer = false; UseMasterServer = false;
Node::Synchronize(); Node::Synchronize();
} }
} }
auto requestLimit = ServerList::NETServerQueryLimit.get<int>(); auto requestLimit = NETServerQueryLimit.get<int>();
for (unsigned int i = 0; i < ServerList::RefreshContainer.servers.size() && requestLimit > 0; ++i) 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; if (server->sent) continue;
// Found server we can send a request to // Found server we can send a request to
@ -726,47 +740,43 @@ namespace Components
server->sendTime = Game::Sys_Milliseconds(); server->sendTime = Game::Sys_Milliseconds();
server->challenge = Utils::Cryptography::Rand::GenerateChallenge(); server->challenge = Utils::Cryptography::Rand::GenerateChallenge();
++ServerList::RefreshContainer.sentCount; ++RefreshContainer.sentCount;
Network::SendCommand(server->target, "getinfo", server->challenge); 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)); //Localization::Set("MPUI_SERVERQUERIED", Utils::String::VA("Sent requests: %d/%d", ServerList::RefreshContainer.sentCount, ServerList::RefreshContainer.sendCount));
} }
ServerList::UpdateVisibleInfo(); UpdateVisibleInfo();
} }
void ServerList::UpdateSource() void ServerList::UpdateSource()
{ {
Dvar::Var netSource("ui_netSource"); auto source = (*Game::ui_netSource)->current.integer;
int source = netSource.get<int>(); if (++source > (*Game::ui_netSource)->domain.integer.max)
if (++source > netSource.get<Game::dvar_t*>()->domain.integer.max)
{ {
source = 0; 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() void ServerList::UpdateGameType()
{ {
Dvar::Var joinGametype("ui_joinGametype"); auto gametype = (*Game::ui_joinGametype)->current.integer;
int gametype = joinGametype.get<int>();
if (++gametype > *Game::gameTypeCount) if (++gametype > *Game::gameTypeCount)
{ {
gametype = 0; gametype = 0;
} }
joinGametype.set(gametype); Game::Dvar_SetInt(*Game::ui_joinGametype, gametype);
ServerList::RefreshVisibleListInternal(UIScript::Token(), nullptr); RefreshVisibleListInternal(UIScript::Token(), nullptr);
} }
void ServerList::UpdateVisibleInfo() void ServerList::UpdateVisibleInfo()
@ -775,7 +785,7 @@ namespace Components
static int players = 0; static int players = 0;
static int bots = 0; static int bots = 0;
auto list = ServerList::GetList(); auto list = GetList();
if (list) if (list)
{ {
@ -783,7 +793,7 @@ namespace Components
int newPlayers = 0; int newPlayers = 0;
int newBots = 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; newPlayers += list->at(i).clients;
newBots += list->at(i).bots; newBots += list->at(i).bots;
@ -816,47 +826,45 @@ namespace Components
ServerList::ServerList() ServerList::ServerList()
{ {
ServerList::OnlineList.clear(); OnlineList.clear();
ServerList::OfflineList.clear(); OfflineList.clear();
ServerList::FavouriteList.clear(); FavouriteList.clear();
ServerList::VisibleList.clear(); VisibleList.clear();
Scheduler::Once([] Scheduler::Once([]
{ {
ServerList::UIServerSelected = Dvar::Register<bool>("ui_serverSelected", false, UIServerSelected = Dvar::Register<bool>("ui_serverSelected", false,
Game::DVAR_NONE, "Whether a server has been selected in the serverlist"); Game::DVAR_NONE, "Whether a server has been selected in the serverlist");
ServerList::UIServerSelectedMap = Dvar::Register<const char*>("ui_serverSelectedMap", "mp_afghan", UIServerSelectedMap = Dvar::Register<const char*>("ui_serverSelectedMap", "mp_afghan",
Game::DVAR_NONE, "Map of the selected server"); Game::DVAR_NONE, "Map of the selected server");
ServerList::NETServerQueryLimit = Dvar::Register<int>("net_serverQueryLimit", 1, NETServerQueryLimit = Dvar::Register<int>("net_serverQueryLimit", 1,
1, 10, Dedicated::IsEnabled() ? Game::DVAR_NONE : Game::DVAR_ARCHIVE, "Amount of server queries per frame"); 1, 10, Dedicated::IsEnabled() ? Game::DVAR_NONE : Game::DVAR_ARCHIVE, "Amount of server queries per frame");
ServerList::NETServerFrames = Dvar::Register<int>("net_serverFrames", 30, NETServerFrames = Dvar::Register<int>("net_serverFrames", 30,
1, 60, Dedicated::IsEnabled() ? Game::DVAR_NONE : Game::DVAR_ARCHIVE, "Amount of server query frames per second"); 1, 60, Dedicated::IsEnabled() ? Game::DVAR_NONE : Game::DVAR_ARCHIVE, "Amount of server query frames per second");
}, Scheduler::Pipeline::MAIN); }, Scheduler::Pipeline::MAIN);
// Fix ui_netsource dvar // Fix ui_netsource dvar
Utils::Hook::Nop(0x4CDEEC, 5); // Don't reset the netsource when gametypes aren't loaded Utils::Hook::Nop(0x4CDEEC, 5); // Don't reset the netsource when gametypes aren't loaded
Dvar::Register<int>("ui_netSource", 1, 0, 2, Game::DVAR_ARCHIVE, reinterpret_cast<const char*>(0x6D9F08));
//Localization::Set("MPUI_SERVERQUERIED", "Sent requests: 0/0");
Localization::Set("MPUI_SERVERQUERIED", "Servers: 0\nPlayers: 0 (0)"); Localization::Set("MPUI_SERVERQUERIED", "Servers: 0\nPlayers: 0 (0)");
Network::OnClientPacket("getServersResponse", [](const Network::Address& address, [[maybe_unused]] const std::string& data) 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<std::recursive_mutex> _(ServerList::RefreshContainer.mutex); std::lock_guard _(RefreshContainer.mutex);
int offset = 0; int offset = 0;
int count = ServerList::RefreshContainer.servers.size(); auto count = RefreshContainer.servers.size();
ServerList::MasterEntry* entry = nullptr; MasterEntry* entry = nullptr;
// Find first entry // Find first entry
do do
{ {
entry = reinterpret_cast<ServerList::MasterEntry*>(const_cast<char*>(data.data()) + offset++); entry = reinterpret_cast<MasterEntry*>(const_cast<char*>(data.data()) + offset++);
} while (!entry->HasSeparator() && !entry->IsEndToken()); } while (!entry->HasSeparator() && !entry->IsEndToken());
for (int i = 0; !entry[i].IsEndToken() && entry[i].HasSeparator(); ++i) for (int i = 0; !entry[i].IsEndToken() && entry[i].HasSeparator(); ++i)
@ -866,29 +874,29 @@ namespace Components
serverAddr.setPort(ntohs(entry[i].port)); serverAddr.setPort(ntohs(entry[i].port));
serverAddr.setType(Game::NA_IP); 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 // Set default masterServerName + port and save it
Utils::Hook::Set<const char*>(0x60AD92, "master.xlabs.dev"); Utils::Hook::Set<const char*>(0x60AD92, "master.xlabs.dev");
Utils::Hook::Set<BYTE>(0x60AD90, Game::DVAR_NONE); // masterServerName Utils::Hook::Set<std::uint8_t>(0x60AD90, Game::DVAR_NONE); // masterServerName
Utils::Hook::Set<BYTE>(0x60ADC6, Game::DVAR_NONE); // masterPort Utils::Hook::Set<std::uint8_t>(0x60ADC6, Game::DVAR_NONE); // masterPort
// Add server list feeder // Add server list feeder
UIFeeder::Add(2.0f, ServerList::GetServerCount, ServerList::GetServerText, ServerList::SelectServer); UIFeeder::Add(2.0f, GetServerCount, GetServerText, SelectServer);
// Add required UIScripts // Add required UIScripts
UIScript::Add("UpdateFilter", ServerList::RefreshVisibleList); UIScript::Add("UpdateFilter", RefreshVisibleList);
UIScript::Add("RefreshFilter", ServerList::UpdateVisibleList); 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) 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) if (serverInfo)
{ {
Party::Connect(serverInfo->addr); 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) UIScript::Add("ServerSort", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{ {
auto key = token.get<int>(); const auto key = token.get<int>();
if (ServerList::SortKey == key) if (SortKey == key)
{ {
ServerList::SortAsc = !ServerList::SortAsc; SortAsc = !SortAsc;
} }
else else
{ {
ServerList::SortKey = key; SortKey = key;
ServerList::SortAsc = true; SortAsc = true;
} }
Logger::Print("Sorting server list by token: {}\n", ServerList::SortKey); Logger::Print("Sorting server list by token: {}\n", SortKey);
ServerList::SortList(); SortList();
}); });
UIScript::Add("CreateListFavorite", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) 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) 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) UIScript::Add("CreateFavorite", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{ {
ServerList::StoreFavourite(Dvar::Var("ui_favoriteAddress").get<std::string>()); StoreFavourite(Dvar::Var("ui_favoriteAddress").get<std::string>());
}); });
UIScript::Add("CreateCurrentServerFavorite", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) UIScript::Add("CreateCurrentServerFavorite", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{ {
if (Game::CL_IsCgameInitialized()) if (Game::CL_IsCgameInitialized())
{ {
std::string addressText = Network::Address(*Game::connectedHost).getString(); const auto addressText = Network::Address(*Game::connectedHost).getString();
if (addressText != "0.0.0.0:0" && addressText != "loopback") 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) 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) if (serverInfo)
{ {
ServerList::RemoveFavourite(serverInfo->addr.getString()); RemoveFavourite(serverInfo->addr.getString());
} }
}); });
@ -951,7 +959,7 @@ namespace Components
Command::Add("playerCount", [](Command::Params*) Command::Add("playerCount", [](Command::Params*)
{ {
auto count = 0; auto count = 0;
for (const auto& server : ServerList::OnlineList) for (const auto& server : OnlineList)
{ {
count += server.clients; count += server.clients;
} }
@ -960,17 +968,17 @@ namespace Components
}); });
#endif #endif
// Add required ownerDraws // Add required ownerDraws
UIScript::AddOwnerDraw(220, ServerList::UpdateSource); UIScript::AddOwnerDraw(220, UpdateSource);
UIScript::AddOwnerDraw(253, ServerList::UpdateGameType); UIScript::AddOwnerDraw(253, UpdateGameType);
// Add frame callback // Add frame callback
Scheduler::Loop(ServerList::Frame, Scheduler::Pipeline::CLIENT); Scheduler::Loop(Frame, Scheduler::Pipeline::CLIENT);
} }
ServerList::~ServerList() ServerList::~ServerList()
{ {
std::lock_guard<std::recursive_mutex> _(ServerList::RefreshContainer.mutex); std::lock_guard _(RefreshContainer.mutex);
ServerList::RefreshContainer.awatingList = false; RefreshContainer.awatingList = false;
ServerList::RefreshContainer.servers.clear(); RefreshContainer.servers.clear();
} }
} }

View File

@ -57,7 +57,7 @@ namespace Components
static bool UseMasterServer; static bool UseMasterServer;
private: private:
enum Column enum class Column : int
{ {
Password, Password,
Matchtype, Matchtype,
@ -69,6 +69,8 @@ namespace Components
Gametype, Gametype,
Mod, Mod,
Ping, Ping,
Count
}; };
static constexpr auto* FavouriteFile = "players/favourites.json"; static constexpr auto* FavouriteFile = "players/favourites.json";
@ -83,13 +85,13 @@ namespace Components
uint16_t port; uint16_t port;
}; };
bool IsEndToken() bool IsEndToken() const
{ {
// End of transmission or file token // End of transmission or file token
return (token[0] == 'E' && token[1] == 'O' && (token[2] == 'T' || token[2] == 'F')); return (token[0] == 'E' && token[1] == 'O' && (token[2] == 'T' || token[2] == 'F'));
} }
bool HasSeparator() bool HasSeparator() const
{ {
return (token[6] == '\\'); return (token[6] == '\\');
} }

View File

@ -22,6 +22,15 @@ namespace Game
Dvar_DisplayableValue_t Dvar_DisplayableValue = Dvar_DisplayableValue_t(0x4B5530); Dvar_DisplayableValue_t Dvar_DisplayableValue = Dvar_DisplayableValue_t(0x4B5530);
Dvar_Reset_t Dvar_Reset = Dvar_Reset_t(0x4FEFD0); 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<const dvar_t**>(0x1AD78E8); const dvar_t** com_developer = reinterpret_cast<const dvar_t**>(0x1AD78E8);
const dvar_t** com_developer_script = reinterpret_cast<const dvar_t**>(0x1AD8F10); const dvar_t** com_developer_script = reinterpret_cast<const dvar_t**>(0x1AD8F10);
const dvar_t** com_timescale = reinterpret_cast<const dvar_t**>(0x1AD7920); const dvar_t** com_timescale = reinterpret_cast<const dvar_t**>(0x1AD7920);
@ -61,7 +70,9 @@ namespace Game
const dvar_t** ui_currentMap = reinterpret_cast<const dvar_t**>(0x62E2834); const dvar_t** ui_currentMap = reinterpret_cast<const dvar_t**>(0x62E2834);
const dvar_t** ui_gametype = reinterpret_cast<const dvar_t**>(0x62E2828); const dvar_t** ui_gametype = reinterpret_cast<const dvar_t**>(0x62E2828);
const dvar_t** ui_mapname = reinterpret_cast<const dvar_t**>(0x62E279C); const dvar_t** ui_mapname = reinterpret_cast<const dvar_t**>(0x62E279C);
const dvar_t** ui_joinGametype = reinterpret_cast<const dvar_t**>(0x62E2840);
const dvar_t** ui_netGameType = reinterpret_cast<const dvar_t**>(0x62E2838); const dvar_t** ui_netGameType = reinterpret_cast<const dvar_t**>(0x62E2838);
const dvar_t** ui_netSource = reinterpret_cast<const dvar_t**>(0x62E27E8);
const dvar_t** loc_warnings = reinterpret_cast<const dvar_t**>(0x62C8700); const dvar_t** loc_warnings = reinterpret_cast<const dvar_t**>(0x62C8700);
const dvar_t** loc_warningsAsErrors = reinterpret_cast<const dvar_t**>(0x62C86FC); const dvar_t** loc_warningsAsErrors = reinterpret_cast<const dvar_t**>(0x62C86FC);

View File

@ -48,6 +48,9 @@ namespace Game
typedef void(*Dvar_SetBool_t)(const dvar_t* dvar, bool enabled); typedef void(*Dvar_SetBool_t)(const dvar_t* dvar, bool enabled);
extern Dvar_SetBool_t Dvar_SetBool; 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); typedef void(*Dvar_SetFloat_t)(const dvar_t* dvar, float value);
extern Dvar_SetFloat_t Dvar_SetFloat; extern Dvar_SetFloat_t Dvar_SetFloat;
@ -117,7 +120,9 @@ namespace Game
extern const dvar_t** ui_currentMap; extern const dvar_t** ui_currentMap;
extern const dvar_t** ui_gametype; extern const dvar_t** ui_gametype;
extern const dvar_t** ui_mapname; extern const dvar_t** ui_mapname;
extern const dvar_t** ui_joinGametype;
extern const dvar_t** ui_netGameType; extern const dvar_t** ui_netGameType;
extern const dvar_t** ui_netSource;
extern const dvar_t** loc_warnings; extern const dvar_t** loc_warnings;
extern const dvar_t** loc_warningsAsErrors; extern const dvar_t** loc_warningsAsErrors;

View File

@ -164,14 +164,6 @@ namespace Game
SEH_ReadCharFromString_t SEH_ReadCharFromString = SEH_ReadCharFromString_t(0x486560); SEH_ReadCharFromString_t SEH_ReadCharFromString = SEH_ReadCharFromString_t(0x486560);
SEH_GetCurrentLanguage_t SEH_GetCurrentLanguage = SEH_GetCurrentLanguage_t(0x4F6110); 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_Init_t SND_Init = SND_Init_t(0x46A630);
SND_InitDriver_t SND_InitDriver = SND_InitDriver_t(0x4F5090); SND_InitDriver_t SND_InitDriver = SND_InitDriver_t(0x4F5090);

View File

@ -19,8 +19,7 @@ namespace Utils
std::string InfoString::get(const std::string& key) const std::string InfoString::get(const std::string& key) const
{ {
const auto value = this->keyValuePairs.find(key); if (const auto value = this->keyValuePairs.find(key); value != this->keyValuePairs.end())
if (value != this->keyValuePairs.end())
{ {
return value->second; return value->second;
} }