feat: Introduce a comprehensive game lobby system including UI, room management, and player interactions.

This commit is contained in:
Yogi Wiguna
2026-03-17 10:32:14 +08:00
parent eb018903aa
commit 49c8d794c2
5 changed files with 156 additions and 163 deletions
+84 -1
View File
@@ -38,8 +38,12 @@ 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
const LAN_DISCOVERY_PORT: int = 7778 # Port for LAN discovery
var local_player_name: String = "Player"
var _udp_peer: PacketPeerUDP
var _broadcast_timer: Timer
# Match duration in seconds (configurable in lobby by host)
var match_duration: int = 180 # Default 3 minutes
@@ -93,12 +97,35 @@ var _all_ready: bool = false
func _ready():
_update_available_areas(game_mode)
# Setup UDP for LAN discovery
_udp_peer = PacketPeerUDP.new()
# Connect to Nakama signals
NakamaManager.match_joined.connect(_on_match_joined)
multiplayer.peer_connected.connect(_on_peer_connected)
multiplayer.peer_disconnected.connect(_on_peer_disconnected)
multiplayer.server_disconnected.connect(_on_server_disconnected)
func _process(_delta):
_listen_for_lan_discovery()
func _listen_for_lan_discovery():
if not _udp_peer or not is_lan_mode or is_host: return
if not _udp_peer.is_bound(): return
while _udp_peer.get_available_packet_count() > 0:
var packet = _udp_peer.get_packet()
var ip = _udp_peer.get_packet_ip()
var data_str = packet.get_string_from_utf8()
if not data_str.begins_with("TEKTON_HOST:"): continue
var room_info_json = data_str.trim_prefix("TEKTON_HOST:")
var room_info = JSON.parse_string(room_info_json)
if room_info is Dictionary:
room_info["ip"] = ip
_update_lan_room_list(room_info)
func _update_available_areas(mode: String) -> void:
match mode:
"Freemode":
@@ -179,9 +206,55 @@ func create_room_lan(room_name: String = "LAN Game") -> bool:
})
print("[LAN] Server created on port %d. Waiting for players..." % LAN_PORT)
_start_lan_broadcast(room_name)
emit_signal("room_joined", current_room)
return true
func _start_lan_broadcast(room_name: String):
_stop_lan_broadcast()
if _udp_peer.bind(0) != OK:
push_error("[LAN] Failed to bind UDP for broadcasting")
return
_udp_peer.set_broadcast_enabled(true)
_broadcast_timer = Timer.new()
_broadcast_timer.name = "LANBroadcastTimer"
_broadcast_timer.wait_time = 2.0
_broadcast_timer.autostart = true
add_child(_broadcast_timer)
_broadcast_timer.timeout.connect(_broadcast_lan_room.bind(room_name))
func _broadcast_lan_room(room_name: String):
var room_data = {
"room_name": room_name,
"host_name": local_player_name,
"player_count": players_in_room.size(),
"max_players": GameStateManager.max_players,
"match_id": "LAN"
}
var msg = "TEKTON_HOST:" + JSON.stringify(room_data)
_udp_peer.set_dest_address("255.255.255.255", LAN_DISCOVERY_PORT)
_udp_peer.put_packet(msg.to_utf8_buffer())
func _stop_lan_broadcast():
if _broadcast_timer:
_broadcast_timer.stop()
_broadcast_timer.queue_free()
_broadcast_timer = null
if _udp_peer and _udp_peer.is_bound():
_udp_peer.close()
func _update_lan_room_list(room_info: Dictionary):
var found = false
for i in range(available_rooms.size()):
if available_rooms[i].get("ip") == room_info["ip"]:
available_rooms[i] = room_info
found = true
break
if not found:
available_rooms.append(room_info)
emit_signal("room_list_updated", available_rooms)
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
@@ -215,6 +288,7 @@ func leave_room() -> void:
# Important: Reset all lobby settings and player lists first
reset()
_stop_lan_broadcast()
if is_lan_mode:
# LAN mode: just close the ENet peer directly
@@ -231,7 +305,16 @@ func leave_room() -> void:
emit_signal("room_left")
func refresh_room_list() -> void:
"""Request updated room list from Nakama."""
"""Request updated room list from Nakama or scan for LAN rooms."""
if is_lan_mode:
available_rooms.clear()
if _udp_peer.is_bound(): _udp_peer.close()
var err = _udp_peer.bind(LAN_DISCOVERY_PORT)
if err != OK:
push_error("[LAN] Failed to bind to discovery port %d" % LAN_DISCOVERY_PORT)
emit_signal("room_list_updated", available_rooms)
return
if not NakamaManager.is_connected_to_nakama():
var success = await NakamaManager.connect_to_nakama_async()
if not success: