diff --git a/src/project.godot b/src/project.godot index c7a815b..0823541 100644 --- a/src/project.godot +++ b/src/project.godot @@ -30,7 +30,9 @@ FileManager="*uid://d2s50p717g3n" AccountServers="*uid://bpysjoq7n0ytu" Random="*uid://1js68qt8w0mv" GlobalAccount="*uid://dtlb70kxvbtvn" +Events="*uid://c656spc3ppdlw" UrlParser="*uid://budprjmmpally" +OAuth="*uid://jd7qlsley1no" [display] diff --git a/src/scenes/players/player.gd b/src/scenes/players/player.gd index d6e6692..9bf7309 100644 --- a/src/scenes/players/player.gd +++ b/src/scenes/players/player.gd @@ -48,10 +48,10 @@ func _input(event): if Input.is_action_just_pressed("escape"): if mouse_captured: capture_mouse(false) - hud.set_active_state(true) + Events.emit_signal("dash_set_state", true) else: capture_mouse(true) - hud.set_active_state(false) + Events.emit_signal("dash_set_state", false) return if event is InputEventMouseMotion && mouse_captured: diff --git a/src/scripts/libs/account.gd b/src/scripts/libs/account.gd index 6960ca3..f6da3e3 100644 --- a/src/scripts/libs/account.gd +++ b/src/scripts/libs/account.gd @@ -1,41 +1,71 @@ +# --- License +# File: /client/src/scripts/libs/account.gd +# Project: OpenMinerva +# Created Date: 26 February 2026 +# Copyright (c) 2026 OpenMinerva +# License: MIT License +# Authors: Armored Dragon +# --- License + extends Node var http = preload("res://scripts/network/http.gd").new() var time_lib = preload("res://scripts/libs/time.gd").new() -var oauth_lib = preload("res://scripts/libs/oauth.gd").new() - +var random_lib = preload("res://scripts/utils/random.gd").new() +var rsa_lib = preload("res://scripts/crypto/rsa.gd").new() + const ACCOUNT_DATABASE_DIRECTORY: String = "user://database/accounts.bin" # TODO: Create proper encryption of the account database # https://github.com/OpenMinerva/client/issues/59 -# This is just here for funsies for now. -const ENCRYPTION_KEY: String = "cb`$BaeGT12^)Zv{" var stop_connection_timer = false var active_account = {} var _database = [] func _ready(): - oauth_lib.start_server() + _load_account_database() ## Get a list of all accounts and return their information. func get_all() -> Array: return _database ## Adds an account to the account database. -func create(account: Dictionary) -> Dictionary: +func create(account: Dictionary, type: String) -> Dictionary: # Make sure we are only recording data we are intending on. + var account_formatted: Dictionary = {} + + if type == "oauth": + account_formatted = _create_oauth(account) + + if len(account_formatted.keys()) == 0: + GlobalLogger.logs("Tried to create an account, but there was nothing to save.", 3) + return {"ok": false, "error": "No account formatted.", "id": null} + + _database.append(account_formatted) + + _save_account_database() + + Events.emit_signal("dash_account_list_loaded") + return {"ok": true, "id": account_formatted.id} + +func _create_oauth(account) -> Dictionary: + var _account_keys = rsa_lib.generate_keypair() + var _clean_account = {} - _clean_account.id = account.get("id", null) - _clean_account.username = account.get("username", null) + _clean_account.id = random_lib.random_string(6, true) + _clean_account.display_name = account.get("display_name", null) _clean_account.account_server = account.get("account_server", null) - _clean_account.remember_me = account.get("remember_me", null) - _clean_account.local_account = account.get("local_account", null) + _clean_account.private_device_key = _account_keys.private + _clean_account.public_device_key = _account_keys.public - _database.append(_clean_account) - _save_account_database() + _clean_account.access_token = "" + _clean_account.refresh_token = "" + _clean_account.id_token = "" + _clean_account.access_token_expiry = 0 - return {"ok": true, "id": account.id} + _clean_account.type = "oauth" + return _clean_account ## Removes an account from the account database. func remove(id: String) -> Dictionary: @@ -43,13 +73,20 @@ func remove(id: String) -> Dictionary: var target_entry = _database.find_custom(func(entry): return entry.get("id") == id) _database.remove_at(target_entry) _save_account_database() + + Events.emit_signal("dash_account_list_loaded") + return {"ok": true} ## Sets an account as the active account. func use(id: String) -> void: GlobalLogger.logs("Setting active account to '%s'." % id, 1) + + # TODO: Check if account is still valid without trying to sign in. + # await authenticate_oauth(id) var _account = _get_account_by_id(id) active_account = _account + Events.emit_signal("dash_active_account_changed", active_account) return ## Signs out of the active account. @@ -57,35 +94,40 @@ func clear() -> void: active_account = {} return -func authenticate(id: String, remember_me: bool = false): - GlobalLogger.logs("Attempting to connect account '%s' to their account server." % id) +func update(id: String, data: Dictionary) -> void: + var target_entry = _database.find_custom(func(entry): return entry.get("id") == id) var account = _get_account_by_id(id) - var request_data = {"username": account.username, "rememberMe": remember_me, "account_server": account.account_server} + var _database_keys = account.keys() + var _data_keys = data.keys() - oauth_lib.start_oauth_process(request_data.account_server + "/oauth/authorize") - _try_check_connection() + for key in _data_keys: + if key not in _database_keys: + GlobalLogger.logs("Tried to update an invalid key in an account, '%s'." % key) + continue -func _try_check_connection(): - if oauth_lib.auth_server_url: - stop_connection_timer = true - return + account[key] = data[key] - if stop_connection_timer == true: - return + _database[target_entry] = account + _save_account_database() + return - var timer = get_tree().create_timer(2.0) - timer.connect("timeout", oauth_lib.check_connection) - await timer.timeout - _try_check_connection() +func authenticate_oauth(id: String, remember_me: bool = false) -> void: + # TODO: Error checks + GlobalLogger.logs("Attempting to connect account '%s' using oauth." % id) + var account = _get_account_by_id(id) + + # TODO: Check if account is still valid without trying to sign in. + var oauth_tokens = await OAuth.authenticate(account.account_server + "/oauth/authorize") + + update(id, oauth_tokens) ## Save the current account database we have in memory to the disk. func _save_account_database() -> void: + GlobalLogger.logs("Saving account database to disk.") DirAccess.open("user://").make_dir_recursive("user://database") - # var file = FileAccess.open_encrypted(ACCOUNT_DATABASE_DIRECTORY, FileAccess.WRITE, ENCRYPTION_KEY.sha256_buffer()) var file = FileAccess.open(ACCOUNT_DATABASE_DIRECTORY, FileAccess.WRITE) - if file: file.store_var(_database) # Serializes variable to binary file.close() @@ -95,12 +137,11 @@ func _save_account_database() -> void: func _load_account_database() -> Array: GlobalLogger.logs("Loading the local account database.", 1) - var account_file_exists = await FileAccess.file_exists(ACCOUNT_DATABASE_DIRECTORY) + var account_file_exists = FileAccess.file_exists(ACCOUNT_DATABASE_DIRECTORY) if account_file_exists == false: GlobalLogger.logs("Account database does not exist, creating one now.", 1) - await _save_account_database() + _save_account_database() - # var file = FileAccess.open_encrypted(ACCOUNT_DATABASE_DIRECTORY, FileAccess.READ, ENCRYPTION_KEY.sha256_buffer()) var file = FileAccess.open(ACCOUNT_DATABASE_DIRECTORY, FileAccess.READ) var account_data @@ -157,3 +198,21 @@ func _handle_response(response: Dictionary) -> Dictionary: response_data.body = JSON.parse_string(response.get("body")) return response_data + +# DEV: Upload public key to the server. +# func test_upload_public_key_to_server(): +# GlobalLogger.logs("Registering the device public key to the account server.") +# var body = { +# "public_key": active_account.public_device_key +# } +# var url_parts = UrlParser.deconstruct(active_account.account_server) +# if url_parts.ok == false: +# GlobalLogger.logs("Unhandled error registering the public device key to the account server. '%s'" % url_parts.error, 3) +# return +# url_parts = url_parts.data + +# print(url_parts) + +# var public_key_response = await http.req(HTTPClient.Method.METHOD_POST, url_parts.host, "/api/v1/device_key", url_parts.port, ["Accept: application/json", "Content-Type: application/json", "authorization: Bearer %s" % oauth_lib.access_token], JSON.stringify(body)) +# print(public_key_response) +# return diff --git a/src/scripts/libs/oauth.gd b/src/scripts/libs/oauth.gd index e485476..fa0d711 100644 --- a/src/scripts/libs/oauth.gd +++ b/src/scripts/libs/oauth.gd @@ -13,56 +13,23 @@ var http = preload("res://scripts/network/http.gd").new() var jwt_lib = preload("res://scripts/libs/jwt.gd").new() var random_lib = preload("res://scripts/utils/random.gd").new() -# TODO: Encrypt and store private token files. https://github.com/OpenMinerva/client/issues/59 - var port: int = 54000 var bind_address: String = "127.0.0.1" var redirect_server = TCPServer.new() -var secret_pkce: String = random_lib.random_string(50) -var auth_server_url: String -var auth_server_port: int -var access_token: String -var refresh_token: String -var id_token: String -var access_token_expiry: int +var _listen_for_oauth_connections: bool = false -func start_server(): - GlobalLogger.logs("Starting OAuth redirect server.", 0) - redirect_server.listen(port, bind_address) - return +func authenticate(account_server: String) -> Dictionary: + var secret_pkce: String = random_lib.random_string(50) + var account_server_url = UrlParser.deconstruct(account_server) + + if account_server_url.ok == false: + return {} + + account_server_url = account_server_url.data + + GlobalLogger.logs("Starting OAuth flow.", 0) -func stop_server(): - GlobalLogger.logs("Closing OAuth redirect server.", 0) - redirect_server = TCPServer.new() - return - -func check_connection(): - GlobalLogger.logs("Checking OAuth connections.", 0) - while redirect_server.is_connection_available(): - GlobalLogger.logs("Took a connection!", 0) - var connection = redirect_server.take_connection() - var request = connection.get_string(connection.get_available_bytes()) - if request: - # TODO: Make this more robust. - # ? How can I make sure that the code returned is valid? - var temp_auth_code: String = request.split("code=")[1].split("&iss=")[0].strip_edges() - var authentication_server = request.split("Referer: ")[1].split("\n")[0].strip_edges() - - GlobalLogger.logs("Got authentication code: '%s'." % temp_auth_code, 0) - _exchange_auth_code(temp_auth_code, authentication_server) - - # Send success. - var html_response = "HTTP/1.1 200 OK\r\n" - html_response += "Content-Type: text/html\r\n" - html_response += "Connection: close\r\n\r\n" - html_response += "
You can close this window now.
" - - connection.put_data(html_response.to_utf8_buffer()) - connection.disconnect_from_host() - stop_server() - -func start_oauth_process(account_server: String): var uri_parts := [ "client_id=%s" % "OpenMinerva-Game-Client", "redirect_uri=http://%s:%s" % [bind_address, port], @@ -73,76 +40,33 @@ func start_oauth_process(account_server: String): "code_challenge=%s" % _get_code_challenge(secret_pkce), "prompt=consent" ] + var uri = account_server + "?" + "&".join(uri_parts) OS.shell_open(uri) - return -func _exchange_auth_code(temp_auth_code: String, authentication_server: String): + GlobalLogger.logs("Starting OAuth redirect server.", 0) + redirect_server.listen(port, bind_address) + + _listen_for_oauth_connections = true + var _auth_code = await _wait_for_auth_code() + + GlobalLogger.logs("Closing OAuth redirect server.", 0) + redirect_server = TCPServer.new() + GlobalLogger.logs("Exchanging retrieved auth code for a proper token.", 0) var form_parts := [ "client_id=%s" % "OpenMinerva-Game-Client", "grant_type=authorization_code", - "code=%s" % temp_auth_code, + "code=%s" % _auth_code, "redirect_uri=http://%s:%s" % [bind_address, port], "code_challenge_method=S256", "code_verifier=%s" % secret_pkce, ] - var form_string: String = "&".join(form_parts) - - var url_parts = UrlParser.deconstruct(authentication_server) - auth_server_url = url_parts.data.host - auth_server_port = int(url_parts.data.port) - - var exchange_response = await http.req(HTTPClient.Method.METHOD_POST, auth_server_url, "/oauth/token", auth_server_port, ["Accept: application/json", "Content-Type: application/x-www-form-urlencoded"], form_string) - - if exchange_response.ok == false: - GlobalLogger.logs("Unhandled error with exchanging auth code for access_token.", 2) - return - + var exchange_response = await http.req(HTTPClient.Method.METHOD_POST, account_server_url.host, "/oauth/token", account_server_url.port, ["Accept: application/json", "Content-Type: application/x-www-form-urlencoded"], form_string) var token_data = JSON.parse_string(exchange_response.get("body")) - _get_tokens_from_response(token_data) - -func _refresh_tokens() -> void: - GlobalLogger.logs("Refreshing OAuth tokens.", 1) - # TODO: Error checks - var form_parts := [ - "client_id=%s" % "OpenMinerva-Game-Client", - "grant_type=refresh_token", - "refresh_token=%s" % refresh_token, - ] - - var form_string: String = "&".join(form_parts) - var refresh_response = await http.req(HTTPClient.Method.METHOD_POST, auth_server_url, "/oauth/token", auth_server_port, ["Accept: application/json", "Content-Type: application/x-www-form-urlencoded"], form_string) - var token_data = JSON.parse_string(refresh_response.get("body")) - _get_tokens_from_response(token_data) - return - -func _validate_token() -> Dictionary: - # TODO: Error checks - GlobalLogger.logs("Validating OAuth token.", 1) - - var return_dict: Dictionary = {"ok": false, "error": "", "data": {}} - - var form_parts := [ - "client_id=%s" % "OpenMinerva-Game-Client", - "token=%s" % access_token, - ] - var form_string: String = "&".join(form_parts) - - var validate_response = await http.req(HTTPClient.Method.METHOD_POST, auth_server_url, "/oauth/token/introspection", auth_server_port, ["Accept: application/json", "Content-Type: application/x-www-form-urlencoded"], form_string) - - if validate_response.ok == false: - GlobalLogger.logs("Unhandled error validating an OAuth token.", 4) - return_dict.error = "Unhandled error." - return return_dict - - var json_response = JSON.parse_string(validate_response.get("body")) - - return_dict.data = {"active": json_response.active} - return_dict.ok = true - return return_dict + return _get_tokens_from_response(token_data) func _get_code_challenge(verifier: String) -> String: var ctx = HashingContext.new() @@ -155,16 +79,46 @@ func _get_code_challenge(verifier: String) -> String: return base64_str -func _get_tokens_from_response(response: Dictionary) -> void: - # TODO: Error checks to prevent overwriting with bad data. - # ! Placeholder for development. Prevents overwriting data. - if access_token: - return +func _wait_for_auth_code() -> String: + var code: String = "" + + while code == "": + if redirect_server.is_connection_available(): + _listen_for_oauth_connections = false + code = _handle_auth_callback(redirect_server.take_connection()) + else: + await get_tree().process_frame + + return code + +func _handle_auth_callback(connection: StreamPeerTCP) -> String: + var request = connection.get_string(connection.get_available_bytes()) - access_token = response.get("access_token") - refresh_token = response.get("refresh_token") - id_token = response.get("id_token") - access_token_expiry = response.get("expires_in") + var temp_auth_code: String = request.split("code=")[1].split("&iss=")[0].strip_edges() - GlobalLogger.logs("New OAuth values:\naccess: %s\nrefresh: %s\nid: %s\nexpiry: %s" % [access_token, refresh_token, id_token, access_token_expiry], 0) - return + GlobalLogger.logs("Got authentication code: '%s'." % temp_auth_code, 0) + + # Send success. + var html_response = "HTTP/1.1 200 OK\r\n" + html_response += "Content-Type: text/html\r\n" + html_response += "Connection: close\r\n\r\n" + html_response += "You can close this window now.
" + + connection.put_data(html_response.to_utf8_buffer()) + connection.disconnect_from_host() + + return temp_auth_code + +func _exchange_code() -> Dictionary: + return {} + +func _get_tokens_from_response(response: Dictionary) -> Dictionary: + # TODO: Error checks to prevent overwriting with bad data. + var oauth_data = { + "access_token" = response.get("access_token"), + "refresh_token" = response.get("refresh_token"), + "id_token" = response.get("id_token"), + "access_token_expiry" = response.get("expires_in") + } + + return oauth_data diff --git a/src/scripts/signal_bus.gd b/src/scripts/signal_bus.gd new file mode 100644 index 0000000..acdea3c --- /dev/null +++ b/src/scripts/signal_bus.gd @@ -0,0 +1,20 @@ +# --- License +# File: /client/src/scripts/signal_bus.gd +# Project: OpenMinerva +# Created Date: 28 March 2026 +# Copyright (c) 2026 OpenMinerva +# License: MIT License +# Authors: Armored Dragon +# --- License +extends Node + +# Dashboard +signal dash_set_state(is_open: bool) +signal dash_switch_tab(page_name: String) +signal dash_active_account_changed(account: Dictionary) +signal dash_storage_changed(storage_data: Dictionary) +signal dash_session_changed(session_data: Dictionary) +signal dash_message_received(message: Dictionary) +signal dash_notification(notification: Dictionary) + +signal dash_account_list_loaded(account_list: PackedStringArray) \ No newline at end of file diff --git a/src/scripts/signal_bus.gd.uid b/src/scripts/signal_bus.gd.uid new file mode 100644 index 0000000..55a5805 --- /dev/null +++ b/src/scripts/signal_bus.gd.uid @@ -0,0 +1 @@ +uid://c656spc3ppdlw diff --git a/src/userinterface/account_create.gd b/src/userinterface/account_create.gd index 3dc38b5..2128804 100644 --- a/src/userinterface/account_create.gd +++ b/src/userinterface/account_create.gd @@ -88,8 +88,6 @@ func create_account() -> void: "local_account": false, # TODO "private_device_key": _device_keys.private, "public_device_key": _device_keys.public, - "private_account_server_jwt": {"token": "", "expires": 0}, - "public_account_server_passport": {"token": "", "expires": 0} } GlobalAccount.create(_account_dictionary) diff --git a/src/userinterface/dash/account_create.gd b/src/userinterface/dash/account_create.gd new file mode 100644 index 0000000..19d6233 --- /dev/null +++ b/src/userinterface/dash/account_create.gd @@ -0,0 +1,60 @@ +# --- License +# File: /client/src/userinterface/dash/account_create.gd +# Project: OpenMinerva +# Created Date: 28 March 2026 +# Copyright (c) 2026 OpenMinerva +# License: MIT License +# Authors: Armored Dragon +# --- License + +extends Control + +var _page_names = [] +@onready var create = get_node("Create") +@onready var select_oauth_btn = get_node("Create/SelectMethod/Container/OAuth") +@onready var create_oauth_btn = get_node("Create/OAuth/Create/HBoxContainer/ConfirmCreateAccount") +@onready var create_oauth_back_btn = get_node("Create/OAuth/Create/HBoxContainer/CreateAccountBack") + +func _ready(): + _get_pages() + select_oauth_btn.pressed.connect(_display_login_route.bind("OAuth")) + + create_oauth_btn.pressed.connect(_create_oauth) + create_oauth_back_btn.pressed.connect(_display_login_route.bind("SelectMethod")) + return + +func _display_oauth(): + return + +func _display_login_route(page_name: String): + if page_name not in _page_names: + GlobalLogger.logs("Tried to display an invalid login route.", 3) + return + + for page in create.get_children(): + if page.name == page_name: + page.visible = true + continue + + page.visible = false + return + +func _get_pages() -> void: + for page in create.get_children(): + _page_names.append(page.name) + return + +func _create_oauth() -> void: + var display_name = get_node("Create/OAuth/Create/VBoxContainer3/CADisplayName").text + var account_server = get_node("Create/OAuth/Create/VBoxContainer3/CAAccountServer").text + + var account = { + "display_name": display_name, + "account_server": account_server + } + + var res = GlobalAccount.create(account, "oauth") + + Events.emit_signal("dash_switch_tab", "AccountDisplay") + + return diff --git a/src/userinterface/dash/account_create.gd.uid b/src/userinterface/dash/account_create.gd.uid new file mode 100644 index 0000000..1866a83 --- /dev/null +++ b/src/userinterface/dash/account_create.gd.uid @@ -0,0 +1 @@ +uid://cchqs4c1p1prd diff --git a/src/userinterface/dash/account_list.gd b/src/userinterface/dash/account_list.gd new file mode 100644 index 0000000..14e47aa --- /dev/null +++ b/src/userinterface/dash/account_list.gd @@ -0,0 +1,69 @@ +# --- License +# File: /client/src/userinterface/dash/account_list.gd +# Project: OpenMinerva +# Created Date: 28 March 2026 +# Copyright (c) 2026 OpenMinerva +# License: MIT License +# Authors: Armored Dragon +# --- License + +extends Control + +@onready var _account_template = get_node("Templates/Account") +@onready var _account_list = get_node("List/ScrollContainer/AccountList") +@onready var _create_account_button = get_node("List/HBoxContainer/NewAccount") + +func _ready(): + _display_account_lists() + _create_account_button.pressed.connect(Events.emit_signal.bind("dash_switch_tab", "AccountCreate")) + + Events.dash_set_state.connect(_handle_dash_set_state) + Events.dash_account_list_loaded.connect(_handle_account_list_loaded) + return + +func _clear_account_listings() -> void: + for child in _account_list.get_children(): + child.queue_free() + return + +func _handle_dash_set_state(state: bool) -> void: + if state == false: + return + + _clear_account_listings() + _display_account_lists() + return + +func _handle_account_list_loaded() -> void: + _clear_account_listings() + _display_account_lists() + return + +func _display_account_lists() -> void: + var _list = GlobalAccount.get_all() + + if len(_list) == 0: + GlobalLogger.logs("No accounts to display.") + return + + for account in _list: + var _account_listing = _account_template.duplicate() + + var _username_node = _account_listing.get_node("MarginContainer/HBoxContainer/VBoxContainer/Username") + var _account_server_node = _account_listing.get_node("MarginContainer/HBoxContainer/VBoxContainer/AccountServer") + var _login_button = _account_listing.get_node("MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer/Login") + var _configure_button = _account_listing.get_node("MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer/Configure") + var _remove_button = _account_listing.get_node("MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer/Remove") + + # Display + if account.type == "oauth": + _username_node.text = account.display_name + _account_server_node.text = account.account_server + + # Event listeners + _login_button.pressed.connect(GlobalAccount.use.bind(account.id)) + _remove_button.pressed.connect(GlobalAccount.remove.bind(account.id)) + + _account_list.add_child(_account_listing) + GlobalLogger.logs("Added account '%s' to the login list." % account.id) + return diff --git a/src/userinterface/dash/account_list.gd.uid b/src/userinterface/dash/account_list.gd.uid new file mode 100644 index 0000000..e8d0fca --- /dev/null +++ b/src/userinterface/dash/account_list.gd.uid @@ -0,0 +1 @@ +uid://ftk8qksc10qg diff --git a/src/userinterface/dash/apps.gd b/src/userinterface/dash/apps.gd new file mode 100644 index 0000000..2f8863f --- /dev/null +++ b/src/userinterface/dash/apps.gd @@ -0,0 +1,10 @@ +# --- License +# File: /client/src/userinterface/dash/apps.gd +# Project: OpenMinerva +# Created Date: 27 March 2026 +# Copyright (c) 2026 OpenMinerva +# License: MIT License +# Authors: Armored Dragon +# --- License + +extends Control \ No newline at end of file diff --git a/src/userinterface/dash/apps.gd.uid b/src/userinterface/dash/apps.gd.uid new file mode 100644 index 0000000..9526fc4 --- /dev/null +++ b/src/userinterface/dash/apps.gd.uid @@ -0,0 +1 @@ +uid://di7li0digjpa8 diff --git a/src/userinterface/dash/contacts.gd b/src/userinterface/dash/contacts.gd new file mode 100644 index 0000000..c54ac2a --- /dev/null +++ b/src/userinterface/dash/contacts.gd @@ -0,0 +1,10 @@ +# --- License +# File: /client/src/userinterface/dash/contacts.gd +# Project: OpenMinerva +# Created Date: 27 March 2026 +# Copyright (c) 2026 OpenMinerva +# License: MIT License +# Authors: Armored Dragon +# --- License + +extends Control diff --git a/src/userinterface/dash/contacts.gd.uid b/src/userinterface/dash/contacts.gd.uid new file mode 100644 index 0000000..5468a3a --- /dev/null +++ b/src/userinterface/dash/contacts.gd.uid @@ -0,0 +1 @@ +uid://crlujtfv2bh1w diff --git a/src/userinterface/dash/debug.gd b/src/userinterface/dash/debug.gd new file mode 100644 index 0000000..3c4ba87 --- /dev/null +++ b/src/userinterface/dash/debug.gd @@ -0,0 +1,10 @@ +# --- License +# File: /client/src/userinterface/dash/debug.gd +# Project: OpenMinerva +# Created Date: 27 March 2026 +# Copyright (c) 2026 OpenMinerva +# License: MIT License +# Authors: Armored Dragon +# --- License + +extends Control \ No newline at end of file diff --git a/src/userinterface/dash/debug.gd.uid b/src/userinterface/dash/debug.gd.uid new file mode 100644 index 0000000..669c34b --- /dev/null +++ b/src/userinterface/dash/debug.gd.uid @@ -0,0 +1 @@ +uid://bwcvodv6u21jm diff --git a/src/userinterface/dash/exit.gd b/src/userinterface/dash/exit.gd new file mode 100644 index 0000000..e421ab5 --- /dev/null +++ b/src/userinterface/dash/exit.gd @@ -0,0 +1,10 @@ +# --- License +# File: /client/src/userinterface/dash/exit.gd +# Project: OpenMinerva +# Created Date: 27 March 2026 +# Copyright (c) 2026 OpenMinerva +# License: MIT License +# Authors: Armored Dragon +# --- License + +extends Control \ No newline at end of file diff --git a/src/userinterface/dash/exit.gd.uid b/src/userinterface/dash/exit.gd.uid new file mode 100644 index 0000000..6bf2d79 --- /dev/null +++ b/src/userinterface/dash/exit.gd.uid @@ -0,0 +1 @@ +uid://e1djdo6st2a7 diff --git a/src/userinterface/dash/home.gd b/src/userinterface/dash/home.gd new file mode 100644 index 0000000..e765a11 --- /dev/null +++ b/src/userinterface/dash/home.gd @@ -0,0 +1,37 @@ +# --- License +# File: /client/src/userinterface/dash/home.gd +# Project: OpenMinerva +# Created Date: 27 March 2026 +# Copyright (c) 2026 OpenMinerva +# License: MIT License +# Authors: Armored Dragon +# --- License + +extends Control + +@onready var account_card_container = get_node("HBoxContainer/VBoxContainer/AccountDisplay") +@onready var storage_card_container = get_node("HBoxContainer/VBoxContainer/StorageDisplay") +@onready var session_card_container = get_node("HBoxContainer/VBoxContainer3/SessionDisplay") + +func _ready(): + account_card_container.get_node("Button").pressed.connect(Events.emit_signal.bind("dash_switch_tab", "AccountDisplay")) + + Events.connect("dash_active_account_changed", _handle_active_account_changed) + Events.connect("dash_storage_changed", _handle_storage_changed) + Events.connect("dash_session_changed", _handle_session_changed) + + return + +func _handle_active_account_changed(account: Dictionary) -> void: + account_card_container.get_node("MarginContainer/HBoxContainer/VBoxContainer/Username").text = account.get("username") if account.get("username") else account.get("display_name") + account_card_container.get_node("MarginContainer/HBoxContainer/VBoxContainer/AccountServer").text = account.account_server + return + +func _handle_storage_changed(storage_data: Dictionary) -> void: + storage_card_container.get_node("MarginContainer/VBoxContainer/ProgressBar").value = storage_data.used_percent + storage_card_container.get_node("MarginContainer/VBoxContainer/Label2").text = "%s GiB used of %s GiB" % [storage_data.used_gigs, storage_data.total_gigs] + return + +func _handle_session_changed(session_data: Dictionary) -> void: + session_card_container.get_node("MarginContainer/HBoxContainer/VBoxContainer/SessionName").text = session_data.session_name + return diff --git a/src/userinterface/dash/home.gd.uid b/src/userinterface/dash/home.gd.uid new file mode 100644 index 0000000..b2c4911 --- /dev/null +++ b/src/userinterface/dash/home.gd.uid @@ -0,0 +1 @@ +uid://bwcgqn33pn62o diff --git a/src/userinterface/dash/instance.gd b/src/userinterface/dash/instance.gd new file mode 100644 index 0000000..4e048d2 --- /dev/null +++ b/src/userinterface/dash/instance.gd @@ -0,0 +1,10 @@ +# --- License +# File: /client/src/userinterface/dash/instance.gd +# Project: OpenMinerva +# Created Date: 27 March 2026 +# Copyright (c) 2026 OpenMinerva +# License: MIT License +# Authors: Armored Dragon +# --- License + +extends Control \ No newline at end of file diff --git a/src/userinterface/dash/instance.gd.uid b/src/userinterface/dash/instance.gd.uid new file mode 100644 index 0000000..1f83515 --- /dev/null +++ b/src/userinterface/dash/instance.gd.uid @@ -0,0 +1 @@ +uid://dpo2x4ddv3ftt diff --git a/src/userinterface/dash/inventory.gd b/src/userinterface/dash/inventory.gd new file mode 100644 index 0000000..25fef36 --- /dev/null +++ b/src/userinterface/dash/inventory.gd @@ -0,0 +1,10 @@ +# --- License +# File: /client/src/userinterface/dash/inventory.gd +# Project: OpenMinerva +# Created Date: 27 March 2026 +# Copyright (c) 2026 OpenMinerva +# License: MIT License +# Authors: Armored Dragon +# --- License + +extends Control \ No newline at end of file diff --git a/src/userinterface/dash/inventory.gd.uid b/src/userinterface/dash/inventory.gd.uid new file mode 100644 index 0000000..68f6055 --- /dev/null +++ b/src/userinterface/dash/inventory.gd.uid @@ -0,0 +1 @@ +uid://c25o2e0f3y6yx diff --git a/src/userinterface/dash/master.gd b/src/userinterface/dash/master.gd new file mode 100644 index 0000000..f7f66fb --- /dev/null +++ b/src/userinterface/dash/master.gd @@ -0,0 +1,56 @@ +# --- License +# File: /client/src/userinterface/dash/master.gd +# Project: OpenMinerva +# Created Date: 27 March 2026 +# Copyright (c) 2026 OpenMinerva +# License: MIT License +# Authors: Armored Dragon +# --- License + +extends Control + +var dashboard_tabs = [] +var dashboard_tab_names = [] + +@onready var dash_tab_master_container = get_node("MarginContainer/VBoxContainer/Master") +@onready var dash_nav_master_container = get_node("MarginContainer/VBoxContainer/NavBar/HBoxContainer") + +func _ready(): + _build_page_list() + + Events.connect("dash_set_state", _handle_set_dash_state) + Events.connect("dash_switch_tab", _handle_switch_tab) + + Events.emit_signal("dash_switch_tab", "Home") + +func _build_page_list(): + for child in get_node("MarginContainer/VBoxContainer/Master").get_children(): + child.add_to_group("_dashboard_pages") + dashboard_tab_names.append(child.name) + + for button in get_node("MarginContainer/VBoxContainer/NavBar/HBoxContainer").get_children(): + button.pressed.connect(_handle_switch_tab.bind(button.name)) + +func _handle_set_dash_state(is_open: bool) -> void: + GlobalLogger.logs("Changing dashboard state: '%s'" % is_open) + visible = is_open + +func _handle_switch_tab(target_name: String) -> void: + GlobalLogger.logs("Switching dashboard to page '%s'" % target_name) + + for dash_tab in dash_tab_master_container.get_children(): + dash_tab.visible = false + + for dash_nav_button in dash_nav_master_container.get_children(): + dash_nav_button.button_pressed = false + + if target_name not in dashboard_tab_names: + GlobalLogger.logs("Tried to switch to an invalid dashboard page: '%s'" % target_name, 2) + return + + dash_tab_master_container.get_node(target_name).visible = true + + if dash_nav_master_container.get_node(target_name): + dash_nav_master_container.get_node(target_name).button_pressed = true + + return diff --git a/src/userinterface/dash/master.gd.uid b/src/userinterface/dash/master.gd.uid new file mode 100644 index 0000000..73601b6 --- /dev/null +++ b/src/userinterface/dash/master.gd.uid @@ -0,0 +1 @@ +uid://cbl7rmnjxarba diff --git a/src/userinterface/dash/sessions.gd b/src/userinterface/dash/sessions.gd new file mode 100644 index 0000000..8610b15 --- /dev/null +++ b/src/userinterface/dash/sessions.gd @@ -0,0 +1,10 @@ +# --- License +# File: /client/src/userinterface/dash/sessions.gd +# Project: OpenMinerva +# Created Date: 27 March 2026 +# Copyright (c) 2026 OpenMinerva +# License: MIT License +# Authors: Armored Dragon +# --- License + +extends Control diff --git a/src/userinterface/dash/sessions.gd.uid b/src/userinterface/dash/sessions.gd.uid new file mode 100644 index 0000000..5cf606c --- /dev/null +++ b/src/userinterface/dash/sessions.gd.uid @@ -0,0 +1 @@ +uid://ccd2fw88a52mp diff --git a/src/userinterface/dash/settings.gd b/src/userinterface/dash/settings.gd new file mode 100644 index 0000000..49aad29 --- /dev/null +++ b/src/userinterface/dash/settings.gd @@ -0,0 +1,10 @@ +# --- License +# File: /client/src/userinterface/dash/settings.gd +# Project: OpenMinerva +# Created Date: 27 March 2026 +# Copyright (c) 2026 OpenMinerva +# License: MIT License +# Authors: Armored Dragon +# --- License + +extends Control \ No newline at end of file diff --git a/src/userinterface/dash/settings.gd.uid b/src/userinterface/dash/settings.gd.uid new file mode 100644 index 0000000..238acd9 --- /dev/null +++ b/src/userinterface/dash/settings.gd.uid @@ -0,0 +1 @@ +uid://cq26hbvdqb4sf diff --git a/src/userinterface/hud.tscn b/src/userinterface/hud.tscn index 25e683f..da75a60 100644 --- a/src/userinterface/hud.tscn +++ b/src/userinterface/hud.tscn @@ -2,26 +2,29 @@ [ext_resource type="Texture2D" uid="uid://7mgxvhy58nhp" path="res://resources/icons/home.svg" id="1_3b2ci"] [ext_resource type="Theme" uid="uid://bg2nbganyysst" path="res://openminerva_default.tres" id="1_cx7w0"] -[ext_resource type="Script" uid="uid://ilnwyivgoxev" path="res://userinterface/hud.gd" id="1_go5o5"] +[ext_resource type="Script" uid="uid://cbl7rmnjxarba" path="res://userinterface/dash/master.gd" id="1_ugu7k"] [ext_resource type="Texture2D" uid="uid://coqi7w7inqyv1" path="res://resources/icons/account.svg" id="2_bucoy"] [ext_resource type="Texture2D" uid="uid://crrjk7c2g4q55" path="res://resources/icons/art.svg" id="3_6vaiq"] +[ext_resource type="Script" uid="uid://bwcgqn33pn62o" path="res://userinterface/dash/home.gd" id="3_bnkjl"] [ext_resource type="Texture2D" uid="uid://c7ofnclcof0ud" path="res://resources/icons/world.svg" id="3_v4ccx"] [ext_resource type="StyleBox" uid="uid://cxx1q037xaswi" path="res://openminerva_darkpanel.tres" id="4_6rlgq"] [ext_resource type="Texture2D" uid="uid://dfckge3u00boi" path="res://resources/icons/contacts.svg" id="4_cyduv"] -[ext_resource type="Script" uid="uid://dv4joq6xcww25" path="res://userinterface/account_display.gd" id="4_pg41k"] -[ext_resource type="Script" uid="uid://dt060wcxkdwip" path="res://userinterface/account_create.gd" id="4_q6jcb"] [ext_resource type="Texture2D" uid="uid://cnhy47i7saehq" path="res://resources/icons/environment.svg" id="4_tkvwg"] [ext_resource type="Texture2D" uid="uid://rdp5i1i18jus" path="res://resources/icons/search.svg" id="4_wfski"] [ext_resource type="Texture2D" uid="uid://fkfiymss8p57" path="res://resources/icons/science.svg" id="5_hu6eh"] [ext_resource type="Texture2D" uid="uid://br6hpysqvuhek" path="res://resources/icons/inventory.svg" id="5_r82dk"] [ext_resource type="Texture2D" uid="uid://blkl4og334med" path="res://resources/icons/dummy16-9.webp" id="5_tkvwg"] +[ext_resource type="Script" uid="uid://ftk8qksc10qg" path="res://userinterface/dash/account_list.gd" id="5_upsw6"] +[ext_resource type="Script" uid="uid://cchqs4c1p1prd" path="res://userinterface/dash/account_create.gd" id="6_3rk53"] [ext_resource type="Texture2D" uid="uid://dp5u16rwxd0bp" path="res://resources/icons/apps.svg" id="6_6ybpt"] [ext_resource type="Texture2D" uid="uid://b0qo67fgifqe8" path="res://resources/icons/circus.svg" id="6_hu6eh"] [ext_resource type="Texture2D" uid="uid://basvqob80u3l6" path="res://resources/icons/settings.svg" id="7_tixj4"] +[ext_resource type="Script" uid="uid://ccd2fw88a52mp" path="res://userinterface/dash/sessions.gd" id="8_4ahgm"] [ext_resource type="Texture2D" uid="uid://b8fed1h3aqw1s" path="res://resources/icons/debug.svg" id="8_fgqsp"] [ext_resource type="Texture2D" uid="uid://8fwxg1ipf0fp" path="res://resources/icons/exit.svg" id="9_amc1p"] [ext_resource type="Texture2D" uid="uid://ckoajckje5mq2" path="res://resources/icons/edit.svg" id="9_xdslj"] [ext_resource type="Texture2D" uid="uid://ddchrocw45muh" path="res://resources/icons/flowchart.svg" id="12_hq11n"] +[ext_resource type="Script" uid="uid://crlujtfv2bh1w" path="res://userinterface/dash/contacts.gd" id="15_gll50"] [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_q6jcb"] bg_color = Color(1, 0, 0, 1) @@ -92,7 +95,7 @@ anchor_right = 1.0 anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 -script = ExtResource("1_go5o5") +script = ExtResource("1_ugu7k") [node name="MarginContainer" type="MarginContainer" parent="." unique_id=1988156212] layout_mode = 1 @@ -127,6 +130,7 @@ theme_override_constants/margin_left = 10 theme_override_constants/margin_top = 10 theme_override_constants/margin_right = 10 theme_override_constants/margin_bottom = 10 +script = ExtResource("3_bnkjl") [node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer/Master/Home" unique_id=581087957] layout_mode = 2 @@ -238,33 +242,33 @@ text = "Cloud" layout_mode = 2 theme_override_styles/normal = SubResource("StyleBoxFlat_kgckq") -[node name="PanelContainer2" type="PanelContainer" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer" unique_id=1169784328] +[node name="StorageDisplay" type="PanelContainer" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer" unique_id=1169784328] layout_mode = 2 size_flags_horizontal = 3 -[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer/PanelContainer2" unique_id=1944750319] +[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer/StorageDisplay" unique_id=1944750319] layout_mode = 2 theme_override_constants/margin_left = 10 theme_override_constants/margin_top = 10 theme_override_constants/margin_right = 10 theme_override_constants/margin_bottom = 10 -[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer/PanelContainer2/MarginContainer" unique_id=1039592827] +[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer/StorageDisplay/MarginContainer" unique_id=1039592827] layout_mode = 2 theme_override_constants/separation = 10 -[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer/PanelContainer2/MarginContainer/VBoxContainer" unique_id=21628856] +[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer/StorageDisplay/MarginContainer/VBoxContainer" unique_id=21628856] layout_mode = 2 text = "Used Storage" horizontal_alignment = 1 -[node name="ProgressBar" type="ProgressBar" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer/PanelContainer2/MarginContainer/VBoxContainer" unique_id=1535856991] +[node name="ProgressBar" type="ProgressBar" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer/StorageDisplay/MarginContainer/VBoxContainer" unique_id=1535856991] layout_mode = 2 theme_override_styles/background = SubResource("StyleBoxFlat_6vaiq") theme_override_styles/fill = SubResource("StyleBoxFlat_wfski") value = 25.0 -[node name="Label2" type="Label" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer/PanelContainer2/MarginContainer/VBoxContainer" unique_id=749951536] +[node name="Label2" type="Label" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer/StorageDisplay/MarginContainer/VBoxContainer" unique_id=749951536] layout_mode = 2 text = "2.5 GiB / 5 GiB" horizontal_alignment = 1 @@ -278,56 +282,56 @@ size_flags_horizontal = 3 layout_mode = 2 size_flags_horizontal = 3 -[node name="PanelContainer3" type="PanelContainer" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer3" unique_id=368133605] +[node name="SessionDisplay" type="PanelContainer" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer3" unique_id=368133605] layout_mode = 2 size_flags_horizontal = 3 -[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer3/PanelContainer3" unique_id=993828895] +[node name="MarginContainer" type="MarginContainer" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer3/SessionDisplay" unique_id=993828895] layout_mode = 2 theme_override_constants/margin_left = 10 theme_override_constants/margin_top = 10 theme_override_constants/margin_right = 10 theme_override_constants/margin_bottom = 10 -[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer3/PanelContainer3/MarginContainer" unique_id=1881644944] +[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer3/SessionDisplay/MarginContainer" unique_id=1881644944] layout_mode = 2 theme_override_constants/separation = 20 -[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer3/PanelContainer3/MarginContainer/HBoxContainer" unique_id=2054814657] +[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer3/SessionDisplay/MarginContainer/HBoxContainer" unique_id=2054814657] layout_mode = 2 size_flags_horizontal = 3 -[node name="Username" type="Label" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer3/PanelContainer3/MarginContainer/HBoxContainer/VBoxContainer" unique_id=1586628075] +[node name="SessionName" type="Label" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer3/SessionDisplay/MarginContainer/HBoxContainer/VBoxContainer" unique_id=1586628075] layout_mode = 2 theme_override_font_sizes/font_size = 20 text = "Session Name" -[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer3/PanelContainer3/MarginContainer/HBoxContainer/VBoxContainer" unique_id=1575315261] +[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer3/SessionDisplay/MarginContainer/HBoxContainer/VBoxContainer" unique_id=1575315261] layout_mode = 2 theme_override_constants/separation = 25 -[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer3/PanelContainer3/MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer" unique_id=408001748] +[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer3/SessionDisplay/MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer" unique_id=408001748] layout_mode = 2 -[node name="Panel" type="Panel" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer3/PanelContainer3/MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer" unique_id=770415475] +[node name="Panel" type="Panel" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer3/SessionDisplay/MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer" unique_id=770415475] custom_minimum_size = Vector2(20, 20) layout_mode = 2 theme_override_styles/panel = SubResource("StyleBoxFlat_bucoy") -[node name="AccountServer2" type="Label" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer3/PanelContainer3/MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer" unique_id=415378036] +[node name="AccountServer2" type="Label" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer3/SessionDisplay/MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer" unique_id=415378036] layout_mode = 2 theme_override_font_sizes/font_size = 12 text = "Spectator" -[node name="HBoxContainer2" type="HBoxContainer" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer3/PanelContainer3/MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer" unique_id=1848382474] +[node name="HBoxContainer2" type="HBoxContainer" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer3/SessionDisplay/MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer" unique_id=1848382474] layout_mode = 2 -[node name="Panel" type="Panel" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer3/PanelContainer3/MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer2" unique_id=1133926083] +[node name="Panel" type="Panel" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer3/SessionDisplay/MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer2" unique_id=1133926083] custom_minimum_size = Vector2(20, 20) layout_mode = 2 theme_override_styles/panel = SubResource("StyleBoxFlat_dr1q3") -[node name="AccountServer2" type="Label" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer3/PanelContainer3/MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer2" unique_id=36948057] +[node name="AccountServer2" type="Label" parent="MarginContainer/VBoxContainer/Master/Home/HBoxContainer/VBoxContainer3/SessionDisplay/MarginContainer/HBoxContainer/VBoxContainer/HBoxContainer/HBoxContainer2" unique_id=36948057] layout_mode = 2 theme_override_font_sizes/font_size = 12 text = "157 ms" @@ -344,7 +348,7 @@ theme_override_constants/margin_left = 10 theme_override_constants/margin_top = 10 theme_override_constants/margin_right = 10 theme_override_constants/margin_bottom = 10 -script = ExtResource("4_pg41k") +script = ExtResource("5_upsw6") [node name="List" type="VBoxContainer" parent="MarginContainer/VBoxContainer/Master/AccountDisplay" unique_id=1462685937] custom_minimum_size = Vector2(500, 0) @@ -433,7 +437,6 @@ size_flags_horizontal = 3 text = "Remove" [node name="AccountCreate" type="MarginContainer" parent="MarginContainer/VBoxContainer/Master" unique_id=476222424] -visible = false layout_mode = 1 anchors_preset = 15 anchor_right = 1.0 @@ -444,7 +447,7 @@ theme_override_constants/margin_left = 10 theme_override_constants/margin_top = 10 theme_override_constants/margin_right = 10 theme_override_constants/margin_bottom = 10 -script = ExtResource("4_q6jcb") +script = ExtResource("6_3rk53") [node name="Create" type="PanelContainer" parent="MarginContainer/VBoxContainer/Master/AccountCreate" unique_id=1338768232] layout_mode = 2 @@ -546,6 +549,15 @@ theme_override_constants/separation = 10 [node name="VBoxContainer3" type="VBoxContainer" parent="MarginContainer/VBoxContainer/Master/AccountCreate/Create/OAuth/Create" unique_id=1971820391] layout_mode = 2 +[node name="DisplayName" type="Label" parent="MarginContainer/VBoxContainer/Master/AccountCreate/Create/OAuth/Create/VBoxContainer3" unique_id=1545576882] +layout_mode = 2 +text = "Display Name" + +[node name="CADisplayName" type="LineEdit" parent="MarginContainer/VBoxContainer/Master/AccountCreate/Create/OAuth/Create/VBoxContainer3" unique_id=1868732970] +layout_mode = 2 +text = "Anonymous" +placeholder_text = "Display Name" + [node name="Label" type="Label" parent="MarginContainer/VBoxContainer/Master/AccountCreate/Create/OAuth/Create/VBoxContainer3" unique_id=1010954308] layout_mode = 2 text = "Account Server" @@ -611,6 +623,7 @@ theme_override_constants/margin_left = 10 theme_override_constants/margin_top = 10 theme_override_constants/margin_right = 10 theme_override_constants/margin_bottom = 10 +script = ExtResource("8_4ahgm") [node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer/Master/Sessions" unique_id=1830116526] layout_mode = 2 @@ -1426,6 +1439,7 @@ theme_override_constants/margin_left = 10 theme_override_constants/margin_top = 10 theme_override_constants/margin_right = 10 theme_override_constants/margin_bottom = 10 +script = ExtResource("15_gll50") [node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer/Master/Contacts" unique_id=609852715] layout_mode = 2 diff --git a/src/userinterface/ui_helper.gd b/src/userinterface/ui_helper.gd index 094f4df..eae450d 100644 --- a/src/userinterface/ui_helper.gd +++ b/src/userinterface/ui_helper.gd @@ -110,7 +110,6 @@ func display_dashboard_section(page_name: String = "") -> void: "Contacts": await tree.process_frame move_chat_scroll_to_bottom() - return func add_event_listeners_to_nav_buttons() -> void: