Refactor network and player goals UI panels

Moved network info UI elements into a dedicated NetworkPanel and updated code references accordingly. Refactored AllPlayerGoals to use individual Panel nodes for each player, improving visibility management and goal UI updates. Enhanced goal synchronization logic to handle dynamic player panels and added safety checks for UI node access.
This commit is contained in:
2025-10-29 14:55:15 +08:00
parent 65be1fcc63
commit 3c3ba0cd63
2 changed files with 3730 additions and 272 deletions
+144 -55
View File
@@ -364,11 +364,11 @@ func show_arrangement_ui():
update_playerboard_ui()
func _on_host_pressed():
$NetworkInfo/NetworkSideDisplay.text = "Server"
$NetworkPanel/NetworkInfo/NetworkSideDisplay.text = "Server"
$Menu.visible = false
multiplayer_peer.create_server(PORT)
multiplayer.multiplayer_peer = multiplayer_peer
$NetworkInfo/UniquePeerID.text = str(multiplayer.get_unique_id())
$NetworkPanel/NetworkInfo/UniquePeerID.text = str(multiplayer.get_unique_id())
# Generate all goals first
preset_goals.clear()
@@ -408,11 +408,11 @@ func sync_preset_goals(goals_list: Array):
preset_goals = goals_list
func _on_join_pressed():
$NetworkInfo/NetworkSideDisplay.text = "Client"
$NetworkPanel/NetworkInfo/NetworkSideDisplay.text = "Client"
$Menu.visible = false
multiplayer_peer.create_client(ADDRESS, PORT)
multiplayer.multiplayer_peer = multiplayer_peer
$NetworkInfo/UniquePeerID.text = str(multiplayer.get_unique_id())
$NetworkPanel/NetworkInfo/UniquePeerID.text = str(multiplayer.get_unique_id())
# After connection is established
await get_tree().create_timer(2.0).timeout
rpc_id(1, "request_full_player_sync", multiplayer.get_unique_id())
@@ -1061,58 +1061,109 @@ func update_board_slot(board_ui: Node, slot_idx: int, value: int):
9: slot_node.get_node("TileStar").show()
10: slot_node.get_node("TileCoin").show()
#func update_all_players_goals():
## Only server/host should manage goals display
#if not game_started:
#return
#
#var all_players = get_tree().get_nodes_in_group("Players")
#all_players.sort_custom(func(a, b):
#var a_str = String(a.name).get_slice("@", 0)
#var b_str = String(b.name).get_slice("@", 0)
#return int(a_str) < int(b_str)
#)
#
## If we're the host, update all goals and sync to clients
#if multiplayer.is_server():
## Clear all goals first
#for player_idx in range(4):
#var goals_grid = $AllPlayerGoals.get_child(player_idx)
#for slot_idx in range(9):
#var slot = goals_grid.get_child(slot_idx)
#for tile in ["TileHeart", "TileDiamond", "TileStar", "TileCoin"]:
#slot.get_node(tile).hide()
#
## Update with current goals and gather goals data
#var all_goals_data = []
#for i in range(min(all_players.size(), 4)):
#var player = all_players[i]
#if player and player.goals.size() > 0:
#_update_player_goals_ui(i, player.goals)
#all_goals_data.append({"player_idx": i, "goals": player.goals.duplicate()})
#else:
#all_goals_data.append({"player_idx": i, "goals": []})
#
## Sync to clients
#rpc("sync_all_goals_to_clients", all_goals_data)
func update_all_players_goals():
# Only server/host should manage goals display
if not game_started:
return
var all_players = get_tree().get_nodes_in_group("Players")
all_players.sort_custom(func(a, b):
var a_str = String(a.name).get_slice("@", 0)
var b_str = String(b.name).get_slice("@", 0)
return int(a_str) < int(b_str)
all_players.sort_custom(func(a, b):
var a_id = int(String(a.name).get_slice("@", 0))
var b_id = int(String(b.name).get_slice("@", 0))
return a_id < b_id
)
# If we're the host, update all goals and sync to clients
# Hide all panels first
for i in range($AllPlayerGoals.get_child_count()):
$AllPlayerGoals.get_child(i).visible = false
# Update only for connected players (up to number of panels available)
var max_panels = $AllPlayerGoals.get_child_count()
for i in range(min(all_players.size(), max_panels)):
var player = all_players[i]
if player and player.goals.size() > 0:
$AllPlayerGoals.get_child(i).visible = true
_update_player_goals_ui(i, player.goals)
# Server also syncs to clients
if multiplayer.is_server():
# Clear all goals first
for player_idx in range(4):
var goals_grid = $AllPlayerGoals.get_child(player_idx)
for slot_idx in range(9):
var slot = goals_grid.get_child(slot_idx)
for tile in ["TileHeart", "TileDiamond", "TileStar", "TileCoin"]:
slot.get_node(tile).hide()
# Update with current goals and gather goals data
var all_goals_data = []
for i in range(min(all_players.size(), 4)):
for i in range(min(all_players.size(), max_panels)):
var player = all_players[i]
if player and player.goals.size() > 0:
_update_player_goals_ui(i, player.goals)
all_goals_data.append({"player_idx": i, "goals": player.goals.duplicate()})
else:
all_goals_data.append({"player_idx": i, "goals": []})
# Sync to clients
all_goals_data.append({
"player_idx": i,
"goals": player.goals.duplicate() if player else []
})
rpc("sync_all_goals_to_clients", all_goals_data)
#@rpc("reliable")
#func sync_all_goals_to_clients(all_goals_data: Array):
#if not multiplayer.is_server(): # Only clients should process this
## Clear all goals first
#for player_idx in range(4):
#var goals_grid = $AllPlayerGoals.get_child(player_idx)
#for slot_idx in range(9):
#var slot = goals_grid.get_child(slot_idx)
#for tile in ["TileHeart", "TileDiamond", "TileStar", "TileCoin"]:
#slot.get_node(tile).hide()
#
## Apply received goals
#for goal_data in all_goals_data:
#var player_idx = goal_data["player_idx"]
#var goals = goal_data["goals"]
#if player_idx >= 0 and player_idx < 4 and goals.size() > 0:
#_update_player_goals_ui(player_idx, goals)
@rpc("reliable")
func sync_all_goals_to_clients(all_goals_data: Array):
if not multiplayer.is_server(): # Only clients should process this
# Clear all goals first
for player_idx in range(4):
var goals_grid = $AllPlayerGoals.get_child(player_idx)
for slot_idx in range(9):
var slot = goals_grid.get_child(slot_idx)
for tile in ["TileHeart", "TileDiamond", "TileStar", "TileCoin"]:
slot.get_node(tile).hide()
# Apply received goals
for goal_data in all_goals_data:
var player_idx = goal_data["player_idx"]
var goals = goal_data["goals"]
if player_idx >= 0 and player_idx < 4 and goals.size() > 0:
_update_player_goals_ui(player_idx, goals)
if multiplayer.is_server():
return # Only clients should process this
# Hide all panels first
for i in range($AllPlayerGoals.get_child_count()):
$AllPlayerGoals.get_child(i).visible = false
# Apply received goals
for goal_data in all_goals_data:
var player_idx = goal_data.get("player_idx", -1)
var goals = goal_data.get("goals", [])
if player_idx >= 0 and player_idx < $AllPlayerGoals.get_child_count() and goals.size() > 0:
$AllPlayerGoals.get_child(player_idx).visible = true
_update_player_goals_ui(player_idx, goals)
@rpc("any_peer", "call_local")
func sync_player_goals(player_id: int, goals: Array):
@@ -1126,22 +1177,60 @@ func sync_player_goals(player_id: int, goals: Array):
update_all_players_goals()
# Helper function to update specific player's goals UI
#func _update_player_goals_ui(player_idx: int, goals: Array):
#var goals_grid = $AllPlayerGoals.get_child(player_idx)
#for slot_idx in range(9):
#var slot = goals_grid.get_child(slot_idx)
#var goal_value = goals[slot_idx] if slot_idx < goals.size() else -1
#
## Hide all tiles first
#for tile in ["TileHeart", "TileDiamond", "TileStar", "TileCoin"]:
#slot.get_node(tile).hide()
#
## Show appropriate tile
#match goal_value:
#7: slot.get_node("TileHeart").show()
#8: slot.get_node("TileDiamond").show()
#9: slot.get_node("TileStar").show()
#10: slot.get_node("TileCoin").show()
# Helper function to update specific player's goals UI
func _update_player_goals_ui(player_idx: int, goals: Array):
var goals_grid = $AllPlayerGoals.get_child(player_idx)
# Safety: ensure player_idx is within bounds of AllPlayerGoals children
if player_idx < 0 or player_idx >= $AllPlayerGoals.get_child_count():
return
var panel = $AllPlayerGoals.get_child(player_idx)
if not panel.has_node("MarginContainer/Playergoals"):
return
var goals_grid = panel.get_node("MarginContainer/Playergoals")
for slot_idx in range(9):
if slot_idx >= goals_grid.get_child_count():
break
var slot = goals_grid.get_child(slot_idx)
var goal_value = goals[slot_idx] if slot_idx < goals.size() else -1
# Hide all tiles first
for tile in ["TileHeart", "TileDiamond", "TileStar", "TileCoin"]:
slot.get_node(tile).hide()
# Show appropriate tile
# Hide all goal tiles first
for tile_name in ["TileHeart", "TileDiamond", "TileStar", "TileCoin"]:
if slot.has_node(tile_name):
slot.get_node(tile_name).hide()
# Show appropriate tile based on goal value
match goal_value:
7: slot.get_node("TileHeart").show()
8: slot.get_node("TileDiamond").show()
9: slot.get_node("TileStar").show()
10: slot.get_node("TileCoin").show()
7:
if slot.has_node("TileHeart"):
slot.get_node("TileHeart").show()
8:
if slot.has_node("TileDiamond"):
slot.get_node("TileDiamond").show()
9:
if slot.has_node("TileStar"):
slot.get_node("TileStar").show()
10:
if slot.has_node("TileCoin"):
slot.get_node("TileCoin").show()
@rpc("any_peer")
func request_goals_from_server(requesting_peer_id: int):