diff --git a/scenes/discovery_ui.tscn b/scenes/discovery_ui.tscn index bd28346..ccc71f3 100644 --- a/scenes/discovery_ui.tscn +++ b/scenes/discovery_ui.tscn @@ -45,6 +45,11 @@ custom_minimum_size = Vector2(100, 36) layout_mode = 2 text = "Refresh" +[node name="WorldListButton" type="Button" parent="VBox/Header"] +custom_minimum_size = Vector2(150, 36) +layout_mode = 2 +text = "πŸ—οΈ World Browser" + [node name="StatusLabel" type="Label" parent="VBox"] visible = false layout_mode = 2 diff --git a/scenes/main_menu.tscn b/scenes/main_menu.tscn index 550c2fa..78b9a63 100644 --- a/scenes/main_menu.tscn +++ b/scenes/main_menu.tscn @@ -107,26 +107,86 @@ visible = false text = "" horizontal_alignment = 1 -[node name="PlayButton" type="Button" parent="CenterContainer/VBoxContainer"] +[node name="DiscoverButton" type="Button" parent="CenterContainer/VBoxContainer"] +custom_minimum_size = Vector2(340, 38) layout_mode = 1 -text = "Play" +text = "πŸ—ΊοΈ Discover Experiences" size_flags_horizontal = 4 +disabled = true + +[node name="PlayButton" type="Button" parent="CenterContainer/VBoxContainer"] +custom_minimum_size = Vector2(340, 38) +layout_mode = 1 +text = "πŸ—οΈ Worlds Browser & Editor" +size_flags_horizontal = 4 +disabled = true [node name="CustomizeButton" type="Button" parent="CenterContainer/VBoxContainer"] +custom_minimum_size = Vector2(340, 38) layout_mode = 1 -text = "Customize Avatar" +text = "πŸ‘€ Customize Avatar" +size_flags_horizontal = 4 +disabled = true + +[node name="SocialButton" type="Button" parent="CenterContainer/VBoxContainer"] +custom_minimum_size = Vector2(340, 38) +layout_mode = 1 +text = "πŸ‘₯ Friends & Presence" +size_flags_horizontal = 4 +disabled = true + +[node name="ChatButton" type="Button" parent="CenterContainer/VBoxContainer"] +custom_minimum_size = Vector2(340, 38) +layout_mode = 1 +text = "πŸ’¬ Chat & Messages" +size_flags_horizontal = 4 +disabled = true + +[node name="MarketplaceButton" type="Button" parent="CenterContainer/VBoxContainer"] +custom_minimum_size = Vector2(340, 38) +layout_mode = 1 +text = "πŸ›’ Marketplace" +size_flags_horizontal = 4 +disabled = true + +[node name="WalletButton" type="Button" parent="CenterContainer/VBoxContainer"] +custom_minimum_size = Vector2(340, 38) +layout_mode = 1 +text = "πŸ’° Wallet & Currency" +size_flags_horizontal = 4 +disabled = true + +[node name="GroupsButton" type="Button" parent="CenterContainer/VBoxContainer"] +custom_minimum_size = Vector2(340, 38) +layout_mode = 1 +text = "πŸ›‘οΈ Groups & Clans" +size_flags_horizontal = 4 +disabled = true + +[node name="SellingButton" type="Button" parent="CenterContainer/VBoxContainer"] +custom_minimum_size = Vector2(340, 38) +layout_mode = 1 +text = "🏷️ Creator & Selling" size_flags_horizontal = 4 disabled = true [node name="QuitButton" type="Button" parent="CenterContainer/VBoxContainer"] +custom_minimum_size = Vector2(340, 38) layout_mode = 1 -text = "Quit" +text = "πŸšͺ Quit" size_flags_horizontal = 4 [connection signal="pressed" from="CenterContainer/VBoxContainer/AuthButtonsRow/LoginButton" to="." method="_on_login_button_pressed"] [connection signal="pressed" from="CenterContainer/VBoxContainer/AuthButtonsRow/RegisterButton" to="." method="_on_register_button_pressed"] +[connection signal="pressed" from="CenterContainer/VBoxContainer/DiscoverButton" to="." method="_on_discover_button_pressed"] [connection signal="pressed" from="CenterContainer/VBoxContainer/PlayButton" to="." method="_on_play_button_pressed"] [connection signal="pressed" from="CenterContainer/VBoxContainer/CustomizeButton" to="." method="_on_customize_button_pressed"] +[connection signal="pressed" from="CenterContainer/VBoxContainer/SocialButton" to="." method="_on_social_button_pressed"] +[connection signal="pressed" from="CenterContainer/VBoxContainer/ChatButton" to="." method="_on_chat_button_pressed"] +[connection signal="pressed" from="CenterContainer/VBoxContainer/MarketplaceButton" to="." method="_on_marketplace_button_pressed"] +[connection signal="pressed" from="CenterContainer/VBoxContainer/WalletButton" to="." method="_on_wallet_button_pressed"] +[connection signal="pressed" from="CenterContainer/VBoxContainer/GroupsButton" to="." method="_on_groups_button_pressed"] +[connection signal="pressed" from="CenterContainer/VBoxContainer/SellingButton" to="." method="_on_selling_button_pressed"] [connection signal="pressed" from="CenterContainer/VBoxContainer/QuitButton" to="." method="_on_quit_button_pressed"] [connection signal="pressed" from="CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/AuthButton" to="." method="_on_auth_button_pressed"] [connection signal="text_submitted" from="CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/UsernameEdit" to="." method="_on_auth_button_pressed"] diff --git a/scenes/world_list.tscn b/scenes/world_list.tscn index 62701a4..405eb8d 100644 --- a/scenes/world_list.tscn +++ b/scenes/world_list.tscn @@ -36,6 +36,11 @@ horizontal_alignment = 1 size_flags_horizontal = 3 theme_override_font_sizes/font_size = 28 +[node name="DiscoverButton" type="Button" parent="VBoxContainer/HeaderHBox"] +layout_mode = 3 +text = "πŸ—ΊοΈ Discover Feed" +size_flags_horizontal = 0 + [node name="CreateButton" type="Button" parent="VBoxContainer/HeaderHBox"] layout_mode = 3 text = "+ Create World" @@ -80,5 +85,6 @@ horizontal_alignment = 1 theme_override_font_sizes/font_size = 18 [connection signal="pressed" from="VBoxContainer/HeaderHBox/BackButton" to="." method="_on_back_button_pressed"] +[connection signal="pressed" from="VBoxContainer/HeaderHBox/DiscoverButton" to="." method="_on_discover_button_pressed"] [connection signal="pressed" from="VBoxContainer/HeaderHBox/CreateButton" to="." method="_on_create_button_pressed"] [connection signal="pressed" from="VBoxContainer/HeaderHBox/RefreshButton" to="." method="_on_refresh_button_pressed"] diff --git a/scripts/discovery_ui.gd b/scripts/discovery_ui.gd index 7810fb9..3b3ec51 100644 --- a/scripts/discovery_ui.gd +++ b/scripts/discovery_ui.gd @@ -10,6 +10,7 @@ signal worlds_loaded(count: int) @onready var back_button: Button = $VBox/Header/BackButton @onready var refresh_button: Button = $VBox/Header/RefreshButton +@onready var world_list_button: Button = $VBox/Header.get_node_or_null("WorldListButton") @onready var status_label: Label = $VBox/StatusLabel # Filter Controls @@ -94,6 +95,8 @@ func _wire_signals() -> void: prev_button.pressed.connect(_on_prev_page_pressed) if next_button and not next_button.pressed.is_connected(_on_next_page_pressed): next_button.pressed.connect(_on_next_page_pressed) + if world_list_button and not world_list_button.pressed.is_connected(_on_world_list_pressed): + world_list_button.pressed.connect(_on_world_list_pressed) func load_categories() -> void: @@ -372,5 +375,10 @@ func _on_next_page_pressed() -> void: func _on_back_pressed() -> void: back_requested.emit() - if get_tree(): + if get_tree() and get_tree().current_scene == self: get_tree().change_scene_to_file("res://scenes/main_menu.tscn") + + +func _on_world_list_pressed() -> void: + if get_tree(): + get_tree().change_scene_to_file("res://scenes/world_list.tscn") diff --git a/scripts/game.gd b/scripts/game.gd index d14f99f..fe06271 100644 --- a/scripts/game.gd +++ b/scripts/game.gd @@ -36,6 +36,10 @@ var _status_label: Label = null ## normal play"). Editing is in-memory only here; the save path to the ## backend is a sibling task (world_persistence_impl.md). var _build_editor: InGameEditor = null +var _chat_overlay: Control = null +var _friends_overlay: Control = null +var _hud_layer: CanvasLayer = null +var _overlay_layer: CanvasLayer = null var _stream_manager: ChunkStreamManager = null @@ -47,6 +51,7 @@ func _ready() -> void: if Session.editing: _open_editor_for_world() else: + _setup_in_game_hud() if Session.active: _setup_networked() _setup_chunk_streaming() @@ -165,6 +170,18 @@ func _hide_default_test_props() -> void: func _unhandled_input(event: InputEvent) -> void: + if event is InputEventKey and event.pressed and not event.echo: + if event.keycode == KEY_T or (event.keycode == KEY_ENTER and not (_chat_overlay != null and is_instance_valid(_chat_overlay))): + if not Session.editing and not (_build_editor != null and is_instance_valid(_build_editor)): + get_viewport().set_input_as_handled() + _toggle_chat_overlay() + return + elif event.keycode == KEY_TAB or event.keycode == KEY_F1: + if not Session.editing and not (_build_editor != null and is_instance_valid(_build_editor)): + get_viewport().set_input_as_handled() + _toggle_friends_overlay() + return + if event.is_action_pressed("toggle_build_mode"): # world_persistence_impl.md Β§6 D4: the non-joined "Edit world" entry # already has its editor open from _ready() -- F2 here is the @@ -174,14 +191,14 @@ func _unhandled_input(event: InputEvent) -> void: _toggle_build_mode() return - # ESC leaves the world back to the browser (or, while build mode is - # open, just closes build mode instead). Handled here (the scene root - # that owns the connection) rather than in player.gd so the teardown is - # a single ordered path -- doing it from two places raced _on_server_lost - # against the scene change and looked like a crash. + # ESC leaves the world back to the browser (or closes an open overlay/editor). if event.is_action_pressed("ui_cancel"): get_viewport().set_input_as_handled() - if Session.editing: + if _chat_overlay != null and is_instance_valid(_chat_overlay): + _close_chat_overlay() + elif _friends_overlay != null and is_instance_valid(_friends_overlay): + _close_friends_overlay() + elif Session.editing: # Non-joined editing has no play session to fall back into -- # closing it means leaving, same as the Close button. _exit_editor_to_browser() @@ -191,6 +208,194 @@ func _unhandled_input(event: InputEvent) -> void: _leave_world() +# ─── In-Game HUD & Social Overlays ─────────────────────────────────────────── + +func _setup_in_game_hud() -> void: + if Session.editing: + return + if _hud_layer != null and is_instance_valid(_hud_layer): + return + _hud_layer = CanvasLayer.new() + _hud_layer.name = "InGameHUD" + _hud_layer.layer = 10 + add_child(_hud_layer) + + var panel := PanelContainer.new() + panel.name = "HUDPanel" + panel.position = Vector2(20, 20) + var style := StyleBoxFlat.new() + style.bg_color = Color(0.1, 0.12, 0.16, 0.8) + style.border_color = Color(0.3, 0.35, 0.45, 0.8) + style.set_border_width_all(1) + style.set_corner_radius_all(6) + style.content_margin_left = 8 + style.content_margin_right = 8 + style.content_margin_top = 6 + style.content_margin_bottom = 6 + panel.add_theme_stylebox_override("panel", style) + _hud_layer.add_child(panel) + + var bar := HBoxContainer.new() + bar.name = "QuickActionBar" + bar.add_theme_constant_override("separation", 8) + panel.add_child(bar) + + var chat_btn := Button.new() + chat_btn.text = "πŸ’¬ Chat [T]" + chat_btn.pressed.connect(_toggle_chat_overlay) + bar.add_child(chat_btn) + + var friends_btn := Button.new() + friends_btn.text = "πŸ‘₯ Friends [Tab]" + friends_btn.pressed.connect(_toggle_friends_overlay) + bar.add_child(friends_btn) + + var build_btn := Button.new() + build_btn.text = "πŸ”¨ Build [F2]" + build_btn.pressed.connect(_toggle_build_mode) + bar.add_child(build_btn) + + var exit_btn := Button.new() + exit_btn.text = "πŸšͺ Menu [ESC]" + exit_btn.pressed.connect(func(): + if _chat_overlay != null and is_instance_valid(_chat_overlay): + _close_chat_overlay() + elif _friends_overlay != null and is_instance_valid(_friends_overlay): + _close_friends_overlay() + elif _build_editor != null and is_instance_valid(_build_editor): + _close_build_mode() + else: + _leave_world() + ) + bar.add_child(exit_btn) + + +func _toggle_chat_overlay() -> void: + if _chat_overlay != null and is_instance_valid(_chat_overlay): + _close_chat_overlay() + else: + _open_chat_overlay() + + +func _open_chat_overlay() -> void: + if _friends_overlay != null and is_instance_valid(_friends_overlay): + _close_friends_overlay() + if _build_editor != null and is_instance_valid(_build_editor): + _close_build_mode() + + Input.mouse_mode = Input.MOUSE_MODE_VISIBLE + _player.set_physics_process(false) + _player.set_process_unhandled_input(false) + + if _overlay_layer == null or not is_instance_valid(_overlay_layer): + _overlay_layer = CanvasLayer.new() + _overlay_layer.name = "OverlayLayer" + _overlay_layer.layer = 20 + add_child(_overlay_layer) + + var bg := ColorRect.new() + bg.name = "OverlayBG" + bg.color = Color(0.06, 0.08, 0.12, 0.9) + bg.set_anchors_preset(Control.PRESET_FULL_RECT) + _overlay_layer.add_child(bg) + + var chat_scene := load("res://scenes/chat_ui.tscn") + _chat_overlay = chat_scene.instantiate() as Control + _chat_overlay.set_anchors_preset(Control.PRESET_FULL_RECT) + bg.add_child(_chat_overlay) + + # If active in a world, configure world chat automatically + if Session.world_id != null and int(Session.world_id) > 0: + var wid_edit = _chat_overlay.find_child("WorldIdEdit", true, false) as LineEdit + if wid_edit != null: + wid_edit.text = str(Session.world_id) + if _chat_overlay.has_method("switch_world_chat"): + _chat_overlay.switch_world_chat(int(Session.world_id)) + + if _chat_overlay.has_signal("back_requested"): + _chat_overlay.back_requested.connect(_close_chat_overlay) + + var back_btn = _chat_overlay.find_child("BackButton", true, false) as Button + if back_btn != null: + back_btn.text = "βœ• Close Chat" + if not back_btn.pressed.is_connected(_close_chat_overlay): + back_btn.pressed.connect(_close_chat_overlay) + + var msg_input = _chat_overlay.find_child("MessageInput", true, false) as LineEdit + if msg_input != null: + msg_input.grab_focus.call_deferred() + + +func _close_chat_overlay() -> void: + if _chat_overlay != null and is_instance_valid(_chat_overlay): + _chat_overlay.queue_free() + _chat_overlay = null + if _overlay_layer != null and is_instance_valid(_overlay_layer): + _overlay_layer.queue_free() + _overlay_layer = null + + _player.set_physics_process(true) + _player.set_process_unhandled_input(true) + _player._refresh_mouse_mode() + + +func _toggle_friends_overlay() -> void: + if _friends_overlay != null and is_instance_valid(_friends_overlay): + _close_friends_overlay() + else: + _open_friends_overlay() + + +func _open_friends_overlay() -> void: + if _chat_overlay != null and is_instance_valid(_chat_overlay): + _close_chat_overlay() + if _build_editor != null and is_instance_valid(_build_editor): + _close_build_mode() + + Input.mouse_mode = Input.MOUSE_MODE_VISIBLE + _player.set_physics_process(false) + _player.set_process_unhandled_input(false) + + if _overlay_layer == null or not is_instance_valid(_overlay_layer): + _overlay_layer = CanvasLayer.new() + _overlay_layer.name = "OverlayLayer" + _overlay_layer.layer = 20 + add_child(_overlay_layer) + + var bg := ColorRect.new() + bg.name = "OverlayBG" + bg.color = Color(0.06, 0.08, 0.12, 0.9) + bg.set_anchors_preset(Control.PRESET_FULL_RECT) + _overlay_layer.add_child(bg) + + var friends_scene := load("res://scenes/friends_presence_ui.tscn") + _friends_overlay = friends_scene.instantiate() as Control + _friends_overlay.set_anchors_preset(Control.PRESET_FULL_RECT) + bg.add_child(_friends_overlay) + + if _friends_overlay.has_signal("back_requested"): + _friends_overlay.back_requested.connect(_close_friends_overlay) + + var back_btn = _friends_overlay.find_child("BackButton", true, false) as Button + if back_btn != null: + back_btn.text = "βœ• Close" + if not back_btn.pressed.is_connected(_close_friends_overlay): + back_btn.pressed.connect(_close_friends_overlay) + + +func _close_friends_overlay() -> void: + if _friends_overlay != null and is_instance_valid(_friends_overlay): + _friends_overlay.queue_free() + _friends_overlay = null + if _overlay_layer != null and is_instance_valid(_overlay_layer): + _overlay_layer.queue_free() + _overlay_layer = null + + _player.set_physics_process(true) + _player.set_process_unhandled_input(true) + _player._refresh_mouse_mode() + + ## Entry point into the in-game editor (docs/architecture/editor.md Β§7.2). ## Freezes the player and opens a fresh, empty in-memory chunk to edit -- ## loading a *real* chunk from the backend for editing is the sibling @@ -204,6 +409,11 @@ func _toggle_build_mode() -> void: func _open_build_mode() -> void: + if _chat_overlay != null and is_instance_valid(_chat_overlay): + _close_chat_overlay() + if _friends_overlay != null and is_instance_valid(_friends_overlay): + _close_friends_overlay() + var world_id_str := str(Session.world_id) if Session.world_id != null else "0" var room_slug := "main" var coord := Vector3i.ZERO diff --git a/scripts/main_menu.gd b/scripts/main_menu.gd index c3f7fe7..bb74b75 100644 --- a/scripts/main_menu.gd +++ b/scripts/main_menu.gd @@ -39,8 +39,15 @@ var _dob_edit: LineEdit var _auth_button: Button var _status_label: Label var _welcome_label: Label +var _discover_button: Button var _play_button: Button var _customize_button: Button +var _social_button: Button +var _chat_button: Button +var _marketplace_button: Button +var _wallet_button: Button +var _groups_button: Button +var _selling_button: Button var _quit_button: Button var _is_register_mode: bool = false @@ -93,16 +100,22 @@ func _ready() -> void: _auth_button = $CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/AuthButton _status_label = $CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/AuthStatusLabel _welcome_label = $CenterContainer/VBoxContainer/AuthPanel/MarginContainer/AuthVBox/WelcomeLabel + _discover_button = $CenterContainer/VBoxContainer.get_node_or_null("DiscoverButton") _play_button = $CenterContainer/VBoxContainer/PlayButton _customize_button = $CenterContainer/VBoxContainer/CustomizeButton + _social_button = $CenterContainer/VBoxContainer.get_node_or_null("SocialButton") + _chat_button = $CenterContainer/VBoxContainer.get_node_or_null("ChatButton") + _marketplace_button = $CenterContainer/VBoxContainer.get_node_or_null("MarketplaceButton") + _wallet_button = $CenterContainer/VBoxContainer.get_node_or_null("WalletButton") + _groups_button = $CenterContainer/VBoxContainer.get_node_or_null("GroupsButton") + _selling_button = $CenterContainer/VBoxContainer.get_node_or_null("SellingButton") _quit_button = $CenterContainer/VBoxContainer/QuitButton - # Default to Play being gated. When a token exists, the async session + # Default to navigation being gated. When a token exists, the async session # check below may take several frames (a real get_me() round-trip); # keeping the button disabled until validation succeeds prevents a fast # click from navigating to world_list with an expired/invalid token. - _play_button.disabled = true - _customize_button.disabled = true + _set_nav_enabled(false) # Check whether a valid session already exists (e.g. user logged in, # navigated to world_list, then clicked Back). If so, restore the @@ -122,6 +135,16 @@ func _ready() -> void: auth_state_ready.emit() +func _set_nav_enabled(enabled: bool) -> void: + var buttons = [ + _discover_button, _play_button, _customize_button, _social_button, + _chat_button, _marketplace_button, _wallet_button, _groups_button, _selling_button + ] + for b in buttons: + if b != null and is_instance_valid(b): + b.disabled = not enabled + + ## Restore the UI to the authenticated state (Play enabled, welcome message ## visible, auth buttons hidden). AuthPanel itself stays visible -- the ## welcome label lives inside it, so hiding the panel hides the label too @@ -148,8 +171,7 @@ func _show_authenticated(username: String) -> void: _dob_edit.visible = false _auth_button.visible = false _auth_mode_label.visible = false - _play_button.disabled = false - _customize_button.disabled = false + _set_nav_enabled(true) _auth_buttons_row.visible = false print("Restored authenticated session for: ", username) @@ -163,18 +185,21 @@ func _reset_to_logged_out() -> void: _email_edit.visible = false _dob_edit.visible = false _dob_edit.text = "" - _play_button.disabled = true # Gate play behind successful auth. - _customize_button.disabled = true + _set_nav_enabled(false) _update_auth_mode_ui() -# ─── Play / Quit ────────────────────────────────────────────────────────────── +# ─── Navigation ─────────────────────────────────────────────────────────────── + +func _on_discover_button_pressed() -> void: + if _discover_button != null and _discover_button.disabled: + return + get_tree().change_scene_to_file("res://scenes/discovery_ui.tscn") + func _on_play_button_pressed() -> void: if _play_button.disabled: return - # Browse worlds is the first real screen past login -- actual gameplay - # (joining a world) doesn't exist yet, browsing does. get_tree().change_scene_to_file("res://scenes/world_list.tscn") @@ -184,6 +209,42 @@ func _on_customize_button_pressed() -> void: get_tree().change_scene_to_file("res://scenes/avatar_customization.tscn") +func _on_social_button_pressed() -> void: + if _social_button != null and _social_button.disabled: + return + get_tree().change_scene_to_file("res://scenes/friends_presence_ui.tscn") + + +func _on_chat_button_pressed() -> void: + if _chat_button != null and _chat_button.disabled: + return + get_tree().change_scene_to_file("res://scenes/chat_ui.tscn") + + +func _on_marketplace_button_pressed() -> void: + if _marketplace_button != null and _marketplace_button.disabled: + return + get_tree().change_scene_to_file("res://scenes/marketplace_ui.tscn") + + +func _on_wallet_button_pressed() -> void: + if _wallet_button != null and _wallet_button.disabled: + return + get_tree().change_scene_to_file("res://scenes/wallet_ui.tscn") + + +func _on_groups_button_pressed() -> void: + if _groups_button != null and _groups_button.disabled: + return + get_tree().change_scene_to_file("res://scenes/groups_ui.tscn") + + +func _on_selling_button_pressed() -> void: + if _selling_button != null and _selling_button.disabled: + return + get_tree().change_scene_to_file("res://scenes/selling_payout_ui.tscn") + + func _on_quit_button_pressed() -> void: get_tree().quit() @@ -301,8 +362,7 @@ func _on_auth_complete(result: Dictionary) -> void: _status_label.visible = false _welcome_label.text = "Welcome, %s!" % _username_edit.text.strip_edges() _welcome_label.visible = true - _play_button.disabled = false - _customize_button.disabled = false + _set_nav_enabled(true) _auth_buttons_row.visible = false print("Auth successful. Token stored.") await _prime_avatar() diff --git a/scripts/marketplace_ui.gd b/scripts/marketplace_ui.gd index a3d8f66..86efec9 100644 --- a/scripts/marketplace_ui.gd +++ b/scripts/marketplace_ui.gd @@ -69,6 +69,8 @@ func _wire_signals() -> void: func _on_back_pressed() -> void: back_requested.emit() + if get_tree() and get_tree().current_scene == self: + get_tree().change_scene_to_file("res://scenes/main_menu.tscn") func show_status(text: String, is_error: bool = false) -> void: diff --git a/scripts/selling_payout_ui.gd b/scripts/selling_payout_ui.gd index 6a80d1a..7ac2f5b 100644 --- a/scripts/selling_payout_ui.gd +++ b/scripts/selling_payout_ui.gd @@ -72,6 +72,8 @@ func _wire_signals() -> void: func _on_back_pressed() -> void: back_requested.emit() + if get_tree() and get_tree().current_scene == self: + get_tree().change_scene_to_file("res://scenes/main_menu.tscn") func show_status(text: String, is_error: bool = false) -> void: diff --git a/scripts/wallet_ui.gd b/scripts/wallet_ui.gd index 9d72292..a390915 100644 --- a/scripts/wallet_ui.gd +++ b/scripts/wallet_ui.gd @@ -68,6 +68,8 @@ func _wire_signals() -> void: func _on_back_pressed() -> void: back_requested.emit() + if get_tree() and get_tree().current_scene == self: + get_tree().change_scene_to_file("res://scenes/main_menu.tscn") func show_status(text: String, is_error: bool = false) -> void: diff --git a/scripts/world_list.gd b/scripts/world_list.gd index d4783c7..028a319 100644 --- a/scripts/world_list.gd +++ b/scripts/world_list.gd @@ -201,6 +201,10 @@ func _on_back_button_pressed() -> void: get_tree().change_scene_to_file("res://scenes/main_menu.tscn") +func _on_discover_button_pressed() -> void: + get_tree().change_scene_to_file("res://scenes/discovery_ui.tscn") + + ## Fetch the world list from the backend and update the UI. func _refresh_worlds() -> void: