diff --git a/scenes/main.gd b/scenes/main.gd index f1f2590..39c6ffd 100644 --- a/scenes/main.gd +++ b/scenes/main.gd @@ -135,12 +135,22 @@ func _setup_host_game(): GameStateManager.local_player_character = player_character ui_manager.set_local_player(player_character) - # Set host goals - player_character.goals = GoalManager.get_goals_for_player(0) - rpc("sync_player_goals", player_id, player_character.goals) + # Wait for player to be fully ready (player.gd has 0.1s await in _ready before managers init) + await get_tree().create_timer(0.2).timeout + + # Set host goals - get goals directly from GoalManager + var host_goals = GoalManager.get_goals_for_player(0) + player_character.goals = host_goals + rpc("sync_player_goals", player_id, host_goals) rpc("sync_preset_goals", GoalManager.preset_goals) + # Update the goals UI immediately for the host + var panel = $AllPlayerGoals.get_child(0) + panel.visible = true + _update_player_goals_ui(0, host_goals) + ui_manager.update_playerboard_ui() + # Add bots if GameStateManager.enable_bots: for i in range(2, GameStateManager.max_players + 1): @@ -186,11 +196,11 @@ func create_bot(bot_id: int): var goal_index = bot_id - 1 if goal_index < GoalManager.preset_goals.size(): + # Wait for bot managers to be ready + await get_tree().create_timer(0.2).timeout bot_character.goals = GoalManager.preset_goals[goal_index].duplicate() - rpc("sync_player_goals", bot_id, bot_character.goals) - - await get_tree().create_timer(0.1).timeout - bot_character.rpc("sync_bot_status", true) + # Use deferred goals sync to avoid timing issues + call_deferred("_deferred_set_player_goals", bot_id, bot_character.goals) @rpc("any_peer", "call_local") func add_player_character(peer_id: int): @@ -214,6 +224,18 @@ func _on_peer_connected(new_peer_id: int): await get_tree().create_timer(1.5).timeout add_player_character(new_peer_id) rpc("add_newly_connected_player_character", new_peer_id) + + # Wait for player to be ready then assign goals + await get_tree().create_timer(0.3).timeout + var player = get_node_or_null(str(new_peer_id)) + if player: + # Get the next available goal set for this player + var player_index = GameStateManager.players.find(new_peer_id) + if player_index >= 0 and player_index < GoalManager.preset_goals.size(): + var player_goals = GoalManager.preset_goals[player_index].duplicate() + player.goals = player_goals + # Update goals UI for all clients + call_deferred("_deferred_set_player_goals", new_peer_id, player_goals) @rpc func add_newly_connected_player_character(new_peer_id: int): @@ -347,9 +369,36 @@ func sync_preset_goals(goals_list: Array): func sync_player_goals(player_id: int, goals: Array): var player = get_node_or_null(str(player_id)) if player: + # Defer the goal setting to ensure managers are ready + call_deferred("_deferred_set_player_goals", player_id, goals) + +func _deferred_set_player_goals(player_id: int, goals: Array): + await get_tree().create_timer(0.25).timeout + var player = get_node_or_null(str(player_id)) + if player and player.race_manager: player.goals = goals.duplicate() - if multiplayer.is_server(): - update_all_players_goals() + # Update the goals UI for all clients + _update_goals_ui_for_player(player_id, goals) + +func _update_goals_ui_for_player(player_id: int, goals: Array): + # Find the player index among all players + var all_players = get_tree().get_nodes_in_group("Players") + 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 + ) + + var player_idx = -1 + for i in range(all_players.size()): + if all_players[i].name == str(player_id): + player_idx = i + break + + # Changed >= 0 to include index 0 (host player) + if player_idx != -1 and player_idx < $AllPlayerGoals.get_child_count(): + $AllPlayerGoals.get_child(player_idx).visible = true + _update_player_goals_ui(player_idx, goals) @rpc("any_peer", "call_local") func sync_playerboard(player_id: int, new_playerboard: Array): @@ -475,27 +524,74 @@ func request_full_player_sync(requesting_peer_id: int): @rpc("reliable") func create_specific_player(data: Dictionary): var peer_id = data["peer_id"] - if has_node(str(peer_id)): - return + var player_character = null + var node_already_exists = has_node(str(peer_id)) - var player_character = PlayerManager.add_player_character(peer_id) - player_character.current_position = data["position"] - add_child(player_character) - player_character.add_to_group("Players", true) + if node_already_exists: + # Player already exists, just get the reference + player_character = get_node(str(peer_id)) + else: + # Create new player + player_character = PlayerManager.add_player_character(peer_id) + player_character.current_position = data["position"] + add_child(player_character) + player_character.add_to_group("Players", true) + + if data["is_bot"]: + player_character.add_to_group("Bots", true) + player_character.is_bot = true - if data["is_bot"]: - player_character.add_to_group("Bots", true) - player_character.is_bot = true - player_character.rpc("sync_bot_status", true) + # Check if this is the local player (client's own player) + var is_local_player = (peer_id == multiplayer.get_unique_id()) + if is_local_player and GameStateManager.local_player_character == null: + GameStateManager.local_player_character = player_character + ui_manager.set_local_player(player_character) + ui_manager.update_button_states() - player_character.goals = data["goals"].duplicate() - player_character.playerboard = data["playerboard"].duplicate() - player_character.global_position = Vector3( - data["position"].x * 2 + 1, - 1.0, - data["position"].y * 2 + 1 - ) - player_character.rpc("sync_position", data["position"]) + # Wait for player managers to initialize (player.gd has 0.1s await in _ready) + await get_tree().create_timer(0.2).timeout + + # Now set goals and playerboard after managers are ready + var goals_to_set = data["goals"].duplicate() if data.has("goals") else [] + if goals_to_set.size() > 0 and player_character.race_manager: + player_character.goals = goals_to_set + + var playerboard_to_set = data["playerboard"].duplicate() if data.has("playerboard") else [] + if playerboard_to_set.size() > 0 and player_character.race_manager: + player_character.playerboard = playerboard_to_set + + # Update position if not already set + if not node_already_exists: + player_character.global_position = Vector3( + data["position"].x * 2 + 1, + 1.0, + data["position"].y * 2 + 1 + ) + + # Update playerboard UI for local player + if is_local_player: + ui_manager.update_playerboard_ui() + + # Update goals UI for this player - use direct panel update + if goals_to_set.size() > 0: + # Find the correct panel index for this player + var all_players = get_tree().get_nodes_in_group("Players") + 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 + ) + + var player_idx = -1 + for i in range(all_players.size()): + var player_name_id = int(String(all_players[i].name).get_slice("@", 0)) + if player_name_id == peer_id: + player_idx = i + break + + if player_idx != -1 and player_idx < $AllPlayerGoals.get_child_count(): + $AllPlayerGoals.get_child(player_idx).visible = true + _update_player_goals_ui(player_idx, goals_to_set) # ============================================================================= # Grid Item Randomization diff --git a/scenes/player.gd b/scenes/player.gd index 15f8b96..cbd384e 100644 --- a/scenes/player.gd +++ b/scenes/player.gd @@ -34,6 +34,7 @@ var can_finish: bool: # Modifier for Turn based var has_performed_action: bool = false +var _is_processing_action: bool = false var selected_gridmap_position = Vector2i(-1, -1) var selected_playerboard_slot = -1 var targeted_playerboard_slot = -1 @@ -346,9 +347,13 @@ func ping_existence(): # They can check if they have this node pass +var last_sent_position: Vector3 + func _physics_process(delta): if is_multiplayer_authority(): - rpc("remote_set_position", global_position) + if global_position.distance_squared_to(last_sent_position) > 0.001: + rpc("remote_set_position", global_position) + last_sent_position = global_position # Add continuous finish line check if race_manager and current_position in race_manager.finish_locations and can_finish and not is_player_moving: @@ -823,12 +828,12 @@ func auto_put_item() -> bool: # Force ActionState : None # ----------------------------------------------------------------- -@rpc("authority", "reliable") +@rpc("any_peer", "call_local", "reliable") func force_action_state_none(): # This is called by the server on the client to reset the UI var main = get_tree().get_root().get_node_or_null("Main") - if main: - main.set_action_state(main.ActionState.NONE) + if main and main.ui_manager: + main.ui_manager.current_action_state = main.ui_manager.ActionState.NONE action_manager.clear_highlights() action_manager.clear_playerboard_highlights() @@ -1024,6 +1029,12 @@ func sync_grid_item(x: int, y: int, z: int, item: int): @rpc("any_peer", "call_local") func sync_goals(new_goals: Array): goals = new_goals.duplicate() # Make sure to duplicate the array + + # Update the AllPlayerGoals UI + var main = get_tree().get_root().get_node_or_null("Main") + if main and main.has_method("_update_goals_ui_for_player"): + var player_id = get_multiplayer_authority() + main._update_goals_ui_for_player(player_id, new_goals) @rpc("any_peer", "call_local") func sync_second_lap_goals(new_goals: Array): diff --git a/scripts/managers/playerboard_manager.gd b/scripts/managers/playerboard_manager.gd index 1155af7..6ecfe95 100644 --- a/scripts/managers/playerboard_manager.gd +++ b/scripts/managers/playerboard_manager.gd @@ -243,8 +243,8 @@ func auto_put_item() -> bool: player.consume_action_points(1) var main = player.get_tree().get_root().get_node_or_null("Main") - if main: - main.set_action_state(main.ActionState.NONE) + if main and main.ui_manager: + main.ui_manager.current_action_state = main.ui_manager.ActionState.NONE return true diff --git a/scripts/managers/ui_manager.gd b/scripts/managers/ui_manager.gd index 83e1623..0f8b864 100644 --- a/scripts/managers/ui_manager.gd +++ b/scripts/managers/ui_manager.gd @@ -99,6 +99,11 @@ func update_playerboard_ui(): for i in range(25): var slot = playerboard_ui.get_child(i) + + # Safety check: Ensure playerboard has enough items + if i >= local_player_character.playerboard.size(): + continue + var item = local_player_character.playerboard[i] slot.texture = item_tex[0]