35 #include <rapidjson/document.h>
40 # include <curl/curl.h>
41 # include <curl/easy.h>
44 #if defined(_MSC_VER) && defined(GetObject) // This MS Windows macro from <wingdi.h> (Windows Kit 8.1) clashes with RapidJSON
54 size_t CurlWriteFunc(
void *ptr,
size_t size,
size_t nmemb, std::string* data)
56 data->append((
char*) ptr, size * nmemb);
62 std::string serverlist_url = portal_url +
"/server-list?json=true";
63 std::string response_payload;
64 std::string response_header;
65 long response_code = 0;
67 CURL *curl = curl_easy_init();
68 curl_easy_setopt(curl, CURLOPT_URL, serverlist_url.c_str());
70 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_payload);
71 curl_easy_setopt(curl, CURLOPT_HEADERDATA, &response_header);
73 CURLcode curl_result = curl_easy_perform(curl);
74 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
76 curl_easy_cleanup(curl);
79 if (curl_result != CURLE_OK || response_code != 200)
81 Ogre::LogManager::getSingleton().stream()
82 <<
"[RoR|Multiplayer] Failed to retrieve serverlist;"
83 <<
" Error: '" << curl_easy_strerror(curl_result) <<
"'; HTTP status code: " << response_code;
86 failinfo->
title =
_LC(
"MultiplayerSelector",
"Error connecting to server :(");
95 rapidjson::Document j_data_doc;
96 j_data_doc.Parse(response_payload.c_str());
97 if (j_data_doc.HasParseError() || !j_data_doc.IsArray())
99 Ogre::LogManager::getSingleton().stream()
100 <<
"[RoR|Multiplayer] Error parsing serverlist JSON";
107 size_t num_rows = j_data_doc.GetArray().Size();
110 servers.resize(num_rows);
111 for (
size_t i = 0; i < num_rows; ++i)
113 rapidjson::Value& j_row = j_data_doc[
static_cast<rapidjson::SizeType
>(i)];
115 servers[i].display_name = j_row[
"name"].GetString();
116 servers[i].display_terrn = j_row[
"terrain-name"].GetString();
117 servers[i].net_host = j_row[
"ip"].GetString();
118 servers[i].net_port = j_row[
"port"].GetInt();
120 servers[i].has_password = j_row[
"has-password"].GetBool();
121 servers[i].display_passwd = servers[i].has_password ?
_LC(
"MultiplayerSelector",
"Yes") :
_LC(
"MultiplayerSelector",
"No");
123 servers[i].display_host =
fmt::format(
"{}:{}", j_row[
"ip"].GetString(), j_row[
"port"].GetInt());
124 servers[i].display_users =
fmt::format(
"{} / {}", j_row[
"current-users"].GetInt(), j_row[
"max-clients"].GetInt());
126 servers[i].net_version = j_row[
"version"].GetString();
127 servers[i].display_version = Ogre::StringUtil::replaceAll(j_row[
"version"].GetString(),
"RoRnet_",
"");
133 #endif // defined(USE_CURL)
137 float table_padding_y = 4.f;
138 ImGui::SetCursorPosY(ImGui::GetCursorPosY() + table_padding_y);
139 ImGui::Text(
"%s", title);
152 ImGui::SetNextWindowPosCenter();
153 bool keep_open =
true;
203 ImGui::PushItemWidth(250.f);
213 ImHyperlink(
"https://forum.rigsofrods.org/account/user-token",
_LC(
"MultiplayerSelector",
"(Get token online)"));
214 ImGui::TextDisabled(
_LC(
"MultiplayerSelector",
"Never share your user token, even if someone is claiming to be an administrator."));
215 ImGui::PopItemWidth();
224 ImGui::PushItemWidth(250.f);
228 ImGui::PopItemWidth();
231 if (ImGui::Button(
_LC(
"MultiplayerSelector",
"Join")))
251 m_lock_icon = Ogre::TextureManager::getSingleton().load(
259 float spinner_size = 25.f;
260 ImGui::SetCursorPosX((ImGui::GetWindowSize().
x / 2.f) - spinner_size);
261 ImGui::SetCursorPosY((ImGui::GetWindowSize().
y / 2.f) - spinner_size);
269 const float table_height = ImGui::GetWindowHeight()
270 - ((2.f * ImGui::GetStyle().WindowPadding.y) + (3.f * ImGui::GetItemsLineHeightWithSpacing())
271 + ImGui::GetStyle().ItemSpacing.y);
272 ImGui::BeginChild(
"scrolling", ImVec2(0.f, table_height),
false);
274 const float table_width = ImGui::GetWindowContentRegionWidth();
313 ImGui::Image(
reinterpret_cast<ImTextureID
>(
m_lock_icon->getHandle()), ImVec2(16, 16));
318 ImVec4 version_color = compatible ? ImVec4(0.0f, 0.9f, 0.0f, 1.0f) : ImVec4(0.9f, 0.0f, 0.0f, 1.0f);
325 ImGui::PopStyleColor();
337 if (ImGui::Button(
_LC(
"MultiplayerSelector",
"Join"), ImVec2(200.f, 0.f)))
348 ImGui::PushItemWidth(250.f);
350 ImGui::PopItemWidth();
359 float y = (ImGui::GetWindowSize().y / 2.f) - (ImGui::GetTextLineHeight() / 2.f);
360 ImGui::SetCursorPosX((ImGui::GetWindowSize().
x / 2.f) - (label_size.x / 2.f));
361 ImGui::SetCursorPosY(
y);
363 y += ImGui::GetTextLineHeightWithSpacing();
368 ImGui::SetCursorPosX((ImGui::GetWindowSize().
x / 2.f) - (detail_size.x / 2.f));
369 ImGui::SetCursorPosY(
y);
371 y += ImGui::GetTextLineHeight();
377 ImGui::SetCursorPosX((ImGui::GetWindowSize().
x / 2.f) - (detail_size.x / 2.f));
378 ImGui::SetCursorPosY(
y);
386 #if defined(USE_CURL)
394 #endif // defined(USE_CURL)