[ServerList]: Check for duplicates (#820)
This commit is contained in:
parent
a1112ed292
commit
c71eddc5a9
@ -471,7 +471,7 @@ namespace Components
|
||||
}
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
@ -167,8 +167,10 @@ namespace Components
|
||||
Scheduler::Once([]
|
||||
{
|
||||
auto* ent = Game::SV_AddTestClient();
|
||||
if (ent == nullptr)
|
||||
if (!ent)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Scheduler::Once([ent]
|
||||
{
|
||||
@ -232,7 +234,7 @@ namespace Components
|
||||
|
||||
const auto* weapon = Game::Scr_GetString(0);
|
||||
|
||||
if (weapon == nullptr || weapon[0] == '\0')
|
||||
if (!weapon || !*weapon)
|
||||
{
|
||||
g_botai[entref.entnum].weapon = 1;
|
||||
return;
|
||||
@ -255,7 +257,7 @@ namespace Components
|
||||
|
||||
const auto* action = Game::Scr_GetString(0);
|
||||
|
||||
if (action == nullptr)
|
||||
if (!action)
|
||||
{
|
||||
Game::Scr_ParamError(0, "^1BotAction: Illegal parameter!");
|
||||
return;
|
||||
@ -305,8 +307,10 @@ namespace Components
|
||||
|
||||
void Bots::BotAiAction(Game::client_t* cl)
|
||||
{
|
||||
if (cl->gentity == nullptr)
|
||||
if (!cl->gentity)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto entnum = cl->gentity->s.number;
|
||||
|
||||
|
@ -205,7 +205,7 @@ namespace Components::GSC
|
||||
{
|
||||
assert(ent);
|
||||
|
||||
if (ent->client == nullptr)
|
||||
if (!ent->client)
|
||||
{
|
||||
Game::Scr_ObjectError(Utils::String::VA("Entity %i is not a player", ent->s.number));
|
||||
return nullptr;
|
||||
|
@ -28,7 +28,7 @@ namespace Components::GSC
|
||||
assert(entref.entnum < Game::MAX_GENTITIES);
|
||||
|
||||
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));
|
||||
return nullptr;
|
||||
|
@ -34,7 +34,7 @@ namespace Components::GSC
|
||||
|
||||
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));
|
||||
return;
|
||||
|
@ -14,7 +14,7 @@ namespace Components::GSC
|
||||
const auto* key = Game::Scr_GetString(0);
|
||||
const auto* value = Game::Scr_GetString(1);
|
||||
|
||||
if (key == nullptr || value == nullptr)
|
||||
if (!key || !value)
|
||||
{
|
||||
Game::Scr_Error("^1StorageSet: Illegal parameters!");
|
||||
return;
|
||||
@ -27,7 +27,7 @@ namespace Components::GSC
|
||||
{
|
||||
const auto* key = Game::Scr_GetString(0);
|
||||
|
||||
if (key == nullptr)
|
||||
if (!key)
|
||||
{
|
||||
Game::Scr_ParamError(0, "^1StorageRemove: Illegal parameter!");
|
||||
return;
|
||||
@ -46,7 +46,7 @@ namespace Components::GSC
|
||||
{
|
||||
const auto* key = Game::Scr_GetString(0);
|
||||
|
||||
if (key == nullptr)
|
||||
if (!key)
|
||||
{
|
||||
Game::Scr_ParamError(0, "^1StorageGet: Illegal parameter!");
|
||||
return;
|
||||
@ -65,7 +65,7 @@ namespace Components::GSC
|
||||
{
|
||||
const auto* key = Game::Scr_GetString(0);
|
||||
|
||||
if (key == nullptr)
|
||||
if (!key)
|
||||
{
|
||||
Game::Scr_ParamError(0, "^1StorageHas: Illegal parameter!");
|
||||
return;
|
||||
|
@ -52,7 +52,7 @@ namespace Components::GSC
|
||||
const auto* ent = Game::GetPlayerEntity(entref);
|
||||
const auto* name = Game::Scr_GetString(0);
|
||||
|
||||
if (name == nullptr)
|
||||
if (!name)
|
||||
{
|
||||
Game::Scr_ParamError(0, "^1SetName: Illegal parameter!");
|
||||
return;
|
||||
@ -77,7 +77,7 @@ namespace Components::GSC
|
||||
const auto* ent = Game::GetPlayerEntity(entref);
|
||||
const auto* clanName = Game::Scr_GetString(0);
|
||||
|
||||
if (clanName == nullptr)
|
||||
if (!clanName)
|
||||
{
|
||||
Game::Scr_ParamError(0, "^1SetClanTag: Illegal parameter!");
|
||||
return;
|
||||
|
@ -96,7 +96,7 @@ namespace Components
|
||||
++(*Game::com_errorPrintsCount);
|
||||
MessagePrint(channel, msg);
|
||||
|
||||
if (Game::cls->uiStarted != 0 && (*Game::com_fixedConsolePosition == 0))
|
||||
if (Game::cls->uiStarted && (*Game::com_fixedConsolePosition == 0))
|
||||
{
|
||||
Game::CL_ConsoleFixPosition();
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ namespace Components
|
||||
}
|
||||
|
||||
const auto* dvar = Game::Dvar_FindVar(name);
|
||||
if (dvar == nullptr)
|
||||
if (!dvar)
|
||||
{
|
||||
// If it's not a dvar let it continue
|
||||
Game::CL_SelectStringTableEntryInDvar_f();
|
||||
|
@ -194,7 +194,7 @@ namespace Components
|
||||
auto* list = GetList();
|
||||
if (!list) return;
|
||||
|
||||
std::vector tempList(*list);
|
||||
const std::vector tempList(*list);
|
||||
|
||||
if (tempList.empty())
|
||||
{
|
||||
@ -209,7 +209,7 @@ namespace Components
|
||||
RefreshContainer.sendCount = 0;
|
||||
RefreshContainer.sentCount = 0;
|
||||
|
||||
for (auto& server : tempList)
|
||||
for (const auto& server : tempList)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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();
|
||||
if (list) list->clear();
|
||||
|
||||
@ -320,7 +314,7 @@ namespace Components
|
||||
RefreshContainer.awaitTime = Game::Sys_Milliseconds();
|
||||
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));
|
||||
}
|
||||
else if (IsFavouriteList())
|
||||
@ -417,8 +411,6 @@ namespace Components
|
||||
if (list) list->clear();
|
||||
|
||||
RefreshVisibleListInternal(UIScript::Token(), nullptr);
|
||||
|
||||
Game::ShowMessageBox("Server removed from favourites.", "Success");
|
||||
}
|
||||
|
||||
void ServerList::LoadFavourties()
|
||||
@ -471,7 +463,7 @@ namespace Components
|
||||
container.sent = false;
|
||||
container.target = address;
|
||||
|
||||
bool alreadyInserted = false;
|
||||
auto alreadyInserted = false;
|
||||
for (auto &server : RefreshContainer.servers)
|
||||
{
|
||||
if (server.target == container.target)
|
||||
@ -510,8 +502,12 @@ namespace Components
|
||||
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)
|
||||
{
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Challenge did not match
|
||||
if (i->challenge != info.get("challenge"))
|
||||
{
|
||||
@ -540,6 +536,9 @@ namespace Components
|
||||
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);
|
||||
@ -550,7 +549,7 @@ namespace Components
|
||||
|
||||
// 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)
|
||||
if (static_cast<std::size_t>(server.clients) > Game::MAX_CLIENTS || static_cast<std::size_t>(server.maxClients) > Game::MAX_CLIENTS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -593,16 +592,14 @@ namespace Components
|
||||
{
|
||||
auto* lList = GetList();
|
||||
if (lList)
|
||||
{
|
||||
if (!IsServerDuplicate(lList, server))
|
||||
{
|
||||
lList->push_back(server);
|
||||
RefreshVisibleListInternal(UIScript::Token(), nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -626,7 +623,7 @@ namespace Components
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -634,6 +631,19 @@ namespace Components
|
||||
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()
|
||||
{
|
||||
return GetServer(CurrentServer);
|
||||
@ -730,6 +740,7 @@ namespace Components
|
||||
}
|
||||
}
|
||||
|
||||
const auto challenge = Utils::Cryptography::Rand::GenerateChallenge();
|
||||
auto requestLimit = NETServerQueryLimit.get<int>();
|
||||
for (std::size_t i = 0; i < RefreshContainer.servers.size() && requestLimit > 0; ++i)
|
||||
{
|
||||
@ -741,14 +752,11 @@ namespace Components
|
||||
requestLimit--;
|
||||
|
||||
server->sendTime = Game::Sys_Milliseconds();
|
||||
server->challenge = Utils::Cryptography::Rand::GenerateChallenge();
|
||||
server->challenge = challenge;
|
||||
|
||||
++RefreshContainer.sentCount;
|
||||
|
||||
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();
|
||||
@ -784,17 +792,17 @@ namespace Components
|
||||
|
||||
void ServerList::UpdateVisibleInfo()
|
||||
{
|
||||
static int servers = 0;
|
||||
static int players = 0;
|
||||
static int bots = 0;
|
||||
static auto servers = 0;
|
||||
static auto players = 0;
|
||||
static auto bots = 0;
|
||||
|
||||
auto list = GetList();
|
||||
auto* list = GetList();
|
||||
|
||||
if (list)
|
||||
{
|
||||
int newSevers = list->size();
|
||||
int newPlayers = 0;
|
||||
int newBots = 0;
|
||||
auto newSevers = static_cast<int>(list->size());
|
||||
auto newPlayers = 0;
|
||||
auto newBots = 0;
|
||||
|
||||
for (std::size_t i = 0; i < list->size(); ++i)
|
||||
{
|
||||
@ -808,7 +816,7 @@ namespace Components
|
||||
players = newPlayers;
|
||||
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
|
||||
UIScript::AddOwnerDraw(220, UpdateSource);
|
||||
UIScript::AddOwnerDraw(253, UpdateGameType);
|
||||
@ -980,7 +976,7 @@ namespace Components
|
||||
Scheduler::Loop(Frame, Scheduler::Pipeline::CLIENT);
|
||||
}
|
||||
|
||||
ServerList::~ServerList()
|
||||
void ServerList::preDestroy()
|
||||
{
|
||||
std::lock_guard _(RefreshContainer.mutex);
|
||||
RefreshContainer.awatingList = false;
|
||||
|
@ -10,15 +10,15 @@ namespace Components
|
||||
public:
|
||||
typedef int(SortCallback)(const void*, const void*);
|
||||
|
||||
class ServerInfo
|
||||
struct ServerInfo
|
||||
{
|
||||
public:
|
||||
Network::Address addr;
|
||||
std::string hostname;
|
||||
std::string mapname;
|
||||
std::string gametype;
|
||||
std::string mod;
|
||||
std::string shortversion;
|
||||
std::size_t hash;
|
||||
int clients;
|
||||
int bots;
|
||||
int maxClients;
|
||||
@ -33,7 +33,8 @@ namespace Components
|
||||
};
|
||||
|
||||
ServerList();
|
||||
~ServerList();
|
||||
|
||||
void preDestroy() override;
|
||||
|
||||
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);
|
||||
@ -138,6 +139,7 @@ namespace Components
|
||||
static ServerInfo* GetServer(unsigned int index);
|
||||
|
||||
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 bool SortAsc;
|
||||
@ -159,3 +161,20 @@ namespace Components
|
||||
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
|
||||
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
|
||||
{
|
||||
MessageBoxA(nullptr,
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <cctype>
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <format>
|
||||
#include <fstream>
|
||||
|
@ -22,11 +22,11 @@ namespace Steam
|
||||
|
||||
if (!idBits)
|
||||
{
|
||||
if (Components::Dedicated::IsEnabled() || Components::ZoneBuilder::IsEnabled()) // Dedi guid
|
||||
if (Components::ZoneBuilder::IsEnabled())
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
@ -18,12 +18,14 @@ namespace Utils
|
||||
|
||||
std::string Rand::GenerateChallenge()
|
||||
{
|
||||
std::string challenge;
|
||||
challenge.append(String::VA("%X", GenerateInt()));
|
||||
challenge.append(String::VA("%X", ~timeGetTime() ^ GenerateInt()));
|
||||
challenge.append(String::VA("%X", GenerateInt()));
|
||||
char buffer[512]{};
|
||||
int buffer_pos = 0;
|
||||
|
||||
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()
|
||||
|
Loading…
Reference in New Issue
Block a user