mirror of
https://github.com/rock88/moonlight-nx
synced 2024-11-22 11:33:11 +00:00
Improve stream quit;
Start work on gamepad input...
This commit is contained in:
parent
a0eeffdb71
commit
b729ccff20
15 changed files with 186 additions and 42 deletions
2
Makefile
2
Makefile
|
@ -197,7 +197,7 @@ CXX_SOURCES = $(MOONLIGHT_LIBRETRO_CXX_SOURCES) $(NANOGUI_CXX_SOURCES)
|
|||
|
||||
OBJECTS := $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o)
|
||||
DEFINES += -DNANOGUI_USE_OPENGL -DNVG_STB_IMAGE_IMPLEMENTATION -DNANOGUI_NO_GLFW \
|
||||
-DHAS_SOCKLEN_T -DHAS_POLL -DHAS_FCNTL -D_GNU_SOURCE
|
||||
-DHAS_SOCKLEN_T -DHAS_POLL -DHAS_FCNTL -D_GNU_SOURCE -D__LIBRETRO__
|
||||
|
||||
CFLAGS += -Wall -pedantic $(fpic) -std=gnu11 $(DEFINES)
|
||||
CXXFLAGS += -std=gnu++17 -fno-permissive $(DEFINES)
|
||||
|
|
|
@ -560,6 +560,7 @@
|
|||
3652F046245C292B001FABF3 /* src */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3652F04E245C292B001FABF3 /* Limelight.h */,
|
||||
3652F047245C292B001FABF3 /* PlatformThreads.h */,
|
||||
3652F048245C292B001FABF3 /* Input.h */,
|
||||
3652F049245C292B001FABF3 /* ControlStream.c */,
|
||||
|
@ -567,7 +568,6 @@
|
|||
3652F04B245C292B001FABF3 /* Rtsp.h */,
|
||||
3652F04C245C292B001FABF3 /* SimpleStun.c */,
|
||||
3652F04D245C292B001FABF3 /* InputStream.c */,
|
||||
3652F04E245C292B001FABF3 /* Limelight.h */,
|
||||
3652F04F245C292B001FABF3 /* RtpFecQueue.h */,
|
||||
3652F050245C292B001FABF3 /* RtspConnection.c */,
|
||||
3652F051245C292B001FABF3 /* ByteBuffer.h */,
|
||||
|
@ -775,7 +775,7 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n\nmake DEBUG=1\n";
|
||||
shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n\n#make DEBUG=1\n";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
|
|
|
@ -41,12 +41,8 @@
|
|||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<PathRunnable
|
||||
runnableDebuggingMode = "0"
|
||||
BundleIdentifier = "libretro.RetroArch"
|
||||
FilePath = "/Applications/RetroArch.app">
|
||||
</PathRunnable>
|
||||
<MacroExpansion>
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "36DBDE8D2450BB7E0057C8D3"
|
||||
|
@ -54,7 +50,7 @@
|
|||
BlueprintName = "moonlight"
|
||||
ReferencedContainer = "container:moonlight.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument
|
||||
argument = "-L /Users/rock88/Documents/Projects/RetroArch/moonlight-libretro/moonlight_libretro.dylib"
|
||||
|
|
|
@ -124,7 +124,7 @@ void GameStreamClient::start(const std::string &address, STREAM_CONFIGURATION co
|
|||
|
||||
m_config = config;
|
||||
|
||||
perform_async([this, address, app_id, callback]() {
|
||||
perform_async([this, address, app_id, callback] {
|
||||
int status = gs_start_app(&m_server_data[address], &m_config, app_id, false, false, 0);
|
||||
|
||||
nanogui::async([this, callback, status] {
|
||||
|
@ -136,3 +136,22 @@ void GameStreamClient::start(const std::string &address, STREAM_CONFIGURATION co
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
void GameStreamClient::quit(const std::string &address, ServerCallback(bool) callback) {
|
||||
if (m_server_data.count(address) == 0) {
|
||||
callback(Result<bool>::failure("Firstly call connect() & pair()..."));
|
||||
return;
|
||||
}
|
||||
|
||||
perform_async([this, address, callback] {
|
||||
int status = gs_quit_app(&m_server_data[address]);
|
||||
|
||||
nanogui::async([this, callback, status] {
|
||||
if (status == GS_OK) {
|
||||
callback(Result<bool>::success(true));
|
||||
} else {
|
||||
callback(Result<bool>::failure(gs_error != NULL ? gs_error : "Unknown error..."));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@ public:
|
|||
void pair(const std::string &address, const std::string &pin, ServerCallback(bool) callback);
|
||||
void applist(const std::string &address, ServerCallback(PAPP_LIST) callback);
|
||||
void start(const std::string &address, STREAM_CONFIGURATION config, int app_id, ServerCallback(STREAM_CONFIGURATION) callback);
|
||||
void quit(const std::string &address, ServerCallback(bool) callback);
|
||||
|
||||
private:
|
||||
GameStreamClient() {};
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
#include "glsym/glsym.h"
|
||||
#include "Application.hpp"
|
||||
#include "GameStreamClient.hpp"
|
||||
#include "moonlight_libretro_wrapper.h"
|
||||
#include "gl_render.h"
|
||||
#include "libretro.h"
|
||||
|
||||
int main(int argc, const char * argv[]) {
|
||||
glfwInit();
|
||||
|
@ -37,6 +39,15 @@ int main(int argc, const char * argv[]) {
|
|||
nanogui::scroll_callback_event(x, y);
|
||||
});
|
||||
|
||||
glfwSetKeyCallback(window, [](GLFWwindow *w, int key, int scancode, int action, int mods) {
|
||||
if (GLFW_KEY_A <= key && key <= GLFW_KEY_Z) {
|
||||
keyboard_state[RETROK_a + key - GLFW_KEY_A] = action == GLFW_PRESS;
|
||||
}
|
||||
|
||||
keyboard_state[RETROK_w] ? game_pad_state.buttonFlags |= UP_FLAG : game_pad_state.buttonFlags &= ~UP_FLAG;
|
||||
keyboard_state[RETROK_s] ? game_pad_state.buttonFlags |= DOWN_FLAG : game_pad_state.buttonFlags &= ~DOWN_FLAG;
|
||||
});
|
||||
|
||||
int width, height, fb_width, fb_height;
|
||||
glfwGetWindowSize(window, &width, &height);
|
||||
glfwGetFramebufferSize(window, &fb_width, &fb_height);
|
||||
|
|
|
@ -38,7 +38,7 @@ static retro_audio_sample_t audio_cb;
|
|||
retro_audio_sample_batch_t audio_batch_cb;
|
||||
static retro_environment_t environ_cb;
|
||||
static retro_input_poll_t input_poll_cb;
|
||||
static retro_input_state_t input_state_cb;
|
||||
retro_input_state_t input_state_cb;
|
||||
static retro_log_printf_t log_cb;
|
||||
|
||||
void retro_init(void) {
|
||||
|
@ -159,6 +159,8 @@ void retro_run(void) {
|
|||
keyboard_state[i] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, i);
|
||||
}
|
||||
|
||||
moonlight_libretro_wrapper_handle_game_pad();
|
||||
|
||||
// Draw
|
||||
glBindFramebuffer(RARCH_GL_FRAMEBUFFER, hw_render.get_current_framebuffer());
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
#include "moonlight_libretro_wrapper.h"
|
||||
#include "libretro.h"
|
||||
#include "gl_render.h"
|
||||
#include "Application.hpp"
|
||||
#include "GameStreamClient.hpp"
|
||||
#include "gl_render.h"
|
||||
#include <openssl/ssl.h>
|
||||
#include "libretro.h"
|
||||
#include "Limelight.h"
|
||||
#include <curl/curl.h>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
static bool moonlight_is_initialized = false;
|
||||
|
||||
|
@ -12,6 +13,9 @@ static Application* app;
|
|||
static std::string working_dir;
|
||||
|
||||
int16_t keyboard_state[RETROK_LAST];
|
||||
struct GamePadState game_pad_state;
|
||||
|
||||
extern retro_input_state_t input_state_cb;
|
||||
|
||||
void moonlight_libretro_wrapper_preinit() {
|
||||
OpenSSL_add_all_algorithms();
|
||||
|
@ -32,7 +36,7 @@ void moonlight_libretro_wrapper_init(int width, int height) {
|
|||
nanogui::init();
|
||||
app = new Application(Size(width, height), Size(width, height));
|
||||
|
||||
nanogui::setup(1.0 / 60.0 * 1000);
|
||||
//nanogui::setup(1.0 / 60.0 * 1000); no needs anymore?
|
||||
}
|
||||
|
||||
void moonlight_libretro_wrapper_set_working_dir(const char* dir) {
|
||||
|
@ -49,6 +53,43 @@ void moonlight_libretro_wrapper_handle_mouse_button(int button, int action, int
|
|||
nanogui::mouse_button_callback_event(button, action, modifiers);
|
||||
}
|
||||
|
||||
static void set_game_pad_state(short flag, int16_t state) {
|
||||
if (state) {
|
||||
game_pad_state.buttonFlags |= flag;
|
||||
} else {
|
||||
game_pad_state.buttonFlags &= ~flag;
|
||||
}
|
||||
}
|
||||
|
||||
void moonlight_libretro_wrapper_handle_game_pad() {
|
||||
game_pad_state.leftStickX = input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X);
|
||||
game_pad_state.leftStickY = input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y);
|
||||
game_pad_state.rightStickX = input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X);
|
||||
game_pad_state.rightStickY = input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y);
|
||||
|
||||
#define GAME_PAD_STATE(KEY) \
|
||||
input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, KEY)
|
||||
|
||||
set_game_pad_state(UP_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_UP));
|
||||
set_game_pad_state(DOWN_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_DOWN));
|
||||
set_game_pad_state(LEFT_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_LEFT));
|
||||
set_game_pad_state(RIGHT_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_RIGHT));
|
||||
|
||||
set_game_pad_state(BACK_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_SELECT));
|
||||
set_game_pad_state(PLAY_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_START));
|
||||
|
||||
set_game_pad_state(A_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_A));
|
||||
set_game_pad_state(B_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_B));
|
||||
set_game_pad_state(X_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_X));
|
||||
set_game_pad_state(Y_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_Y));
|
||||
|
||||
set_game_pad_state(LB_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_L));
|
||||
set_game_pad_state(RB_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_R));
|
||||
|
||||
set_game_pad_state(LS_CLK_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_L3));
|
||||
set_game_pad_state(RS_CLK_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_R3));
|
||||
}
|
||||
|
||||
void moonlight_libretro_wrapper_draw() {
|
||||
nanogui::draw();
|
||||
}
|
||||
|
|
|
@ -9,9 +9,22 @@
|
|||
|
||||
EXTERN int16_t keyboard_state[];
|
||||
|
||||
struct GamePadState {
|
||||
short buttonFlags;
|
||||
unsigned char leftTrigger;
|
||||
unsigned char rightTrigger;
|
||||
short leftStickX;
|
||||
short leftStickY;
|
||||
short rightStickX;
|
||||
short rightStickY;
|
||||
};
|
||||
|
||||
EXTERN struct GamePadState game_pad_state;
|
||||
|
||||
EXTERN void moonlight_libretro_wrapper_preinit();
|
||||
EXTERN void moonlight_libretro_wrapper_init(int width, int height);
|
||||
EXTERN void moonlight_libretro_wrapper_set_working_dir(const char* dir);
|
||||
EXTERN void moonlight_libretro_wrapper_handle_mouse_move(double x, double y);
|
||||
EXTERN void moonlight_libretro_wrapper_handle_mouse_button(int button, int action, int modifiers);
|
||||
EXTERN void moonlight_libretro_wrapper_handle_game_pad();
|
||||
EXTERN void moonlight_libretro_wrapper_draw();
|
||||
|
|
|
@ -21,4 +21,9 @@ void Application::pop_window() {
|
|||
m_windows.back()->set_visible(true);
|
||||
perform_layout();
|
||||
}
|
||||
|
||||
if (m_windows.size() == 1) {
|
||||
auto main = static_cast<MainWindow *>(m_windows.front());
|
||||
main->reload();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ AddHostWindow::AddHostWindow(Widget *parent): ContentWindow(parent, "Add Host")
|
|||
loader->dispose();
|
||||
|
||||
if (result.isSuccess()) {
|
||||
m_host_added_callback(result.value());
|
||||
this->pop();
|
||||
} else {
|
||||
screen()->add<MessageDialog>(MessageDialog::Type::Information, "Error", result.error());
|
||||
}
|
||||
|
|
|
@ -5,9 +5,4 @@
|
|||
class AddHostWindow: public ContentWindow {
|
||||
public:
|
||||
AddHostWindow(Widget *parent);
|
||||
|
||||
void set_host_added_callback(const std::function<void(SERVER_DATA)> &callback) { m_host_added_callback = callback; }
|
||||
|
||||
private:
|
||||
std::function<void(SERVER_DATA)> m_host_added_callback;
|
||||
};
|
||||
|
|
|
@ -47,11 +47,7 @@ void MainWindow::reload() {
|
|||
auto button = container()->add<Button>("Add Host");
|
||||
button->set_fixed_size(Size(100, 100));
|
||||
button->set_callback([this] {
|
||||
auto add_host = application()->push_window<AddHostWindow>();
|
||||
add_host->set_host_added_callback([this](auto _) {
|
||||
this->reload();
|
||||
this->application()->pop_window();
|
||||
});
|
||||
application()->push_window<AddHostWindow>();
|
||||
});
|
||||
|
||||
screen()->perform_layout();
|
||||
|
|
|
@ -15,13 +15,19 @@ static int start_mouse_x = 0, start_mouse_y = 0;
|
|||
|
||||
using namespace nanogui;
|
||||
|
||||
static std::weak_ptr<StreamWindow *> _weak;
|
||||
|
||||
StreamWindow::StreamWindow(Widget *parent, const std::string &address, int app_id): Widget(parent) {
|
||||
_weak = std::make_shared<StreamWindow *>(this);
|
||||
|
||||
m_address = address;
|
||||
m_app_id = app_id;
|
||||
m_connection_status_is_poor = false;
|
||||
m_size = parent->size();
|
||||
|
||||
pressed = sent_l_press = sent_r_press = false;
|
||||
current_mouse_x = parent->width() / 2;
|
||||
current_mouse_y = parent->height() / 2;
|
||||
current_mouse_x = width() / 2;
|
||||
current_mouse_y = height() / 2;
|
||||
start_mouse_x = start_mouse_y = 0;
|
||||
|
||||
LiInitializeStreamConfiguration(&m_config);
|
||||
|
@ -54,8 +60,31 @@ StreamWindow::StreamWindow(Widget *parent, const std::string &address, int app_i
|
|||
|
||||
void StreamWindow::setup_stream() {
|
||||
perform_async([this] {
|
||||
CONNECTION_LISTENER_CALLBACKS connection_listener_callbacks = {
|
||||
.stageStarting = NULL,
|
||||
.stageComplete = NULL,
|
||||
.stageFailed = NULL,
|
||||
.connectionStarted = NULL,
|
||||
.connectionTerminated = [](int errorCode) {
|
||||
if (auto stream = _weak.lock()) {
|
||||
(*stream)->terminate();
|
||||
}
|
||||
},
|
||||
.logMessage = NULL,
|
||||
.rumble = NULL,
|
||||
.connectionStatusUpdate = [](int status) {
|
||||
if (auto stream = _weak.lock()) {
|
||||
if (status == CONN_STATUS_POOR) {
|
||||
(*stream)->m_connection_status_is_poor = true;
|
||||
} else {
|
||||
(*stream)->m_connection_status_is_poor = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
auto m_data = GameStreamClient::client()->server_data(m_address);
|
||||
LiStartConnection(&m_data.serverInfo, &m_config, NULL, &video_decoder_callbacks, &audio_decoder_callbacks, NULL, 0, NULL, 0);
|
||||
LiStartConnection(&m_data.serverInfo, &m_config, &connection_listener_callbacks, &video_decoder_callbacks, &audio_decoder_callbacks, NULL, 0, NULL, 0);
|
||||
|
||||
async([this] {
|
||||
if (m_loader) {
|
||||
|
@ -69,7 +98,7 @@ void StreamWindow::setup_stream() {
|
|||
void StreamWindow::draw(NVGcontext *ctx) {
|
||||
nvgSave(ctx);
|
||||
|
||||
gl_render_setup(1280, 720);
|
||||
gl_render_setup(width(), height());
|
||||
|
||||
if (frame != NULL) {
|
||||
gl_render_draw(frame->data);
|
||||
|
@ -77,23 +106,36 @@ void StreamWindow::draw(NVGcontext *ctx) {
|
|||
|
||||
nvgRestore(ctx);
|
||||
|
||||
if (m_connection_status_is_poor) {
|
||||
nvgFillColor(ctx, Color(255, 255, 255, 200));
|
||||
nvgFontSize(ctx, 20);
|
||||
nvgFontFace(ctx, "icons");
|
||||
nvgTextAlign(ctx, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
|
||||
nvgText(ctx, 20, height() - 30, utf8(FA_EXCLAMATION_TRIANGLE).data(), NULL);
|
||||
nvgFontFace(ctx, "sans-bold");
|
||||
nvgText(ctx, 50, height() - 28, "Bad connection...", NULL);
|
||||
}
|
||||
|
||||
// TODO: Get out of here...
|
||||
if (keyboard_state[RETROK_q]) {
|
||||
LiStopConnection();
|
||||
|
||||
async([this]{
|
||||
if (m_loader) {
|
||||
m_loader->dispose();
|
||||
m_loader = NULL;
|
||||
}
|
||||
|
||||
auto app = static_cast<Application *>(screen());
|
||||
app->pop_window();
|
||||
async([this] {
|
||||
this->terminate();
|
||||
});
|
||||
}
|
||||
|
||||
LiSendControllerEvent(
|
||||
game_pad_state.buttonFlags,
|
||||
game_pad_state.leftTrigger,
|
||||
game_pad_state.rightTrigger,
|
||||
game_pad_state.leftStickX,
|
||||
game_pad_state.leftStickY,
|
||||
game_pad_state.rightStickX,
|
||||
game_pad_state.rightStickY
|
||||
);
|
||||
}
|
||||
|
||||
bool StreamWindow::mouse_button_event(const nanogui::Vector2i &p, int button, bool down, int modifiers) {
|
||||
#if defined(__LIBRETRO__) && (defined(__LAKKA_SWITCH__) || defined(__APPLE__))
|
||||
if (button == 0) {
|
||||
if (down && !pressed) {
|
||||
start_mouse_x = p.x();
|
||||
|
@ -117,11 +159,18 @@ bool StreamWindow::mouse_button_event(const nanogui::Vector2i &p, int button, bo
|
|||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (button == 0) {
|
||||
LiSendMouseButtonEvent(down ? BUTTON_ACTION_PRESS : BUTTON_ACTION_RELEASE, BUTTON_LEFT);
|
||||
} else if (button == 1) {
|
||||
LiSendMouseButtonEvent(down ? BUTTON_ACTION_PRESS : BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StreamWindow::mouse_motion_event(const Vector2i &p, const Vector2i &rel, int button, int modifiers) {
|
||||
#if defined(__LAKKA_SWITCH__) || defined(__APPLE__)
|
||||
#if defined(__LIBRETRO__) && (defined(__LAKKA_SWITCH__) || defined(__APPLE__))
|
||||
if (pressed) {
|
||||
current_mouse_x = std::min(std::max(current_mouse_x + p.x() - start_mouse_x, 0), width());
|
||||
current_mouse_y = std::min(std::max(current_mouse_y + p.y() - start_mouse_y, 0), height());
|
||||
|
@ -136,3 +185,16 @@ bool StreamWindow::mouse_motion_event(const Vector2i &p, const Vector2i &rel, in
|
|||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void StreamWindow::terminate() {
|
||||
if (m_loader) {
|
||||
m_loader->dispose();
|
||||
m_loader = NULL;
|
||||
}
|
||||
|
||||
GameStreamClient::client()->quit(m_address, [](auto _) {});
|
||||
LiStopConnection();
|
||||
|
||||
auto app = static_cast<Application *>(screen());
|
||||
app->pop_window();
|
||||
}
|
||||
|
|
|
@ -14,9 +14,12 @@ public:
|
|||
bool mouse_button_event(const nanogui::Vector2i &p, int button, bool down, int modifiers) override;
|
||||
bool mouse_motion_event(const nanogui::Vector2i &p, const nanogui::Vector2i &rel, int button, int modifiers) override;
|
||||
|
||||
void terminate();
|
||||
|
||||
private:
|
||||
std::string m_address;
|
||||
int m_app_id;
|
||||
STREAM_CONFIGURATION m_config;
|
||||
LoadingOverlay* m_loader;
|
||||
bool m_connection_status_is_poor;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue