Serverlist sorting.
This commit is contained in:
parent
58ce9f0d17
commit
0d8538da2c
@ -27,6 +27,13 @@ namespace Components
|
|||||||
*out = '\0';
|
*out = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Colors::Strip(std::string in)
|
||||||
|
{
|
||||||
|
char buffer[1000] = { 0 }; // Should be more than enough
|
||||||
|
Colors::Strip(in.data(), buffer, sizeof(buffer));
|
||||||
|
return std::string(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
void __declspec(naked) Colors::ClientUserinfoChanged(int length)
|
void __declspec(naked) Colors::ClientUserinfoChanged(int length)
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
|
@ -9,6 +9,7 @@ namespace Components
|
|||||||
const char* GetName() { return "Colors"; };
|
const char* GetName() { return "Colors"; };
|
||||||
|
|
||||||
static void Strip(const char* in, char* out, int max);
|
static void Strip(const char* in, char* out, int max);
|
||||||
|
static std::string Strip(std::string in);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Dvar::Var NewColors;
|
static Dvar::Var NewColors;
|
||||||
|
@ -138,10 +138,8 @@ namespace Components
|
|||||||
// Don't perform any checks if name didn't change
|
// Don't perform any checks if name didn't change
|
||||||
if (name == lastValidName) return;
|
if (name == lastValidName) return;
|
||||||
|
|
||||||
char saneName[64] = { 0 };
|
std::string saneName = Colors::Strip(Utils::Trim(name));
|
||||||
Colors::Strip(Utils::Trim(name).data(), saneName, sizeof(saneName));
|
if (saneName.size() < 3 || (saneName[0] == '[' && saneName[1] == '{'))
|
||||||
|
|
||||||
if (strlen(saneName) < 3 || (saneName[0] == '[' && saneName[1] == '{'))
|
|
||||||
{
|
{
|
||||||
Logger::Print("Username '%s' is invalid. It must at least be 3 characters long and not appear empty!\n", name.data());
|
Logger::Print("Username '%s' is invalid. It must at least be 3 characters long and not appear empty!\n", name.data());
|
||||||
Dvar::Var("name").Set(lastValidName);
|
Dvar::Var("name").Set(lastValidName);
|
||||||
|
@ -2,56 +2,62 @@
|
|||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
|
bool ServerList::SortAsc = true;
|
||||||
|
int ServerList::SortKey = ServerList::Column::Ping;
|
||||||
unsigned int ServerList::CurrentServer = 0;
|
unsigned int ServerList::CurrentServer = 0;
|
||||||
ServerList::Container ServerList::RefreshContainer;
|
ServerList::Container ServerList::RefreshContainer;
|
||||||
std::vector<ServerList::ServerInfo> ServerList::OnlineList;
|
std::vector<ServerList::ServerInfo> ServerList::OnlineList;
|
||||||
|
std::vector<int> ServerList::VisibleList;
|
||||||
|
|
||||||
int ServerList::GetServerCount()
|
int ServerList::GetServerCount()
|
||||||
{
|
{
|
||||||
return ServerList::OnlineList.size();
|
return (int)ServerList::VisibleList.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* ServerList::GetServerText(int index, int column)
|
const char* ServerList::GetServerText(int index, int column)
|
||||||
{
|
{
|
||||||
if ((unsigned int)index >= ServerList::OnlineList.size()) return "";
|
return ServerList::GetServerText(ServerList::GetServer(index), column);
|
||||||
|
}
|
||||||
|
|
||||||
ServerList::ServerInfo* Server = &ServerList::OnlineList[index];
|
const char* ServerList::GetServerText(ServerList::ServerInfo* server, int column)
|
||||||
|
{
|
||||||
|
if (!server) return "";
|
||||||
|
|
||||||
switch (column)
|
switch (column)
|
||||||
{
|
{
|
||||||
case Column::Password:
|
case Column::Password:
|
||||||
{
|
{
|
||||||
return (Server->Password ? "X" : "");
|
return (server->Password ? "X" : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
case Column::Hostname:
|
case Column::Hostname:
|
||||||
{
|
{
|
||||||
return Server->Hostname.data();
|
return server->Hostname.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
case Column::Mapname:
|
case Column::Mapname:
|
||||||
{
|
{
|
||||||
return Game::UI_LocalizeMapName(Server->Mapname.data());
|
return Game::UI_LocalizeMapName(server->Mapname.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
case Column::Players:
|
case Column::Players:
|
||||||
{
|
{
|
||||||
return Utils::VA("%i (%i)", Server->Clients, Server->MaxClients);
|
return Utils::VA("%i (%i)", server->Clients, server->MaxClients);
|
||||||
}
|
}
|
||||||
|
|
||||||
case Column::Gametype:
|
case Column::Gametype:
|
||||||
{
|
{
|
||||||
if (Server->Mod != "")
|
if (server->Mod != "")
|
||||||
{
|
{
|
||||||
return (Server->Mod.data() + 5);
|
return (server->Mod.data() + 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Game::UI_LocalizeGameType(Server->Gametype.data());
|
return Game::UI_LocalizeGameType(server->Gametype.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
case Column::Ping:
|
case Column::Ping:
|
||||||
{
|
{
|
||||||
return Utils::VA("%i", Server->Ping);
|
return Utils::VA("%i", server->Ping);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,6 +72,7 @@ namespace Components
|
|||||||
void ServerList::Refresh()
|
void ServerList::Refresh()
|
||||||
{
|
{
|
||||||
ServerList::OnlineList.clear();
|
ServerList::OnlineList.clear();
|
||||||
|
ServerList::VisibleList.clear();
|
||||||
|
|
||||||
ServerList::RefreshContainer.Mutex.lock();
|
ServerList::RefreshContainer.Mutex.lock();
|
||||||
ServerList::RefreshContainer.Servers.clear();
|
ServerList::RefreshContainer.Servers.clear();
|
||||||
@ -123,7 +130,8 @@ namespace Components
|
|||||||
server.Addr = address;
|
server.Addr = address;
|
||||||
|
|
||||||
// Check if already inserted and remove
|
// Check if already inserted and remove
|
||||||
for (auto j = ServerList::OnlineList.begin(); j != ServerList::OnlineList.end(); j++)
|
int k = 0;
|
||||||
|
for (auto j = ServerList::OnlineList.begin(); j != ServerList::OnlineList.end(); j++, k++)
|
||||||
{
|
{
|
||||||
if (j->Addr == address)
|
if (j->Addr == address)
|
||||||
{
|
{
|
||||||
@ -132,9 +140,21 @@ namespace Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Also remove from visible list
|
||||||
|
for (auto j = ServerList::VisibleList.begin(); j != ServerList::VisibleList.end(); j++)
|
||||||
|
{
|
||||||
|
if (*j == k)
|
||||||
|
{
|
||||||
|
ServerList::VisibleList.erase(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (info.Get("gamename") == "IW4" && server.MatchType && server.Shortversion == VERSION_STR)
|
if (info.Get("gamename") == "IW4" && server.MatchType && server.Shortversion == VERSION_STR)
|
||||||
{
|
{
|
||||||
|
int index = ServerList::OnlineList.size();
|
||||||
ServerList::OnlineList.push_back(server);
|
ServerList::OnlineList.push_back(server);
|
||||||
|
ServerList::VisibleList.push_back(index);
|
||||||
|
ServerList::SortListByKey(ServerList::SortKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -144,6 +164,56 @@ namespace Components
|
|||||||
ServerList::RefreshContainer.Mutex.unlock();
|
ServerList::RefreshContainer.Mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ServerList::SortListByKey(int key)
|
||||||
|
{
|
||||||
|
static int column = 0;
|
||||||
|
column = key;
|
||||||
|
|
||||||
|
qsort(ServerList::VisibleList.data(), ServerList::VisibleList.size(), sizeof(int), [] (const void* first, const void* second)
|
||||||
|
{
|
||||||
|
int server1 = *(int*)first;
|
||||||
|
int server2 = *(int*)second;
|
||||||
|
|
||||||
|
ServerInfo* info1 = nullptr;
|
||||||
|
ServerInfo* info2 = nullptr;
|
||||||
|
|
||||||
|
if (ServerList::OnlineList.size() > (unsigned int)server1) info1 = &ServerList::OnlineList[server1];
|
||||||
|
if (ServerList::OnlineList.size() > (unsigned int)server2) info2 = &ServerList::OnlineList[server2];
|
||||||
|
|
||||||
|
if (!info1) return 1;
|
||||||
|
if (!info2) return -1;
|
||||||
|
|
||||||
|
// Numerical comparisons
|
||||||
|
if (column == ServerList::Column::Ping)
|
||||||
|
{
|
||||||
|
return ((info1->Ping - info2->Ping) * (ServerList::SortAsc ? 1 : -1));
|
||||||
|
}
|
||||||
|
else if (column == ServerList::Column::Players)
|
||||||
|
{
|
||||||
|
return ((info1->Clients - info2->Clients) * (ServerList::SortAsc ? 1 : -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string text1 = Colors::Strip(ServerList::GetServerText(info1, column));
|
||||||
|
std::string text2 = Colors::Strip(ServerList::GetServerText(info2, column));
|
||||||
|
|
||||||
|
// ASCII-based comparison
|
||||||
|
return (text1.compare(text2) * (ServerList::SortAsc ? 1 : -1));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerList::ServerInfo* ServerList::GetServer(int index)
|
||||||
|
{
|
||||||
|
if (ServerList::VisibleList.size() > (unsigned int)index)
|
||||||
|
{
|
||||||
|
if (ServerList::OnlineList.size() > (unsigned int)ServerList::VisibleList[index])
|
||||||
|
{
|
||||||
|
return &ServerList::OnlineList[ServerList::VisibleList[index]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void ServerList::Frame()
|
void ServerList::Frame()
|
||||||
{
|
{
|
||||||
ServerList::RefreshContainer.Mutex.lock();
|
ServerList::RefreshContainer.Mutex.lock();
|
||||||
@ -190,6 +260,7 @@ namespace Components
|
|||||||
ServerList::ServerList()
|
ServerList::ServerList()
|
||||||
{
|
{
|
||||||
ServerList::OnlineList.clear();
|
ServerList::OnlineList.clear();
|
||||||
|
ServerList::VisibleList.clear();
|
||||||
|
|
||||||
Network::Handle("getServersResponse", [] (Network::Address address, std::string data)
|
Network::Handle("getServersResponse", [] (Network::Address address, std::string data)
|
||||||
{
|
{
|
||||||
@ -244,7 +315,7 @@ namespace Components
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Set default masterServerName + port and save it
|
// Set default masterServerName + port and save it
|
||||||
Utils::Hook::Set<const char*>(0x60AD92, "localhost");
|
Utils::Hook::Set<char*>(0x60AD92, "localhost");
|
||||||
Utils::Hook::Set<BYTE>(0x60AD90, Game::dvar_flag::DVAR_FLAG_SAVED); // masterServerName
|
Utils::Hook::Set<BYTE>(0x60AD90, Game::dvar_flag::DVAR_FLAG_SAVED); // masterServerName
|
||||||
Utils::Hook::Set<BYTE>(0x60ADC6, Game::dvar_flag::DVAR_FLAG_SAVED); // masterPort
|
Utils::Hook::Set<BYTE>(0x60ADC6, Game::dvar_flag::DVAR_FLAG_SAVED); // masterPort
|
||||||
|
|
||||||
@ -255,14 +326,27 @@ namespace Components
|
|||||||
UIScript::Add("RefreshServers", ServerList::Refresh);
|
UIScript::Add("RefreshServers", ServerList::Refresh);
|
||||||
UIScript::Add("JoinServer", [] ()
|
UIScript::Add("JoinServer", [] ()
|
||||||
{
|
{
|
||||||
if (ServerList::OnlineList.size() > ServerList::CurrentServer)
|
if (ServerList::GetServer(ServerList::CurrentServer))
|
||||||
{
|
{
|
||||||
Party::Connect(ServerList::OnlineList[ServerList::CurrentServer].Addr);
|
Party::Connect(ServerList::GetServer(ServerList::CurrentServer)->Addr);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
UIScript::Add("ServerSort", [] (UIScript::Token token)
|
UIScript::Add("ServerSort", [] (UIScript::Token token)
|
||||||
{
|
{
|
||||||
Logger::Print("Server list sorting by token: %d\n", token.Get<int>());
|
int key = token.Get<int>();
|
||||||
|
|
||||||
|
if (ServerList::SortKey == key)
|
||||||
|
{
|
||||||
|
ServerList::SortAsc = !ServerList::SortAsc;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ServerList::SortKey = key;
|
||||||
|
ServerList::SortAsc = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::Print("Sorting server list by token: %d\n", ServerList::SortKey);
|
||||||
|
ServerList::SortListByKey(ServerList::SortKey);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add frame callback
|
// Add frame callback
|
||||||
@ -272,5 +356,6 @@ namespace Components
|
|||||||
ServerList::~ServerList()
|
ServerList::~ServerList()
|
||||||
{
|
{
|
||||||
ServerList::OnlineList.clear();
|
ServerList::OnlineList.clear();
|
||||||
|
ServerList::VisibleList.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,11 @@ namespace Components
|
|||||||
class ServerList : public Component
|
class ServerList : public Component
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
typedef int(SortCallback)(const void*, const void*);
|
||||||
|
|
||||||
struct ServerInfo
|
struct ServerInfo
|
||||||
{
|
{
|
||||||
Network::Address Addr;
|
Network::Address Addr;
|
||||||
bool Visible;
|
|
||||||
std::string Hostname;
|
std::string Hostname;
|
||||||
std::string Mapname;
|
std::string Mapname;
|
||||||
std::string Gametype;
|
std::string Gametype;
|
||||||
@ -84,12 +85,21 @@ namespace Components
|
|||||||
|
|
||||||
static int GetServerCount();
|
static int GetServerCount();
|
||||||
static const char* GetServerText(int index, int column);
|
static const char* GetServerText(int index, int column);
|
||||||
|
static const char* GetServerText(ServerInfo* server, int column);
|
||||||
static void SelectServer(int index);
|
static void SelectServer(int index);
|
||||||
|
|
||||||
static void Frame();
|
static void Frame();
|
||||||
|
|
||||||
|
static void SortListByKey(int key);
|
||||||
|
|
||||||
|
static ServerInfo* GetServer(int index);
|
||||||
|
|
||||||
|
static int SortKey;
|
||||||
|
static bool SortAsc;
|
||||||
|
|
||||||
static unsigned int CurrentServer;
|
static unsigned int CurrentServer;
|
||||||
static Container RefreshContainer;
|
static Container RefreshContainer;
|
||||||
static std::vector<ServerInfo> OnlineList;
|
static std::vector<ServerInfo> OnlineList;
|
||||||
|
static std::vector<int> VisibleList;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user