feat: Implement core lobby system including UI, player management, and game mode settings.

This commit is contained in:
2026-03-16 05:21:49 +08:00
parent f4307a8405
commit 71d688ed63
7 changed files with 84 additions and 13 deletions
+27 -1
View File
@@ -144,6 +144,13 @@ func leave_room() -> void:
"""Leave the current room."""
print("[LobbyManager] Leaving room. Clearing all local state.")
# If we are the host, notify all clients to kick them back to menu/lobby
if is_host and multiplayer.has_multiplayer_peer() and multiplayer.is_server():
print("[LobbyManager] Host is leaving. Kicking all clients...")
# We use rpc() instead of .rpc() for compatibility with older Godot 4 versions if applicable,
# but .rpc() is standard in 4.x. Let's stick to standard.
kick_all_clients.rpc()
# Important: Reset all lobby settings and player lists first
reset()
@@ -214,6 +221,16 @@ func _check_all_ready() -> void:
func is_all_ready() -> bool:
return _all_ready
@rpc("authority", "call_local", "reliable")
func kick_all_clients() -> void:
"""Called on all clients when the host leaves to ensure they are returned to the menu."""
if not is_host:
print("[LobbyManager] Received kick from host. Returning to menu...")
disconnect_reason = "Host left the lobby. Room closed."
emit_signal("host_disconnected")
# We use call_deferred to avoid potential issues during RPC stack processing
call_deferred("leave_room")
# =============================================================================
# Game Start
# =============================================================================
@@ -636,6 +653,14 @@ func _on_peer_connected(peer_id: int) -> void:
func _on_peer_disconnected(peer_id: int) -> void:
"""Called when peer disconnects."""
print("Peer disconnected: ", peer_id)
# If the host (peer 1) disconnected and we are not host, we should be kicked
if peer_id == 1 and not is_host:
print("[LobbyManager] Host peer disconnected. Kicking self...")
_on_server_disconnected()
return
for i in range(players_in_room.size()):
if players_in_room[i]["id"] == peer_id:
players_in_room.remove_at(i)
@@ -652,8 +677,9 @@ func _on_server_disconnected() -> void:
print("[LobbyManager] Server (Host) disconnected. Terminating room...")
disconnect_reason = "Host disconnected. Match terminated."
rematch_votes.clear()
emit_signal("host_disconnected")
# Ensure full cleanup and state reset
leave_room()
emit_signal("host_disconnected")
# =============================================================================
# Rematch Logic
+12 -1
View File
@@ -370,7 +370,18 @@ func auto_put_item() -> bool:
var pos = neighbor.position
var cell_3d = Vector3i(pos.x, 1, pos.y)
if enhanced_gridmap.get_cell_item(cell_3d) == -1 and not player.is_position_occupied(pos):
valid_put_positions.append(pos)
# TEKTON DOORS: Avoid portal doors
var is_on_portal = false
if LobbyManager.is_game_mode(GameMode.Mode.TEKTON_DOORS):
var doors = get_tree().get_nodes_in_group("PortalDoors")
for door in doors:
var door_grid = enhanced_gridmap.local_to_map(enhanced_gridmap.to_local(door.global_position))
if Vector2i(door_grid.x, door_grid.z) == pos:
is_on_portal = true
break
if not is_on_portal:
valid_put_positions.append(pos)
if valid_put_positions.is_empty():
return false
+1 -1
View File
@@ -479,7 +479,7 @@ func _refresh_tiles():
var door_positions = []
for door in doors:
if is_instance_valid(door):
var local_pos = gridmap.local_to_map(door.global_position)
var local_pos = gridmap.local_to_map(gridmap.to_local(door.global_position))
door_positions.append(Vector2i(local_pos.x, local_pos.z))
for x in range(GRID_SIZE):