Serverlist sorting.

This commit is contained in:
momo5502 2016-01-02 15:19:34 +01:00
parent 58ce9f0d17
commit 0d8538da2c
5 changed files with 122 additions and 21 deletions

View File

@ -27,6 +27,13 @@ namespace Components
*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)
{
__asm

View File

@ -9,6 +9,7 @@ namespace Components
const char* GetName() { return "Colors"; };
static void Strip(const char* in, char* out, int max);
static std::string Strip(std::string in);
private:
static Dvar::Var NewColors;

View File

@ -138,10 +138,8 @@ namespace Components
// Don't perform any checks if name didn't change
if (name == lastValidName) return;
char saneName[64] = { 0 };
Colors::Strip(Utils::Trim(name).data(), saneName, sizeof(saneName));
if (strlen(saneName) < 3 || (saneName[0] == '[' && saneName[1] == '{'))
std::string saneName = Colors::Strip(Utils::Trim(name));
if (saneName.size() < 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());
Dvar::Var("name").Set(lastValidName);

View File

@ -2,56 +2,62 @@
namespace Components
{
bool ServerList::SortAsc = true;
int ServerList::SortKey = ServerList::Column::Ping;
unsigned int ServerList::CurrentServer = 0;
ServerList::Container ServerList::RefreshContainer;
std::vector<ServerList::ServerInfo> ServerList::OnlineList;
std::vector<int> ServerList::VisibleList;
int ServerList::GetServerCount()
{
return ServerList::OnlineList.size();
return (int)ServerList::VisibleList.size();
}
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)
{
case Column::Password:
{
return (Server->Password ? "X" : "");
return (server->Password ? "X" : "");
}
case Column::Hostname:
{
return Server->Hostname.data();
return server->Hostname.data();
}
case Column::Mapname:
{
return Game::UI_LocalizeMapName(Server->Mapname.data());
return Game::UI_LocalizeMapName(server->Mapname.data());
}
case Column::Players:
{
return Utils::VA("%i (%i)", Server->Clients, Server->MaxClients);
return Utils::VA("%i (%i)", server->Clients, server->MaxClients);
}
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:
{
return Utils::VA("%i", Server->Ping);
return Utils::VA("%i", server->Ping);
}
}
@ -66,6 +72,7 @@ namespace Components
void ServerList::Refresh()
{
ServerList::OnlineList.clear();
ServerList::VisibleList.clear();
ServerList::RefreshContainer.Mutex.lock();
ServerList::RefreshContainer.Servers.clear();
@ -123,7 +130,8 @@ namespace Components
server.Addr = address;
// 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)
{
@ -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)
{
int index = ServerList::OnlineList.size();
ServerList::OnlineList.push_back(server);
ServerList::VisibleList.push_back(index);
ServerList::SortListByKey(ServerList::SortKey);
}
break;
@ -144,6 +164,56 @@ namespace Components
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()
{
ServerList::RefreshContainer.Mutex.lock();
@ -190,6 +260,7 @@ namespace Components
ServerList::ServerList()
{
ServerList::OnlineList.clear();
ServerList::VisibleList.clear();
Network::Handle("getServersResponse", [] (Network::Address address, std::string data)
{
@ -244,7 +315,7 @@ namespace Components
});
// 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>(0x60ADC6, Game::dvar_flag::DVAR_FLAG_SAVED); // masterPort
@ -255,14 +326,27 @@ namespace Components
UIScript::Add("RefreshServers", ServerList::Refresh);
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)
{
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
@ -272,5 +356,6 @@ namespace Components
ServerList::~ServerList()
{
ServerList::OnlineList.clear();
ServerList::VisibleList.clear();
}
}

View File

@ -3,10 +3,11 @@ namespace Components
class ServerList : public Component
{
public:
typedef int(SortCallback)(const void*, const void*);
struct ServerInfo
{
Network::Address Addr;
bool Visible;
std::string Hostname;
std::string Mapname;
std::string Gametype;
@ -84,12 +85,21 @@ namespace Components
static int GetServerCount();
static const char* GetServerText(int index, int column);
static const char* GetServerText(ServerInfo* server, int column);
static void SelectServer(int index);
static void Frame();
static void SortListByKey(int key);
static ServerInfo* GetServer(int index);
static int SortKey;
static bool SortAsc;
static unsigned int CurrentServer;
static Container RefreshContainer;
static std::vector<ServerInfo> OnlineList;
static std::vector<int> VisibleList;
};
}