Server info via http
This commit is contained in:
parent
2b5a171668
commit
367b76b8df
@ -150,6 +150,61 @@ namespace Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Download::InfoHandler(mg_connection *nc, int ev, void *ev_data)
|
||||||
|
{
|
||||||
|
// Only handle http requests
|
||||||
|
if (ev != MG_EV_HTTP_REQUEST) return;
|
||||||
|
|
||||||
|
//http_message* message = reinterpret_cast<http_message*>(ev_data);
|
||||||
|
|
||||||
|
Utils::InfoString status = ServerInfo::GetInfo();
|
||||||
|
|
||||||
|
std::map<std::string, json11::Json> info;
|
||||||
|
info["status"] = status.to_json();
|
||||||
|
|
||||||
|
std::vector<json11::Json> players;
|
||||||
|
|
||||||
|
// Build player list
|
||||||
|
for (int i = 0; i < atoi(status.Get("sv_maxclients").data()); ++i) // Maybe choose 18 here?
|
||||||
|
{
|
||||||
|
std::map<std::string, json11::Json> playerInfo;
|
||||||
|
playerInfo["score"] = 0;
|
||||||
|
playerInfo["ping"] = 0;
|
||||||
|
playerInfo["name"] = "";
|
||||||
|
|
||||||
|
if (Dvar::Var("sv_running").Get<bool>())
|
||||||
|
{
|
||||||
|
if (Game::svs_clients[i].state < 3) continue;
|
||||||
|
|
||||||
|
playerInfo["score"] = Game::SV_GameClientNum_Score(i);
|
||||||
|
playerInfo["ping"] = Game::svs_clients[i].ping;
|
||||||
|
playerInfo["name"] = Game::svs_clients[i].name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Score and ping are irrelevant
|
||||||
|
const char* namePtr = Game::PartyHost_GetMemberName(reinterpret_cast<Game::PartyData_t*>(0x1081C00), i);
|
||||||
|
if (!namePtr || !namePtr[0]) continue;
|
||||||
|
|
||||||
|
playerInfo["name"] = namePtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
players.push_back(playerInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
info["players"] = players;
|
||||||
|
|
||||||
|
mg_printf(nc,
|
||||||
|
"HTTP/1.1 200 OK\r\n"
|
||||||
|
"Content-Type: application/json\r\n"
|
||||||
|
"Connection: close\r\n"
|
||||||
|
"Access-Control-Allow-Origin: *\r\n"
|
||||||
|
"\r\n"
|
||||||
|
"%s", json11::Json(info).dump().data());
|
||||||
|
|
||||||
|
nc->flags |= MG_F_SEND_AND_CLOSE;
|
||||||
|
}
|
||||||
|
|
||||||
void Download::EventHandler(mg_connection *nc, int ev, void *ev_data)
|
void Download::EventHandler(mg_connection *nc, int ev, void *ev_data)
|
||||||
{
|
{
|
||||||
// Only handle http requests
|
// Only handle http requests
|
||||||
@ -194,7 +249,8 @@ namespace Components
|
|||||||
{
|
{
|
||||||
mg_connection* nc = mg_bind(&Download::Mgr, Utils::VA("%hu", (Dvar::Var("net_port").Get<int>() & 0xFFFF)), Download::EventHandler);
|
mg_connection* nc = mg_bind(&Download::Mgr, Utils::VA("%hu", (Dvar::Var("net_port").Get<int>() & 0xFFFF)), Download::EventHandler);
|
||||||
|
|
||||||
// Handle list requests
|
// Handle special requests
|
||||||
|
mg_register_http_endpoint(nc, "/info", Download::InfoHandler);
|
||||||
mg_register_http_endpoint(nc, "/list", Download::ListHandler);
|
mg_register_http_endpoint(nc, "/list", Download::ListHandler);
|
||||||
mg_register_http_endpoint(nc, "/file", Download::FileHandler);
|
mg_register_http_endpoint(nc, "/file", Download::FileHandler);
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ namespace Components
|
|||||||
static void EventHandler(mg_connection *nc, int ev, void *ev_data);
|
static void EventHandler(mg_connection *nc, int ev, void *ev_data);
|
||||||
static void ListHandler(mg_connection *nc, int ev, void *ev_data);
|
static void ListHandler(mg_connection *nc, int ev, void *ev_data);
|
||||||
static void FileHandler(mg_connection *nc, int ev, void *ev_data);
|
static void FileHandler(mg_connection *nc, int ev, void *ev_data);
|
||||||
|
static void InfoHandler(mg_connection *nc, int ev, void *ev_data);
|
||||||
|
|
||||||
static bool IsClient(mg_connection *nc);
|
static bool IsClient(mg_connection *nc);
|
||||||
static Game::client_t* GetClient(mg_connection *nc);
|
static Game::client_t* GetClient(mg_connection *nc);
|
||||||
|
@ -100,46 +100,27 @@ namespace Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerInfo::ServerInfo()
|
Utils::InfoString ServerInfo::GetInfo()
|
||||||
{
|
{
|
||||||
ServerInfo::PlayerContainer.CurrentPlayer = 0;
|
|
||||||
ServerInfo::PlayerContainer.PlayerList.clear();
|
|
||||||
|
|
||||||
// Draw IP and hostname on the scoreboard
|
|
||||||
Utils::Hook(0x4FC6EA, ServerInfo::DrawScoreboardStub, HOOK_CALL).Install()->Quick();
|
|
||||||
|
|
||||||
// Ignore native getStatus implementation
|
|
||||||
Utils::Hook::Nop(0x62654E, 6);
|
|
||||||
|
|
||||||
// Add uiscript
|
|
||||||
UIScript::Add("ServerStatus", ServerInfo::ServerStatus);
|
|
||||||
|
|
||||||
// Add uifeeder
|
|
||||||
UIFeeder::Add(13.0f, ServerInfo::GetPlayerCount, ServerInfo::GetPlayerText, ServerInfo::SelectPlayer);
|
|
||||||
|
|
||||||
Network::Handle("getStatus", [] (Network::Address address, std::string data)
|
|
||||||
{
|
|
||||||
bool isInLobby = false;
|
|
||||||
int maxclientCount = *Game::svs_numclients;
|
int maxclientCount = *Game::svs_numclients;
|
||||||
|
|
||||||
if (!maxclientCount)
|
if (!maxclientCount)
|
||||||
{
|
{
|
||||||
isInLobby = true;
|
|
||||||
|
|
||||||
//maxclientCount = Dvar::Var("sv_maxclients").Get<int>();
|
//maxclientCount = Dvar::Var("sv_maxclients").Get<int>();
|
||||||
maxclientCount = Game::Party_GetMaxPlayers(*Game::partyIngame);
|
maxclientCount = Game::Party_GetMaxPlayers(*Game::partyIngame);
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::InfoString info(Game::Dvar_InfoString_Big(1024));
|
Utils::InfoString info(Game::Dvar_InfoString_Big(1024));
|
||||||
info.Set("challenge", Utils::ParseChallenge(data));
|
|
||||||
info.Set("gamename", "IW4");
|
info.Set("gamename", "IW4");
|
||||||
info.Set("sv_maxclients", Utils::VA("%i", maxclientCount));
|
info.Set("sv_maxclients", Utils::VA("%i", maxclientCount));
|
||||||
info.Set("protocol", Utils::VA("%i", PROTOCOL));
|
info.Set("protocol", Utils::VA("%i", PROTOCOL));
|
||||||
info.Set("shortversion", VERSION_STR);
|
info.Set("shortversion", VERSION_STR);
|
||||||
info.Set("checksum", Utils::VA("%d", Game::Com_Milliseconds()));
|
|
||||||
info.Set("mapname", Dvar::Var("mapname").Get<const char*>());
|
info.Set("mapname", Dvar::Var("mapname").Get<const char*>());
|
||||||
info.Set("isPrivate", (Dvar::Var("g_password").Get<std::string>().size() ? "1" : "0"));
|
info.Set("isPrivate", (Dvar::Var("g_password").Get<std::string>().size() ? "1" : "0"));
|
||||||
|
|
||||||
|
std::string time = Utils::VA("%u", Game::Com_Milliseconds());
|
||||||
|
info.Set("checksum", Utils::VA("%X", Utils::Cryptography::JenkinsOneAtATime::Compute(time.data(), time.size())));
|
||||||
|
|
||||||
// Ensure mapname is set
|
// Ensure mapname is set
|
||||||
if (info.Get("mapname").empty())
|
if (info.Get("mapname").empty())
|
||||||
{
|
{
|
||||||
@ -164,15 +145,40 @@ namespace Components
|
|||||||
info.Set("matchtype", "0");
|
info.Set("matchtype", "0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerInfo::ServerInfo()
|
||||||
|
{
|
||||||
|
ServerInfo::PlayerContainer.CurrentPlayer = 0;
|
||||||
|
ServerInfo::PlayerContainer.PlayerList.clear();
|
||||||
|
|
||||||
|
// Draw IP and hostname on the scoreboard
|
||||||
|
Utils::Hook(0x4FC6EA, ServerInfo::DrawScoreboardStub, HOOK_CALL).Install()->Quick();
|
||||||
|
|
||||||
|
// Ignore native getStatus implementation
|
||||||
|
Utils::Hook::Nop(0x62654E, 6);
|
||||||
|
|
||||||
|
// Add uiscript
|
||||||
|
UIScript::Add("ServerStatus", ServerInfo::ServerStatus);
|
||||||
|
|
||||||
|
// Add uifeeder
|
||||||
|
UIFeeder::Add(13.0f, ServerInfo::GetPlayerCount, ServerInfo::GetPlayerText, ServerInfo::SelectPlayer);
|
||||||
|
|
||||||
|
Network::Handle("getStatus", [] (Network::Address address, std::string data)
|
||||||
|
{
|
||||||
std::string playerList;
|
std::string playerList;
|
||||||
|
|
||||||
for (int i = 0; i < maxclientCount; ++i) // Maybe choose 18 here?
|
Utils::InfoString info = ServerInfo::GetInfo();
|
||||||
|
info.Set("challenge", Utils::ParseChallenge(data));
|
||||||
|
|
||||||
|
for (int i = 0; i < atoi(info.Get("sv_maxclients").data()); ++i) // Maybe choose 18 here?
|
||||||
{
|
{
|
||||||
int score = 0;
|
int score = 0;
|
||||||
int ping = 0;
|
int ping = 0;
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
if (!isInLobby)
|
if (Dvar::Var("sv_running").Get<bool>())
|
||||||
{
|
{
|
||||||
if (Game::svs_clients[i].state < 3) continue;
|
if (Game::svs_clients[i].state < 3) continue;
|
||||||
|
|
||||||
|
@ -7,6 +7,8 @@ namespace Components
|
|||||||
~ServerInfo();
|
~ServerInfo();
|
||||||
const char* GetName() { return "ServerInfo"; };
|
const char* GetName() { return "ServerInfo"; };
|
||||||
|
|
||||||
|
static Utils::InfoString GetInfo();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Container
|
struct Container
|
||||||
{
|
{
|
||||||
|
@ -235,6 +235,11 @@ namespace Utils
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
json11::Json InfoString::to_json()
|
||||||
|
{
|
||||||
|
return this->KeyValuePairs;
|
||||||
|
}
|
||||||
|
|
||||||
void InfoString::Parse(std::string buffer)
|
void InfoString::Parse(std::string buffer)
|
||||||
{
|
{
|
||||||
if (buffer[0] == '\\')
|
if (buffer[0] == '\\')
|
||||||
|
@ -37,6 +37,8 @@ namespace Utils
|
|||||||
|
|
||||||
void Dump();
|
void Dump();
|
||||||
|
|
||||||
|
json11::Json to_json();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::map<std::string, std::string> KeyValuePairs;
|
std::map<std::string, std::string> KeyValuePairs;
|
||||||
void Parse(std::string buffer);
|
void Parse(std::string buffer);
|
||||||
|
Loading…
Reference in New Issue
Block a user