feat: Implement comprehensive lobby system with main menu, room management, and loading screen.
This commit is contained in:
+49
-21
@@ -460,6 +460,8 @@ func _setup_global_match_timer_ui():
|
||||
add_child(panel)
|
||||
|
||||
func _process(delta):
|
||||
if not is_inside_tree(): return
|
||||
if not check_multiplayer(): return
|
||||
if multiplayer.is_server() and GameStateManager.is_game_started():
|
||||
if TurnManager.turn_based_mode:
|
||||
rpc("sync_turn_index", TurnManager.current_turn_index)
|
||||
@@ -528,7 +530,9 @@ func _setup_host_game():
|
||||
# Moved _assign_random_spawn_positions() to after bot loop
|
||||
|
||||
# Wait for players to be fully ready (player.gd has 0.1s await in _ready before managers init)
|
||||
await get_tree().create_timer(0.3).timeout
|
||||
# Faster for LAN mode
|
||||
var setup_delay = 0.1 if LobbyManager.is_lan_mode else 0.3
|
||||
await get_tree().create_timer(setup_delay).timeout
|
||||
|
||||
# Set host goals - get goals directly from GoalManager
|
||||
var host_goals = GoalManager.get_goals_for_player(0)
|
||||
@@ -651,18 +655,20 @@ func _setup_client_game():
|
||||
powerup_ui.setup(player_character)
|
||||
print("Client: PowerUpInventoryUI setup forced for ", my_id)
|
||||
|
||||
# Wait shorter time for host to be ready, then request full sync to correct positions/state
|
||||
await get_tree().create_timer(1.0).timeout
|
||||
# Wait for host to be ready, then request full sync
|
||||
# Snappier for LAN mode as peer is already established
|
||||
var client_setup_delay = 0.2 if LobbyManager.is_lan_mode else 1.0
|
||||
await get_tree().create_timer(client_setup_delay).timeout
|
||||
|
||||
if multiplayer.has_multiplayer_peer() and multiplayer.multiplayer_peer.get_connection_status() == MultiplayerPeer.CONNECTION_CONNECTED:
|
||||
if check_multiplayer():
|
||||
# Ensure we see the server (Peer 1)
|
||||
if 1 in multiplayer.get_peers():
|
||||
rpc_id(1, "request_full_player_sync", my_id)
|
||||
rpc_id(1, "request_full_grid_sync")
|
||||
else:
|
||||
print("Client: Connected but Peer 1 not found yet. Retrying in 1s...")
|
||||
await get_tree().create_timer(1.0).timeout
|
||||
if 1 in multiplayer.get_peers():
|
||||
await get_tree().create_timer(0.5).timeout
|
||||
if check_multiplayer() and 1 in multiplayer.get_peers():
|
||||
rpc_id(1, "request_full_player_sync", my_id)
|
||||
rpc_id(1, "request_full_grid_sync")
|
||||
|
||||
@@ -692,17 +698,19 @@ func _auto_start_from_lobby():
|
||||
func _start_game():
|
||||
if multiplayer.is_server():
|
||||
# Wait for Nakama websocket to actually be open, up to 5 seconds
|
||||
var nakama = get_node_or_null("/root/NakamaManager")
|
||||
if nakama and nakama.has_method("is_connected_to_nakama"):
|
||||
var wait_time = 0.0
|
||||
while not nakama.is_connected_to_nakama() and wait_time < 5.0:
|
||||
await get_tree().create_timer(0.2).timeout
|
||||
wait_time += 0.2
|
||||
# SKIP THIS FOR LAN MODE
|
||||
if not LobbyManager.is_lan_mode:
|
||||
var nakama = get_node_or_null("/root/NakamaManager")
|
||||
if nakama and nakama.has_method("is_connected_to_nakama"):
|
||||
var wait_time = 0.0
|
||||
while not nakama.is_connected_to_nakama() and wait_time < 5.0:
|
||||
await get_tree().create_timer(0.2).timeout
|
||||
wait_time += 0.2
|
||||
|
||||
# Allow socket/peer to stabilize before blasting RPCs
|
||||
# Snappier delay since we already waited for scene load
|
||||
var delay = 0.2 if LobbyManager.is_lan_mode else 0.5
|
||||
await get_tree().create_timer(delay).timeout
|
||||
# Stabilization delay to allow clients to finish loading and spawning
|
||||
# We wait 1.5s to ensure the 1.2s loading screen buffer has finished
|
||||
# before the countdown starts.
|
||||
await get_tree().create_timer(1.5).timeout
|
||||
|
||||
# NOW assign spawn positions for EVERYONE (Host, Client, Bots)
|
||||
# This safely sends RPCs over the completed socket connection
|
||||
@@ -1230,6 +1238,7 @@ func add_player_character(peer_id: int, is_bot: bool = false):
|
||||
ui_manager.update_playerboard_ui()
|
||||
|
||||
func _on_peer_connected(new_peer_id: int):
|
||||
if not is_inside_tree(): return
|
||||
if multiplayer.is_server():
|
||||
await get_tree().create_timer(0.1).timeout
|
||||
add_player_character(new_peer_id)
|
||||
@@ -1252,6 +1261,7 @@ func add_newly_connected_player_character(new_peer_id: int):
|
||||
add_player_character(new_peer_id)
|
||||
|
||||
func _on_peer_disconnected(peer_id: int):
|
||||
if not is_inside_tree(): return
|
||||
if multiplayer.is_server():
|
||||
print("[Main] Peer %d disconnected. Checking for bot replacement..." % peer_id)
|
||||
|
||||
@@ -1305,14 +1315,24 @@ func create_bot_with_state(bot_id: int, pos: Vector2i, p_score: int, p_goals: Ar
|
||||
bot_character.update_player_position(pos)
|
||||
|
||||
func _on_host_disconnected():
|
||||
"""Called when the host leaves. Returns clients to the main menu."""
|
||||
if not is_inside_tree(): return
|
||||
"""Called when the host leaves. Returns clients to the lobby."""
|
||||
print("[Main] Host disconnected. Match terminated. Cleaning up and returning to lobby...")
|
||||
LobbyManager.leave_room()
|
||||
get_tree().change_scene_to_file("res://scenes/lobby.tscn")
|
||||
|
||||
# Use loading screen to return to lobby
|
||||
var loading_screen_scene = load("res://scenes/loading_screen/loading_screen.tscn")
|
||||
if loading_screen_scene:
|
||||
var loading_screen = loading_screen_scene.instantiate()
|
||||
get_tree().root.add_child(loading_screen)
|
||||
loading_screen.load_level("res://scenes/lobby.tscn")
|
||||
else:
|
||||
get_tree().change_scene_to_file("res://scenes/lobby.tscn")
|
||||
|
||||
func _on_rematch_starting():
|
||||
if not is_inside_tree(): return
|
||||
"""Called when a rematch is triggered. Reloads the game scene."""
|
||||
print("[Main] Rematch starting! Resetting state and reloading scene...")
|
||||
print("[Main] Rematch starting. Resetting local state...")
|
||||
|
||||
# Reset singletons/managers that persist across scene reloads
|
||||
GameStateManager.reset()
|
||||
@@ -2439,8 +2459,7 @@ func _on_joystick_toggled(enabled: bool):
|
||||
touch_controls._save_settings()
|
||||
|
||||
func can_rpc() -> bool:
|
||||
if not multiplayer.has_multiplayer_peer(): return false
|
||||
if multiplayer.multiplayer_peer.get_connection_status() != MultiplayerPeer.CONNECTION_CONNECTED: return false
|
||||
if not check_multiplayer(): return false
|
||||
|
||||
if LobbyManager.is_lan_mode:
|
||||
return true
|
||||
@@ -2451,6 +2470,15 @@ func can_rpc() -> bool:
|
||||
|
||||
return true
|
||||
|
||||
func check_multiplayer() -> bool:
|
||||
"""Safety check for multiplayer peer access."""
|
||||
if not is_inside_tree(): return false
|
||||
# Accessing multiplayer here is safe because we checked is_inside_tree
|
||||
var peer = multiplayer.multiplayer_peer
|
||||
if not peer: return false
|
||||
if peer.get_connection_status() == MultiplayerPeer.CONNECTION_DISCONNECTED: return false
|
||||
return true
|
||||
|
||||
@rpc("authority", "call_local", "reliable")
|
||||
func display_message(message: String, type: int = 0):
|
||||
"""Broadcasts a message to the local player's UI. This is called via main.rpc from various managers."""
|
||||
|
||||
Reference in New Issue
Block a user