[ServerList]: Check for duplicates (#820)
This commit is contained in:
parent
a1112ed292
commit
c71eddc5a9
@ -471,7 +471,7 @@ namespace Components
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const auto level = static_cast<uint32_t>(atoi(params->get(1)));
|
const auto level = std::strtoul(params->get(1), nullptr, 10);
|
||||||
Auth::IncreaseSecurityLevel(level);
|
Auth::IncreaseSecurityLevel(level);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -167,8 +167,10 @@ namespace Components
|
|||||||
Scheduler::Once([]
|
Scheduler::Once([]
|
||||||
{
|
{
|
||||||
auto* ent = Game::SV_AddTestClient();
|
auto* ent = Game::SV_AddTestClient();
|
||||||
if (ent == nullptr)
|
if (!ent)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Scheduler::Once([ent]
|
Scheduler::Once([ent]
|
||||||
{
|
{
|
||||||
@ -232,7 +234,7 @@ namespace Components
|
|||||||
|
|
||||||
const auto* weapon = Game::Scr_GetString(0);
|
const auto* weapon = Game::Scr_GetString(0);
|
||||||
|
|
||||||
if (weapon == nullptr || weapon[0] == '\0')
|
if (!weapon || !*weapon)
|
||||||
{
|
{
|
||||||
g_botai[entref.entnum].weapon = 1;
|
g_botai[entref.entnum].weapon = 1;
|
||||||
return;
|
return;
|
||||||
@ -255,7 +257,7 @@ namespace Components
|
|||||||
|
|
||||||
const auto* action = Game::Scr_GetString(0);
|
const auto* action = Game::Scr_GetString(0);
|
||||||
|
|
||||||
if (action == nullptr)
|
if (!action)
|
||||||
{
|
{
|
||||||
Game::Scr_ParamError(0, "^1BotAction: Illegal parameter!");
|
Game::Scr_ParamError(0, "^1BotAction: Illegal parameter!");
|
||||||
return;
|
return;
|
||||||
@ -305,8 +307,10 @@ namespace Components
|
|||||||
|
|
||||||
void Bots::BotAiAction(Game::client_t* cl)
|
void Bots::BotAiAction(Game::client_t* cl)
|
||||||
{
|
{
|
||||||
if (cl->gentity == nullptr)
|
if (!cl->gentity)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const auto entnum = cl->gentity->s.number;
|
const auto entnum = cl->gentity->s.number;
|
||||||
|
|
||||||
|
@ -205,7 +205,7 @@ namespace Components::GSC
|
|||||||
{
|
{
|
||||||
assert(ent);
|
assert(ent);
|
||||||
|
|
||||||
if (ent->client == nullptr)
|
if (!ent->client)
|
||||||
{
|
{
|
||||||
Game::Scr_ObjectError(Utils::String::VA("Entity %i is not a player", ent->s.number));
|
Game::Scr_ObjectError(Utils::String::VA("Entity %i is not a player", ent->s.number));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -28,7 +28,7 @@ namespace Components::GSC
|
|||||||
assert(entref.entnum < Game::MAX_GENTITIES);
|
assert(entref.entnum < Game::MAX_GENTITIES);
|
||||||
|
|
||||||
auto* ent = &Game::g_entities[entref.entnum];
|
auto* ent = &Game::g_entities[entref.entnum];
|
||||||
if (ent->client == nullptr)
|
if (!ent->client)
|
||||||
{
|
{
|
||||||
Game::Scr_ObjectError(Utils::String::VA("entity %i is not a player", entref.entnum));
|
Game::Scr_ObjectError(Utils::String::VA("entity %i is not a player", entref.entnum));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -34,7 +34,7 @@ namespace Components::GSC
|
|||||||
|
|
||||||
const auto* table = Game::DB_FindXAssetHeader(Game::ASSET_TYPE_STRINGTABLE, fileName).stringTable;
|
const auto* table = Game::DB_FindXAssetHeader(Game::ASSET_TYPE_STRINGTABLE, fileName).stringTable;
|
||||||
|
|
||||||
if (table == nullptr)
|
if (!table)
|
||||||
{
|
{
|
||||||
Game::Scr_ParamError(0, Utils::String::VA("%s does not exist", fileName));
|
Game::Scr_ParamError(0, Utils::String::VA("%s does not exist", fileName));
|
||||||
return;
|
return;
|
||||||
|
@ -14,7 +14,7 @@ namespace Components::GSC
|
|||||||
const auto* key = Game::Scr_GetString(0);
|
const auto* key = Game::Scr_GetString(0);
|
||||||
const auto* value = Game::Scr_GetString(1);
|
const auto* value = Game::Scr_GetString(1);
|
||||||
|
|
||||||
if (key == nullptr || value == nullptr)
|
if (!key || !value)
|
||||||
{
|
{
|
||||||
Game::Scr_Error("^1StorageSet: Illegal parameters!");
|
Game::Scr_Error("^1StorageSet: Illegal parameters!");
|
||||||
return;
|
return;
|
||||||
@ -27,7 +27,7 @@ namespace Components::GSC
|
|||||||
{
|
{
|
||||||
const auto* key = Game::Scr_GetString(0);
|
const auto* key = Game::Scr_GetString(0);
|
||||||
|
|
||||||
if (key == nullptr)
|
if (!key)
|
||||||
{
|
{
|
||||||
Game::Scr_ParamError(0, "^1StorageRemove: Illegal parameter!");
|
Game::Scr_ParamError(0, "^1StorageRemove: Illegal parameter!");
|
||||||
return;
|
return;
|
||||||
@ -46,7 +46,7 @@ namespace Components::GSC
|
|||||||
{
|
{
|
||||||
const auto* key = Game::Scr_GetString(0);
|
const auto* key = Game::Scr_GetString(0);
|
||||||
|
|
||||||
if (key == nullptr)
|
if (!key)
|
||||||
{
|
{
|
||||||
Game::Scr_ParamError(0, "^1StorageGet: Illegal parameter!");
|
Game::Scr_ParamError(0, "^1StorageGet: Illegal parameter!");
|
||||||
return;
|
return;
|
||||||
@ -65,7 +65,7 @@ namespace Components::GSC
|
|||||||
{
|
{
|
||||||
const auto* key = Game::Scr_GetString(0);
|
const auto* key = Game::Scr_GetString(0);
|
||||||
|
|
||||||
if (key == nullptr)
|
if (!key)
|
||||||
{
|
{
|
||||||
Game::Scr_ParamError(0, "^1StorageHas: Illegal parameter!");
|
Game::Scr_ParamError(0, "^1StorageHas: Illegal parameter!");
|
||||||
return;
|
return;
|
||||||
|
@ -52,7 +52,7 @@ namespace Components::GSC
|
|||||||
const auto* ent = Game::GetPlayerEntity(entref);
|
const auto* ent = Game::GetPlayerEntity(entref);
|
||||||
const auto* name = Game::Scr_GetString(0);
|
const auto* name = Game::Scr_GetString(0);
|
||||||
|
|
||||||
if (name == nullptr)
|
if (!name)
|
||||||
{
|
{
|
||||||
Game::Scr_ParamError(0, "^1SetName: Illegal parameter!");
|
Game::Scr_ParamError(0, "^1SetName: Illegal parameter!");
|
||||||
return;
|
return;
|
||||||
@ -77,7 +77,7 @@ namespace Components::GSC
|
|||||||
const auto* ent = Game::GetPlayerEntity(entref);
|
const auto* ent = Game::GetPlayerEntity(entref);
|
||||||
const auto* clanName = Game::Scr_GetString(0);
|
const auto* clanName = Game::Scr_GetString(0);
|
||||||
|
|
||||||
if (clanName == nullptr)
|
if (!clanName)
|
||||||
{
|
{
|
||||||
Game::Scr_ParamError(0, "^1SetClanTag: Illegal parameter!");
|
Game::Scr_ParamError(0, "^1SetClanTag: Illegal parameter!");
|
||||||
return;
|
return;
|
||||||
|
@ -96,7 +96,7 @@ namespace Components
|
|||||||
++(*Game::com_errorPrintsCount);
|
++(*Game::com_errorPrintsCount);
|
||||||
MessagePrint(channel, msg);
|
MessagePrint(channel, msg);
|
||||||
|
|
||||||
if (Game::cls->uiStarted != 0 && (*Game::com_fixedConsolePosition == 0))
|
if (Game::cls->uiStarted && (*Game::com_fixedConsolePosition == 0))
|
||||||
{
|
{
|
||||||
Game::CL_ConsoleFixPosition();
|
Game::CL_ConsoleFixPosition();
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ namespace Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto* dvar = Game::Dvar_FindVar(name);
|
const auto* dvar = Game::Dvar_FindVar(name);
|
||||||
if (dvar == nullptr)
|
if (!dvar)
|
||||||
{
|
{
|
||||||
// If it's not a dvar let it continue
|
// If it's not a dvar let it continue
|
||||||
Game::CL_SelectStringTableEntryInDvar_f();
|
Game::CL_SelectStringTableEntryInDvar_f();
|
||||||
|
@ -194,7 +194,7 @@ namespace Components
|
|||||||
auto* list = GetList();
|
auto* list = GetList();
|
||||||
if (!list) return;
|
if (!list) return;
|
||||||
|
|
||||||
std::vector tempList(*list);
|
const std::vector tempList(*list);
|
||||||
|
|
||||||
if (tempList.empty())
|
if (tempList.empty())
|
||||||
{
|
{
|
||||||
@ -209,7 +209,7 @@ namespace Components
|
|||||||
RefreshContainer.sendCount = 0;
|
RefreshContainer.sendCount = 0;
|
||||||
RefreshContainer.sentCount = 0;
|
RefreshContainer.sentCount = 0;
|
||||||
|
|
||||||
for (auto& server : tempList)
|
for (const auto& server : tempList)
|
||||||
{
|
{
|
||||||
InsertRequest(server.addr);
|
InsertRequest(server.addr);
|
||||||
}
|
}
|
||||||
@ -274,13 +274,7 @@ namespace Components
|
|||||||
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)
|
||||||
{
|
{
|
||||||
Dvar::Var("ui_serverSelected").set(false);
|
Dvar::Var("ui_serverSelected").set(false);
|
||||||
//Localization::Set("MPUI_SERVERQUERIED", "Sent requests: 0/0");
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
OnlineList.clear();
|
|
||||||
OfflineList.clear();
|
|
||||||
FavouriteList.clear();
|
|
||||||
#endif
|
|
||||||
auto* list = GetList();
|
auto* list = GetList();
|
||||||
if (list) list->clear();
|
if (list) list->clear();
|
||||||
|
|
||||||
@ -320,7 +314,7 @@ namespace Components
|
|||||||
RefreshContainer.awaitTime = Game::Sys_Milliseconds();
|
RefreshContainer.awaitTime = Game::Sys_Milliseconds();
|
||||||
RefreshContainer.host = Network::Address(std::format("{}:{}", masterServerName, masterPort));
|
RefreshContainer.host = Network::Address(std::format("{}:{}", masterServerName, masterPort));
|
||||||
|
|
||||||
Logger::Print("Sending serverlist request to master\n");
|
Logger::Print("Sending server list request to master\n");
|
||||||
Network::SendCommand(RefreshContainer.host, "getservers", std::format("IW4 {} full empty", PROTOCOL));
|
Network::SendCommand(RefreshContainer.host, "getservers", std::format("IW4 {} full empty", PROTOCOL));
|
||||||
}
|
}
|
||||||
else if (IsFavouriteList())
|
else if (IsFavouriteList())
|
||||||
@ -417,8 +411,6 @@ namespace Components
|
|||||||
if (list) list->clear();
|
if (list) list->clear();
|
||||||
|
|
||||||
RefreshVisibleListInternal(UIScript::Token(), nullptr);
|
RefreshVisibleListInternal(UIScript::Token(), nullptr);
|
||||||
|
|
||||||
Game::ShowMessageBox("Server removed from favourites.", "Success");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerList::LoadFavourties()
|
void ServerList::LoadFavourties()
|
||||||
@ -471,7 +463,7 @@ namespace Components
|
|||||||
container.sent = false;
|
container.sent = false;
|
||||||
container.target = address;
|
container.target = address;
|
||||||
|
|
||||||
bool alreadyInserted = false;
|
auto alreadyInserted = false;
|
||||||
for (auto &server : RefreshContainer.servers)
|
for (auto &server : RefreshContainer.servers)
|
||||||
{
|
{
|
||||||
if (server.target == container.target)
|
if (server.target == container.target)
|
||||||
@ -510,99 +502,104 @@ namespace Components
|
|||||||
for (auto i = RefreshContainer.servers.begin(); i != 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
|
++i;
|
||||||
if (i->challenge != info.get("challenge"))
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Challenge did not match
|
||||||
|
if (i->challenge != info.get("challenge"))
|
||||||
|
{
|
||||||
|
// Shall we remove the server from the queue?
|
||||||
|
// Better not, it might send a second response with the correct challenge.
|
||||||
|
// This might happen when users refresh twice (or more often) in a short period of time
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerInfo server;
|
||||||
|
server.hostname = info.get("hostname");
|
||||||
|
server.mapname = info.get("mapname");
|
||||||
|
server.gametype = info.get("gametype");
|
||||||
|
server.shortversion = info.get("shortversion");
|
||||||
|
server.mod = info.get("fs_game");
|
||||||
|
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;
|
||||||
|
|
||||||
|
std::hash<ServerInfo> hashFn;
|
||||||
|
server.hash = hashFn(server);
|
||||||
|
|
||||||
|
server.hostname = TextRenderer::StripMaterialTextIcons(server.hostname);
|
||||||
|
server.mapname = TextRenderer::StripMaterialTextIcons(server.mapname);
|
||||||
|
server.gametype = TextRenderer::StripMaterialTextIcons(server.gametype);
|
||||||
|
server.mod = TextRenderer::StripMaterialTextIcons(server.mod);
|
||||||
|
|
||||||
|
// Remove server from queue
|
||||||
|
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 (static_cast<std::size_t>(server.clients) > Game::MAX_CLIENTS || static_cast<std::size_t>(server.maxClients) > Game::MAX_CLIENTS)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if already inserted and remove
|
||||||
|
auto* list = GetList();
|
||||||
|
if (!list) return;
|
||||||
|
|
||||||
|
std::size_t k = 0;
|
||||||
|
for (auto j = list->begin(); j != list->end(); ++k)
|
||||||
|
{
|
||||||
|
if (j->addr == address)
|
||||||
{
|
{
|
||||||
// Shall we remove the server from the queue?
|
j = list->erase(j);
|
||||||
// Better not, it might send a second response with the correct challenge.
|
|
||||||
// This might happen when users refresh twice (or more often) in a short period of time
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
ServerInfo server;
|
|
||||||
server.hostname = info.get("hostname");
|
|
||||||
server.mapname = info.get("mapname");
|
|
||||||
server.gametype = info.get("gametype");
|
|
||||||
server.shortversion = info.get("shortversion");
|
|
||||||
server.mod = info.get("fs_game");
|
|
||||||
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;
|
|
||||||
|
|
||||||
server.hostname = TextRenderer::StripMaterialTextIcons(server.hostname);
|
|
||||||
server.mapname = TextRenderer::StripMaterialTextIcons(server.mapname);
|
|
||||||
server.gametype = TextRenderer::StripMaterialTextIcons(server.gametype);
|
|
||||||
server.mod = TextRenderer::StripMaterialTextIcons(server.mod);
|
|
||||||
|
|
||||||
// Remove server from queue
|
|
||||||
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;
|
++j;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if already inserted and remove
|
// Also remove from visible list
|
||||||
auto* list = GetList();
|
for (auto j = VisibleList.begin(); j != VisibleList.end();)
|
||||||
if (!list) return;
|
{
|
||||||
|
if (*j == k)
|
||||||
std::size_t k = 0;
|
|
||||||
for (auto j = list->begin(); j != list->end(); ++k)
|
|
||||||
{
|
{
|
||||||
if (j->addr == address)
|
j = VisibleList.erase(j);
|
||||||
{
|
|
||||||
j = list->erase(j);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
++j;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// Also remove from visible list
|
|
||||||
for (auto j = VisibleList.begin(); j != VisibleList.end();)
|
|
||||||
{
|
{
|
||||||
if (*j == k)
|
++j;
|
||||||
{
|
|
||||||
j = VisibleList.erase(j);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
++j;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
||||||
&& CompareVersion(server.shortversion, SHORTVERSION)
|
&& CompareVersion(server.shortversion, SHORTVERSION)
|
||||||
#endif
|
#endif
|
||||||
)
|
)
|
||||||
|
{
|
||||||
|
auto* lList = GetList();
|
||||||
|
if (lList)
|
||||||
{
|
{
|
||||||
auto* lList = GetList();
|
if (!IsServerDuplicate(lList, server))
|
||||||
if (lList)
|
|
||||||
{
|
{
|
||||||
lList->push_back(server);
|
lList->push_back(server);
|
||||||
RefreshVisibleListInternal(UIScript::Token(), nullptr);
|
RefreshVisibleListInternal(UIScript::Token(), nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -626,7 +623,7 @@ namespace Components
|
|||||||
}
|
}
|
||||||
catch (const std::exception& ex)
|
catch (const std::exception& ex)
|
||||||
{
|
{
|
||||||
Logger::Warning(Game::CON_CHANNEL_CONSOLEONLY, "{} while performing numeric comparison between {} and {}\n", ex.what(), subVersions1[i], subVersions2[i]);
|
Logger::PrintError(Game::CON_CHANNEL_ERROR, "{} while performing numeric comparison between {} and {}\n", ex.what(), subVersions1[i], subVersions2[i]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -634,6 +631,19 @@ namespace Components
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ServerList::IsServerDuplicate(const std::vector<ServerInfo>* list, const ServerInfo& server)
|
||||||
|
{
|
||||||
|
for (auto l = list->begin(); l != list->end(); ++l)
|
||||||
|
{
|
||||||
|
if (l->hash == server.hash)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ServerList::ServerInfo* ServerList::GetCurrentServer()
|
ServerList::ServerInfo* ServerList::GetCurrentServer()
|
||||||
{
|
{
|
||||||
return GetServer(CurrentServer);
|
return GetServer(CurrentServer);
|
||||||
@ -730,6 +740,7 @@ namespace Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto challenge = Utils::Cryptography::Rand::GenerateChallenge();
|
||||||
auto requestLimit = NETServerQueryLimit.get<int>();
|
auto requestLimit = NETServerQueryLimit.get<int>();
|
||||||
for (std::size_t i = 0; i < RefreshContainer.servers.size() && requestLimit > 0; ++i)
|
for (std::size_t i = 0; i < RefreshContainer.servers.size() && requestLimit > 0; ++i)
|
||||||
{
|
{
|
||||||
@ -741,14 +752,11 @@ namespace Components
|
|||||||
requestLimit--;
|
requestLimit--;
|
||||||
|
|
||||||
server->sendTime = Game::Sys_Milliseconds();
|
server->sendTime = Game::Sys_Milliseconds();
|
||||||
server->challenge = Utils::Cryptography::Rand::GenerateChallenge();
|
server->challenge = challenge;
|
||||||
|
|
||||||
++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 - Disabled to avoid spamming?
|
|
||||||
//Localization::Set("MPUI_SERVERQUERIED", Utils::String::VA("Sent requests: %d/%d", ServerList::RefreshContainer.sentCount, ServerList::RefreshContainer.sendCount));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateVisibleInfo();
|
UpdateVisibleInfo();
|
||||||
@ -784,17 +792,17 @@ namespace Components
|
|||||||
|
|
||||||
void ServerList::UpdateVisibleInfo()
|
void ServerList::UpdateVisibleInfo()
|
||||||
{
|
{
|
||||||
static int servers = 0;
|
static auto servers = 0;
|
||||||
static int players = 0;
|
static auto players = 0;
|
||||||
static int bots = 0;
|
static auto bots = 0;
|
||||||
|
|
||||||
auto list = GetList();
|
auto* list = GetList();
|
||||||
|
|
||||||
if (list)
|
if (list)
|
||||||
{
|
{
|
||||||
int newSevers = list->size();
|
auto newSevers = static_cast<int>(list->size());
|
||||||
int newPlayers = 0;
|
auto newPlayers = 0;
|
||||||
int newBots = 0;
|
auto newBots = 0;
|
||||||
|
|
||||||
for (std::size_t i = 0; i < list->size(); ++i)
|
for (std::size_t i = 0; i < list->size(); ++i)
|
||||||
{
|
{
|
||||||
@ -808,7 +816,7 @@ namespace Components
|
|||||||
players = newPlayers;
|
players = newPlayers;
|
||||||
bots = newBots;
|
bots = newBots;
|
||||||
|
|
||||||
Localization::Set("MPUI_SERVERQUERIED", Utils::String::VA("Servers: %i\nPlayers: %i (%i)", servers, players, bots));
|
Localization::Set("MPUI_SERVERQUERIED", std::format("Servers: {}\nPlayers: {} ({})", servers, players, bots));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -960,18 +968,6 @@ namespace Components
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
Command::Add("playerCount", [](Command::Params*)
|
|
||||||
{
|
|
||||||
auto count = 0;
|
|
||||||
for (const auto& server : OnlineList)
|
|
||||||
{
|
|
||||||
count += server.clients;
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger::Debug("There are {} players playing", count);
|
|
||||||
});
|
|
||||||
#endif
|
|
||||||
// Add required ownerDraws
|
// Add required ownerDraws
|
||||||
UIScript::AddOwnerDraw(220, UpdateSource);
|
UIScript::AddOwnerDraw(220, UpdateSource);
|
||||||
UIScript::AddOwnerDraw(253, UpdateGameType);
|
UIScript::AddOwnerDraw(253, UpdateGameType);
|
||||||
@ -980,7 +976,7 @@ namespace Components
|
|||||||
Scheduler::Loop(Frame, Scheduler::Pipeline::CLIENT);
|
Scheduler::Loop(Frame, Scheduler::Pipeline::CLIENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerList::~ServerList()
|
void ServerList::preDestroy()
|
||||||
{
|
{
|
||||||
std::lock_guard _(RefreshContainer.mutex);
|
std::lock_guard _(RefreshContainer.mutex);
|
||||||
RefreshContainer.awatingList = false;
|
RefreshContainer.awatingList = false;
|
||||||
|
@ -10,15 +10,15 @@ namespace Components
|
|||||||
public:
|
public:
|
||||||
typedef int(SortCallback)(const void*, const void*);
|
typedef int(SortCallback)(const void*, const void*);
|
||||||
|
|
||||||
class ServerInfo
|
struct ServerInfo
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
Network::Address addr;
|
Network::Address addr;
|
||||||
std::string hostname;
|
std::string hostname;
|
||||||
std::string mapname;
|
std::string mapname;
|
||||||
std::string gametype;
|
std::string gametype;
|
||||||
std::string mod;
|
std::string mod;
|
||||||
std::string shortversion;
|
std::string shortversion;
|
||||||
|
std::size_t hash;
|
||||||
int clients;
|
int clients;
|
||||||
int bots;
|
int bots;
|
||||||
int maxClients;
|
int maxClients;
|
||||||
@ -33,7 +33,8 @@ namespace Components
|
|||||||
};
|
};
|
||||||
|
|
||||||
ServerList();
|
ServerList();
|
||||||
~ServerList();
|
|
||||||
|
void preDestroy() override;
|
||||||
|
|
||||||
static void Refresh([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info);
|
static void Refresh([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info);
|
||||||
static void RefreshVisibleList([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info);
|
static void RefreshVisibleList([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info);
|
||||||
@ -138,6 +139,7 @@ namespace Components
|
|||||||
static ServerInfo* GetServer(unsigned int index);
|
static ServerInfo* GetServer(unsigned int index);
|
||||||
|
|
||||||
static bool CompareVersion(const std::string& version1, const std::string& version2);
|
static bool CompareVersion(const std::string& version1, const std::string& version2);
|
||||||
|
static bool IsServerDuplicate(const std::vector<ServerInfo>* list, const ServerInfo& server);
|
||||||
|
|
||||||
static int SortKey;
|
static int SortKey;
|
||||||
static bool SortAsc;
|
static bool SortAsc;
|
||||||
@ -159,3 +161,20 @@ namespace Components
|
|||||||
static bool IsServerListOpen();
|
static bool IsServerListOpen();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct std::hash<Components::ServerList::ServerInfo>
|
||||||
|
{
|
||||||
|
std::size_t operator()(const Components::ServerList::ServerInfo& x) const noexcept
|
||||||
|
{
|
||||||
|
std::size_t hash = 0;
|
||||||
|
|
||||||
|
hash ^= std::hash<std::string>()(x.hostname);
|
||||||
|
hash ^= std::hash<std::string>()(x.mapname);
|
||||||
|
hash ^= std::hash<std::string>()(x.mod);
|
||||||
|
hash ^= std::hash<std::uint32_t>()(*reinterpret_cast<const std::uint32_t*>(&x.addr.getIP().bytes[0]));;
|
||||||
|
hash ^= x.clients;
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -56,7 +56,7 @@ BOOL APIENTRY DllMain(HINSTANCE /*hinstDLL*/, DWORD fdwReason, LPVOID /*lpvReser
|
|||||||
|
|
||||||
#ifndef DEBUG_BINARY_CHECK
|
#ifndef DEBUG_BINARY_CHECK
|
||||||
const auto* binary = reinterpret_cast<const char*>(0x6F9358);
|
const auto* binary = reinterpret_cast<const char*>(0x6F9358);
|
||||||
if (binary == nullptr || std::memcmp(binary, BASEGAME_NAME, 14) != 0)
|
if (!binary || std::memcmp(binary, BASEGAME_NAME, 14) != 0)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
MessageBoxA(nullptr,
|
MessageBoxA(nullptr,
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <cstring>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
@ -22,11 +22,11 @@ namespace Steam
|
|||||||
|
|
||||||
if (!idBits)
|
if (!idBits)
|
||||||
{
|
{
|
||||||
if (Components::Dedicated::IsEnabled() || Components::ZoneBuilder::IsEnabled()) // Dedi guid
|
if (Components::ZoneBuilder::IsEnabled())
|
||||||
{
|
{
|
||||||
idBits = *reinterpret_cast<unsigned __int64*>(const_cast<char*>("DEDICATE"));
|
idBits = *reinterpret_cast<unsigned __int64*>(const_cast<char*>("DEDICATE"));
|
||||||
}
|
}
|
||||||
else if (Components::Singleton::IsFirstInstance()) // ECDSA guid
|
else if (Components::Singleton::IsFirstInstance() && !Components::Dedicated::IsEnabled()) // ECDSA guid
|
||||||
{
|
{
|
||||||
idBits = Components::Auth::GetKeyHash();
|
idBits = Components::Auth::GetKeyHash();
|
||||||
}
|
}
|
||||||
|
@ -18,12 +18,14 @@ namespace Utils
|
|||||||
|
|
||||||
std::string Rand::GenerateChallenge()
|
std::string Rand::GenerateChallenge()
|
||||||
{
|
{
|
||||||
std::string challenge;
|
char buffer[512]{};
|
||||||
challenge.append(String::VA("%X", GenerateInt()));
|
int buffer_pos = 0;
|
||||||
challenge.append(String::VA("%X", ~timeGetTime() ^ GenerateInt()));
|
|
||||||
challenge.append(String::VA("%X", GenerateInt()));
|
|
||||||
|
|
||||||
return challenge;
|
buffer_pos += sprintf_s(&buffer[buffer_pos], sizeof(buffer) - buffer_pos, "%X", GenerateInt());
|
||||||
|
buffer_pos += sprintf_s(&buffer[buffer_pos], sizeof(buffer) - buffer_pos, "%X", ~timeGetTime() ^ GenerateInt());
|
||||||
|
buffer_pos += sprintf_s(&buffer[buffer_pos], sizeof(buffer) - buffer_pos, "%X", GenerateInt());
|
||||||
|
|
||||||
|
return std::string(buffer, static_cast<std::size_t>(buffer_pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint32_t Rand::GenerateInt()
|
std::uint32_t Rand::GenerateInt()
|
||||||
|
Loading…
Reference in New Issue
Block a user