feat: implement initial lobby scene with main menu, server browser, and networking options.
This commit is contained in:
@@ -36,6 +36,8 @@ var current_room: Dictionary = {}
|
||||
var players_in_room: Array = [] # [{id, name, is_ready}]
|
||||
var available_rooms: Array = []
|
||||
var is_host: bool = false
|
||||
var is_lan_mode: bool = false # True when using direct ENet (no Nakama)
|
||||
const LAN_PORT: int = 7777 # Port for LAN direct connections
|
||||
var local_player_name: String = "Player"
|
||||
|
||||
# Match duration in seconds (configurable in lobby by host)
|
||||
@@ -113,8 +115,9 @@ func _update_available_areas(mode: String) -> void:
|
||||
# =============================================================================
|
||||
|
||||
func create_room(room_name: String) -> void:
|
||||
"""Host creates a new room with the given name."""
|
||||
"""Host creates a new room with the given name (Nakama)."""
|
||||
is_host = true
|
||||
is_lan_mode = false
|
||||
current_room = {
|
||||
"room_name": room_name,
|
||||
"host_name": local_player_name,
|
||||
@@ -130,8 +133,9 @@ func create_room(room_name: String) -> void:
|
||||
NakamaManager.host_game()
|
||||
|
||||
func join_room(match_id: String) -> void:
|
||||
"""Client joins an existing room by match ID."""
|
||||
"""Client joins an existing room by match ID (Nakama)."""
|
||||
is_host = false
|
||||
is_lan_mode = false
|
||||
|
||||
var success = await NakamaManager.connect_to_nakama_async()
|
||||
if not success:
|
||||
@@ -140,6 +144,66 @@ func join_room(match_id: String) -> void:
|
||||
|
||||
NakamaManager.join_game(match_id)
|
||||
|
||||
# =============================================================================
|
||||
# LAN Mode (Direct ENet, no Nakama/Docker needed)
|
||||
# =============================================================================
|
||||
|
||||
func create_room_lan(room_name: String = "LAN Game") -> bool:
|
||||
"""Host creates a LAN room via direct ENet. No Nakama/Docker required."""
|
||||
is_host = true
|
||||
is_lan_mode = true
|
||||
|
||||
var peer = ENetMultiplayerPeer.new()
|
||||
var err = peer.create_server(LAN_PORT, GameStateManager.max_players)
|
||||
if err != OK:
|
||||
push_error("[LAN] Failed to create ENet server on port %d: %s" % [LAN_PORT, err])
|
||||
return false
|
||||
|
||||
multiplayer.set_multiplayer_peer(peer)
|
||||
|
||||
current_room = {
|
||||
"room_name": room_name,
|
||||
"host_name": local_player_name,
|
||||
"max_players": GameStateManager.max_players,
|
||||
"match_id": "LAN"
|
||||
}
|
||||
|
||||
# Add host to player list
|
||||
var my_id = multiplayer.get_unique_id() # Will be 1
|
||||
players_in_room.clear()
|
||||
players_in_room.append({
|
||||
"id": my_id,
|
||||
"name": local_player_name,
|
||||
"is_ready": false,
|
||||
"character": available_characters[local_character_index]
|
||||
})
|
||||
|
||||
print("[LAN] Server created on port %d. Waiting for players..." % LAN_PORT)
|
||||
emit_signal("room_joined", current_room)
|
||||
return true
|
||||
|
||||
func join_room_lan(host_ip: String) -> bool:
|
||||
"""Client joins a LAN room by the host's IP address. No Nakama/Docker required."""
|
||||
is_host = false
|
||||
is_lan_mode = true
|
||||
|
||||
var peer = ENetMultiplayerPeer.new()
|
||||
var err = peer.create_client(host_ip, LAN_PORT)
|
||||
if err != OK:
|
||||
push_error("[LAN] Failed to connect to %s:%d: %s" % [host_ip, LAN_PORT, err])
|
||||
return false
|
||||
|
||||
multiplayer.set_multiplayer_peer(peer)
|
||||
|
||||
current_room = {
|
||||
"room_name": "LAN Game",
|
||||
"match_id": "LAN"
|
||||
}
|
||||
|
||||
print("[LAN] Connecting to %s:%d..." % [host_ip, LAN_PORT])
|
||||
# _on_peer_connected will fire once connected and trigger request_room_info.
|
||||
return true
|
||||
|
||||
func leave_room() -> void:
|
||||
"""Leave the current room."""
|
||||
print("[LobbyManager] Leaving room. Clearing all local state.")
|
||||
@@ -147,15 +211,19 @@ func leave_room() -> void:
|
||||
# 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()
|
||||
|
||||
# Disconnect from Nakama and reset multiplayer peer
|
||||
NakamaManager.cleanup()
|
||||
if is_lan_mode:
|
||||
# LAN mode: just close the ENet peer directly
|
||||
if multiplayer.has_multiplayer_peer():
|
||||
multiplayer.set_multiplayer_peer(null)
|
||||
is_lan_mode = false
|
||||
else:
|
||||
# Nakama mode: full Nakama cleanup
|
||||
NakamaManager.cleanup()
|
||||
|
||||
# Important: Clean up game state as well to prevent ghost players
|
||||
GameStateManager.reset()
|
||||
@@ -206,7 +274,9 @@ func sync_ready_state(player_id: int, is_ready: bool) -> void:
|
||||
|
||||
func _check_all_ready() -> void:
|
||||
"""Check if all players are ready."""
|
||||
if players_in_room.size() < 2:
|
||||
# In LAN mode allow solo play - only 1 player needed
|
||||
var min_players = 1 if is_lan_mode else 2
|
||||
if players_in_room.size() < min_players:
|
||||
_all_ready = false
|
||||
return
|
||||
|
||||
@@ -218,6 +288,17 @@ func _check_all_ready() -> void:
|
||||
_all_ready = true
|
||||
emit_signal("all_players_ready")
|
||||
|
||||
func force_solo_ready() -> void:
|
||||
"""Mark the local player as ready immediately (for solo LAN play)."""
|
||||
if not multiplayer.has_multiplayer_peer():
|
||||
return
|
||||
var my_id = multiplayer.get_unique_id()
|
||||
for player in players_in_room:
|
||||
if player["id"] == my_id:
|
||||
player["is_ready"] = true
|
||||
break
|
||||
_check_all_ready()
|
||||
|
||||
func is_all_ready() -> bool:
|
||||
return _all_ready
|
||||
|
||||
@@ -562,6 +643,11 @@ func _on_game_starting() -> void:
|
||||
|
||||
func _on_match_joined(match_id: String) -> void:
|
||||
"""Called when successfully joined a Nakama match."""
|
||||
# LAN mode handles room setup entirely in create_room_lan() / join_room_lan().
|
||||
# Skip this Nakama-specific handler to avoid double-adding the player.
|
||||
if is_lan_mode:
|
||||
return
|
||||
|
||||
current_room["match_id"] = match_id
|
||||
# Use first 8 chars of match ID as room name (matches server browser)
|
||||
var short_id = match_id.substr(0, 8) if match_id.length() > 8 else match_id
|
||||
|
||||
Reference in New Issue
Block a user