658 lines
24 KiB
GDScript
658 lines
24 KiB
GDScript
extends CanvasLayer
|
|
|
|
# Game UI - Main menu and multiplayer lobby
|
|
|
|
@onready var main_menu = $Control/MainMenu
|
|
@onready var host_button = $Control/MainMenu/VBoxContainer/HostButton
|
|
@onready var join_button = $Control/MainMenu/VBoxContainer/JoinButton
|
|
@onready var network_mode_option = $Control/MainMenu/VBoxContainer/NetworkModeContainer/NetworkModeOption
|
|
@onready var network_mode_container = $Control/MainMenu/VBoxContainer/NetworkModeContainer
|
|
@onready var local_players_spinbox = $Control/MainMenu/VBoxContainer/LocalPlayersContainer/SpinBox
|
|
@onready var address_input = $Control/MainMenu/VBoxContainer/AddressContainer/AddressInput
|
|
@onready var room_fetch_status_container = $Control/MainMenu/VBoxContainer/RoomFetchStatusContainer
|
|
@onready var loading_label = $Control/MainMenu/VBoxContainer/RoomFetchStatusContainer/RoomFetchLoadingContainer/LoadingLabel
|
|
@onready var loading_spinner = $Control/MainMenu/VBoxContainer/RoomFetchStatusContainer/RoomFetchLoadingContainer/LoadingSpinner
|
|
@onready var last_fetch_label = $Control/MainMenu/VBoxContainer/RoomFetchStatusContainer/LastFetchLabel
|
|
|
|
@onready var network_manager = $"/root/NetworkManager"
|
|
|
|
var connection_error_label: Label = null
|
|
var connection_error_shown: bool = false # Prevent spamming error messages
|
|
var is_joining_attempt: bool = false
|
|
var last_join_address: String = ""
|
|
var room_fetch_timer: Timer = null # Timer for retrying room fetches
|
|
var is_auto_joining: bool = false # Track if we're in auto-join mode
|
|
var is_hosting: bool = false # Track if we're hosting (don't fetch rooms when hosting)
|
|
var room_list_container: VBoxContainer = null # Container for displaying available rooms
|
|
var refresh_button: Button = null # Refresh button for manually reloading rooms
|
|
var refresh_cooldown_timer: Timer = null # Timer for refresh button cooldown
|
|
|
|
func _ready():
|
|
# Wait for nodes to be ready
|
|
await get_tree().process_frame
|
|
|
|
# Debug: Print node paths (UI category - disabled by default for network debugging)
|
|
LogManager.log("GameUI _ready() called", LogManager.CATEGORY_UI)
|
|
LogManager.log("Main menu node: " + str(main_menu), LogManager.CATEGORY_UI)
|
|
LogManager.log("Host button node: " + str(host_button), LogManager.CATEGORY_UI)
|
|
LogManager.log("Join button node: " + str(join_button), LogManager.CATEGORY_UI)
|
|
|
|
# Verify nodes exist
|
|
if not host_button:
|
|
push_error("host_button is null! Check node path: $Control/MainMenu/VBoxContainer/HostButton")
|
|
return
|
|
if not join_button:
|
|
push_error("join_button is null! Check node path: $Control/MainMenu/VBoxContainer/JoinButton")
|
|
return
|
|
|
|
# Connect buttons
|
|
host_button.pressed.connect(_on_host_pressed)
|
|
join_button.pressed.connect(_on_join_pressed)
|
|
|
|
# Setup network mode dropdown
|
|
if network_mode_option:
|
|
network_mode_option.item_selected.connect(_on_network_mode_changed)
|
|
|
|
# On web builds, filter out ENet option (only WebRTC and WebSocket available)
|
|
if OS.get_name() == "Web":
|
|
LogManager.log("GameUI: Web platform detected, filtering network mode options", LogManager.CATEGORY_UI)
|
|
# Remove ENet option (index 0) for web builds
|
|
network_mode_option.remove_item(0)
|
|
# Adjust selected index (was 0 for ENet, now 0 is WebRTC)
|
|
network_mode_option.selected = 0
|
|
# Update network manager to use WebRTC by default
|
|
network_manager.set_network_mode(1)
|
|
else:
|
|
# On native builds, default to ENet (index 0)
|
|
network_mode_option.selected = 0
|
|
network_manager.set_network_mode(0)
|
|
|
|
# Update address input placeholder based on initial mode
|
|
_on_network_mode_changed(network_mode_option.selected)
|
|
|
|
# Connect network signals
|
|
if network_manager:
|
|
network_manager.connection_succeeded.connect(_on_connection_succeeded)
|
|
network_manager.connection_failed.connect(_on_connection_failed)
|
|
# Connect to rooms_fetched for displaying rooms (non-auto-join mode)
|
|
if not network_manager.rooms_fetched.is_connected(_on_rooms_fetched_display):
|
|
network_manager.rooms_fetched.connect(_on_rooms_fetched_display)
|
|
else:
|
|
push_error("NetworkManager not found!")
|
|
|
|
# Check for command-line arguments
|
|
_check_command_line_args()
|
|
|
|
# If WebRTC is selected at startup (not auto-joining and not hosting), fetch rooms
|
|
if not is_auto_joining and not is_hosting:
|
|
var current_mode = network_manager.network_mode
|
|
if current_mode == 1: # WebRTC
|
|
_start_room_fetch()
|
|
|
|
func _check_command_line_args():
|
|
var args = OS.get_cmdline_args()
|
|
LogManager.log("GameUI: Parsing command-line arguments: " + str(args), LogManager.CATEGORY_UI)
|
|
|
|
# Parse arguments
|
|
var should_host = false
|
|
var should_join = false
|
|
var should_debug = false
|
|
var force_webrtc = false
|
|
var join_address = "" # Empty by default - will fetch rooms if WebRTC/WebSocket
|
|
var local_count = 1
|
|
|
|
for arg in args:
|
|
if arg == "--host":
|
|
should_host = true
|
|
LogManager.log("GameUI: Found --host argument", LogManager.CATEGORY_UI)
|
|
elif arg == "--join":
|
|
should_join = true
|
|
LogManager.log("GameUI: Found --join argument", LogManager.CATEGORY_UI)
|
|
elif arg == "--websocket" or arg == "--webrtc":
|
|
force_webrtc = true
|
|
LogManager.log("GameUI: Found --websocket/--webrtc argument (forcing WebSocket mode)", LogManager.CATEGORY_UI)
|
|
elif arg == "--room-debug":
|
|
should_debug = true
|
|
LogManager.log("GameUI: Found --room-debug argument", LogManager.CATEGORY_UI)
|
|
elif arg.begins_with("--address="):
|
|
join_address = arg.split("=")[1]
|
|
elif arg.begins_with("--players="):
|
|
local_count = int(arg.split("=")[1])
|
|
|
|
LogManager.log("GameUI: Parsed flags - should_host: " + str(should_host) + ", should_join: " + str(should_join) + ", force_webrtc: " + str(force_webrtc) + ", should_debug: " + str(should_debug), LogManager.CATEGORY_UI)
|
|
|
|
# Force WebRTC mode if --webrtc flag is present
|
|
if force_webrtc:
|
|
network_manager.set_network_mode(1) # WebRTC
|
|
if network_mode_option:
|
|
if OS.get_name() == "Web":
|
|
network_mode_option.selected = 0 # WebRTC is first option on web
|
|
else:
|
|
network_mode_option.selected = 1 # WebRTC is second option on native
|
|
_on_network_mode_changed(network_mode_option.selected)
|
|
LogManager.log("GameUI: WebRTC mode forced via --webrtc flag", LogManager.CATEGORY_UI)
|
|
|
|
# Set debug flag only if --room-debug is used with --host or --join
|
|
if should_debug and (should_host or should_join):
|
|
network_manager.show_room_labels = true
|
|
LogManager.log("Debug mode enabled: room labels will be shown", LogManager.CATEGORY_UI)
|
|
else:
|
|
LogManager.log("GameUI: Debug mode NOT enabled - should_debug: " + str(should_debug) + ", should_host: " + str(should_host) + ", should_join: " + str(should_join), LogManager.CATEGORY_UI)
|
|
|
|
# Auto-start based on arguments
|
|
if should_host:
|
|
is_hosting = true # Set flag so we don't fetch rooms
|
|
LogManager.log("Auto-hosting due to --host argument", LogManager.CATEGORY_UI)
|
|
network_manager.set_local_player_count(local_count)
|
|
if network_manager.host_game():
|
|
_start_game()
|
|
elif should_join:
|
|
# Check network mode after it's been set
|
|
var current_mode = network_manager.network_mode
|
|
if join_address.is_empty() and (current_mode == 1 or current_mode == 2):
|
|
# No address provided, and using WebRTC or WebSocket - fetch and auto-join first available room
|
|
LogManager.log("Auto-joining: No address provided, fetching available rooms (mode: " + str(current_mode) + ")...", LogManager.CATEGORY_UI)
|
|
network_manager.set_local_player_count(local_count)
|
|
is_auto_joining = true
|
|
# Create timer for retrying room fetches
|
|
room_fetch_timer = Timer.new()
|
|
room_fetch_timer.name = "RoomFetchTimer"
|
|
room_fetch_timer.wait_time = 2.0 # Retry every 2 seconds
|
|
room_fetch_timer.timeout.connect(_retry_room_fetch)
|
|
room_fetch_timer.autostart = false
|
|
add_child(room_fetch_timer)
|
|
# Connect to rooms_fetched signal (not one-shot, so we can keep retrying)
|
|
if not network_manager.rooms_fetched.is_connected(_on_rooms_fetched_auto_join):
|
|
network_manager.rooms_fetched.connect(_on_rooms_fetched_auto_join)
|
|
# Show room fetch status UI and start fetching
|
|
_show_room_fetch_status()
|
|
_start_room_fetch()
|
|
elif not join_address.is_empty():
|
|
LogManager.log("Auto-joining to " + join_address + " due to --join argument", LogManager.CATEGORY_UI)
|
|
address_input.text = join_address
|
|
network_manager.set_local_player_count(local_count)
|
|
if network_manager.join_game(join_address):
|
|
# Connection callback will handle starting the game
|
|
pass
|
|
else:
|
|
# ENet mode without address - need a default address
|
|
var default_address = "127.0.0.1"
|
|
LogManager.log("Auto-joining to " + default_address + " due to --join argument (ENet mode, no address provided)", LogManager.CATEGORY_UI)
|
|
address_input.text = default_address
|
|
network_manager.set_local_player_count(local_count)
|
|
if network_manager.join_game(default_address):
|
|
# Connection callback will handle starting the game
|
|
pass
|
|
|
|
func _on_rooms_fetched_display(rooms: Array):
|
|
"""Display available rooms when fetched (non-auto-join mode)"""
|
|
# Only handle if not in auto-join mode (auto-join has its own handler)
|
|
if is_auto_joining:
|
|
return # Let auto-join handler take care of it
|
|
|
|
# Hide loading indicator - request completed
|
|
_hide_loading_indicator()
|
|
|
|
# Update last fetch time
|
|
_update_last_fetch_time()
|
|
|
|
# Clear existing room list
|
|
_clear_room_list()
|
|
|
|
# Display rooms if any are found
|
|
if rooms.is_empty():
|
|
LogManager.log("GameUI: No available rooms found", LogManager.CATEGORY_UI)
|
|
# Keep room fetch status visible so user can see "Last fetched: ..." even with no rooms
|
|
# Add a "No rooms available" message
|
|
_add_room_list_header("No available rooms")
|
|
else:
|
|
LogManager.log("GameUI: Found " + str(rooms.size()) + " available room(s)", LogManager.CATEGORY_UI)
|
|
# Add header
|
|
_add_room_list_header("Available Rooms:")
|
|
# Add each room to the list
|
|
for room in rooms:
|
|
var room_code = room.get("room", "")
|
|
var players = room.get("players", 0)
|
|
var level = room.get("level", 1)
|
|
_add_room_item(room_code, players, level)
|
|
|
|
func _on_rooms_fetched_auto_join(rooms: Array):
|
|
"""Auto-join the first available room when --join --webrtc is used without address"""
|
|
if not is_auto_joining:
|
|
return # Not in auto-join mode, ignore
|
|
|
|
# Hide loading indicator - request completed
|
|
_hide_loading_indicator()
|
|
|
|
# Update last fetch time
|
|
_update_last_fetch_time()
|
|
|
|
if rooms.is_empty():
|
|
LogManager.log("No available rooms found, will retry in 2 seconds...", LogManager.CATEGORY_UI)
|
|
# Start timer to retry fetching
|
|
if room_fetch_timer:
|
|
room_fetch_timer.start()
|
|
return
|
|
|
|
# Stop retrying - we found rooms!
|
|
if room_fetch_timer:
|
|
room_fetch_timer.stop()
|
|
is_auto_joining = false
|
|
|
|
# Hide room fetch status UI
|
|
_hide_room_fetch_status()
|
|
|
|
# Disconnect from signal since we're done
|
|
if network_manager.rooms_fetched.is_connected(_on_rooms_fetched_auto_join):
|
|
network_manager.rooms_fetched.disconnect(_on_rooms_fetched_auto_join)
|
|
|
|
# Sort rooms by player count (prefer rooms with more players, but not full)
|
|
rooms.sort_custom(func(a, b): return a.get("players", 0) < b.get("players", 0))
|
|
|
|
# Try to join the first room
|
|
var room = rooms[0]
|
|
var room_code = room.get("room", "")
|
|
if room_code.is_empty():
|
|
LogManager.log("Room code is empty, cannot join - will retry", LogManager.CATEGORY_UI)
|
|
# Restart timer to retry
|
|
if room_fetch_timer:
|
|
room_fetch_timer.start()
|
|
is_auto_joining = true
|
|
# Keep showing status UI
|
|
return
|
|
|
|
# Get local player count from spinbox (same as _on_join_pressed does)
|
|
var local_count = int(local_players_spinbox.value)
|
|
|
|
LogManager.log("Auto-joining room: " + room_code + " (players: " + str(room.get("players", 0)) + ", level: " + str(room.get("level", 1)) + ")", LogManager.CATEGORY_UI)
|
|
address_input.text = room_code
|
|
network_manager.set_local_player_count(local_count)
|
|
if network_manager.join_game(room_code):
|
|
# Connection callback will handle starting the game
|
|
pass
|
|
|
|
func _retry_room_fetch():
|
|
"""Retry fetching available rooms"""
|
|
if not is_auto_joining:
|
|
if room_fetch_timer:
|
|
room_fetch_timer.stop()
|
|
return
|
|
|
|
LogManager.log("Retrying room fetch...", LogManager.CATEGORY_UI)
|
|
_start_room_fetch()
|
|
|
|
func _start_room_fetch():
|
|
"""Start fetching rooms and show loading indicator"""
|
|
# Only fetch if WebRTC mode and not hosting
|
|
if network_manager.network_mode != 1: # Not WebRTC
|
|
return
|
|
|
|
if is_hosting or network_manager.is_hosting:
|
|
LogManager.log("GameUI: Skipping room fetch - we are hosting", LogManager.CATEGORY_UI)
|
|
return
|
|
|
|
# Show the status container and loading indicator
|
|
_show_room_fetch_status()
|
|
_show_loading_indicator()
|
|
|
|
# Check if a request is already in progress before starting a new one
|
|
var fetch_result = network_manager.fetch_available_rooms()
|
|
if not fetch_result:
|
|
# Request failed or is already in progress - hide loading indicator
|
|
_hide_loading_indicator()
|
|
# Start timer to retry (only in auto-join mode)
|
|
if is_auto_joining and room_fetch_timer:
|
|
room_fetch_timer.start()
|
|
|
|
func _show_room_fetch_status():
|
|
"""Show the room fetch status UI"""
|
|
if room_fetch_status_container:
|
|
room_fetch_status_container.visible = true
|
|
if last_fetch_label:
|
|
last_fetch_label.text = "Last fetched: Never"
|
|
# Create room list container if it doesn't exist
|
|
_create_room_list_container()
|
|
# Create refresh button if it doesn't exist
|
|
_create_refresh_button()
|
|
|
|
func _show_loading_indicator():
|
|
"""Show the loading indicator"""
|
|
if loading_label:
|
|
loading_label.text = "Loading rooms..."
|
|
if loading_spinner:
|
|
loading_spinner.text = "⏳"
|
|
|
|
func _hide_loading_indicator():
|
|
"""Hide the loading indicator"""
|
|
if loading_label:
|
|
loading_label.text = ""
|
|
if loading_spinner:
|
|
loading_spinner.text = ""
|
|
|
|
func _hide_room_fetch_status():
|
|
"""Hide the room fetch status UI"""
|
|
if room_fetch_status_container:
|
|
room_fetch_status_container.visible = false
|
|
|
|
func _create_refresh_button():
|
|
"""Create a refresh button for manually reloading the room list"""
|
|
if refresh_button:
|
|
return # Already exists
|
|
|
|
if not room_fetch_status_container:
|
|
return
|
|
|
|
# Create HBoxContainer for refresh button (below last fetch label)
|
|
var refresh_container = HBoxContainer.new()
|
|
refresh_container.name = "RefreshButtonContainer"
|
|
refresh_container.alignment = BoxContainer.ALIGNMENT_END
|
|
|
|
# Create refresh button
|
|
refresh_button = Button.new()
|
|
refresh_button.name = "RefreshButton"
|
|
refresh_button.text = "Refresh Rooms"
|
|
refresh_button.pressed.connect(_on_refresh_button_pressed)
|
|
|
|
refresh_container.add_child(refresh_button)
|
|
|
|
# Add refresh container after LastFetchLabel (or at the end if LastFetchLabel doesn't exist)
|
|
var last_fetch_node = room_fetch_status_container.get_node_or_null("LastFetchLabel")
|
|
if last_fetch_node:
|
|
var index = last_fetch_node.get_index() + 1
|
|
room_fetch_status_container.add_child(refresh_container)
|
|
room_fetch_status_container.move_child(refresh_container, index)
|
|
else:
|
|
room_fetch_status_container.add_child(refresh_container)
|
|
|
|
# Create cooldown timer
|
|
refresh_cooldown_timer = Timer.new()
|
|
refresh_cooldown_timer.name = "RefreshCooldownTimer"
|
|
refresh_cooldown_timer.wait_time = 5.0
|
|
refresh_cooldown_timer.one_shot = true
|
|
refresh_cooldown_timer.timeout.connect(_on_refresh_cooldown_finished)
|
|
refresh_cooldown_timer.autostart = false
|
|
add_child(refresh_cooldown_timer)
|
|
|
|
func _on_refresh_button_pressed():
|
|
"""Handle refresh button click"""
|
|
# Disable button and start cooldown
|
|
if refresh_button:
|
|
refresh_button.disabled = true
|
|
refresh_button.text = "Refreshing..."
|
|
|
|
if refresh_cooldown_timer:
|
|
refresh_cooldown_timer.start()
|
|
|
|
# Fetch rooms
|
|
_start_room_fetch()
|
|
|
|
func _on_refresh_cooldown_finished():
|
|
"""Re-enable refresh button after cooldown"""
|
|
if refresh_button:
|
|
refresh_button.disabled = false
|
|
refresh_button.text = "Refresh Rooms"
|
|
|
|
func _update_last_fetch_time():
|
|
"""Update the last fetch time label with current datetime"""
|
|
if last_fetch_label:
|
|
var now = Time.get_datetime_dict_from_system()
|
|
var time_str = "%02d:%02d:%02d" % [now.hour, now.minute, now.second]
|
|
last_fetch_label.text = "Last fetched: " + time_str
|
|
|
|
func _create_room_list_container():
|
|
"""Create the container for displaying available rooms"""
|
|
if room_list_container:
|
|
return # Already exists
|
|
|
|
if not room_fetch_status_container:
|
|
return
|
|
|
|
# Create a ScrollContainer for the room list
|
|
var scroll_container = ScrollContainer.new()
|
|
scroll_container.name = "RoomListScrollContainer"
|
|
scroll_container.custom_minimum_size = Vector2(0, 150) # Set a reasonable height
|
|
scroll_container.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
|
|
# Create VBoxContainer inside scroll container
|
|
room_list_container = VBoxContainer.new()
|
|
room_list_container.name = "RoomListContainer"
|
|
room_list_container.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
|
|
scroll_container.add_child(room_list_container)
|
|
|
|
# Add scroll container to room_fetch_status_container (after LastFetchLabel)
|
|
room_fetch_status_container.add_child(scroll_container)
|
|
|
|
func _clear_room_list():
|
|
"""Clear all room items from the list"""
|
|
if room_list_container:
|
|
for child in room_list_container.get_children():
|
|
child.queue_free()
|
|
|
|
func _add_room_list_header(text: String):
|
|
"""Add a header label to the room list"""
|
|
if not room_list_container:
|
|
_create_room_list_container()
|
|
if not room_list_container:
|
|
return
|
|
|
|
var label = Label.new()
|
|
label.text = text
|
|
label.add_theme_font_size_override("font_size", 14)
|
|
room_list_container.add_child(label)
|
|
|
|
func _add_room_item(room_code: String, players: int, level: int):
|
|
"""Add a room item with join button to the list"""
|
|
if not room_list_container:
|
|
_create_room_list_container()
|
|
if not room_list_container:
|
|
return
|
|
|
|
# Create HBoxContainer for this room
|
|
var room_row = HBoxContainer.new()
|
|
room_row.name = "RoomRow_" + room_code
|
|
|
|
# Room code label
|
|
var code_label = Label.new()
|
|
code_label.text = room_code
|
|
code_label.custom_minimum_size = Vector2(100, 0)
|
|
code_label.add_theme_font_size_override("font_size", 12)
|
|
room_row.add_child(code_label)
|
|
|
|
# Info label (players, level)
|
|
var info_label = Label.new()
|
|
info_label.text = "Players: %d | Level: %d" % [players, level]
|
|
info_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
info_label.add_theme_font_size_override("font_size", 12)
|
|
room_row.add_child(info_label)
|
|
|
|
# Join button
|
|
var room_join_button = Button.new()
|
|
room_join_button.text = "Join"
|
|
room_join_button.custom_minimum_size = Vector2(80, 0)
|
|
# Connect button to join function
|
|
room_join_button.pressed.connect(func(): _join_room(room_code))
|
|
room_row.add_child(room_join_button)
|
|
|
|
room_list_container.add_child(room_row)
|
|
|
|
func _join_room(room_code: String):
|
|
"""Join a room by setting the address and clicking join"""
|
|
if room_code.is_empty():
|
|
return
|
|
|
|
# Set the address input
|
|
if address_input:
|
|
address_input.text = room_code
|
|
|
|
# Get local player count
|
|
var local_count = int(local_players_spinbox.value)
|
|
network_manager.set_local_player_count(local_count)
|
|
|
|
# Join the game
|
|
if network_manager.join_game(room_code):
|
|
LogManager.log("Joining room: " + room_code, LogManager.CATEGORY_UI)
|
|
|
|
func _on_network_mode_changed(index: int):
|
|
# On web builds, index 0 = WebRTC, index 1 = WebSocket
|
|
# On native builds, index 0 = ENet, index 1 = WebRTC, index 2 = WebSocket
|
|
var actual_mode: int
|
|
if OS.get_name() == "Web":
|
|
# Web builds: 0 = WebRTC, 1 = WebSocket
|
|
actual_mode = index + 1 # Map 0->1 (WebRTC), 1->2 (WebSocket)
|
|
else:
|
|
# Native builds: 0 = ENet, 1 = WebRTC, 2 = WebSocket
|
|
actual_mode = index
|
|
|
|
network_manager.set_network_mode(actual_mode)
|
|
|
|
# Update address input placeholder based on mode
|
|
if address_input:
|
|
match actual_mode:
|
|
0: # ENet
|
|
address_input.placeholder_text = "Server IP or domain"
|
|
1: # WebRTC
|
|
address_input.placeholder_text = "Enter Room Code (e.g., ABC123)"
|
|
2: # WebSocket
|
|
address_input.placeholder_text = "Enter Room Code (e.g., ABC123)"
|
|
|
|
var mode_names = ["ENet", "WebRTC", "WebSocket"]
|
|
LogManager.log("GameUI: Network mode changed to: " + mode_names[actual_mode], LogManager.CATEGORY_UI)
|
|
|
|
# If WebRTC is selected, fetch available rooms (unless we're auto-joining or hosting)
|
|
if actual_mode == 1 and not is_auto_joining and not is_hosting: # WebRTC mode
|
|
_start_room_fetch()
|
|
elif actual_mode != 1: # Not WebRTC mode
|
|
# Hide room fetch status if switching away from WebRTC
|
|
_hide_room_fetch_status()
|
|
|
|
func _on_host_pressed():
|
|
is_hosting = true # Set flag so we don't fetch rooms
|
|
var local_count = int(local_players_spinbox.value)
|
|
network_manager.set_local_player_count(local_count)
|
|
|
|
if network_manager.host_game():
|
|
var mode = network_manager.network_mode
|
|
if mode == 1 or mode == 2: # WebRTC or WebSocket
|
|
var room_id = network_manager.get_room_id()
|
|
var mode_name = "WebRTC" if mode == 1 else "WebSocket"
|
|
print("Hosting ", mode_name, " game - Room Code: ", room_id)
|
|
print("Share this code with players!")
|
|
else:
|
|
print("Hosting ENet game with ", local_count, " local players")
|
|
_start_game()
|
|
|
|
func _on_join_pressed():
|
|
# Reset error state when attempting new connection
|
|
connection_error_shown = false
|
|
_hide_connection_error()
|
|
is_joining_attempt = true
|
|
var address = address_input.text
|
|
if address.is_empty():
|
|
var mode = network_manager.network_mode
|
|
if mode == 1 or mode == 2: # WebRTC or WebSocket
|
|
LogManager.log("Error: Please enter a room code", LogManager.CATEGORY_UI)
|
|
return
|
|
else: # ENet mode without address - use default
|
|
address = "127.0.0.1"
|
|
|
|
var local_count = int(local_players_spinbox.value)
|
|
network_manager.set_local_player_count(local_count)
|
|
|
|
if network_manager.join_game(address):
|
|
last_join_address = address
|
|
var mode = network_manager.network_mode
|
|
if mode == 1: # WebRTC
|
|
LogManager.log("Joining WebRTC game with room code: " + address, LogManager.CATEGORY_UI)
|
|
elif mode == 2: # WebSocket
|
|
LogManager.log("Joining WebSocket game with room code: " + address, LogManager.CATEGORY_UI)
|
|
else: # ENet
|
|
LogManager.log("Joining ENet game at " + address + " with " + str(local_count) + " local players", LogManager.CATEGORY_UI)
|
|
|
|
func _on_connection_succeeded():
|
|
LogManager.log("GameUI: Connection succeeded signal received, starting game", LogManager.CATEGORY_UI)
|
|
is_joining_attempt = false
|
|
# Check if node is still valid before starting game
|
|
if not is_inside_tree():
|
|
LogManager.log_error("GameUI: Cannot start game - node not in tree", LogManager.CATEGORY_UI)
|
|
return
|
|
# Use call_deferred to ensure we're in a safe state to change scenes
|
|
call_deferred("_start_game")
|
|
|
|
func _on_connection_failed():
|
|
LogManager.log("Connection failed", LogManager.CATEGORY_UI)
|
|
if connection_error_shown:
|
|
# Already shown, don't spam
|
|
return
|
|
|
|
connection_error_shown = true
|
|
var mode = network_manager.network_mode
|
|
var mode_name = "ENet"
|
|
if mode == 1:
|
|
mode_name = "WebRTC"
|
|
elif mode == 2:
|
|
mode_name = "WebSocket"
|
|
|
|
if is_joining_attempt:
|
|
var code_hint = (" (" + last_join_address + ")") if not last_join_address.is_empty() else ""
|
|
_show_connection_error("Failed to join room" + code_hint + ". Did you enter the correct code?")
|
|
# For WebRTC, refresh signaling connection after a failed join
|
|
if mode == 1 and network_manager and network_manager.has_method("refresh_webrtc_servers"):
|
|
network_manager.refresh_webrtc_servers(last_join_address)
|
|
# Show room list UI and refresh rooms after a failed WebRTC join
|
|
_show_room_fetch_status()
|
|
_show_loading_indicator()
|
|
_start_room_fetch()
|
|
else:
|
|
_show_connection_error("Connection failed (" + mode_name + "). Please try again.")
|
|
|
|
func _show_connection_error(message: String):
|
|
"""Show a temporary error message in the UI"""
|
|
if not main_menu:
|
|
return
|
|
|
|
# Remove existing error label if any
|
|
_hide_connection_error()
|
|
|
|
# Create error label
|
|
connection_error_label = Label.new()
|
|
connection_error_label.name = "ConnectionErrorLabel"
|
|
connection_error_label.text = message
|
|
connection_error_label.modulate = Color.RED
|
|
connection_error_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
|
connection_error_label.add_theme_font_size_override("font_size", 14)
|
|
|
|
# Add to main menu VBoxContainer (after the title)
|
|
var vbox = main_menu.get_node_or_null("VBoxContainer")
|
|
if vbox:
|
|
# Insert after title (index 0) or at the beginning
|
|
vbox.add_child(connection_error_label)
|
|
vbox.move_child(connection_error_label, 1) # Move to position 1 (after title)
|
|
|
|
# Auto-hide after 5 seconds
|
|
await get_tree().create_timer(5.0).timeout
|
|
_hide_connection_error()
|
|
|
|
func _hide_connection_error():
|
|
"""Hide and remove the connection error label"""
|
|
if connection_error_label:
|
|
connection_error_label.queue_free()
|
|
connection_error_label = null
|
|
|
|
func _start_game():
|
|
# Check if node is still in the tree before trying to access get_tree()
|
|
if not is_inside_tree():
|
|
LogManager.log_error("GameUI: Cannot change scene - node is not in tree", LogManager.CATEGORY_UI)
|
|
return
|
|
|
|
# Hide menu
|
|
if main_menu:
|
|
main_menu.visible = false
|
|
|
|
# Load the game scene
|
|
var tree = get_tree()
|
|
if tree:
|
|
tree.change_scene_to_file("res://scenes/game_world.tscn")
|
|
else:
|
|
LogManager.log_error("GameUI: Cannot change scene - get_tree() is null", LogManager.CATEGORY_UI)
|