diff --git a/modules/blazium_sdk/config.py b/modules/blazium_sdk/config.py index a3d931918b48..3c4746cf1dc1 100644 --- a/modules/blazium_sdk/config.py +++ b/modules/blazium_sdk/config.py @@ -19,8 +19,8 @@ def get_doc_classes(): "ViewLobbyResponse", "ViewLobbyResult", "AuthoritativeClient", - "LobbyCallResponse", - "LobbyCallResult", + "AuthoritativeResponse", + "AuthoritativeResult", "POGRClient", "POGRResult", "POGRResponse", diff --git a/modules/blazium_sdk/doc_classes/AuthoritativeClient.xml b/modules/blazium_sdk/doc_classes/AuthoritativeClient.xml index 8a289c3cbeee..cd48bde1f9de 100644 --- a/modules/blazium_sdk/doc_classes/AuthoritativeClient.xml +++ b/modules/blazium_sdk/doc_classes/AuthoritativeClient.xml @@ -1,24 +1,306 @@ - + - A lobby client that is authoritative. + Node for connecting to the Blazium Lobby service. Offers authoritative lobby making features. - A lobby client that is authoritative. + The [AuthoritativeClient] node provides an interface for connecting to the Blazium Authoritative service. There is a free instance hosted on the [url=https://blazium.app]blazium.app[/url] domain that is used by default. + The normal flow is as follows: + 1. Listen to all the signals you are interested in. + 2. Connect to the server using [method connect_to_lobby] method. + 3. Call any other methods to create, view or join lobbies, as well as add data to them. + 4. Close the session using [method disconnect_from_lobby] method at the end of the game. + [b]Note:[/b] Some methods are non blocking and can be awaited in order to get the result. + There are also members on this class that are automatically updated as the lobby gets updated, such as: + - [member peer]: The current peer. Reflects changes to the self peer. + - [member peers]: The lobby peers. Reflects changes to all peers. + - [member lobby]: The lobby. Reflects changes to the lobby. + + + + + Add tags to the lobby. Only works if you are host. + Returns a [LobbyResponse] object that has a [signal LobbyResponse.finished] signal that is emitted when finished. + Generates [signal lobby_tagged]. + + + + + + Connect to a Blazium Lobby Server using the [member game_id] and [member server_url]. + Generates [signal connected_to_lobby] signal if successful. + + + + + + + + + + Create a lobby and become host. If you are already in a lobby, you cannot create one. You need to leave first. + The new lobby can have a title, tags, max players and password. 0 max players means unlimited. + Returns a [ViewLobbyResponse] object that has a [signal ViewLobbyResponse.finished] signal that is emitted when finished. + Generates [signal lobby_created] signal. + + + + + + + Delete one or more keys from the lobby tags. Only works if you are host. + Returns a [LobbyResponse] object that has a [signal LobbyResponse.finished] signal that is emitted when finished. + Generates [signal lobby_tagged]. + + + + + + Disconnect from the lobby server. + Generates [signal disconnected_from_lobby] signal. + + + + + + Returns true if you are the host of the current lobby. + + + + + + + + Join a lobby. If you are already in a lobby, you cannot join another one. You need to leave first. + If the lobby you want to join is password protected, you need to provide the password. + Returns a [ViewLobbyResponse] object that has a [signal ViewLobbyResponse.finished] signal that is emitted when finished. + Generates [signal lobby_joined]. + + + + + + + Kick a peer. You need to be host to do so. + Returns a [LobbyResponse] object that has a [signal LobbyResponse.finished] signal that is emitted when finished. + Generates [signal peer_left] signal with kicked set to true. + + + + + + Leave a lobby. You need to be in a lobby to leave one. + Returns a [LobbyResponse] object that has a [signal LobbyResponse.finished] signal that is emitted when finished. + Generates [signal lobby_left]. + + + + + + + + + Lists all lobbies. Lobbies that are sealed won't show in the list, except if you disconnected and trying to reconnect to a lobby. + + - + Call a method on the server. + + + + + Send a chat message. Only works if you are in a lobby. + Returns a [LobbyResponse] object that has a [signal LobbyResponse.finished] signal that is emitted when finished. + Generates [signal peer_messaged]. + + + + + + + Ready up in the lobby. You need to be in a lobby and unready to run this. + Returns a [LobbyResponse] object that has a [signal LobbyResponse.finished] signal that is emitted when finished. + Generates [signal peer_ready]. + + + + + + + Seals the lobby. You need to be the host to do this and the lobby needs to be unsealed. + Returns a [LobbyResponse] object that has a [signal LobbyResponse.finished] signal that is emitted when finished. + Generates [signal lobby_sealed]. + + + + + + + Set your peer name. + Returns a [LobbyResponse] object that has a [signal LobbyResponse.finished] signal that is emitted when finished. + Generates [signal peer_named] signal if you are in lobby. + + + + + + + + View data from a lobby. Returns lobby settings and peers. + Returns a [ViewLobbyResponse] object that has a [signal ViewLobbyResponse.finished] signal that is emitted when finished. + + - + + True if the client is connected, else false. + + + The game id. + + + The current lobby. Reflects changes to the lobby. + + + The current peer. Reflects changes to the self peer. + + + The lobby peers. Reflects changes to all peers. + + + Reconnection token. + + + Set to what url this lobby should connect to. + + + + + + + Signal generated after you connect to the lobby. + + + + + + Signal generated after you disconnect from the lobby. + + + + + + + Signal generated after a lobby is created. + + + + + + + Signal generated after you joint a lobby. + + + + + + Signal generated after you leave a lobby. + + + + + + + Signal generated after a notification is received. + + + + + + Signal generated after the host seals the lobby. + + + + + + Signal generated after the host updated the tags of the lobby + + + + + + + Signals a log from a command. + + + + + + Signal generated after a peer disconnects. If they don't reconnect they will be removed. + + + + + + Signal generated after a peer joins the lobby. + + + + + + + Signal generated after a peer leaves the lobby. + + + + + + + Signal generated after a peer sends a chat message. + + + + + + Signal generated after a peer names himself. + + + + + + + Signal generated after a peer is ready. + + + + + + Signal generated after a peer reconnects. + + + + + + Signal generated after data is sent to the lobby. + + + + + + + Signal generated after data is sent to peer. + + + diff --git a/modules/blazium_sdk/doc_classes/LobbyCallResponse.xml b/modules/blazium_sdk/doc_classes/AuthoritativeResponse.xml similarity index 58% rename from modules/blazium_sdk/doc_classes/LobbyCallResponse.xml rename to modules/blazium_sdk/doc_classes/AuthoritativeResponse.xml index 1a24850684d3..67f608cf1759 100644 --- a/modules/blazium_sdk/doc_classes/LobbyCallResponse.xml +++ b/modules/blazium_sdk/doc_classes/AuthoritativeResponse.xml @@ -1,16 +1,16 @@ - + Response from a [method AuthoritativeClient.lobby_call] call. - Response from a [method AuthoritativeClient.lobby_call] call. Await on [signal finished] signal to get the [LobbyCallResult]. + Response from a [method AuthoritativeClient.lobby_call] call. Await on [signal finished] signal to get the [AuthoritativeResult]. - + Signal emitted when the request is finished. diff --git a/modules/blazium_sdk/doc_classes/LobbyCallResult.xml b/modules/blazium_sdk/doc_classes/AuthoritativeResult.xml similarity index 69% rename from modules/blazium_sdk/doc_classes/LobbyCallResult.xml rename to modules/blazium_sdk/doc_classes/AuthoritativeResult.xml index a40307d47762..648f4e72dd42 100644 --- a/modules/blazium_sdk/doc_classes/LobbyCallResult.xml +++ b/modules/blazium_sdk/doc_classes/AuthoritativeResult.xml @@ -1,10 +1,10 @@ - + - A result from a [LobbyCallResponse]. + A result from a [AuthoritativeResponse]. - A result from a [LobbyCallResponse]. Contains either result or error. + A result from a [AuthoritativeResponse]. Contains either result or error. diff --git a/modules/blazium_sdk/icons/AuthoritativeClient.svg b/modules/blazium_sdk/icons/AuthoritativeClient.svg index e000cd5827ab..a64229e346ce 100644 --- a/modules/blazium_sdk/icons/AuthoritativeClient.svg +++ b/modules/blazium_sdk/icons/AuthoritativeClient.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/modules/blazium_sdk/lobby/authoritative_client.cpp b/modules/blazium_sdk/lobby/authoritative_client.cpp index 474bd91093a4..699d7fa53257 100644 --- a/modules/blazium_sdk/lobby/authoritative_client.cpp +++ b/modules/blazium_sdk/lobby/authoritative_client.cpp @@ -1,6 +1,208 @@ -#include "authoritative_client.h" +/**************************************************************************/ +/* authoritative_client.cpp */ +/**************************************************************************/ +/* 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. */ +/**************************************************************************/ -Ref AuthoritativeClient::lobby_call(const String &p_method, const Array &p_args) { +#include "./authoritative_client.h" +#include "./lobby_client.h" +#include "lobby_info.h" +#include "scene/main/node.h" +AuthoritativeClient::AuthoritativeClient() { + lobby.instantiate(); + peer.instantiate(); + _socket = Ref(WebSocketPeer::create()); + set_process_internal(false); +} + +AuthoritativeClient::~AuthoritativeClient() { + _socket->close(); + set_process_internal(false); +} + +void AuthoritativeClient::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_server_url", "server_url"), &AuthoritativeClient::set_server_url); + ClassDB::bind_method(D_METHOD("get_server_url"), &AuthoritativeClient::get_server_url); + ClassDB::bind_method(D_METHOD("set_reconnection_token", "reconnection_token"), &AuthoritativeClient::set_reconnection_token); + ClassDB::bind_method(D_METHOD("get_reconnection_token"), &AuthoritativeClient::get_reconnection_token); + ClassDB::bind_method(D_METHOD("set_game_id", "game_id"), &AuthoritativeClient::set_game_id); + ClassDB::bind_method(D_METHOD("get_game_id"), &AuthoritativeClient::get_game_id); + + ClassDB::bind_method(D_METHOD("is_host"), &AuthoritativeClient::is_host); + ClassDB::bind_method(D_METHOD("get_connected"), &AuthoritativeClient::get_connected); + ClassDB::bind_method(D_METHOD("get_lobby"), &AuthoritativeClient::get_lobby); + ClassDB::bind_method(D_METHOD("get_peer"), &AuthoritativeClient::get_peer); + ClassDB::bind_method(D_METHOD("get_peers"), &AuthoritativeClient::get_peers); + + ADD_PROPERTY(PropertyInfo(Variant::STRING, "server_url", PROPERTY_HINT_NONE, ""), "set_server_url", "get_server_url"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "reconnection_token", PROPERTY_HINT_NONE, ""), "set_reconnection_token", "get_reconnection_token"); + 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_PROPERTY(PropertyInfo(Variant::OBJECT, "lobby", PROPERTY_HINT_RESOURCE_TYPE, "LobbyInfo"), "", "get_lobby"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "peer", PROPERTY_HINT_RESOURCE_TYPE, "LobbyPeer"), "", "get_peer"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "peers", PROPERTY_HINT_ARRAY_TYPE, "LobbyPeer"), "", "get_peers"); + ADD_PROPERTY_DEFAULT("peers", TypedArray()); + ADD_PROPERTY_DEFAULT("peer", Ref()); + ADD_PROPERTY_DEFAULT("lobby", Ref()); + // Register methods + ClassDB::bind_method(D_METHOD("connect_to_lobby"), &AuthoritativeClient::connect_to_lobby); + ClassDB::bind_method(D_METHOD("disconnect_from_lobby"), &AuthoritativeClient::disconnect_from_lobby); + ClassDB::bind_method(D_METHOD("set_peer_name", "peer_name"), &AuthoritativeClient::set_peer_name); + ClassDB::bind_method(D_METHOD("create_lobby", "title", "tags", "max_players", "password"), &AuthoritativeClient::create_lobby, DEFVAL(Dictionary()), DEFVAL(4), DEFVAL("")); + ClassDB::bind_method(D_METHOD("join_lobby", "lobby_id", "password"), &AuthoritativeClient::join_lobby, DEFVAL("")); + ClassDB::bind_method(D_METHOD("leave_lobby"), &AuthoritativeClient::leave_lobby); + ClassDB::bind_method(D_METHOD("lobby_call", "method", "args"), &AuthoritativeClient::lobby_call); + ClassDB::bind_method(D_METHOD("list_lobbies", "tags", "start", "count"), &AuthoritativeClient::list_lobby, DEFVAL(Dictionary()), DEFVAL(0), DEFVAL(10)); + ClassDB::bind_method(D_METHOD("view_lobby", "lobby_id", "password"), &AuthoritativeClient::view_lobby, DEFVAL(""), DEFVAL("")); + ClassDB::bind_method(D_METHOD("kick_peer", "peer_id"), &AuthoritativeClient::kick_peer); + ClassDB::bind_method(D_METHOD("send_chat_message", "chat_message"), &AuthoritativeClient::lobby_chat); + ClassDB::bind_method(D_METHOD("set_lobby_ready", "ready"), &AuthoritativeClient::lobby_ready); + ClassDB::bind_method(D_METHOD("add_lobby_tags", "tags"), &AuthoritativeClient::set_lobby_tags); + ClassDB::bind_method(D_METHOD("del_lobby_tags", "keys"), &AuthoritativeClient::del_lobby_tags); + ClassDB::bind_method(D_METHOD("set_lobby_sealed", "seal"), &AuthoritativeClient::seal_lobby); + + // Register signals + ADD_SIGNAL(MethodInfo("connected_to_lobby", PropertyInfo(Variant::OBJECT, "peer", PROPERTY_HINT_RESOURCE_TYPE, "LobbyPeer"), PropertyInfo(Variant::STRING, "reconnection_token"))); + ADD_SIGNAL(MethodInfo("disconnected_from_lobby", PropertyInfo(Variant::STRING, "reason"))); + ADD_SIGNAL(MethodInfo("peer_named", PropertyInfo(Variant::OBJECT, "peer", PROPERTY_HINT_RESOURCE_TYPE, "LobbyPeer"))); + ADD_SIGNAL(MethodInfo("lobby_notified", PropertyInfo(Variant::OBJECT, "data"), PropertyInfo(Variant::OBJECT, "from_peer", PROPERTY_HINT_RESOURCE_TYPE, "LobbyPeer"))); + ADD_SIGNAL(MethodInfo("received_peer_data", PropertyInfo(Variant::OBJECT, "data"), PropertyInfo(Variant::OBJECT, "to_peer", PROPERTY_HINT_RESOURCE_TYPE, "LobbyPeer"))); + ADD_SIGNAL(MethodInfo("received_lobby_data", PropertyInfo(Variant::OBJECT, "data"))); + ADD_SIGNAL(MethodInfo("lobby_created", PropertyInfo(Variant::OBJECT, "lobby", PROPERTY_HINT_RESOURCE_TYPE, "LobbyInfo"), PropertyInfo(Variant::ARRAY, "peers", PROPERTY_HINT_ARRAY_TYPE, "LobbyPeer"))); + ADD_SIGNAL(MethodInfo("lobby_joined", PropertyInfo(Variant::OBJECT, "lobby", PROPERTY_HINT_RESOURCE_TYPE, "LobbyInfo"), PropertyInfo(Variant::ARRAY, "peers", PROPERTY_HINT_ARRAY_TYPE, "LobbyPeer"))); + ADD_SIGNAL(MethodInfo("lobby_left", PropertyInfo(Variant::BOOL, "kicked"))); + ADD_SIGNAL(MethodInfo("lobby_sealed", PropertyInfo(Variant::BOOL, "sealed"))); + ADD_SIGNAL(MethodInfo("lobby_tagged", PropertyInfo(Variant::DICTIONARY, "tags"))); + ADD_SIGNAL(MethodInfo("peer_joined", PropertyInfo(Variant::OBJECT, "peer", PROPERTY_HINT_RESOURCE_TYPE, "LobbyPeer"))); + ADD_SIGNAL(MethodInfo("peer_reconnected", PropertyInfo(Variant::OBJECT, "peer", PROPERTY_HINT_RESOURCE_TYPE, "LobbyPeer"))); + ADD_SIGNAL(MethodInfo("peer_left", PropertyInfo(Variant::OBJECT, "peer", PROPERTY_HINT_RESOURCE_TYPE, "LobbyPeer"), PropertyInfo(Variant::BOOL, "kicked"))); + ADD_SIGNAL(MethodInfo("peer_disconnected", PropertyInfo(Variant::OBJECT, "peer", PROPERTY_HINT_RESOURCE_TYPE, "LobbyPeer"))); + ADD_SIGNAL(MethodInfo("peer_messaged", PropertyInfo(Variant::OBJECT, "peer", PROPERTY_HINT_RESOURCE_TYPE, "LobbyPeer"), PropertyInfo(Variant::STRING, "chat_message"))); + ADD_SIGNAL(MethodInfo("peer_ready", PropertyInfo(Variant::OBJECT, "peer", PROPERTY_HINT_RESOURCE_TYPE, "LobbyPeer"), PropertyInfo(Variant::BOOL, "is_ready"))); + ADD_SIGNAL(MethodInfo("log_updated", PropertyInfo(Variant::STRING, "command"), PropertyInfo(Variant::STRING, "logs"))); +} + +void AuthoritativeClient::set_server_url(const String &p_server_url) { this->server_url = p_server_url; } +String AuthoritativeClient::get_server_url() { return server_url; } +void AuthoritativeClient::set_reconnection_token(const String &p_reconnection_token) { this->reconnection_token = p_reconnection_token; } +String AuthoritativeClient::get_reconnection_token() { return reconnection_token; } +void AuthoritativeClient::set_game_id(const String &p_game_id) { this->game_id = p_game_id; } +String AuthoritativeClient::get_game_id() { return game_id; } +bool AuthoritativeClient::is_host() { return lobby->get_host() == peer->get_id(); } +bool AuthoritativeClient::get_connected() { return connected; } +void AuthoritativeClient::set_lobby(const Ref &p_lobby) { this->lobby = p_lobby; } +Ref AuthoritativeClient::get_lobby() { return lobby; } +void AuthoritativeClient::set_peer(const Ref &p_peer) { this->peer = p_peer; } +Ref AuthoritativeClient::get_peer() { return peer; } +TypedArray AuthoritativeClient::get_peers() { return peers; } + +bool AuthoritativeClient::connect_to_lobby() { + 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); + if (reconnection_token != "") { + protocols.push_back(reconnection_token); + } + _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", "Connecting to: " + url); + return true; +} + +void AuthoritativeClient::disconnect_from_lobby() { + if (connected) { + _socket->close(1000, "Normal Closure"); + connected = false; + peer->set_data(Dictionary()); + peers.clear(); + lobby->set_data(Dictionary()); + set_process_internal(false); + emit_signal("disconnected_from_lobby", _socket->get_close_reason()); + emit_signal("log_updated", "disconnect_from_lobby", "Disconnected from: " + get_server_url()); + } +} + +String AuthoritativeClient::_increment_counter() { + return String::num(_counter++); +} + +Ref AuthoritativeClient::create_lobby(const String &p_name, const Dictionary &p_tags, int p_max_players, const String &p_password) { + String id = _increment_counter(); + Dictionary command; + command["command"] = "create_lobby"; + Dictionary data_dict; + command["data"] = data_dict; + data_dict["name"] = p_name; + data_dict["max_players"] = p_max_players; + data_dict["password"] = p_password; + data_dict["tags"] = p_tags; + data_dict["id"] = id; + Array command_array; + Ref response; + response.instantiate(); + command_array.push_back(LOBBY_VIEW); + command_array.push_back(response); + _commands[id] = command_array; + _send_data(command); + return response; +} + +Ref AuthoritativeClient::join_lobby(const String &p_lobby_id, const String &p_password) { + String id = _increment_counter(); + Dictionary command; + command["command"] = "join_lobby"; + Dictionary data_dict; + command["data"] = data_dict; + data_dict["lobby_id"] = p_lobby_id; + data_dict["password"] = p_password; + data_dict["id"] = id; + Array command_array; + Ref response; + response.instantiate(); + command_array.push_back(LOBBY_VIEW); + command_array.push_back(response); + _commands[id] = command_array; + _send_data(command); + return response; +} + +Ref AuthoritativeClient::lobby_call(const String &p_method, const Array &p_args) { String id = _increment_counter(); Dictionary command; command["command"] = "lobby_call"; @@ -9,18 +211,571 @@ Ref AuthoritativeClient::lobby_call(cons data_dict["inputs"] = p_args; command["data"] = data_dict; Array command_array; - Ref response; + Ref response; response.instantiate(); - command_array.push_back(LobbyClient::LOBBY_CALL); + command_array.push_back(LOBBY_CALL); command_array.push_back(response); _commands[id] = command_array; _send_data(command); return response; } -void AuthoritativeClient::_bind_methods() { - ClassDB::bind_method(D_METHOD("lobby_call", "method", "args"), &AuthoritativeClient::lobby_call); - ADD_PROPERTY_DEFAULT("peers", TypedArray()); - ADD_PROPERTY_DEFAULT("peer", Ref()); - ADD_PROPERTY_DEFAULT("lobby", Ref()); +Ref AuthoritativeClient::leave_lobby() { + String id = _increment_counter(); + Dictionary command; + command["command"] = "leave_lobby"; + Dictionary data_dict; + command["data"] = data_dict; + data_dict["id"] = id; + Array command_array; + Ref response; + response.instantiate(); + command_array.push_back(LOBBY_REQUEST); + command_array.push_back(response); + _commands[id] = command_array; + _send_data(command); + return response; +} + +Ref AuthoritativeClient::list_lobby(const Dictionary &p_tags, int p_start, int p_count) { + String id = _increment_counter(); + Dictionary command; + command["command"] = "list_lobby"; + Dictionary data_dict; + data_dict["id"] = id; + data_dict["start"] = p_start; + data_dict["count"] = p_count; + Dictionary filter_dict; + data_dict["filter"] = filter_dict; + if (p_tags.size() != 0) { + filter_dict["tags"] = p_tags; + } + command["data"] = data_dict; + Array command_array; + Ref response; + response.instantiate(); + command_array.push_back(LOBBY_LIST); + command_array.push_back(response); + _commands[id] = command_array; + _send_data(command); + return response; +} + +Ref AuthoritativeClient::view_lobby(const String &p_lobby_id, const String &p_password) { + String id = _increment_counter(); + Dictionary command; + command["command"] = "view_lobby"; + Dictionary data_dict; + command["data"] = data_dict; + if (p_lobby_id.is_empty()) { + data_dict["lobby_id"] = lobby->get_id(); + } else { + data_dict["lobby_id"] = p_lobby_id; + } + data_dict["password"] = p_password; + data_dict["id"] = id; + Array command_array; + Ref response; + response.instantiate(); + command_array.push_back(LOBBY_VIEW); + command_array.push_back(response); + _commands[id] = command_array; + _send_data(command); + return response; +} + +Ref AuthoritativeClient::kick_peer(const String &p_peer_id) { + String id = _increment_counter(); + Dictionary command; + command["command"] = "kick_peer"; + Dictionary data_dict; + command["data"] = data_dict; + data_dict["peer_id"] = p_peer_id; + data_dict["id"] = id; + Array command_array; + Ref response; + response.instantiate(); + command_array.push_back(LOBBY_REQUEST); + command_array.push_back(response); + _commands[id] = command_array; + _send_data(command); + return response; +} + +Ref AuthoritativeClient::set_lobby_tags(const Dictionary &p_tags) { + String id = _increment_counter(); + Dictionary command; + command["command"] = "lobby_tags"; + Dictionary data_dict; + command["data"] = data_dict; + data_dict["tags"] = p_tags; + data_dict["id"] = id; + Array command_array; + Ref response; + response.instantiate(); + command_array.push_back(LOBBY_REQUEST); + command_array.push_back(response); + _commands[id] = command_array; + _send_data(command); + return response; +} + +Ref AuthoritativeClient::del_lobby_tags(const TypedArray &p_keys) { + String id = _increment_counter(); + Dictionary command; + command["command"] = "lobby_tags"; + Dictionary data_dict; + command["data"] = data_dict; + Dictionary data_object_dict; + // set null value + for (int i = 0; i < p_keys.size(); i++) { + data_object_dict[p_keys[i]] = Variant(); + } + data_dict["tags"] = data_object_dict; + data_dict["id"] = id; + Array command_array; + Ref response; + response.instantiate(); + command_array.push_back(LOBBY_REQUEST); + command_array.push_back(response); + _commands[id] = command_array; + _send_data(command); + return response; +} + +Ref AuthoritativeClient::lobby_chat(const String &p_chat_message) { + String id = _increment_counter(); + Dictionary command; + command["command"] = "chat_lobby"; + Dictionary data_dict; + command["data"] = data_dict; + data_dict["chat"] = p_chat_message; + data_dict["id"] = id; + Array command_array; + Ref response; + response.instantiate(); + command_array.push_back(LOBBY_REQUEST); + command_array.push_back(response); + _commands[id] = command_array; + _send_data(command); + return response; +} + +Ref AuthoritativeClient::lobby_ready(bool p_ready) { + String id = _increment_counter(); + Dictionary command; + if (p_ready) { + command["command"] = "lobby_ready"; + } else { + command["command"] = "lobby_unready"; + } + Dictionary data_dict; + command["data"] = data_dict; + data_dict["id"] = id; + Array command_array; + Ref response; + response.instantiate(); + command_array.push_back(LOBBY_REQUEST); + command_array.push_back(response); + _commands[id] = command_array; + _send_data(command); + return response; +} + +Ref AuthoritativeClient::set_peer_name(const String &p_peer_name) { + String id = _increment_counter(); + Dictionary command; + command["command"] = "set_name"; + Dictionary data_dict; + data_dict["name"] = p_peer_name; + data_dict["id"] = id; + command["data"] = data_dict; + Array command_array; + Ref response; + response.instantiate(); + command_array.push_back(LOBBY_REQUEST); + command_array.push_back(response); + _commands[id] = command_array; + _send_data(command); + return response; +} + +Ref AuthoritativeClient::seal_lobby(bool seal) { + String id = _increment_counter(); + Dictionary command; + if (seal) { + command["command"] = "seal_lobby"; + } else { + command["command"] = "unseal_lobby"; + } + Dictionary data_dict; + command["data"] = data_dict; + data_dict["id"] = id; + Array command_array; + Ref response; + response.instantiate(); + command_array.push_back(LOBBY_REQUEST); + command_array.push_back(response); + _commands[id] = command_array; + _send_data(command); + return response; +} + +void AuthoritativeClient::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_INTERNAL_PROCESS: { + _socket->poll(); + + WebSocketPeer::State state = _socket->get_ready_state(); + if (state == WebSocketPeer::STATE_OPEN) { + if (!connected) { + connected = true; + emit_signal("log_updated", "connect_to_lobby", "Connected to: " + server_url); + } + while (_socket->get_available_packet_count() > 0) { + Vector packet_buffer; + Error err = _socket->get_packet_buffer(packet_buffer); + if (err != OK) { + emit_signal("log_updated", "error", "Unable to get packet."); + 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("log_updated", "error", _socket->get_close_reason()); + emit_signal("disconnected_from_lobby", _socket->get_close_reason()); + set_process_internal(false); + connected = false; + } + } break; + } +} + +void AuthoritativeClient::_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"); + } +} + +void AuthoritativeClient::_update_peers(Dictionary p_data_dict, TypedArray &p_peers) { + Array peers_array = p_data_dict.get("peers", Array()); + TypedArray peers_info; + p_peers.clear(); + for (int i = 0; i < peers_array.size(); ++i) { + Ref peer_info = Ref(memnew(LobbyPeer)); + Dictionary peer_dict = peers_array[i]; + peer_info->set_dict(peer_dict); + p_peers.push_back(peer_info); + } +} + +void AuthoritativeClient::_clear_lobby() { + lobby->set_dict(Dictionary()); + peers.clear(); + peer->set_data(Dictionary()); + peer->set_ready(false); +} + +void AuthoritativeClient::_receive_data(const Dictionary &p_dict) { + String command = p_dict.get("command", "error"); + String message = p_dict.get("message", ""); + Dictionary data_dict = p_dict.get("data", Dictionary()); + String message_id = data_dict.get("id", ""); + Array command_array = _commands.get(message_id, Array()); + _commands.erase(message_id); + // update lobby and peers + { + TypedArray peers_info; + if (data_dict.has("peers")) { + // Iterate through peers and populate arrays + _update_peers(data_dict, peers_info); + sort_peers_by_id(peers_info); + } + if (data_dict.has("lobby")) { + Dictionary lobby_dict = data_dict.get("lobby", Dictionary()); + Ref lobby_info = Ref(memnew(LobbyInfo)); + lobby_info->set_dict(lobby_dict); + if (lobby_info->get_id() == lobby->get_id() || command == "lobby_created" || command == "joined_lobby") { + // Update lobby info because we viewed our own lobby + lobby->set_dict(lobby_info->get_dict()); + peers = peers_info; + } + } + } + if (command == "peer_state") { + Dictionary peer_dict = data_dict.get("peer", Dictionary()); + peer->set_dict(peer_dict); + reconnection_token = peer_dict.get("reconnection_token", ""); + emit_signal("connected_to_lobby", peer, reconnection_token); + } else if (command == "lobby_created") { + emit_signal("lobby_created", lobby, peers); + } else if (command == "joined_lobby") { + emit_signal("lobby_joined", lobby, peers); + } else if (command == "lobby_left") { + _clear_lobby(); + emit_signal("lobby_left", false); + } else if (command == "lobby_kicked") { + _clear_lobby(); + emit_signal("lobby_left", true); + } else if (command == "lobby_sealed") { + Dictionary lobby_dict = data_dict.get("lobby", Dictionary()); + lobby->set_sealed(true); + emit_signal("lobby_sealed", true); + } else if (command == "lobby_unsealed") { + lobby->set_sealed(false); + emit_signal("lobby_sealed", false); + } else if (command == "lobby_tags") { + lobby->set_tags(data_dict.get("tags", Dictionary())); + emit_signal("lobby_tagged", lobby->get_tags()); + } else if (command == "lobby_list") { + Array arr = data_dict.get("lobbies", Array()); + TypedArray lobbies_input = arr; + TypedArray lobbies_output; + for (int i = 0; i < lobbies_input.size(); ++i) { + Dictionary lobby_dict = lobbies_input[i]; + Ref lobby_info; + lobby_info.instantiate(); + lobby_info->set_dict(lobby_dict); + + lobbies_output.push_back(lobby_info); + } + if (command_array.size() == 2) { + Ref response = command_array[1]; + if (response.is_valid()) { + Ref result; + result.instantiate(); + result->set_lobbies(lobbies_output); + response->emit_signal("finished", result); + } + } + } else if (command == "lobby_view") { + // nothing for now + } else if (command == "peer_chat") { + String peer_id = data_dict.get("from_peer", ""); + String chat_data = data_dict.get("chat_data", ""); + for (int i = 0; i < peers.size(); ++i) { + Ref found_peer = peers[i]; + if (found_peer->get_id() == peer_id) { + emit_signal("peer_messaged", found_peer, chat_data); + break; + } + } + } else if (command == "peer_name") { + String peer_id = data_dict.get("peer_id", ""); + String peer_name = data_dict.get("name", ""); + if (peer->get_id() == peer_id) { + peer->set_peer_name(peer_name); + } + for (int i = 0; i < peers.size(); ++i) { + Ref updated_peer = peers[i]; + if (updated_peer->get_id() == peer_id) { + updated_peer->set_peer_name(peer_name); + // if the named peer is the host, update the host name + if (updated_peer->get_id() == lobby->get_host()) { + lobby->set_host_name(peer_name); + } + emit_signal("peer_named", updated_peer); + break; + } + } + } else if (command == "peer_ready") { + String peer_id = data_dict.get("peer_id", ""); + if (peer->get_id() == peer_id) { + peer->set_ready(true); + } + for (int i = 0; i < peers.size(); ++i) { + Ref updated_peer = peers[i]; + if (updated_peer->get_id() == String(peer_id)) { + updated_peer->set_ready(true); + emit_signal("peer_ready", updated_peer, true); + break; + } + } + } else if (command == "peer_unready") { + String peer_id = data_dict.get("peer_id", ""); + if (peer->get_id() == peer_id) { + peer->set_ready(false); + } + for (int i = 0; i < peers.size(); ++i) { + Ref updated_peer = peers[i]; + if (updated_peer->get_id() == String(data_dict.get("peer_id", ""))) { + updated_peer->set_ready(false); + emit_signal("peer_ready", updated_peer, false); + break; + } + } + } else if (command == "peer_joined") { + Ref joining_peer = Ref(memnew(LobbyPeer)); + Dictionary peer_dict = data_dict.get("peer", Dictionary()); + joining_peer->set_id(peer_dict.get("id", "")); + joining_peer->set_peer_name(peer_dict.get("name", "")); + peers.append(joining_peer); + sort_peers_by_id(peers); + lobby->set_players(peers.size()); + emit_signal("peer_joined", joining_peer); + } else if (command == "peer_reconnected") { + for (int i = 0; i < peers.size(); ++i) { + Ref updated_peer = peers[i]; + if (updated_peer->get_id() == String(data_dict.get("peer_id", ""))) { + emit_signal("peer_reconnected", updated_peer); + break; + } + } + } else if (command == "peer_left") { + for (int i = 0; i < peers.size(); ++i) { + Ref leaving_peer = peers[i]; + if (leaving_peer->get_id() == String(data_dict.get("peer_id", ""))) { + peers.remove_at(i); + lobby->set_players(peers.size()); + emit_signal("peer_left", leaving_peer, data_dict.get("kicked", false)); + break; + } + } + sort_peers_by_id(peers); + } else if (command == "peer_disconnected") { + for (int i = 0; i < peers.size(); ++i) { + Ref leaving_peer = peers[i]; + if (leaving_peer->get_id() == String(data_dict.get("peer_id", ""))) { + peers.remove_at(i); + lobby->set_players(peers.size()); + emit_signal("peer_disconnected", leaving_peer); + break; + } + } + sort_peers_by_id(peers); + } else if (command == "peer_notify") { + String from_peer_id = data_dict.get("from_peer", ""); + for (int i = 0; i < peers.size(); ++i) { + Ref from_peer = peers[i]; + if (from_peer->get_id() == from_peer_id) { + emit_signal("lobby_notified", data_dict.get("peer_data", Variant()), from_peer); + break; + } + } + } else if (command == "lobby_data") { + Dictionary lobby_data = data_dict.get("lobby_data", Dictionary()); + lobby->set_data(lobby_data); + emit_signal("received_lobby_data", lobby_data); + // nothing for now + } else if (command == "data_to") { + String target_peer_id = data_dict.get("target_peer", ""); + Dictionary peer_data_variant = data_dict.get("peer_data", Dictionary()); + for (int i = 0; i < peers.size(); ++i) { + Ref updated_peer = peers[i]; + if (updated_peer->get_id() == target_peer_id) { + // got peer data, update it + updated_peer->set_data(peer_data_variant); + emit_signal("received_peer_data", peer_data_variant, updated_peer); + break; + } + } + } else if (command == "lobby_call") { + Ref response = command_array[1]; + if (response.is_valid()) { + Ref result = Ref(memnew(AuthoritativeResponse::AuthoritativeResult)); + result->set_result(data_dict.get("result", "")); + response->emit_signal("finished", result); + } + } else if (command == "notified_to") { + String from_peer_id = data_dict.get("from_peer", ""); + for (int i = 0; i < peers.size(); ++i) { + Ref from_peer = peers[i]; + if (from_peer->get_id() == from_peer_id) { + emit_signal("lobby_notified", data_dict.get("peer_data", Variant()), from_peer); + break; + } + } + } else if (command == "data_to_sent") { + // nothing for now + } else if (command == "lobby_notify_sent") { + // nothing for now + } else if (command == "notify_to_sent") { + // nothing for now + } else if (command == "error") { + if (command_array.size() == 2) { + int command_type = command_array[0]; + switch (command_type) { + case LOBBY_REQUEST: { + Ref lobby_response = command_array[1]; + if (lobby_response.is_valid()) { + Ref result; + result.instantiate(); + result->set_error(message); + lobby_response->emit_signal("finished", result); + } + } break; + case LOBBY_LIST: { + Ref list_response = command_array[1]; + if (list_response.is_valid()) { + Ref result; + result.instantiate(); + result->set_error(message); + list_response->emit_signal("finished", result); + } + } break; + case LOBBY_VIEW: { + Ref view_response = command_array[1]; + if (view_response.is_valid()) { + Ref result; + result.instantiate(); + result->set_error(message); + view_response->emit_signal("finished", result); + } + } break; + case LOBBY_CALL: { + Ref view_response = command_array[1]; + if (view_response.is_valid()) { + Ref result; + result.instantiate(); + result->set_error(message); + view_response->emit_signal("finished", result); + } + } break; + default: { + emit_signal("log_updated", "error", p_dict["message"]); + } break; + } + } + } else { + emit_signal("log_updated", "error", "Unknown command received."); + } + emit_signal("log_updated", command, message); + if (command_array.size() == 2 && command != "error") { + int command_type = command_array[0]; + switch (command_type) { + case LOBBY_REQUEST: { + Ref response = command_array[1]; + if (response.is_valid()) { + Ref result = Ref(memnew(LobbyResponse::LobbyResult)); + response->emit_signal("finished", result); + } + } break; + case LOBBY_VIEW: { + Dictionary lobby_dict = data_dict.get("lobby", Dictionary()); + + // Iterate through peers and populate arrays + TypedArray peers_info; + _update_peers(data_dict, peers_info); + sort_peers_by_id(peers_info); + Ref lobby_info = Ref(memnew(LobbyInfo)); + lobby_info->set_dict(lobby_dict); + // notify + Ref response = command_array[1]; + if (response.is_valid()) { + Ref result; + result.instantiate(); + result->set_peers(peers_info); + result->set_lobby(lobby_info); + response->emit_signal("finished", result); + } + } break; + } + } } diff --git a/modules/blazium_sdk/lobby/authoritative_client.h b/modules/blazium_sdk/lobby/authoritative_client.h index c165218c8961..f173416f66f7 100644 --- a/modules/blazium_sdk/lobby/authoritative_client.h +++ b/modules/blazium_sdk/lobby/authoritative_client.h @@ -31,53 +31,74 @@ #ifndef AUTHORITATIVE_CLIENT_H #define AUTHORITATIVE_CLIENT_H +#include "authoritative_response.h" #include "lobby_client.h" -class AuthoritativeClient : public LobbyClient { - GDCLASS(AuthoritativeClient, LobbyClient); +class AuthoritativeClient : public BlaziumClient { + GDCLASS(AuthoritativeClient, BlaziumClient); -public: - class LobbyCallResponse : public RefCounted { - GDCLASS(LobbyCallResponse, RefCounted); - - protected: - static void _bind_methods() { - ADD_SIGNAL(MethodInfo("finished", PropertyInfo(Variant::OBJECT, "result", PROPERTY_HINT_RESOURCE_TYPE, "LobbyCallResult"))); - } - - public: - class LobbyCallResult : public RefCounted { - GDCLASS(LobbyCallResult, RefCounted); - Variant result; - String error; +protected: + String server_url = "wss://authlobby.blazium.app/connect"; + String reconnection_token = ""; + String game_id = ""; + Ref lobby; + Ref peer; + TypedArray peers = TypedArray(); - protected: - static void _bind_methods() { - ClassDB::bind_method(D_METHOD("has_error"), &LobbyCallResult::has_error); - ClassDB::bind_method(D_METHOD("get_error"), &LobbyCallResult::get_error); - ClassDB::bind_method(D_METHOD("get_result"), &LobbyCallResult::get_result); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "error"), "", "get_error"); - } + Ref _socket; + int _counter = 0; + bool connected = false; + Dictionary _commands; - public: - void set_error(String p_error) { this->error = p_error; } - void set_result(Variant p_result) { this->result = p_result; } + void _clear_lobby(); + void _receive_data(const Dictionary &p_data); + void _send_data(const Dictionary &p_data); + void _update_peers(Dictionary p_data_dict, TypedArray &peers); + String _increment_counter(); - bool has_error() const { return !error.is_empty(); } - String get_error() const { return error; } - Variant get_result() const { return result; } - }; + enum CommandType { + LOBBY_REQUEST = 0, + LOBBY_VIEW, + LOBBY_LIST, + LOBBY_CALL }; -protected: + void _notification(int p_notification); static void _bind_methods(); public: - Ref lobby_call(const String &p_method, const Array &p_args); + void set_server_url(const String &p_server_url); + String get_server_url(); + void set_reconnection_token(const String &p_reconnection_token); + String get_reconnection_token(); + void set_game_id(const String &p_game_id); + String get_game_id(); + bool is_host(); + bool get_connected(); + void set_lobby(const Ref &p_lobby); + Ref get_lobby(); + void set_peer(const Ref &p_peer); + Ref get_peer(); + TypedArray get_peers(); + + bool connect_to_lobby(); + void disconnect_from_lobby(); + Ref create_lobby(const String &p_name, const Dictionary &p_tags, int p_max_players, const String &p_password); + Ref join_lobby(const String &p_lobby_id, const String &p_password); + Ref leave_lobby(); + Ref list_lobby(const Dictionary &p_tags, int p_start, int p_count); + Ref view_lobby(const String &p_lobby_id, const String &p_password); + Ref kick_peer(const String &p_peer_id); + Ref set_lobby_tags(const Dictionary &p_tags); + Ref del_lobby_tags(const TypedArray &p_keys); + Ref lobby_chat(const String &chat_message); + Ref lobby_ready(bool p_ready); + Ref set_peer_name(const String &p_peer_name); + Ref seal_lobby(bool seal); + Ref lobby_call(const String &p_method, const Array &p_args); - AuthoritativeClient() { - server_url = "wss://authlobby.blazium.app/connect"; - } + AuthoritativeClient(); + ~AuthoritativeClient(); }; #endif // AUTHORITATIVE_CLIENT_H diff --git a/modules/blazium_sdk/lobby/authoritative_response.h b/modules/blazium_sdk/lobby/authoritative_response.h new file mode 100644 index 000000000000..03c48fae9868 --- /dev/null +++ b/modules/blazium_sdk/lobby/authoritative_response.h @@ -0,0 +1,71 @@ +/**************************************************************************/ +/* authoritative_response.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 AUTHORITATIVE_RESPONSE_H +#define AUTHORITATIVE_RESPONSE_H + +#include "core/object/ref_counted.h" +#include "core/variant/typed_array.h" +#include "lobby_info.h" +#include "lobby_peer.h" + +class AuthoritativeResponse : public RefCounted { + GDCLASS(AuthoritativeResponse, RefCounted); + +protected: + static void _bind_methods() { + ADD_SIGNAL(MethodInfo("finished", PropertyInfo(Variant::OBJECT, "result", PROPERTY_HINT_RESOURCE_TYPE, "AuthoritativeResult"))); + } + +public: + class AuthoritativeResult : public RefCounted { + GDCLASS(AuthoritativeResult, RefCounted); + Variant result; + String error; + + protected: + static void _bind_methods() { + ClassDB::bind_method(D_METHOD("has_error"), &AuthoritativeResult::has_error); + ClassDB::bind_method(D_METHOD("get_error"), &AuthoritativeResult::get_error); + ClassDB::bind_method(D_METHOD("get_result"), &AuthoritativeResult::get_result); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "error"), "", "get_error"); + } + + public: + void set_error(String p_error) { this->error = p_error; } + void set_result(Variant p_result) { this->result = p_result; } + + bool has_error() const { return !error.is_empty(); } + String get_error() const { return error; } + Variant get_result() const { return result; } + }; +}; + +#endif // AUTHORITATIVE_RESPONSE_H diff --git a/modules/blazium_sdk/lobby/lobby_client.cpp b/modules/blazium_sdk/lobby/lobby_client.cpp index c94cc777f41e..1571ddef4024 100644 --- a/modules/blazium_sdk/lobby/lobby_client.cpp +++ b/modules/blazium_sdk/lobby/lobby_client.cpp @@ -30,6 +30,7 @@ #include "./lobby_client.h" #include "./authoritative_client.h" +#include "lobby_info.h" #include "scene/main/node.h" LobbyClient::LobbyClient() { lobby.instantiate(); @@ -119,6 +120,22 @@ void LobbyClient::_bind_methods() { ADD_SIGNAL(MethodInfo("log_updated", PropertyInfo(Variant::STRING, "command"), PropertyInfo(Variant::STRING, "logs"))); } +void LobbyClient::set_server_url(const String &p_server_url) { this->server_url = p_server_url; } +String LobbyClient::get_server_url() { return server_url; } +void LobbyClient::set_reconnection_token(const String &p_reconnection_token) { this->reconnection_token = p_reconnection_token; } +String LobbyClient::get_reconnection_token() { return reconnection_token; } +void LobbyClient::set_game_id(const String &p_game_id) { this->game_id = p_game_id; } +String LobbyClient::get_game_id() { return game_id; } +bool LobbyClient::is_host() { return lobby->get_host() == peer->get_id(); } +bool LobbyClient::get_connected() { return connected; } +Dictionary LobbyClient::get_host_data() { return host_data; } +Dictionary LobbyClient::get_peer_data() { return peer_data; } +void LobbyClient::set_lobby(const Ref &p_lobby) { this->lobby = p_lobby; } +Ref LobbyClient::get_lobby() { return lobby; } +void LobbyClient::set_peer(const Ref &p_peer) { this->peer = p_peer; } +Ref LobbyClient::get_peer() { return peer; } +TypedArray LobbyClient::get_peers() { return peers; } + bool LobbyClient::connect_to_lobby() { if (connected) { return true; @@ -140,7 +157,7 @@ bool LobbyClient::connect_to_lobby() { return false; } set_process_internal(true); - emit_signal("log_updated", "connect_to_lobby", "Connected to: " + url); + emit_signal("log_updated", "connect_to_lobby", "Connecting to: " + url); return true; } @@ -163,13 +180,13 @@ String LobbyClient::_increment_counter() { return String::num(_counter++); } -Ref LobbyClient::create_lobby(const String &p_lobby_name, const Dictionary &p_tags, int p_max_players, const String &p_password) { +Ref LobbyClient::create_lobby(const String &p_name, const Dictionary &p_tags, int p_max_players, const String &p_password) { String id = _increment_counter(); Dictionary command; command["command"] = "create_lobby"; Dictionary data_dict; command["data"] = data_dict; - data_dict["name"] = p_lobby_name; + data_dict["name"] = p_name; data_dict["max_players"] = p_max_players; data_dict["password"] = p_password; data_dict["tags"] = p_tags; @@ -184,7 +201,7 @@ Ref LobbyClient::create_lobby(const String &p_lo return response; } -Ref LobbyClient::join_lobby(const String &p_lobby_id, const String &p_password) { +Ref LobbyClient::join_lobby(const String &p_lobby_id, const String &p_password) { String id = _increment_counter(); Dictionary command; command["command"] = "join_lobby"; @@ -203,7 +220,7 @@ Ref LobbyClient::join_lobby(const String &p_lobb return response; } -Ref LobbyClient::leave_lobby() { +Ref LobbyClient::leave_lobby() { String id = _increment_counter(); Dictionary command; command["command"] = "leave_lobby"; @@ -220,7 +237,7 @@ Ref LobbyClient::leave_lobby() { return response; } -Ref LobbyClient::list_lobby(const Dictionary &p_tags, int p_start, int p_count) { +Ref LobbyClient::list_lobby(const Dictionary &p_tags, int p_start, int p_count) { String id = _increment_counter(); Dictionary command; command["command"] = "list_lobby"; @@ -244,7 +261,7 @@ Ref LobbyClient::list_lobby(const Dictionary &p_ return response; } -Ref LobbyClient::view_lobby(const String &p_lobby_id, const String &p_password) { +Ref LobbyClient::view_lobby(const String &p_lobby_id, const String &p_password) { String id = _increment_counter(); Dictionary command; command["command"] = "view_lobby"; @@ -267,7 +284,7 @@ Ref LobbyClient::view_lobby(const String &p_lobb return response; } -Ref LobbyClient::kick_peer(const String &p_peer_id) { +Ref LobbyClient::kick_peer(const String &p_peer_id) { String id = _increment_counter(); Dictionary command; command["command"] = "kick_peer"; @@ -285,7 +302,7 @@ Ref LobbyClient::kick_peer(const String &p_peer_id) return response; } -Ref LobbyClient::set_lobby_tags(const Dictionary &p_tags) { +Ref LobbyClient::set_lobby_tags(const Dictionary &p_tags) { String id = _increment_counter(); Dictionary command; command["command"] = "lobby_tags"; @@ -303,7 +320,7 @@ Ref LobbyClient::set_lobby_tags(const Dictionary &p_ return response; } -Ref LobbyClient::del_lobby_tags(const TypedArray &p_keys) { +Ref LobbyClient::del_lobby_tags(const TypedArray &p_keys) { String id = _increment_counter(); Dictionary command; command["command"] = "lobby_tags"; @@ -326,7 +343,7 @@ Ref LobbyClient::del_lobby_tags(const TypedArray LobbyClient::lobby_chat(const String &p_chat_message) { +Ref LobbyClient::lobby_chat(const String &p_chat_message) { String id = _increment_counter(); Dictionary command; command["command"] = "chat_lobby"; @@ -344,7 +361,7 @@ Ref LobbyClient::lobby_chat(const String &p_chat_mes return response; } -Ref LobbyClient::lobby_ready(bool p_ready) { +Ref LobbyClient::lobby_ready(bool p_ready) { String id = _increment_counter(); Dictionary command; if (p_ready) { @@ -365,7 +382,7 @@ Ref LobbyClient::lobby_ready(bool p_ready) { return response; } -Ref LobbyClient::set_peer_name(const String &p_peer_name) { +Ref LobbyClient::set_peer_name(const String &p_peer_name) { String id = _increment_counter(); Dictionary command; command["command"] = "set_name"; @@ -383,7 +400,7 @@ Ref LobbyClient::set_peer_name(const String &p_peer_ return response; } -Ref LobbyClient::seal_lobby(bool seal) { +Ref LobbyClient::seal_lobby(bool seal) { String id = _increment_counter(); Dictionary command; if (seal) { @@ -404,7 +421,7 @@ Ref LobbyClient::seal_lobby(bool seal) { return response; } -Ref LobbyClient::lobby_notify(const Variant &p_peer_data) { +Ref LobbyClient::lobby_notify(const Variant &p_peer_data) { String id = _increment_counter(); Dictionary command; command["command"] = "lobby_notify"; @@ -422,7 +439,7 @@ Ref LobbyClient::lobby_notify(const Variant &p_peer_ return response; } -Ref LobbyClient::peer_notify(const Variant &p_peer_data, const String &p_target_peer) { +Ref LobbyClient::peer_notify(const Variant &p_peer_data, const String &p_target_peer) { String id = _increment_counter(); Dictionary command; command["command"] = "notify_to"; @@ -441,7 +458,7 @@ Ref LobbyClient::peer_notify(const Variant &p_peer_d return response; } -Ref LobbyClient::lobby_data(const Dictionary &p_lobby_data, bool p_is_private) { +Ref LobbyClient::lobby_data(const Dictionary &p_lobby_data, bool p_is_private) { String id = _increment_counter(); Dictionary command; command["command"] = "lobby_data"; @@ -460,7 +477,7 @@ Ref LobbyClient::lobby_data(const Dictionary &p_lobb return response; } -Ref LobbyClient::del_lobby_data(const TypedArray &p_keys, bool p_is_private) { +Ref LobbyClient::del_lobby_data(const TypedArray &p_keys, bool p_is_private) { String id = _increment_counter(); Dictionary command; command["command"] = "lobby_data"; @@ -484,7 +501,7 @@ Ref LobbyClient::del_lobby_data(const TypedArray LobbyClient::set_peer_data(const Dictionary &p_peer_data, const String &p_target_peer, bool p_is_private) { +Ref LobbyClient::set_peer_data(const Dictionary &p_peer_data, const String &p_target_peer, bool p_is_private) { String id = _increment_counter(); Dictionary command; command["command"] = "data_to"; @@ -504,7 +521,7 @@ Ref LobbyClient::set_peer_data(const Dictionary &p_p return response; } -Ref LobbyClient::del_peer_data(const TypedArray &p_keys, const String &p_target_peer, bool p_is_private) { +Ref LobbyClient::del_peer_data(const TypedArray &p_keys, const String &p_target_peer, bool p_is_private) { String id = _increment_counter(); Dictionary command; command["command"] = "data_to"; @@ -529,7 +546,7 @@ Ref LobbyClient::del_peer_data(const TypedArray LobbyClient::set_peers_data(const Dictionary &p_peer_data, bool p_is_private) { +Ref LobbyClient::set_peers_data(const Dictionary &p_peer_data, bool p_is_private) { String id = _increment_counter(); Dictionary command; command["command"] = "data_to_all"; @@ -548,7 +565,7 @@ Ref LobbyClient::set_peers_data(const Dictionary &p_ return response; } -Ref LobbyClient::del_peers_data(const TypedArray &p_keys, bool p_is_private) { +Ref LobbyClient::del_peers_data(const TypedArray &p_keys, bool p_is_private) { String id = _increment_counter(); Dictionary command; command["command"] = "data_to_all"; @@ -579,7 +596,10 @@ void LobbyClient::_notification(int p_what) { WebSocketPeer::State state = _socket->get_ready_state(); if (state == WebSocketPeer::STATE_OPEN) { - connected = true; + if (!connected) { + connected = true; + emit_signal("log_updated", "connect_to_lobby", "Connected to: " + server_url); + } while (_socket->get_available_packet_count() > 0) { Vector packet_buffer; Error err = _socket->get_packet_buffer(packet_buffer); @@ -859,14 +879,6 @@ void LobbyClient::_receive_data(const Dictionary &p_dict) { break; } } - } else if (command == "lobby_call") { - // authoritative call - Ref response = command_array[1]; - if (response.is_valid()) { - Ref result = Ref(memnew(AuthoritativeClient::LobbyCallResponse::LobbyCallResult)); - result->set_result(data_dict.get("result", "")); - response->emit_signal("finished", result); - } } else if (command == "notified_to") { String from_peer_id = data_dict.get("from_peer", ""); for (int i = 0; i < peers.size(); ++i) { @@ -913,19 +925,6 @@ void LobbyClient::_receive_data(const Dictionary &p_dict) { view_response->emit_signal("finished", result); } } break; - // From AuthoritativeClient - case LOBBY_CALL: { - Ref view_response = command_array[1]; - if (view_response.is_valid()) { - Ref result; - result.instantiate(); - result->set_error(message); - view_response->emit_signal("finished", result); - } - } break; - default: { - emit_signal("log_updated", "error", p_dict["message"]); - } break; } } } else { diff --git a/modules/blazium_sdk/lobby/lobby_client.h b/modules/blazium_sdk/lobby/lobby_client.h index e0f0b867895f..f0a1ff4a8185 100644 --- a/modules/blazium_sdk/lobby/lobby_client.h +++ b/modules/blazium_sdk/lobby/lobby_client.h @@ -33,143 +33,12 @@ #include "../blazium_client.h" #include "core/io/json.h" +#include "lobby_info.h" +#include "lobby_peer.h" +#include "lobby_response.h" #include "modules/websocket/websocket_peer.h" -class LobbyInfo : public Resource { - GDCLASS(LobbyInfo, Resource); - 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; - bool password_protected = false; - -protected: - static void _bind_methods() { - ClassDB::bind_method(D_METHOD("get_host"), &LobbyInfo::get_host); - ClassDB::bind_method(D_METHOD("get_max_players"), &LobbyInfo::get_max_players); - ClassDB::bind_method(D_METHOD("is_sealed"), &LobbyInfo::is_sealed); - ClassDB::bind_method(D_METHOD("is_password_protected"), &LobbyInfo::is_password_protected); - ClassDB::bind_method(D_METHOD("get_id"), &LobbyInfo::get_id); - ClassDB::bind_method(D_METHOD("get_lobby_name"), &LobbyInfo::get_lobby_name); - ClassDB::bind_method(D_METHOD("get_host_name"), &LobbyInfo::get_host_name); - ClassDB::bind_method(D_METHOD("get_players"), &LobbyInfo::get_players); - ClassDB::bind_method(D_METHOD("get_tags"), &LobbyInfo::get_tags); - ClassDB::bind_method(D_METHOD("get_data"), &LobbyInfo::get_data); - - ADD_PROPERTY(PropertyInfo(Variant::STRING, "id"), "", "get_id"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "tags"), "", "get_tags"); - ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data"), "", "get_data"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "lobby_name"), "", "get_lobby_name"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "host_name"), "", "get_host_name"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "players"), "", "get_players"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "host"), "", "get_host"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "max_players"), "", "get_max_players"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sealed"), "", "is_sealed"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "password_protected"), "", "is_password_protected"); - } - -public: - void set_id(const String &p_id) { this->id = p_id; } - void set_lobby_name(const String &p_lobby_name) { this->lobby_name = p_lobby_name; } - void set_host(const String &p_host) { this->host = p_host; } - void set_host_name(const String &p_host_name) { this->host_name = p_host_name; } - 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_sealed(bool p_sealed) { this->sealed = p_sealed; } - void set_password_protected(bool p_password_protected) { this->password_protected = p_password_protected; } - void set_tags(const Dictionary &p_tags) { this->tags = p_tags; } - void set_data(const Dictionary &p_data) { this->data = p_data; } - - void set_dict(const Dictionary &p_dict) { - this->set_host(p_dict.get("host", "")); - this->set_max_players(p_dict.get("max_players", 0)); - this->set_sealed(p_dict.get("sealed", false)); - this->set_players(p_dict.get("players", 0)); - this->set_id(p_dict.get("id", "")); - this->set_lobby_name(p_dict.get("name", "")); - this->set_host_name(p_dict.get("host_name", "")); - this->set_password_protected(p_dict.get("has_password", false)); - this->set_tags(p_dict.get("tags", Dictionary())); - this->set_data(p_dict.get("public_data", Dictionary())); - } - Dictionary get_dict() const { - Dictionary dict; - dict["host"] = this->get_host(); - dict["max_players"] = this->get_max_players(); - dict["sealed"] = this->is_sealed(); - dict["players"] = this->get_players(); - dict["id"] = this->get_id(); - dict["name"] = this->get_lobby_name(); - dict["host_name"] = this->get_host_name(); - dict["has_password"] = this->is_password_protected(); - dict["tags"] = this->get_tags(); - dict["public_data"] = this->get_data(); - return dict; - } - - Dictionary get_data() const { return data; } - Dictionary get_tags() const { return tags; } - String get_id() const { return id; } - String get_lobby_name() const { return lobby_name; } - String get_host() const { return host; } - String get_host_name() const { return host_name; } - int get_max_players() const { return max_players; } - int get_players() const { return players; } - bool is_sealed() const { return sealed; } - bool is_password_protected() const { return password_protected; } - LobbyInfo() {} -}; - -class LobbyPeer : public Resource { - GDCLASS(LobbyPeer, Resource); - String id = ""; - String peer_name = ""; - bool ready = false; - Dictionary data = Dictionary(); - -protected: - static void _bind_methods() { - ClassDB::bind_method(D_METHOD("get_id"), &LobbyPeer::get_id); - ClassDB::bind_method(D_METHOD("get_peer_name"), &LobbyPeer::get_peer_name); - ClassDB::bind_method(D_METHOD("is_ready"), &LobbyPeer::is_ready); - ClassDB::bind_method(D_METHOD("get_data"), &LobbyPeer::get_data); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "id"), "", "get_id"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "peer_name"), "", "get_peer_name"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ready"), "", "is_ready"); - ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data"), "", "get_data"); - } - -public: - void set_id(const String &p_id) { this->id = p_id; } - void set_peer_name(const String &p_peer_name) { this->peer_name = p_peer_name; } - void set_ready(bool p_ready) { this->ready = p_ready; } - void set_data(const Dictionary &p_data) { this->data = p_data; } - void set_dict(const Dictionary &p_dict) { - this->set_id(p_dict.get("id", "")); - this->set_peer_name(p_dict.get("name", "")); - this->set_ready(p_dict.get("ready", "")); - this->set_data(p_dict.get("public_data", Dictionary())); - } - Dictionary get_dict() const { - Dictionary dict; - dict["id"] = this->get_id(); - dict["name"] = this->get_peer_name(); - dict["ready"] = this->is_ready(); - dict["public_data"] = this->get_data(); - return dict; - } - - Dictionary get_data() const { return data; } - String get_id() const { return id; } - String get_peer_name() const { return peer_name; } - bool is_ready() const { return ready; } - LobbyPeer() {} -}; +void sort_peers_by_id(TypedArray &peers); class LobbyClient : public BlaziumClient { GDCLASS(LobbyClient, BlaziumClient); @@ -184,115 +53,6 @@ class LobbyClient : public BlaziumClient { Ref peer; TypedArray peers = TypedArray(); -public: - class LobbyResponse : public RefCounted { - GDCLASS(LobbyResponse, RefCounted); - - protected: - static void _bind_methods() { - ADD_SIGNAL(MethodInfo("finished", PropertyInfo(Variant::OBJECT, "result", PROPERTY_HINT_RESOURCE_TYPE, "LobbyResult"))); - } - - public: - class LobbyResult : public RefCounted { - GDCLASS(LobbyResult, RefCounted); - - String error = ""; - - protected: - static void _bind_methods() { - ClassDB::bind_method(D_METHOD("has_error"), &LobbyResult::has_error); - ClassDB::bind_method(D_METHOD("get_error"), &LobbyResult::get_error); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "error"), "", "get_error"); - } - - public: - void set_error(String p_error) { this->error = p_error; } - - bool has_error() const { return !error.is_empty(); } - String get_error() const { return error; } - }; - }; - - class ListLobbyResponse : public RefCounted { - GDCLASS(ListLobbyResponse, RefCounted); - - protected: - static void _bind_methods() { - ADD_SIGNAL(MethodInfo("finished", PropertyInfo(Variant::OBJECT, "result", PROPERTY_HINT_RESOURCE_TYPE, "ListLobbyResult"))); - } - - public: - class ListLobbyResult : public RefCounted { - GDCLASS(ListLobbyResult, RefCounted); - - String error = ""; - TypedArray lobbies = TypedArray(); - - protected: - static void _bind_methods() { - ClassDB::bind_method(D_METHOD("has_error"), &ListLobbyResult::has_error); - ClassDB::bind_method(D_METHOD("get_error"), &ListLobbyResult::get_error); - 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"); - } - - public: - void set_error(const String &p_error) { this->error = p_error; } - void set_lobbies(const TypedArray &p_lobbies) { this->lobbies = p_lobbies; } - - bool has_error() const { return !error.is_empty(); } - String get_error() const { return error; } - TypedArray get_lobbies() const { return lobbies; } - }; - }; - - class ViewLobbyResponse : public RefCounted { - GDCLASS(ViewLobbyResponse, RefCounted); - - protected: - static void _bind_methods() { - ADD_SIGNAL(MethodInfo("finished", PropertyInfo(Variant::OBJECT, "result", PROPERTY_HINT_RESOURCE_TYPE, "ViewLobbyResult"))); - } - - public: - class ViewLobbyResult : public RefCounted { - GDCLASS(ViewLobbyResult, RefCounted); - String error = ""; - TypedArray peers_info = TypedArray(); - Ref lobby_info; - - protected: - static void _bind_methods() { - ClassDB::bind_method(D_METHOD("has_error"), &ViewLobbyResult::has_error); - ClassDB::bind_method(D_METHOD("get_error"), &ViewLobbyResult::get_error); - ClassDB::bind_method(D_METHOD("get_peers"), &ViewLobbyResult::get_peers); - 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(PropertyInfo(Variant::STRING, "error"), "", "get_error"); - ADD_PROPERTY_DEFAULT("lobby", Ref()); - } - - public: - void set_error(const String &p_error) { this->error = p_error; } - void set_peers(const TypedArray &p_peers) { this->peers_info = p_peers; } - void set_lobby(const Ref &p_lobby_info) { this->lobby_info = p_lobby_info; } - - bool has_error() const { return !error.is_empty(); } - String get_error() const { return error; } - TypedArray get_peers() const { return peers_info; } - Ref get_lobby() const { return lobby_info; } - ViewLobbyResult() { - lobby_info.instantiate(); - } - ~ViewLobbyResult() { - } - }; - }; - -protected: Ref _socket; int _counter = 0; bool connected = false; @@ -308,32 +68,31 @@ class LobbyClient : public BlaziumClient { LOBBY_REQUEST = 0, LOBBY_VIEW, LOBBY_LIST, - LOBBY_CALL }; void _notification(int p_notification); static void _bind_methods(); 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_reconnection_token(const String &p_reconnection_token) { this->reconnection_token = p_reconnection_token; } - String get_reconnection_token() { return reconnection_token; } - void set_game_id(const String &p_game_id) { this->game_id = p_game_id; } - String get_game_id() { return game_id; } - bool is_host() { return lobby->get_host() == peer->get_id(); } - bool get_connected() { return connected; } - Dictionary get_host_data() { return host_data; } - Dictionary get_peer_data() { return peer_data; } - void set_lobby(const Ref &p_lobby) { this->lobby = p_lobby; } - Ref get_lobby() { return lobby; } - void set_peer(const Ref &p_peer) { this->peer = p_peer; } - Ref get_peer() { return peer; } - TypedArray get_peers() { return peers; } + void set_server_url(const String &p_server_url); + String get_server_url(); + void set_reconnection_token(const String &p_reconnection_token); + String get_reconnection_token(); + void set_game_id(const String &p_game_id); + String get_game_id(); + bool is_host(); + bool get_connected(); + Dictionary get_host_data(); + Dictionary get_peer_data(); + void set_lobby(const Ref &p_lobby); + Ref get_lobby(); + void set_peer(const Ref &p_peer); + Ref get_peer(); + TypedArray get_peers(); bool connect_to_lobby(); void disconnect_from_lobby(); - Ref create_lobby(const String &p_lobby_name, const Dictionary &p_tags, int p_max_players, const String &p_password); + Ref create_lobby(const String &p_name, const Dictionary &p_tags, int p_max_players, const String &p_password); Ref join_lobby(const String &p_lobby_id, const String &p_password); Ref leave_lobby(); Ref list_lobby(const Dictionary &p_tags, int p_start, int p_count); @@ -345,7 +104,6 @@ class LobbyClient : public BlaziumClient { Ref lobby_ready(bool p_ready); Ref set_peer_name(const String &p_peer_name); Ref seal_lobby(bool seal); - Ref lobby_call(const String &p_method, const Array &p_args); Ref lobby_notify(const Variant &p_peer_data); Ref peer_notify(const Variant &p_peer_data, const String &p_target_peer); diff --git a/modules/blazium_sdk/lobby/lobby_info.cpp b/modules/blazium_sdk/lobby/lobby_info.cpp new file mode 100644 index 000000000000..fe33ad2ad745 --- /dev/null +++ b/modules/blazium_sdk/lobby/lobby_info.cpp @@ -0,0 +1,74 @@ +#include "lobby_info.h" + +void LobbyInfo::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_host"), &LobbyInfo::get_host); + ClassDB::bind_method(D_METHOD("get_max_players"), &LobbyInfo::get_max_players); + ClassDB::bind_method(D_METHOD("is_sealed"), &LobbyInfo::is_sealed); + ClassDB::bind_method(D_METHOD("is_password_protected"), &LobbyInfo::is_password_protected); + ClassDB::bind_method(D_METHOD("get_id"), &LobbyInfo::get_id); + ClassDB::bind_method(D_METHOD("get_lobby_name"), &LobbyInfo::get_lobby_name); + ClassDB::bind_method(D_METHOD("get_host_name"), &LobbyInfo::get_host_name); + ClassDB::bind_method(D_METHOD("get_players"), &LobbyInfo::get_players); + ClassDB::bind_method(D_METHOD("get_tags"), &LobbyInfo::get_tags); + ClassDB::bind_method(D_METHOD("get_data"), &LobbyInfo::get_data); + + ADD_PROPERTY(PropertyInfo(Variant::STRING, "id"), "", "get_id"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "tags"), "", "get_tags"); + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data"), "", "get_data"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "lobby_name"), "", "get_lobby_name"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "host_name"), "", "get_host_name"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "players"), "", "get_players"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "host"), "", "get_host"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "max_players"), "", "get_max_players"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sealed"), "", "is_sealed"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "password_protected"), "", "is_password_protected"); +} + +void LobbyInfo::set_id(const String &p_id) { id = p_id; } +void LobbyInfo::set_lobby_name(const String &p_lobby_name) { lobby_name = p_lobby_name; } +void LobbyInfo::set_host(const String &p_host) { host = p_host; } +void LobbyInfo::set_host_name(const String &p_host_name) { host_name = p_host_name; } +void LobbyInfo::set_max_players(int p_max_players) { max_players = p_max_players; } +void LobbyInfo::set_players(int p_players) { players = p_players; } +void LobbyInfo::set_sealed(bool p_sealed) { sealed = p_sealed; } +void LobbyInfo::set_password_protected(bool p_password_protected) { password_protected = p_password_protected; } +void LobbyInfo::set_tags(const Dictionary &p_tags) { tags = p_tags; } +void LobbyInfo::set_data(const Dictionary &p_data) { data = p_data; } + +void LobbyInfo::set_dict(const Dictionary &p_dict) { + set_host(p_dict.get("host", "")); + set_max_players(p_dict.get("max_players", 0)); + set_sealed(p_dict.get("sealed", false)); + set_players(p_dict.get("players", 0)); + set_id(p_dict.get("id", "")); + set_lobby_name(p_dict.get("name", "")); + set_host_name(p_dict.get("host_name", "")); + set_password_protected(p_dict.get("has_password", false)); + set_tags(p_dict.get("tags", Dictionary())); + set_data(p_dict.get("public_data", Dictionary())); +} +Dictionary LobbyInfo::get_dict() const { + Dictionary dict; + dict["host"] = get_host(); + dict["max_players"] = get_max_players(); + dict["sealed"] = is_sealed(); + dict["players"] = get_players(); + dict["id"] = get_id(); + dict["name"] = get_lobby_name(); + dict["host_name"] = get_host_name(); + dict["has_password"] = is_password_protected(); + dict["tags"] = get_tags(); + dict["public_data"] = get_data(); + return dict; +} + +Dictionary LobbyInfo::get_data() const { return data; } +Dictionary LobbyInfo::get_tags() const { return tags; } +String LobbyInfo::get_id() const { return id; } +String LobbyInfo::get_lobby_name() const { return lobby_name; } +String LobbyInfo::get_host() const { return host; } +String LobbyInfo::get_host_name() const { return host_name; } +int LobbyInfo::get_max_players() const { return max_players; } +int LobbyInfo::get_players() const { return players; } +bool LobbyInfo::is_sealed() const { return sealed; } +bool LobbyInfo::is_password_protected() const { return password_protected; } diff --git a/modules/blazium_sdk/lobby/lobby_info.h b/modules/blazium_sdk/lobby/lobby_info.h new file mode 100644 index 000000000000..6fb1a7b381e6 --- /dev/null +++ b/modules/blazium_sdk/lobby/lobby_info.h @@ -0,0 +1,79 @@ +/**************************************************************************/ +/* lobby_info.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 LOBBY_INFO_H +#define LOBBY_INFO_H + +#include "core/io/resource.h" + +class LobbyInfo : public Resource { + GDCLASS(LobbyInfo, Resource); + 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; + bool password_protected = false; + +protected: + static void _bind_methods(); + +public: + void set_id(const String &p_id); + void set_lobby_name(const String &p_lobby_name); + void set_host(const String &p_host); + void set_host_name(const String &p_host_name); + void set_max_players(int p_max_players); + void set_players(int p_players); + void set_sealed(bool p_sealed); + void set_password_protected(bool p_password_protected); + void set_tags(const Dictionary &p_tags); + void set_data(const Dictionary &p_data); + + void set_dict(const Dictionary &p_dict); + Dictionary get_dict() const; + + Dictionary get_data() const; + Dictionary get_tags() const; + String get_id() const; + String get_lobby_name() const; + String get_host() const; + String get_host_name() const; + int get_max_players() const; + int get_players() const; + bool is_sealed() const; + bool is_password_protected() const; +}; + +#endif // LOBBY_INFO_H diff --git a/modules/blazium_sdk/lobby/lobby_peer.cpp b/modules/blazium_sdk/lobby/lobby_peer.cpp new file mode 100644 index 000000000000..25436b44cfc3 --- /dev/null +++ b/modules/blazium_sdk/lobby/lobby_peer.cpp @@ -0,0 +1,36 @@ +#include "lobby_peer.h" + +void LobbyPeer::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_id"), &LobbyPeer::get_id); + ClassDB::bind_method(D_METHOD("get_peer_name"), &LobbyPeer::get_peer_name); + ClassDB::bind_method(D_METHOD("is_ready"), &LobbyPeer::is_ready); + ClassDB::bind_method(D_METHOD("get_data"), &LobbyPeer::get_data); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "id"), "", "get_id"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "peer_name"), "", "get_peer_name"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ready"), "", "is_ready"); + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data"), "", "get_data"); +} + +void LobbyPeer::set_id(const String &p_id) { id = p_id; } +void LobbyPeer::set_peer_name(const String &p_peer_name) { peer_name = p_peer_name; } +void LobbyPeer::set_ready(bool p_ready) { ready = p_ready; } +void LobbyPeer::set_data(const Dictionary &p_data) { data = p_data; } +void LobbyPeer::set_dict(const Dictionary &p_dict) { + set_id(p_dict.get("id", "")); + set_peer_name(p_dict.get("name", "")); + set_ready(p_dict.get("ready", "")); + set_data(p_dict.get("public_data", Dictionary())); +} +Dictionary LobbyPeer::get_dict() const { + Dictionary dict; + dict["id"] = get_id(); + dict["name"] = get_peer_name(); + dict["ready"] = is_ready(); + dict["public_data"] = get_data(); + return dict; +} + +Dictionary LobbyPeer::get_data() const { return data; } +String LobbyPeer::get_id() const { return id; } +String LobbyPeer::get_peer_name() const { return peer_name; } +bool LobbyPeer::is_ready() const { return ready; } diff --git a/modules/blazium_sdk/lobby/lobby_peer.h b/modules/blazium_sdk/lobby/lobby_peer.h new file mode 100644 index 000000000000..eee10c92ec8a --- /dev/null +++ b/modules/blazium_sdk/lobby/lobby_peer.h @@ -0,0 +1,60 @@ +/**************************************************************************/ +/* lobby_peer.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 LOBBY_PEER_H +#define LOBBY_PEER_H + +#include "core/io/resource.h" + +class LobbyPeer : public Resource { + GDCLASS(LobbyPeer, Resource); + String id = ""; + String peer_name = ""; + bool ready = false; + Dictionary data = Dictionary(); + +protected: + static void _bind_methods(); + +public: + void set_id(const String &p_id); + void set_peer_name(const String &p_name); + void set_ready(bool p_ready); + void set_data(const Dictionary &p_data); + void set_dict(const Dictionary &p_dict); + + Dictionary get_dict() const; + Dictionary get_data() const; + String get_id() const; + String get_peer_name() const; + bool is_ready() const; +}; + +#endif // LOBBY_PEER_H diff --git a/modules/blazium_sdk/lobby/lobby_response.h b/modules/blazium_sdk/lobby/lobby_response.h new file mode 100644 index 000000000000..802250acd120 --- /dev/null +++ b/modules/blazium_sdk/lobby/lobby_response.h @@ -0,0 +1,146 @@ +/**************************************************************************/ +/* lobby_response.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 LOBBY_RESPONSE_H +#define LOBBY_RESPONSE_H + +#include "core/object/ref_counted.h" +#include "core/variant/typed_array.h" +#include "lobby_info.h" +#include "lobby_peer.h" + +class LobbyResponse : public RefCounted { + GDCLASS(LobbyResponse, RefCounted); + +protected: + static void _bind_methods() { + ADD_SIGNAL(MethodInfo("finished", PropertyInfo(Variant::OBJECT, "result", PROPERTY_HINT_RESOURCE_TYPE, "LobbyResult"))); + } + +public: + class LobbyResult : public RefCounted { + GDCLASS(LobbyResult, RefCounted); + + String error = ""; + + protected: + static void _bind_methods() { + ClassDB::bind_method(D_METHOD("has_error"), &LobbyResult::has_error); + ClassDB::bind_method(D_METHOD("get_error"), &LobbyResult::get_error); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "error"), "", "get_error"); + } + + public: + void set_error(String p_error) { this->error = p_error; } + + bool has_error() const { return !error.is_empty(); } + String get_error() const { return error; } + }; +}; + +class ListLobbyResponse : public RefCounted { + GDCLASS(ListLobbyResponse, RefCounted); + +protected: + static void _bind_methods() { + ADD_SIGNAL(MethodInfo("finished", PropertyInfo(Variant::OBJECT, "result", PROPERTY_HINT_RESOURCE_TYPE, "ListLobbyResult"))); + } + +public: + class ListLobbyResult : public RefCounted { + GDCLASS(ListLobbyResult, RefCounted); + + String error = ""; + TypedArray lobbies = TypedArray(); + + protected: + static void _bind_methods() { + ClassDB::bind_method(D_METHOD("has_error"), &ListLobbyResult::has_error); + ClassDB::bind_method(D_METHOD("get_error"), &ListLobbyResult::get_error); + 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"); + } + + public: + void set_error(const String &p_error) { this->error = p_error; } + void set_lobbies(const TypedArray &p_lobbies) { this->lobbies = p_lobbies; } + + bool has_error() const { return !error.is_empty(); } + String get_error() const { return error; } + TypedArray get_lobbies() const { return lobbies; } + }; +}; + +class ViewLobbyResponse : public RefCounted { + GDCLASS(ViewLobbyResponse, RefCounted); + +protected: + static void _bind_methods() { + ADD_SIGNAL(MethodInfo("finished", PropertyInfo(Variant::OBJECT, "result", PROPERTY_HINT_RESOURCE_TYPE, "ViewLobbyResult"))); + } + +public: + class ViewLobbyResult : public RefCounted { + GDCLASS(ViewLobbyResult, RefCounted); + String error = ""; + TypedArray peers_info = TypedArray(); + Ref lobby_info; + + protected: + static void _bind_methods() { + ClassDB::bind_method(D_METHOD("has_error"), &ViewLobbyResult::has_error); + ClassDB::bind_method(D_METHOD("get_error"), &ViewLobbyResult::get_error); + ClassDB::bind_method(D_METHOD("get_peers"), &ViewLobbyResult::get_peers); + 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(PropertyInfo(Variant::STRING, "error"), "", "get_error"); + ADD_PROPERTY_DEFAULT("lobby", Ref()); + } + + public: + void set_error(const String &p_error) { this->error = p_error; } + void set_peers(const TypedArray &p_peers) { this->peers_info = p_peers; } + void set_lobby(const Ref &p_lobby_info) { this->lobby_info = p_lobby_info; } + + bool has_error() const { return !error.is_empty(); } + String get_error() const { return error; } + TypedArray get_peers() const { return peers_info; } + Ref get_lobby() const { return lobby_info; } + ViewLobbyResult() { + lobby_info.instantiate(); + } + ~ViewLobbyResult() { + } + }; +}; + +#endif // LOBBY_RESPONSE_H diff --git a/modules/blazium_sdk/register_types.cpp b/modules/blazium_sdk/register_types.cpp index 47086482c6b7..44839e6b873a 100644 --- a/modules/blazium_sdk/register_types.cpp +++ b/modules/blazium_sdk/register_types.cpp @@ -31,7 +31,11 @@ #include "register_types.h" #include "blazium_client.h" #include "lobby/authoritative_client.h" +#include "lobby/authoritative_response.h" #include "lobby/lobby_client.h" +#include "lobby/lobby_info.h" +#include "lobby/lobby_peer.h" +#include "lobby/lobby_response.h" #include "login/login_client.h" #include "master_server/master_server_client.h" #include "pogr/pogr_client.h" @@ -42,15 +46,15 @@ void initialize_blazium_sdk_module(ModuleInitializationLevel p_level) { GDREGISTER_CLASS(LobbyInfo); GDREGISTER_CLASS(LobbyPeer); GDREGISTER_CLASS(LobbyClient); - GDREGISTER_CLASS(LobbyClient::LobbyResponse::LobbyResult); - GDREGISTER_CLASS(LobbyClient::LobbyResponse); - GDREGISTER_CLASS(LobbyClient::ListLobbyResponse::ListLobbyResult); - GDREGISTER_CLASS(LobbyClient::ListLobbyResponse); - GDREGISTER_CLASS(LobbyClient::ViewLobbyResponse::ViewLobbyResult); - GDREGISTER_CLASS(LobbyClient::ViewLobbyResponse); + GDREGISTER_CLASS(LobbyResponse::LobbyResult); + GDREGISTER_CLASS(LobbyResponse); + GDREGISTER_CLASS(ListLobbyResponse::ListLobbyResult); + GDREGISTER_CLASS(ListLobbyResponse); + GDREGISTER_CLASS(ViewLobbyResponse::ViewLobbyResult); + GDREGISTER_CLASS(ViewLobbyResponse); GDREGISTER_CLASS(AuthoritativeClient); - GDREGISTER_CLASS(AuthoritativeClient::LobbyCallResponse); - GDREGISTER_CLASS(AuthoritativeClient::LobbyCallResponse::LobbyCallResult); + GDREGISTER_CLASS(AuthoritativeResponse); + GDREGISTER_CLASS(AuthoritativeResponse::AuthoritativeResult); GDREGISTER_CLASS(POGRClient); GDREGISTER_CLASS(POGRClient::POGRResponse); GDREGISTER_CLASS(POGRClient::POGRResult);