35#include <rapidjson/document.h>
40# include <curl/curl.h>
41# include <curl/easy.h>
44#if defined(_MSC_VER) && defined(GetObject)
54size_t CurlWriteFunc(
void *ptr,
size_t size,
size_t nmemb, std::string* data)
56 data->append((
char*) ptr, size * nmemb);
54size_t CurlWriteFunc(
void *ptr,
size_t size,
size_t nmemb, std::string* data) {
…}
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_",
"");
137 float table_padding_y = 4.f;
138 ImGui::SetCursorPosY(ImGui::GetCursorPosY() + table_padding_y);
139 ImGui::Text(
"%s", title);
150 int window_flags = ImGuiWindowFlags_NoCollapse;
151 ImGui::SetNextWindowSize(ImVec2(750.f, 400.f), ImGuiCond_FirstUseEver);
152 ImGui::SetNextWindowPosCenter();
153 bool keep_open =
true;
156 ImGui::BeginTabBar(
"GameSettingsTabs");
158 if (ImGui::BeginTabItem(
_LC(
"MultiplayerSelector",
"Online (click to refresh)")))
160 if (ImGui::IsItemClicked())
167 if (ImGui::BeginTabItem(
_LC(
"MultiplayerSelector",
"Direct IP")))
174 if (ImGui::BeginTabItem(
_LC(
"MultiplayerSelector",
"Settings"),
nullptr, settingstab_flags))
191 ImGui::PushID(
"setup");
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();
222 ImGui::PushID(
"direct");
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();
275 ImGui::Columns(5,
"mp-selector-columns");
276 ImGui::SetColumnOffset(1, 0.36f * table_width);
277 ImGui::SetColumnOffset(2, 0.67f * table_width);
278 ImGui::SetColumnOffset(3, 0.74f * table_width);
279 ImGui::SetColumnOffset(4, 0.82f * table_width);
301 if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(0))
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);
321 ImGui::Text(
"%s", server.
display_terrn.c_str()); ImGui::NextColumn();
322 ImGui::Text(
"%s", server.
display_users.c_str()); ImGui::NextColumn();
323 ImGui::PushStyleColor(ImGuiCol_Text, version_color);
324 ImGui::Text(
"%s", server.
display_version.c_str()); ImGui::NextColumn();
325 ImGui::PopStyleColor();
326 ImGui::Text(
"%s", server.
display_host.c_str()); ImGui::NextColumn();
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);
Central state/object manager and communications hub.
size_t CurlWriteFunc(void *ptr, size_t size, size_t nmemb, std::string *data)
void FetchServerlist(std::string portal_url)
void DrawTableHeader(const char *title)
Game state manager and message-queue provider.
const char *const ROR_VERSION_STRING
std::string const & getStr() const
void setStr(std::string const &str)
void AddResourcePack(ResourcePack const &resource_pack, std::string const &override_rgn="")
Loads resources if not already loaded.
const float BUTTONS_EXTRA_SPACE
std::string m_serverlist_httpmsg
Displayed as dimmed text.
ImVec4 m_serverlist_msg_color
void DisplayRefreshFailed(CurlFailInfo *failinfo)
void StartAsyncRefresh()
Launch refresh from main thread.
std::string m_serverlist_curlmsg
Displayed as dimmed text.
Str< 1000 > m_user_token_buf
Str< 1000 > m_password_buf
void UpdateServerlist(MpServerInfoVec *data)
const float TABLE_PADDING_LEFT
bool m_set_settings_tab_selected
Str< 1000 > m_server_host_buf
MpServerInfoVec m_serverlist_data
Ogre::TexturePtr m_lock_icon
Str< 1000 > m_player_name_buf
std::string m_serverlist_msg
GUI::GameMainMenu GameMainMenu
void PushMessage(Message m)
Doesn't guarantee order! Use ChainMessage() if order matters.
size_t GetCapacity() const
@ MSG_NET_CONNECT_REQUESTED
@ MSG_NET_REFRESH_SERVERLIST_FAILURE
Payload = RoR::CurlFailInfo* (owner)
@ MSG_NET_REFRESH_SERVERLIST_SUCCESS
Payload = GUI::MpServerInfoVec* (owner)
CVar * mp_server_password
ContentManager * GetContentManager()
CVar * mp_hide_own_net_label
CVar * mp_hide_net_labels
CVar * mp_cyclethru_net_actors
Include remote actors when cycling through with CTRL + [ and CTRL + ].
GUIManager * GetGuiManager()
GameContext * GetGameContext()
CVar * mp_pseudo_collisions
CVar * mp_join_on_startup
std::vector< MpServerInfo > MpServerInfoVec
void DrawGTextEdit(CVar *cvar, const char *label, Str< 1000 > &buf)
void ImHyperlink(std::string url, std::string caption="", bool tooltip=true)
Full-featured hypertext with tooltip showing full URL.
void DrawGIntBox(CVar *cvar, const char *label)
bool DrawGCheckbox(CVar *cvar, const char *label)
void LoadingIndicatorCircle(const char *label, const float indicator_radius, const ImVec4 &main_color, const ImVec4 &backdrop_color, const int circle_count, const float speed)
Draws animated loading spinner.
static const ResourcePack FAMICONS
std::string display_version
std::string display_users
std::string display_terrn
ImVec4 value_blue_text_color
ImVec4 no_entries_text_color
Unified game event system - all requests and state changes are reported using a message.