From 03f502e4d0b96b8a77c740b4dbed3b3add337c1b Mon Sep 17 00:00:00 2001 From: Dragos Daian Date: Fri, 13 Dec 2024 23:47:09 +0100 Subject: [PATCH] add master server node and login node add master server node fix default values fix some defaults update connected logic Add login node upd Update login_client.h lint Update login_client.cpp --- modules/blazium_sdk/SCsub | 3 + modules/blazium_sdk/config.py | 9 + .../doc_classes/GameServerInfo.xml | 37 ++ .../blazium_sdk/doc_classes/LoginClient.xml | 71 ++++ .../blazium_sdk/doc_classes/LoginResponse.xml | 19 + .../blazium_sdk/doc_classes/LoginResult.xml | 30 ++ .../doc_classes/MasterServerClient.xml | 41 +++ .../doc_classes/MasterServerListResponse.xml | 19 + .../doc_classes/MasterServerListResult.xml | 27 ++ .../doc_classes/MasterServerResponse.xml | 19 + .../doc_classes/MasterServerResult.xml | 27 ++ modules/blazium_sdk/icons/LoginClient.svg | 1 + .../blazium_sdk/icons/MasterServerClient.svg | 1 + modules/blazium_sdk/lobby/lobby_client.cpp | 3 +- modules/blazium_sdk/lobby/lobby_client.h | 41 +-- modules/blazium_sdk/login/login_client.cpp | 54 +++ modules/blazium_sdk/login/login_client.h | 188 ++++++++++ .../master_server/master_server_client.h | 333 ++++++++++++++++++ modules/blazium_sdk/pogr/pogr_client.h | 4 +- modules/blazium_sdk/register_types.cpp | 11 + 20 files changed, 912 insertions(+), 26 deletions(-) create mode 100644 modules/blazium_sdk/doc_classes/GameServerInfo.xml create mode 100644 modules/blazium_sdk/doc_classes/LoginClient.xml create mode 100644 modules/blazium_sdk/doc_classes/LoginResponse.xml create mode 100644 modules/blazium_sdk/doc_classes/LoginResult.xml create mode 100644 modules/blazium_sdk/doc_classes/MasterServerClient.xml create mode 100644 modules/blazium_sdk/doc_classes/MasterServerListResponse.xml create mode 100644 modules/blazium_sdk/doc_classes/MasterServerListResult.xml create mode 100644 modules/blazium_sdk/doc_classes/MasterServerResponse.xml create mode 100644 modules/blazium_sdk/doc_classes/MasterServerResult.xml create mode 100644 modules/blazium_sdk/icons/LoginClient.svg create mode 100644 modules/blazium_sdk/icons/MasterServerClient.svg create mode 100644 modules/blazium_sdk/login/login_client.cpp create mode 100644 modules/blazium_sdk/login/login_client.h create mode 100644 modules/blazium_sdk/master_server/master_server_client.h 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); } }