diff --git a/src/Components/Modules/Download.cpp b/src/Components/Modules/Download.cpp index a4f54836..7937e97f 100644 --- a/src/Components/Modules/Download.cpp +++ b/src/Components/Modules/Download.cpp @@ -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(ev_data); + + Utils::InfoString status = ServerInfo::GetInfo(); + + std::map info; + info["status"] = status.to_json(); + + std::vector players; + + // Build player list + for (int i = 0; i < atoi(status.Get("sv_maxclients").data()); ++i) // Maybe choose 18 here? + { + std::map playerInfo; + playerInfo["score"] = 0; + playerInfo["ping"] = 0; + playerInfo["name"] = ""; + + if (Dvar::Var("sv_running").Get()) + { + 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(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) { // 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() & 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, "/file", Download::FileHandler); diff --git a/src/Components/Modules/Download.hpp b/src/Components/Modules/Download.hpp index 7e7db04f..4797aac4 100644 --- a/src/Components/Modules/Download.hpp +++ b/src/Components/Modules/Download.hpp @@ -13,6 +13,7 @@ namespace Components static void EventHandler(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 InfoHandler(mg_connection *nc, int ev, void *ev_data); static bool IsClient(mg_connection *nc); static Game::client_t* GetClient(mg_connection *nc); diff --git a/src/Components/Modules/ServerInfo.cpp b/src/Components/Modules/ServerInfo.cpp index 59c1b5d5..bed183da 100644 --- a/src/Components/Modules/ServerInfo.cpp +++ b/src/Components/Modules/ServerInfo.cpp @@ -100,6 +100,54 @@ namespace Components } } + Utils::InfoString ServerInfo::GetInfo() + { + int maxclientCount = *Game::svs_numclients; + + if (!maxclientCount) + { + //maxclientCount = Dvar::Var("sv_maxclients").Get(); + maxclientCount = Game::Party_GetMaxPlayers(*Game::partyIngame); + } + + Utils::InfoString info(Game::Dvar_InfoString_Big(1024)); + info.Set("gamename", "IW4"); + info.Set("sv_maxclients", Utils::VA("%i", maxclientCount)); + info.Set("protocol", Utils::VA("%i", PROTOCOL)); + info.Set("shortversion", VERSION_STR); + info.Set("mapname", Dvar::Var("mapname").Get()); + info.Set("isPrivate", (Dvar::Var("g_password").Get().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 + if (info.Get("mapname").empty()) + { + info.Set("mapname", Dvar::Var("ui_mapname").Get()); + } + + // Set matchtype + // 0 - No match, connecting not possible + // 1 - Party, use Steam_JoinLobby to connect + // 2 - Match, use CL_ConnectFromParty to connect + + if (Dvar::Var("party_enable").Get() && Dvar::Var("party_host").Get()) // Party hosting + { + info.Set("matchtype", "1"); + } + else if (Dvar::Var("sv_running").Get()) // Match hosting + { + info.Set("matchtype", "2"); + } + else + { + info.Set("matchtype", "0"); + } + + return info; + } + ServerInfo::ServerInfo() { ServerInfo::PlayerContainer.CurrentPlayer = 0; @@ -119,60 +167,18 @@ namespace Components Network::Handle("getStatus", [] (Network::Address address, std::string data) { - bool isInLobby = false; - int maxclientCount = *Game::svs_numclients; - - if(!maxclientCount) - { - isInLobby = true; - - //maxclientCount = Dvar::Var("sv_maxclients").Get(); - maxclientCount = Game::Party_GetMaxPlayers(*Game::partyIngame); - } - - Utils::InfoString info(Game::Dvar_InfoString_Big(1024)); - info.Set("challenge", Utils::ParseChallenge(data)); - info.Set("gamename", "IW4"); - info.Set("sv_maxclients", Utils::VA("%i", maxclientCount)); - info.Set("protocol", Utils::VA("%i", PROTOCOL)); - info.Set("shortversion", VERSION_STR); - info.Set("checksum", Utils::VA("%d", Game::Com_Milliseconds())); - info.Set("mapname", Dvar::Var("mapname").Get()); - info.Set("isPrivate", (Dvar::Var("g_password").Get().size() ? "1" : "0")); - - // Ensure mapname is set - if (info.Get("mapname").empty()) - { - info.Set("mapname", Dvar::Var("ui_mapname").Get()); - } - - // Set matchtype - // 0 - No match, connecting not possible - // 1 - Party, use Steam_JoinLobby to connect - // 2 - Match, use CL_ConnectFromParty to connect - - if (Dvar::Var("party_enable").Get() && Dvar::Var("party_host").Get()) // Party hosting - { - info.Set("matchtype", "1"); - } - else if (Dvar::Var("sv_running").Get()) // Match hosting - { - info.Set("matchtype", "2"); - } - else - { - info.Set("matchtype", "0"); - } - 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 ping = 0; std::string name; - if (!isInLobby) + if (Dvar::Var("sv_running").Get()) { if (Game::svs_clients[i].state < 3) continue; diff --git a/src/Components/Modules/ServerInfo.hpp b/src/Components/Modules/ServerInfo.hpp index c96d138b..4edaac3f 100644 --- a/src/Components/Modules/ServerInfo.hpp +++ b/src/Components/Modules/ServerInfo.hpp @@ -7,6 +7,8 @@ namespace Components ~ServerInfo(); const char* GetName() { return "ServerInfo"; }; + static Utils::InfoString GetInfo(); + private: struct Container { diff --git a/src/Utils/Utils.cpp b/src/Utils/Utils.cpp index bdea8266..d6afad73 100644 --- a/src/Utils/Utils.cpp +++ b/src/Utils/Utils.cpp @@ -235,6 +235,11 @@ namespace Utils } } + json11::Json InfoString::to_json() + { + return this->KeyValuePairs; + } + void InfoString::Parse(std::string buffer) { if (buffer[0] == '\\') diff --git a/src/Utils/Utils.hpp b/src/Utils/Utils.hpp index 190536fb..141f4796 100644 --- a/src/Utils/Utils.hpp +++ b/src/Utils/Utils.hpp @@ -37,6 +37,8 @@ namespace Utils void Dump(); + json11::Json to_json(); + private: std::map KeyValuePairs; void Parse(std::string buffer);