Server info via http

This commit is contained in:
momo5502 2016-06-05 17:34:55 +02:00
parent 2b5a171668
commit 367b76b8df
6 changed files with 120 additions and 48 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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
{ {

View File

@ -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] == '\\')

View File

@ -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);