diff --git a/modules/blazium_sdk/SCsub b/modules/blazium_sdk/SCsub
index 47e18716d56d..2feda23b8a92 100644
--- a/modules/blazium_sdk/SCsub
+++ b/modules/blazium_sdk/SCsub
@@ -5,4 +5,7 @@ Import("env_modules")
env_blazium_sdk = env_modules.Clone()
env_blazium_sdk.add_source_files(env.modules_sources, "lobby/*.cpp")
+env_blazium_sdk.add_source_files(env.modules_sources, "login/*.cpp")
+env_blazium_sdk.add_source_files(env.modules_sources, "master_server/*.cpp")
+env_blazium_sdk.add_source_files(env.modules_sources, "pogr/*.cpp")
env_blazium_sdk.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/blazium_sdk/config.py b/modules/blazium_sdk/config.py
index 4ae256a5ab6a..a3d931918b48 100644
--- a/modules/blazium_sdk/config.py
+++ b/modules/blazium_sdk/config.py
@@ -24,6 +24,15 @@ def get_doc_classes():
"POGRClient",
"POGRResult",
"POGRResponse",
+ "MasterServerClient",
+ "MasterServerResult",
+ "MasterServerResponse",
+ "MasterServerListResult",
+ "MasterServerListResponse",
+ "GameServerInfo",
+ "LoginClient",
+ "LoginResponse",
+ "LoginResult",
]
diff --git a/modules/blazium_sdk/doc_classes/GameServerInfo.xml b/modules/blazium_sdk/doc_classes/GameServerInfo.xml
new file mode 100644
index 000000000000..01526b117330
--- /dev/null
+++ b/modules/blazium_sdk/doc_classes/GameServerInfo.xml
@@ -0,0 +1,37 @@
+
+
+
+ Game server info used by the [MasterServerClient].
+
+
+ Game server info used by the [MasterServerClient]. Used to create or update a game server.
+
+
+
+
+
+ Description of the game server.
+
+
+ Name of the game server.
+
+
+ Id of the game server. Generated after call to create game server.
+
+
+ Ip address of the game server.
+
+
+ Max players of the game server.
+
+
+ Players of the game server.
+
+
+ Port of the game server.
+
+
+ Version of the game server.
+
+
+
diff --git a/modules/blazium_sdk/doc_classes/LoginClient.xml b/modules/blazium_sdk/doc_classes/LoginClient.xml
new file mode 100644
index 000000000000..33a7e9615981
--- /dev/null
+++ b/modules/blazium_sdk/doc_classes/LoginClient.xml
@@ -0,0 +1,71 @@
+
+
+
+ A node used to connect to a login server.
+
+
+ A node used to connect to a login server.
+
+
+
+
+
+
+
+ Connect to the server.
+
+
+
+
+
+ Disconnect from the server.
+ Generates [signal disconnected_from_server] when disconnected.
+
+
+
+
+
+
+ Request login info.
+
+
+
+
+
+ True if the client is connected, else false.
+
+
+ The game id.
+
+
+ Set to what url this login should connect to.
+
+
+
+
+
+ Signal emitted when the client connects to the server.
+
+
+
+
+
+ Signal emitted when the client disconnects from the server.
+
+
+
+
+
+
+ Signals a log from a command.
+
+
+
+
+
+
+ Signal emitted when a JWT is received.
+
+
+
+
diff --git a/modules/blazium_sdk/doc_classes/LoginResponse.xml b/modules/blazium_sdk/doc_classes/LoginResponse.xml
new file mode 100644
index 000000000000..738e13200fd4
--- /dev/null
+++ b/modules/blazium_sdk/doc_classes/LoginResponse.xml
@@ -0,0 +1,19 @@
+
+
+
+ Response from a connect request.
+
+
+ Response from a connect request.
+
+
+
+
+
+
+
+ Signal emitted when the request is finished.
+
+
+
+
diff --git a/modules/blazium_sdk/doc_classes/LoginResult.xml b/modules/blazium_sdk/doc_classes/LoginResult.xml
new file mode 100644
index 000000000000..289229971a8c
--- /dev/null
+++ b/modules/blazium_sdk/doc_classes/LoginResult.xml
@@ -0,0 +1,30 @@
+
+
+
+ A result from a [LoginResponse].
+
+
+ A result from a [LoginResponse].
+
+
+
+
+
+
+
+ Returns true if there is an error.
+
+
+
+
+
+ The error message.
+
+
+ The login type.
+
+
+ The login url.
+
+
+
diff --git a/modules/blazium_sdk/doc_classes/MasterServerClient.xml b/modules/blazium_sdk/doc_classes/MasterServerClient.xml
new file mode 100644
index 000000000000..cf9279471fd2
--- /dev/null
+++ b/modules/blazium_sdk/doc_classes/MasterServerClient.xml
@@ -0,0 +1,41 @@
+
+
+
+ A node used to connect to a master server.
+
+
+ A node used to connect to a master server.
+
+
+
+
+
+
+
+
+ Create a game server.
+
+
+
+
+
+ Get a list of recent games.
+
+
+
+
+
+
+ Update a game server.
+
+
+
+
+
+ Game id of the game server.
+
+
+ Set to what url this master server should connect to.
+
+
+
diff --git a/modules/blazium_sdk/doc_classes/MasterServerListResponse.xml b/modules/blazium_sdk/doc_classes/MasterServerListResponse.xml
new file mode 100644
index 000000000000..4eaed5c27267
--- /dev/null
+++ b/modules/blazium_sdk/doc_classes/MasterServerListResponse.xml
@@ -0,0 +1,19 @@
+
+
+
+ Response from a list games request.
+
+
+ Response from a list games request.
+
+
+
+
+
+
+
+ Signal emitted when the request is finished.
+
+
+
+
diff --git a/modules/blazium_sdk/doc_classes/MasterServerListResult.xml b/modules/blazium_sdk/doc_classes/MasterServerListResult.xml
new file mode 100644
index 000000000000..a4a8ed91c2e3
--- /dev/null
+++ b/modules/blazium_sdk/doc_classes/MasterServerListResult.xml
@@ -0,0 +1,27 @@
+
+
+
+ A result from a [MasterServerListResponse].
+
+
+ A result from a [MasterServerListResponse]. Contains either result or error.
+
+
+
+
+
+
+
+ Returns true if there is an error.
+
+
+
+
+
+ The error message.
+
+
+ The results.
+
+
+
diff --git a/modules/blazium_sdk/doc_classes/MasterServerResponse.xml b/modules/blazium_sdk/doc_classes/MasterServerResponse.xml
new file mode 100644
index 000000000000..833ee825ba3d
--- /dev/null
+++ b/modules/blazium_sdk/doc_classes/MasterServerResponse.xml
@@ -0,0 +1,19 @@
+
+
+
+ Response from a create or update game request.
+
+
+ Response from a create or update game request.
+
+
+
+
+
+
+
+ Signal emitted when the request is finished.
+
+
+
+
diff --git a/modules/blazium_sdk/doc_classes/MasterServerResult.xml b/modules/blazium_sdk/doc_classes/MasterServerResult.xml
new file mode 100644
index 000000000000..b79de2e983fc
--- /dev/null
+++ b/modules/blazium_sdk/doc_classes/MasterServerResult.xml
@@ -0,0 +1,27 @@
+
+
+
+ A result from a [MasterServerResponse].
+
+
+ A result from a [MasterServerResponse]. Contains either result or error.
+
+
+
+
+
+
+
+ Returns true if there is an error.
+
+
+
+
+
+ Gets the error message.
+
+
+ Gets the result.
+
+
+
diff --git a/modules/blazium_sdk/icons/LoginClient.svg b/modules/blazium_sdk/icons/LoginClient.svg
new file mode 100644
index 000000000000..e000cd5827ab
--- /dev/null
+++ b/modules/blazium_sdk/icons/LoginClient.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/modules/blazium_sdk/icons/MasterServerClient.svg b/modules/blazium_sdk/icons/MasterServerClient.svg
new file mode 100644
index 000000000000..e000cd5827ab
--- /dev/null
+++ b/modules/blazium_sdk/icons/MasterServerClient.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/modules/blazium_sdk/lobby/lobby_client.cpp b/modules/blazium_sdk/lobby/lobby_client.cpp
index f9f680cf9fcf..c94cc777f41e 100644
--- a/modules/blazium_sdk/lobby/lobby_client.cpp
+++ b/modules/blazium_sdk/lobby/lobby_client.cpp
@@ -32,7 +32,6 @@
#include "./authoritative_client.h"
#include "scene/main/node.h"
LobbyClient::LobbyClient() {
- server_url = "wss://lobby.blazium.app/connect";
lobby.instantiate();
peer.instantiate();
_socket = Ref(WebSocketPeer::create());
@@ -140,7 +139,6 @@ bool LobbyClient::connect_to_lobby() {
connected = false;
return false;
}
- connected = true;
set_process_internal(true);
emit_signal("log_updated", "connect_to_lobby", "Connected to: " + url);
return true;
@@ -581,6 +579,7 @@ void LobbyClient::_notification(int p_what) {
WebSocketPeer::State state = _socket->get_ready_state();
if (state == WebSocketPeer::STATE_OPEN) {
+ connected = true;
while (_socket->get_available_packet_count() > 0) {
Vector packet_buffer;
Error err = _socket->get_packet_buffer(packet_buffer);
diff --git a/modules/blazium_sdk/lobby/lobby_client.h b/modules/blazium_sdk/lobby/lobby_client.h
index 28633537918b..caec677441fe 100644
--- a/modules/blazium_sdk/lobby/lobby_client.h
+++ b/modules/blazium_sdk/lobby/lobby_client.h
@@ -37,12 +37,12 @@
class LobbyInfo : public Resource {
GDCLASS(LobbyInfo, Resource);
- String id;
- String lobby_name;
- String host;
- String host_name;
- Dictionary tags;
- Dictionary data;
+ String id = "";
+ String lobby_name = "";
+ String host = "";
+ String host_name = "";
+ Dictionary tags = Dictionary();
+ Dictionary data = Dictionary();
int max_players = 0;
int players = 0;
bool sealed = false;
@@ -127,10 +127,10 @@ class LobbyInfo : public Resource {
class LobbyPeer : public Resource {
GDCLASS(LobbyPeer, Resource);
- String id;
- String peer_name;
+ String id = "";
+ String peer_name = "";
bool ready = false;
- Dictionary data;
+ Dictionary data = Dictionary();
protected:
static void _bind_methods() {
@@ -175,14 +175,14 @@ class LobbyClient : public BlaziumClient {
GDCLASS(LobbyClient, BlaziumClient);
protected:
- String server_url;
- String reconnection_token;
+ String server_url = "wss://lobby.blazium.app/connect";
+ String reconnection_token = "";
String game_id = "";
- Dictionary host_data;
- Dictionary peer_data;
+ Dictionary host_data = Dictionary();
+ Dictionary peer_data = Dictionary();
Ref lobby;
Ref peer;
- TypedArray peers;
+ TypedArray peers = TypedArray();
public:
class LobbyResponse : public RefCounted {
@@ -197,7 +197,7 @@ class LobbyClient : public BlaziumClient {
class LobbyResult : public RefCounted {
GDCLASS(LobbyResult, RefCounted);
- String error;
+ String error = "";
protected:
static void _bind_methods() {
@@ -226,8 +226,8 @@ class LobbyClient : public BlaziumClient {
class ListLobbyResult : public RefCounted {
GDCLASS(ListLobbyResult, RefCounted);
- String error;
- TypedArray lobbies;
+ String error = "";
+ TypedArray lobbies = TypedArray();
protected:
static void _bind_methods() {
@@ -236,7 +236,6 @@ class LobbyClient : public BlaziumClient {
ClassDB::bind_method(D_METHOD("get_lobbies"), &ListLobbyResult::get_lobbies);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "error"), "", "get_error");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "lobbies", PROPERTY_HINT_ARRAY_TYPE, "LobbyInfo"), "", "get_lobbies");
- ADD_PROPERTY_DEFAULT("lobbies", TypedArray());
}
public:
@@ -260,8 +259,8 @@ class LobbyClient : public BlaziumClient {
public:
class ViewLobbyResult : public RefCounted {
GDCLASS(ViewLobbyResult, RefCounted);
- String error;
- TypedArray peers_info;
+ String error = "";
+ TypedArray peers_info = TypedArray();
Ref lobby_info;
protected:
@@ -272,8 +271,6 @@ class LobbyClient : public BlaziumClient {
ClassDB::bind_method(D_METHOD("get_lobby"), &ViewLobbyResult::get_lobby);
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "peers", PROPERTY_HINT_ARRAY_TYPE, "LobbyPeer"), "", "get_peers");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "lobby", PROPERTY_HINT_RESOURCE_TYPE, "LobbyInfo"), "", "get_lobby");
- ADD_PROPERTY_DEFAULT("lobby", Ref());
- ADD_PROPERTY_DEFAULT("peers", TypedArray());
ADD_PROPERTY(PropertyInfo(Variant::STRING, "error"), "", "get_error");
}
diff --git a/modules/blazium_sdk/login/login_client.cpp b/modules/blazium_sdk/login/login_client.cpp
new file mode 100644
index 000000000000..0d2563e1ec78
--- /dev/null
+++ b/modules/blazium_sdk/login/login_client.cpp
@@ -0,0 +1,54 @@
+#include "login_client.h"
+
+void LoginClient::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("request_login_info", "login_type"), &LoginClient::request_login_info);
+ ClassDB::bind_method(D_METHOD("set_server_url", "server_url"), &LoginClient::set_server_url);
+ ClassDB::bind_method(D_METHOD("get_server_url"), &LoginClient::get_server_url);
+ ClassDB::bind_method(D_METHOD("set_game_id", "game_id"), &LoginClient::set_game_id);
+ ClassDB::bind_method(D_METHOD("get_game_id"), &LoginClient::get_game_id);
+ ClassDB::bind_method(D_METHOD("get_connected"), &LoginClient::get_connected);
+
+ ClassDB::bind_method(D_METHOD("connect_to_server"), &LoginClient::connect_to_server);
+ ClassDB::bind_method(D_METHOD("disconnect_from_server"), &LoginClient::disconnect_from_server);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "server_url", PROPERTY_HINT_NONE, ""), "set_server_url", "get_server_url");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "game_id", PROPERTY_HINT_NONE, ""), "set_game_id", "get_game_id");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "connected"), "", "get_connected");
+
+ ADD_SIGNAL(MethodInfo("log_updated", PropertyInfo(Variant::STRING, "command"), PropertyInfo(Variant::STRING, "logs")));
+ ADD_SIGNAL(MethodInfo("disconnected_from_server", PropertyInfo(Variant::STRING, "reason")));
+ ADD_SIGNAL(MethodInfo("connected_to_server"));
+ ADD_SIGNAL(MethodInfo("received_jwt", PropertyInfo(Variant::STRING, "jwt"), PropertyInfo(Variant::STRING, "type")));
+}
+
+bool LoginClient::connect_to_server() {
+ if (connected) {
+ return true;
+ }
+ String lobby_url = get_server_url();
+ String url = lobby_url;
+ PackedStringArray protocols;
+ protocols.push_back("blazium");
+ protocols.push_back(game_id);
+ _socket->set_supported_protocols(protocols);
+ Error err = _socket->connect_to_url(url);
+ if (err != OK) {
+ set_process_internal(false);
+ emit_signal("log_updated", "error", "Unable to connect to lobby server at: " + url);
+ connected = false;
+ return false;
+ }
+ set_process_internal(true);
+ emit_signal("log_updated", "connect_to_lobby", "Connected to: " + url);
+ return true;
+}
+
+void LoginClient::disconnect_from_server() {
+ if (connected) {
+ _socket->close(1000, "Normal Closure");
+ connected = false;
+ set_process_internal(false);
+ emit_signal("disconnected_from_server", _socket->get_close_reason());
+ emit_signal("log_updated", "disconnected_from_server", "Disconnected from: " + get_server_url());
+ }
+}
diff --git a/modules/blazium_sdk/login/login_client.h b/modules/blazium_sdk/login/login_client.h
new file mode 100644
index 000000000000..2259faec233e
--- /dev/null
+++ b/modules/blazium_sdk/login/login_client.h
@@ -0,0 +1,188 @@
+/**************************************************************************/
+/* login_client.h */
+/**************************************************************************/
+/* This file is part of: */
+/* BLAZIUM ENGINE */
+/* https://blazium.app */
+/**************************************************************************/
+/* Copyright (c) 2024-present Blazium Engine contributors. */
+/* Copyright (c) 2024 Dragos Daian, Randolph William Aarseth II. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef LOGIN_CLIENT_H
+#define LOGIN_CLIENT_H
+
+#include "../blazium_client.h"
+#include "core/io/json.h"
+#include "modules/websocket/websocket_peer.h"
+
+class LoginClient : public BlaziumClient {
+ GDCLASS(LoginClient, BlaziumClient);
+
+protected:
+ String server_url = "wss://login.blazium.app/connect";
+ String game_id = "";
+ bool connected = false;
+
+public:
+ class LoginResponse : public RefCounted {
+ GDCLASS(LoginResponse, RefCounted);
+
+ protected:
+ static void _bind_methods() {
+ ADD_SIGNAL(MethodInfo("finished", PropertyInfo(Variant::OBJECT, "result", PROPERTY_HINT_RESOURCE_TYPE, "LobbyResult")));
+ }
+
+ public:
+ class LoginResult : public RefCounted {
+ GDCLASS(LoginResult, RefCounted);
+
+ String error = "";
+ String login_url = "";
+ String login_type = "";
+
+ protected:
+ static void _bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_login_url"), &LoginResult::get_login_url);
+ ClassDB::bind_method(D_METHOD("get_login_type"), &LoginResult::get_login_type);
+ ClassDB::bind_method(D_METHOD("has_error"), &LoginResult::has_error);
+ ClassDB::bind_method(D_METHOD("get_error"), &LoginResult::get_error);
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "error"), "", "get_error");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "login_url"), "", "get_login_url");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "login_type"), "", "get_login_type");
+ }
+
+ public:
+ void set_login_type(String p_type) { this->login_type = p_type; }
+ void set_login_url(String p_url) { this->login_url = p_url; }
+ void set_error(String p_error) { this->error = p_error; }
+
+ bool has_error() const { return !error.is_empty(); }
+ String get_error() const { return error; }
+ String get_login_url() const { return login_url; }
+ String get_login_type() const { return login_type; }
+ };
+ };
+
+protected:
+ Ref _socket;
+ Ref login_response;
+
+ void _receive_data(const Dictionary &p_data) {
+ String action = p_data.get("action", "");
+ if (action == "login_url") {
+ String url = p_data.get("url", "");
+ String type = p_data.get("type", "");
+ Ref login_result;
+ login_result.instantiate();
+ login_result->set_login_url(url);
+ login_result->set_login_type(type);
+ login_response->emit_signal("finished", login_result);
+ }
+ if (action == "error") {
+ String error = p_data.get("error", "");
+ Ref login_result;
+ login_result.instantiate();
+ login_result->set_error(error);
+ login_response->emit_signal("finished", login_result);
+ }
+ if (action == "jwt") {
+ String jwt = p_data.get("url", "");
+ String type = p_data.get("type", "");
+ emit_signal("received_jwt", jwt, type);
+ }
+ }
+
+ void _notification(int p_notification) {
+ switch (p_notification) {
+ case NOTIFICATION_INTERNAL_PROCESS: {
+ _socket->poll();
+
+ WebSocketPeer::State state = _socket->get_ready_state();
+ if (state == WebSocketPeer::STATE_OPEN) {
+ if (!connected) {
+ emit_signal("connected_to_server");
+ }
+ connected = true;
+ while (_socket->get_available_packet_count() > 0) {
+ Vector packet_buffer;
+ Error err = _socket->get_packet_buffer(packet_buffer);
+ if (err != OK) {
+ return;
+ }
+ String packet_string = String::utf8((const char *)packet_buffer.ptr(), packet_buffer.size());
+ _receive_data(JSON::parse_string(packet_string));
+ }
+ } else if (state == WebSocketPeer::STATE_CLOSED) {
+ emit_signal("disconnected_from_server", _socket->get_close_reason());
+ set_process_internal(false);
+ connected = false;
+ }
+ } break;
+ }
+ }
+ static void _bind_methods();
+
+ void _send_data(const Dictionary &p_data_dict) {
+ if (_socket->get_ready_state() != WebSocketPeer::STATE_OPEN) {
+ emit_signal("log_updated", "error", "Socket is not ready.");
+ return;
+ }
+ Error err = _socket->send_text(JSON::stringify(p_data_dict));
+ if (err != OK) {
+ emit_signal("log_updated", "error", "No longer connected.");
+ _socket->close(1000, "Disconnected");
+ }
+ }
+
+public:
+ void set_server_url(const String &p_server_url) { this->server_url = p_server_url; }
+ String get_server_url() { return server_url; }
+ void set_game_id(const String &p_game_id) { this->game_id = p_game_id; }
+ String get_game_id() { return game_id; }
+ bool get_connected() { return connected; }
+
+ bool connect_to_server();
+ void disconnect_from_server();
+
+ Ref request_login_info(String p_type) {
+ Dictionary command;
+ command["action"] = "getLogin";
+ command["type"] = p_type;
+ login_response = Ref();
+ login_response.instantiate();
+ _send_data(command);
+ return login_response;
+ }
+
+ LoginClient() {
+ _socket = Ref(WebSocketPeer::create());
+ set_process_internal(false);
+ }
+
+ ~LoginClient() {
+ _socket->close();
+ set_process_internal(false);
+ }
+};
+
+#endif // LOGIN_CLIENT_H
diff --git a/modules/blazium_sdk/master_server/master_server_client.h b/modules/blazium_sdk/master_server/master_server_client.h
new file mode 100644
index 000000000000..a58b4290b0ad
--- /dev/null
+++ b/modules/blazium_sdk/master_server/master_server_client.h
@@ -0,0 +1,333 @@
+/**************************************************************************/
+/* master_server_client.h */
+/**************************************************************************/
+/* This file is part of: */
+/* BLAZIUM ENGINE */
+/* https://blazium.app */
+/**************************************************************************/
+/* Copyright (c) 2024-present Blazium Engine contributors. */
+/* Copyright (c) 2024 Dragos Daian, Randolph William Aarseth II. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef MASTER_SERVER_CLIENT_H
+#define MASTER_SERVER_CLIENT_H
+
+#include "../blazium_client.h"
+#include "core/io/json.h"
+#include "core/templates/vector.h"
+#include "core/version.h"
+#include "main/performance.h"
+#include "scene/main/http_request.h"
+
+class GameServerInfo : public Resource {
+ GDCLASS(GameServerInfo, Resource);
+ String id = "";
+ String game_name = "";
+ String ip_address = "";
+ int port = 0;
+ String description = "";
+ int max_players = 0;
+ int players = 0;
+ String version = "";
+
+protected:
+ static void _bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_id"), &GameServerInfo::get_id);
+ ClassDB::bind_method(D_METHOD("get_game_name"), &GameServerInfo::get_game_name);
+ ClassDB::bind_method(D_METHOD("get_ip_address"), &GameServerInfo::get_ip_address);
+ ClassDB::bind_method(D_METHOD("get_port"), &GameServerInfo::get_port);
+ ClassDB::bind_method(D_METHOD("get_description"), &GameServerInfo::get_description);
+ ClassDB::bind_method(D_METHOD("get_max_players"), &GameServerInfo::get_max_players);
+ ClassDB::bind_method(D_METHOD("get_players"), &GameServerInfo::get_players);
+ ClassDB::bind_method(D_METHOD("get_version"), &GameServerInfo::get_version);
+
+ ClassDB::bind_method(D_METHOD("set_id", "id"), &GameServerInfo::set_id);
+ ClassDB::bind_method(D_METHOD("set_game_name", "game_name"), &GameServerInfo::set_game_name);
+ ClassDB::bind_method(D_METHOD("set_ip_address", "ip_address"), &GameServerInfo::set_ip_address);
+ ClassDB::bind_method(D_METHOD("set_port", "port"), &GameServerInfo::set_port);
+ ClassDB::bind_method(D_METHOD("set_description", "description"), &GameServerInfo::set_description);
+ ClassDB::bind_method(D_METHOD("set_max_players", "max_players"), &GameServerInfo::set_max_players);
+ ClassDB::bind_method(D_METHOD("set_players", "players"), &GameServerInfo::set_players);
+ ClassDB::bind_method(D_METHOD("set_version", "version"), &GameServerInfo::set_version);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "id"), "set_id", "get_id");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "game_name"), "set_game_name", "get_game_name");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "ip_address"), "set_ip_address", "get_ip_address");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "port"), "set_port", "get_port");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "description"), "set_description", "get_description");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_players"), "set_max_players", "get_max_players");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "players"), "set_players", "get_players");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "version"), "set_version", "get_version");
+ }
+
+public:
+ String get_id() const { return id; }
+ String get_game_name() const { return game_name; }
+ String get_ip_address() const { return ip_address; }
+ int get_port() const { return port; }
+ String get_description() const { return description; }
+ int get_max_players() const { return max_players; }
+ int get_players() const { return players; }
+ String get_version() const { return version; }
+
+ void set_id(String p_id) { this->id = p_id; }
+ void set_game_name(String p_game_name) { this->game_name = p_game_name; }
+ void set_ip_address(String p_ip_address) { this->ip_address = p_ip_address; }
+ void set_port(int p_port) { this->port = p_port; }
+ void set_description(String p_description) { this->description = p_description; }
+ void set_max_players(int p_max_players) { this->max_players = p_max_players; }
+ void set_players(int p_players) { this->players = p_players; }
+ void set_version(String p_version) { this->version = p_version; }
+
+ void set_dict(const Dictionary &p_dict) {
+ if (!p_dict.has("id") && p_dict.get("id", "") != "") {
+ this->set_id(p_dict.get("id", ""));
+ }
+ this->set_game_name(p_dict.get("name", ""));
+ this->set_ip_address(p_dict.get("ip_address", ""));
+ this->set_port(p_dict.get("port", 0));
+ this->set_description(p_dict.get("description", ""));
+ this->set_max_players(p_dict.get("max_players", 0));
+ this->set_players(p_dict.get("players", 0));
+ this->set_version(p_dict.get("version", ""));
+ }
+
+ Dictionary get_dict() {
+ Dictionary dict;
+ dict["id"] = this->get_id();
+ dict["name"] = this->get_game_name();
+ dict["ip_address"] = this->get_ip_address();
+ dict["port"] = this->get_port();
+ dict["description"] = this->get_description();
+ dict["max_players"] = this->get_max_players();
+ dict["cur_players"] = this->get_players();
+ dict["version"] = this->get_version();
+ return dict;
+ }
+};
+
+class MasterServerClient : public BlaziumClient {
+ GDCLASS(MasterServerClient, BlaziumClient);
+
+private:
+ String server_url = "https://masterserver.blazium.app/api/v1";
+ String game_id = "";
+ Vector get_headers() {
+ Vector headers;
+ headers.append("BLAZIUM_GAMEID: " + game_id);
+ return headers;
+ }
+
+protected:
+ static void _bind_methods() {
+ ClassDB::bind_method(D_METHOD("create_game", "game_server_info"), &MasterServerClient::create_game);
+ ClassDB::bind_method(D_METHOD("update_game", "game_server_info"), &MasterServerClient::update_game);
+ ClassDB::bind_method(D_METHOD("recent_games"), &MasterServerClient::recent_games);
+ ClassDB::bind_method(D_METHOD("set_server_url", "server_url"), &MasterServerClient::set_server_url);
+ ClassDB::bind_method(D_METHOD("get_server_url"), &MasterServerClient::get_server_url);
+ ClassDB::bind_method(D_METHOD("set_game_id", "game_id"), &MasterServerClient::set_game_id);
+ ClassDB::bind_method(D_METHOD("get_game_id"), &MasterServerClient::get_game_id);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "server_url", PROPERTY_HINT_NONE, ""), "set_server_url", "get_server_url");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "game_id", PROPERTY_HINT_NONE, ""), "set_game_id", "get_game_id");
+ }
+
+public:
+ class MasterServerListResult : public RefCounted {
+ GDCLASS(MasterServerListResult, RefCounted);
+ String error = "";
+ TypedArray results = TypedArray();
+
+ protected:
+ static void _bind_methods() {
+ ClassDB::bind_method(D_METHOD("has_error"), &MasterServerListResult::has_error);
+ ClassDB::bind_method(D_METHOD("get_error"), &MasterServerListResult::get_error);
+ ClassDB::bind_method(D_METHOD("get_results"), &MasterServerListResult::get_result);
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "error"), "", "get_error");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "results", PROPERTY_HINT_RESOURCE_TYPE, "GameServerInfo"), "", "get_results");
+ }
+
+ public:
+ void set_error(String p_error) { error = p_error; }
+ void set_result(TypedArray p_results) { results = p_results; }
+
+ bool has_error() const { return error != ""; }
+ String get_error() const { return error; }
+ TypedArray get_result() const { return results; }
+ };
+ class MasterServerListResponse : public RefCounted {
+ GDCLASS(MasterServerListResponse, RefCounted);
+ HTTPRequest *request;
+
+ protected:
+ static void _bind_methods() {
+ ADD_SIGNAL(MethodInfo("finished", PropertyInfo(Variant::OBJECT, "result", PROPERTY_HINT_RESOURCE_TYPE, "MasterServerResult")));
+ }
+
+ public:
+ void _on_request_completed(int p_status, int p_code, const PackedStringArray &p_headers, const PackedByteArray &p_data) {
+ Ref result;
+ result.instantiate();
+ String result_str = String::utf8((const char *)p_data.ptr(), p_data.size());
+ if (p_code != 200 || result_str == "") {
+ result->set_error("Result code is not 200: code = " + String::num(p_code) + " " + result_str);
+ } else {
+ if (result_str != "") {
+ Dictionary result_dict = JSON::parse_string(result_str);
+ Dictionary data_result = result_dict.get("data", Dictionary());
+ if (!result_dict.get("success", false)) {
+ if (data_result.get("error", "") != "") {
+ result->set_error(data_result.get("error", ""));
+ } else {
+ result->set_error("Request failed with code: " + String::num(p_code) + " " + result_str);
+ }
+ } else {
+ Array servers_dict = data_result.get("servers", Array());
+ TypedArray servers_array;
+ for (int i = 0; i < servers_dict.size(); i++) {
+ Dictionary server_dict = servers_dict[i];
+ Ref game_info;
+ game_info.instantiate();
+ game_info->set_dict(server_dict);
+ servers_array.push_back(game_info);
+ }
+ result->set_result(servers_array);
+ }
+ }
+ }
+ emit_signal(SNAME("finished"), result);
+ }
+ void call_request(String p_url, Vector p_headers, MasterServerClient *p_client) {
+ request = memnew(HTTPRequest);
+ p_client->add_child(request);
+ request->connect("request_completed", callable_mp(this, &MasterServerListResponse::_on_request_completed));
+ request->request(p_url, p_headers, HTTPClient::METHOD_GET, String(""));
+ }
+ };
+
+ class MasterServerResult : public RefCounted {
+ GDCLASS(MasterServerResult, RefCounted);
+ String error = "";
+ Ref result;
+
+ protected:
+ static void _bind_methods() {
+ ClassDB::bind_method(D_METHOD("has_error"), &MasterServerResult::has_error);
+ ClassDB::bind_method(D_METHOD("get_error"), &MasterServerResult::get_error);
+ ClassDB::bind_method(D_METHOD("get_result"), &MasterServerResult::get_result);
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "error"), "", "get_error");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "result", PROPERTY_HINT_RESOURCE_TYPE, "GameServerInfo"), "", "get_result");
+ }
+
+ public:
+ void set_error(String p_error) { error = p_error; }
+ void set_result(Ref p_result) { result = p_result; }
+
+ bool has_error() const { return error != ""; }
+ String get_error() const { return error; }
+ Ref get_result() const { return result; }
+
+ MasterServerResult() {
+ result.instantiate();
+ }
+ };
+ class MasterServerResponse : public RefCounted {
+ GDCLASS(MasterServerResponse, RefCounted);
+ HTTPRequest *request;
+ Ref game_info;
+
+ protected:
+ static void _bind_methods() {
+ ADD_SIGNAL(MethodInfo("finished", PropertyInfo(Variant::OBJECT, "result", PROPERTY_HINT_RESOURCE_TYPE, "MasterServerResult")));
+ }
+
+ public:
+ void _on_request_completed(int p_status, int p_code, const PackedStringArray &p_headers, const PackedByteArray &p_data) {
+ Ref result;
+ result.instantiate();
+ String result_str = String::utf8((const char *)p_data.ptr(), p_data.size());
+ if (p_code != 200 || result_str == "") {
+ result->set_error("code: " + String::num(p_code) + " " + result_str);
+ } else {
+ if (result_str != "") {
+ Dictionary result_dict = JSON::parse_string(result_str);
+ Dictionary data_result = result_dict.get("data", Dictionary());
+ if (!result_dict.get("success", false)) {
+ if (data_result.get("error", "") != "") {
+ result->set_error(data_result.get("error", ""));
+ } else {
+ result->set_error("Request failed with code: " + String::num(p_code) + " " + result_str);
+ }
+ } else {
+ // create call
+ if (data_result.has("server")) {
+ game_info->set_id(data_result.get("server", ""));
+ }
+ result->set_result(game_info);
+ }
+ }
+ }
+ emit_signal(SNAME("finished"), result);
+ }
+ void call_request(String p_url, Vector p_headers, HTTPClient::Method p_method, Dictionary p_data, MasterServerClient *p_client, Ref p_game_server_info) {
+ game_info = p_game_server_info;
+ request = memnew(HTTPRequest);
+ p_client->add_child(request);
+ request->connect("request_completed", callable_mp(this, &MasterServerResponse::_on_request_completed));
+ request->request(p_url, p_headers, p_method, JSON::stringify(p_data));
+ }
+
+ MasterServerResponse() {
+ game_info.instantiate();
+ }
+ };
+
+ Ref create_game(Ref p_game_server_info) {
+ Ref response;
+ response.instantiate();
+ Dictionary dict_data = p_game_server_info->get_dict();
+ response->call_request(server_url + "/server/create", get_headers(), HTTPClient::METHOD_POST, dict_data, this, p_game_server_info);
+ return response;
+ }
+
+ Ref update_game(Ref p_game_server_info) {
+ Ref response;
+ response.instantiate();
+ Dictionary dict_data = p_game_server_info->get_dict();
+ response->call_request(server_url + "/server/update/" + p_game_server_info->get_id(), get_headers(), HTTPClient::METHOD_PUT, dict_data, this, p_game_server_info);
+ return response;
+ }
+
+ Ref recent_games() {
+ Ref response;
+ response.instantiate();
+ response->call_request(server_url + "/servers/recent", get_headers(), this);
+ return response;
+ }
+
+ void set_server_url(String p_server_url) { server_url = p_server_url; }
+ String get_server_url() const { return server_url; }
+ void set_game_id(String p_game_id) { game_id = p_game_id; }
+ String get_game_id() const { return game_id; }
+};
+
+#endif // MASTER_SERVER_CLIENT_H
diff --git a/modules/blazium_sdk/pogr/pogr_client.h b/modules/blazium_sdk/pogr/pogr_client.h
index 2fc5f5bd487f..5198427c27da 100644
--- a/modules/blazium_sdk/pogr/pogr_client.h
+++ b/modules/blazium_sdk/pogr/pogr_client.h
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* lobby_client.h */
+/* pogr_client.h */
/**************************************************************************/
/* This file is part of: */
/* BLAZIUM ENGINE */
@@ -112,7 +112,7 @@ class POGRClient : public BlaziumClient {
Ref result;
result.instantiate();
String result_str = String::utf8((const char *)p_data.ptr(), p_data.size());
- if (p_status != 200 || result_str == "") {
+ if (p_code != 200 || result_str == "") {
result->set_error("Request failed with code: " + String::num(p_code) + " " + result_str);
} else {
if (result_str != "") {
diff --git a/modules/blazium_sdk/register_types.cpp b/modules/blazium_sdk/register_types.cpp
index 45e5833da652..47086482c6b7 100644
--- a/modules/blazium_sdk/register_types.cpp
+++ b/modules/blazium_sdk/register_types.cpp
@@ -32,6 +32,8 @@
#include "blazium_client.h"
#include "lobby/authoritative_client.h"
#include "lobby/lobby_client.h"
+#include "login/login_client.h"
+#include "master_server/master_server_client.h"
#include "pogr/pogr_client.h"
void initialize_blazium_sdk_module(ModuleInitializationLevel p_level) {
@@ -52,6 +54,15 @@ void initialize_blazium_sdk_module(ModuleInitializationLevel p_level) {
GDREGISTER_CLASS(POGRClient);
GDREGISTER_CLASS(POGRClient::POGRResponse);
GDREGISTER_CLASS(POGRClient::POGRResult);
+ GDREGISTER_CLASS(GameServerInfo);
+ GDREGISTER_CLASS(MasterServerClient);
+ GDREGISTER_CLASS(MasterServerClient::MasterServerResponse);
+ GDREGISTER_CLASS(MasterServerClient::MasterServerResult);
+ GDREGISTER_CLASS(MasterServerClient::MasterServerListResponse);
+ GDREGISTER_CLASS(MasterServerClient::MasterServerListResult);
+ GDREGISTER_CLASS(LoginClient);
+ GDREGISTER_CLASS(LoginClient::LoginResponse);
+ GDREGISTER_CLASS(LoginClient::LoginResponse::LoginResult);
}
}