feat: 2.3.1

This commit is contained in:
2026-05-11 17:24:47 +08:00
parent 57e56412e0
commit 13f3c3d591
733 changed files with 17957 additions and 798 deletions
+73 -9
View File
@@ -116,7 +116,12 @@ func connect_to_nakama_async(email: String = "", password: String = "") -> bool:
socket = Nakama.create_socket_from(client)
var socket_result = await socket.connect_async(session)
if socket_result.is_exception():
if typeof(socket_result) == TYPE_INT:
if socket_result != OK:
printerr("[NakamaManager] Socket Error (Code: %s)" % socket_result)
emit_signal("connection_failed", "Socket connect failed with code " + str(socket_result))
return false
elif socket_result.is_exception():
var err = socket_result.get_exception()
printerr("[NakamaManager] Socket Error: %s (Code: %s)" % [err.message, err.status_code])
emit_signal("connection_failed", err.message)
@@ -154,6 +159,12 @@ func cleanup():
socket.close()
socket = null
# Delete match metadata from storage (best-effort, don't block cleanup)
if session and client and not current_match_id.is_empty():
client.delete_storage_objects_async(session, [
NakamaStorageObjectId.new("match_meta", current_match_id, session.user_id)
])
current_match_id = ""
# Reset Godot's multiplayer peer
@@ -164,7 +175,7 @@ func cleanup():
# --- Match Management ---
func host_game():
func host_game(room_meta: Dictionary = {}):
if not bridge:
printerr("Cannot host: Bridge not initialized")
return
@@ -172,6 +183,19 @@ func host_game():
var result = await bridge.create_match()
if result and result.is_exception():
emit_signal("match_join_error", result.get_exception().message)
return
# Store room metadata in Nakama storage so other players can see it in listings
if session and current_match_id and room_meta.size() > 0:
var meta_json = JSON.stringify(room_meta)
var write_obj = NakamaWriteStorageObject.new(
"match_meta", current_match_id,
2, 1, meta_json, ""
)
var wr = await client.write_storage_objects_async(session, [write_obj])
if wr.is_exception():
push_warning("[NakamaManager] Failed to write match metadata: ", wr.get_exception().message)
else:
print("[NakamaManager] Match metadata stored for: ", current_match_id)
func join_game(match_id: String):
if not bridge:
@@ -206,8 +230,10 @@ func is_connected_to_nakama() -> bool:
# --- Match Listing ---
func list_matches_async() -> Array:
"""Query available matches from Nakama server."""
func list_matches_async(mode_filter: String = "") -> Array:
"""Query available matches from Nakama server.
mode_filter: optional game mode string — used as label query for authoritative matches.
For relayed matches this has no server-side effect; filtering is client-side."""
if not client:
push_error("Cannot list matches: Client not initialized")
return []
@@ -216,9 +242,10 @@ func list_matches_async() -> Array:
push_error("Cannot list matches: No valid session")
return []
print("Querying matches from Nakama server...")
print("Querying matches from Nakama server... (filter: '%s')" % mode_filter)
# Query matches - min 0, max 8 players, limit 20, authoritative=false for relayed matches
# Query matches — label filter works for authoritative matches only.
# For relayed matches all rooms are returned; game_mode is parsed from label field if present.
var result = await client.list_matches_async(session, 0, 8, 20, false, "", "")
if result.is_exception():
@@ -228,16 +255,53 @@ func list_matches_async() -> Array:
var rooms: Array = []
if result.matches:
print("Found %d matches" % result.matches.size())
# Build storage read requests for all matches
var read_ids: Array = []
for match_data in result.matches:
# Try to read metadata stored by each host
read_ids.append(match_data.match_id)
# Batch-read room metadata from Nakama storage
var meta_map: Dictionary = {} # match_id -> {host_name, game_mode, ...}
if read_ids.size() > 0:
var storage_reads: Array = []
for mid in read_ids:
# We don't know the owner_id, so list objects by collection+key
# Use list_storage_objects per match or batch read
pass
# Read all match metas from our own storage (other users' objects are public read)
for mid in read_ids:
var list_result = await client.list_storage_objects_async(session, "match_meta", "", 100)
if not list_result.is_exception() and list_result.objects:
for obj in list_result.objects:
var parsed = JSON.parse_string(obj.value)
if parsed is Dictionary:
meta_map[obj.key] = parsed
break # Only need one call — lists all match_meta objects
for match_data in result.matches:
print(" Match: ", match_data.match_id, " - Size: ", match_data.size)
# Use first 8 chars of match ID as room identifier since Nakama doesn't store custom names
var short_id = match_data.match_id.substr(0, 8) if match_data.match_id.length() > 8 else match_data.match_id
# Get metadata from storage (host_name, game_mode)
var meta = meta_map.get(match_data.match_id, {})
var host_name = meta.get("host_name", "Unknown")
var game_mode = meta.get("game_mode", "")
var max_players = int(meta.get("max_players", 8))
# Fallback: parse game_mode from label if available
if game_mode.is_empty():
var label: String = match_data.label if match_data.label != null else ""
if label.begins_with("[") and "]" in label:
game_mode = label.substr(1, label.find("]") - 1)
rooms.append({
"match_id": match_data.match_id,
"room_name": short_id,
"host_name": "Host",
"host_name": host_name,
"player_count": match_data.size if match_data.size else 1,
"max_players": 4
"max_players": max_players,
"game_mode": game_mode
})
else:
print("No matches found")