fix the instance of player

This commit is contained in:
2025-03-03 14:22:27 +08:00
parent 276aa439ab
commit 23e2e50c0c
2 changed files with 308 additions and 35 deletions
+278 -23
View File
@@ -40,6 +40,7 @@ const ADDRESS = "127.0.0.1"
@export var enable_bots: bool = true # Add this line @export var enable_bots: bool = true # Add this line
var connected_peer_ids = [] var connected_peer_ids = []
var _connection_check_timer: float = 0.0
var local_player_character : CharacterBody3D var local_player_character : CharacterBody3D
var player_scene = preload("res://scenes/player.tscn") var player_scene = preload("res://scenes/player.tscn")
var current_turn_index = 0 var current_turn_index = 0
@@ -95,6 +96,28 @@ func _process(delta):
# Sync all players' goals to the new peer # Sync all players' goals to the new peer
update_all_players_goals() update_all_players_goals()
# Also periodically verify client connections
_connection_check_timer += delta
if _connection_check_timer >= 5.0:
_connection_check_timer = 0.0
verify_all_connections()
func verify_all_connections():
if multiplayer.is_server():
for peer_id in players:
if peer_id != 1: # Skip server
# Ping each client
rpc_id(peer_id, "connection_verify", players)
@rpc
func connection_verify(expected_players: Array):
# Client checks if it has all expected players
for peer_id in expected_players:
if peer_id != multiplayer.get_unique_id() and not has_node(str(peer_id)):
# Missing a player - request it
rpc_id(1, "request_specific_player_data", peer_id)
print("Requesting missing player: ", peer_id)
func setup_action_buttons(): func setup_action_buttons():
move_button.pressed.connect(func(): set_action_state(ActionState.MOVING)) move_button.pressed.connect(func(): set_action_state(ActionState.MOVING))
grab_button.pressed.connect(func(): set_action_state(ActionState.GRABBING)) grab_button.pressed.connect(func(): set_action_state(ActionState.GRABBING))
@@ -319,49 +342,251 @@ func _on_join_pressed():
multiplayer_peer.create_client(ADDRESS, PORT) multiplayer_peer.create_client(ADDRESS, PORT)
multiplayer.multiplayer_peer = multiplayer_peer multiplayer.multiplayer_peer = multiplayer_peer
$NetworkInfo/UniquePeerID.text = str(multiplayer.get_unique_id()) $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())
#func _on_peer_connected(new_peer_id):
#if multiplayer.is_server():
## Increase delay to ensure scene is ready
#await get_tree().create_timer(1.5).timeout
#
## First sync game state
#rpc_id(new_peer_id, "sync_game_state", players, bots, game_started, turn_based_mode)
#rpc_id(new_peer_id, "sync_preset_goals", preset_goals)
#
## Wait a bit for the client to process state
#await get_tree().create_timer(0.5).timeout
#
## Then sync all existing players in order
#var sorted_players = players.duplicate()
#sorted_players.sort()
#for peer_id in sorted_players:
#if peer_id != new_peer_id:
## First ensure player exists
#var player = get_node_or_null(str(peer_id))
#if player:
## Sync player's full state
#var player_data = {
#"position": player.current_position,
#"goals": player.goals,
#"playerboard": player.playerboard
#}
#rpc_id(new_peer_id, "sync_existing_player", peer_id, player_data)
#await get_tree().create_timer(0.1).timeout # Small delay between players
#
## Finally add the new player
#await get_tree().create_timer(0.5).timeout
#add_player_character(new_peer_id)
#rpc("add_newly_connected_player_character", new_peer_id)
#
## Replace bot if needed
#if bots.size() > 0:
#replace_bot_with_player(new_peer_id)
#
## Final sync of all goals
#await get_tree().create_timer(0.5).timeout
#rpc("force_update_all_goals")
func _on_peer_connected(new_peer_id): func _on_peer_connected(new_peer_id):
if multiplayer.is_server(): if multiplayer.is_server():
# Increase delay to ensure scene is ready # Create a more robust state sync process
await get_tree().create_timer(1.5).timeout await get_tree().create_timer(1.5).timeout
# First sync game state # First sync complete game state
rpc_id(new_peer_id, "sync_game_state", players, bots, game_started, turn_based_mode) var complete_state = {
rpc_id(new_peer_id, "sync_preset_goals", preset_goals) "players": players,
"bots": bots,
"game_started": game_started,
"turn_based": turn_based_mode,
"preset_goals": preset_goals,
"player_states": {}
}
# Wait a bit for the client to process state # Gather all existing player states
await get_tree().create_timer(0.5).timeout for peer_id in players:
# Then sync all existing players in order
var sorted_players = players.duplicate()
sorted_players.sort()
for peer_id in sorted_players:
if peer_id != new_peer_id:
# First ensure player exists
var player = get_node_or_null(str(peer_id)) var player = get_node_or_null(str(peer_id))
if player: if player:
# Sync player's full state complete_state["player_states"][peer_id] = {
var player_data = {
"position": player.current_position, "position": player.current_position,
"goals": player.goals, "goals": player.goals,
"playerboard": player.playerboard "playerboard": player.playerboard,
"is_bot": player.is_bot || player.is_in_group("Bots")
} }
rpc_id(new_peer_id, "sync_existing_player", peer_id, player_data)
await get_tree().create_timer(0.1).timeout # Small delay between players # Send complete state in one RPC
rpc_id(new_peer_id, "receive_complete_game_state", complete_state)
# Finally add the new player # Finally add the new player
await get_tree().create_timer(0.5).timeout await get_tree().create_timer(0.5).timeout
add_player_character(new_peer_id) add_player_character(new_peer_id)
rpc("add_newly_connected_player_character", new_peer_id) rpc("add_newly_connected_player_character", new_peer_id)
# Replace bot if needed # Make sure all clients know about all players
if bots.size() > 0: rpc("sync_complete_player_list", players)
replace_bot_with_player(new_peer_id)
## Replace bot if needed
#if bots.size() > 0:
#replace_bot_with_player(new_peer_id)
#
# Final sync of all goals # Final sync of all goals
await get_tree().create_timer(0.5).timeout await get_tree().create_timer(0.5).timeout
rpc("force_update_all_goals") rpc("force_update_all_goals")
@rpc("reliable")
func sync_complete_player_list(player_list: Array):
# Ensure we have all players in our list
players = player_list.duplicate()
# Check which players we don't have nodes for
for peer_id in players:
if not has_node(str(peer_id)) and peer_id != multiplayer.get_unique_id():
# Request this specific player's data from server
rpc_id(1, "request_specific_player_data", peer_id)
@rpc("any_peer")
func request_specific_player_data(requested_peer_id: int):
if multiplayer.is_server():
var player = get_node_or_null(str(requested_peer_id))
if player:
var player_data = {
"peer_id": requested_peer_id,
"position": player.current_position,
"goals": player.goals,
"playerboard": player.playerboard,
"is_bot": player.is_bot || player.is_in_group("Bots")
}
# Send to the requesting client only
rpc_id(multiplayer.get_remote_sender_id(), "create_specific_player", player_data)
@rpc("any_peer")
func request_full_player_sync(requesting_peer_id):
if multiplayer.is_server():
print("Full sync requested by: ", requesting_peer_id)
# Send the complete list of players
rpc_id(requesting_peer_id, "sync_complete_player_list", players)
# Send each player's data
for peer_id in players:
var player = get_node_or_null(str(peer_id))
if player:
var player_data = {
"peer_id": peer_id,
"position": player.current_position,
"goals": player.goals,
"playerboard": player.playerboard,
"is_bot": player.is_bot || player.is_in_group("Bots")
}
rpc_id(requesting_peer_id, "create_specific_player", player_data)
# Allow a short delay between player creations
await get_tree().create_timer(0.1).timeout
@rpc("reliable")
func create_specific_player(data: Dictionary):
var peer_id = data["peer_id"]
# Don't create if already exists
if has_node(str(peer_id)):
return
# Create the player
var player_character = player_scene.instantiate()
player_character.set_multiplayer_authority(peer_id)
player_character.name = str(peer_id)
# Set properties before adding to tree
player_character.current_position = data["position"]
# Add to scene
add_child(player_character)
# Apply properties after adding
player_character.add_to_group("Players", true)
if data["is_bot"]:
player_character.add_to_group("Bots", true)
player_character.is_bot = true
player_character.rpc("sync_bot_status", true)
# Apply data
player_character.goals = data["goals"].duplicate()
player_character.playerboard = data["playerboard"].duplicate()
# Force position sync
player_character.global_position = Vector3(
data["position"].x * 2 + 1,
1.0,
data["position"].y * 2 + 1
)
player_character.rpc("sync_position", data["position"])
# Update UI
update_all_players_goals()
update_all_players_boards()
@rpc("reliable")
func force_update_all_goals():
# This is called but might be getting lost in the sequence
# Make sure it's called after all players are created
await get_tree().create_timer(0.2).timeout
update_all_players_goals()
update_all_players_boards()
# Set
@rpc("reliable")
func receive_complete_game_state(state):
# Apply complete game state
players = state["players"]
bots = state["bots"]
game_started = state["game_started"]
turn_based_mode = state["turn_based"]
preset_goals = state["preset_goals"]
# Process each player state in a consistent order
var sorted_peers = state["player_states"].keys()
sorted_peers.sort()
for peer_id in sorted_peers:
var player_data = state["player_states"][peer_id]
# Create player if doesn't exist
if not has_node(str(peer_id)):
var player_character = player_scene.instantiate()
player_character.set_multiplayer_authority(peer_id)
player_character.name = str(peer_id)
# Set basic properties before adding to scene tree
player_character.current_position = player_data["position"]
# Add to scene
add_child(player_character)
# Apply state after adding to tree
player_character.add_to_group("Players", true)
if player_data["is_bot"]:
player_character.add_to_group("Bots", true)
player_character.is_bot = true
player_character.rpc("sync_bot_status", true)
player_character.goals = player_data["goals"].duplicate()
player_character.playerboard = player_data["playerboard"].duplicate()
# Ensure proper grid-aligned positioning
player_character.global_position = Vector3(
player_data["position"].x * 2 + 1,
1.0,
player_data["position"].y * 2 + 1
)
# Force position sync
player_character.rpc("sync_position", player_data["position"])
# Force UI updates
update_all_players_goals()
update_all_players_boards()
@rpc("reliable") @rpc("reliable")
func sync_existing_player(peer_id: int, player_data: Dictionary): func sync_existing_player(peer_id: int, player_data: Dictionary):
# Create player if doesn't exist # Create player if doesn't exist
@@ -404,10 +629,13 @@ func _on_peer_disconnected(peer_id):
@rpc("any_peer", "call_local") @rpc("any_peer", "call_local")
func add_player_character(peer_id): func add_player_character(peer_id):
# Check if player already exists # First check if this player already exists
if has_node(str(peer_id)): if has_node(str(peer_id)):
print("Player already exists: ", peer_id)
return return
print("Adding player: ", peer_id)
connected_peer_ids.append(peer_id) connected_peer_ids.append(peer_id)
var player_character = player_scene.instantiate() var player_character = player_scene.instantiate()
player_character.set_multiplayer_authority(peer_id) player_character.set_multiplayer_authority(peer_id)
@@ -428,7 +656,14 @@ func add_player_character(peer_id):
add_child(player_character) add_child(player_character)
player_character.add_to_group("Players", true) player_character.add_to_group("Players", true)
# Force position sync after adding to tree # Wait for the node to be properly added to the scene
await get_tree().process_frame
# Ensure the player list is updated
if not peer_id in players:
players.append(peer_id)
# Finish setup and sync position
if multiplayer.is_server(): if multiplayer.is_server():
await get_tree().create_timer(0.1).timeout await get_tree().create_timer(0.1).timeout
player_character.rpc("sync_position", player_character.current_position) player_character.rpc("sync_position", player_character.current_position)
@@ -560,6 +795,26 @@ func replace_bot_with_player(player_id):
rpc("remove_bot_keep_board", bot_id) rpc("remove_bot_keep_board", bot_id)
rpc("sync_players", players) rpc("sync_players", players)
@rpc("call_local")
func remove_bot_keep_board(bot_id):
# This RPC is called but not implemented in your code
var bot_node = get_node_or_null(str(bot_id))
if bot_node:
# Don't immediately queue_free - this can cause timing issues
# Instead, mark for removal and remove after a short delay
bot_node.visible = false # Hide immediately
bot_node.set_process(false)
bot_node.set_physics_process(false)
# Disable all input and behavior
var behavior_tree = bot_node.get_node_or_null("BehaviorTree")
if behavior_tree:
behavior_tree.enabled = false
# Remove after a short delay
await get_tree().create_timer(0.5).timeout
if is_instance_valid(bot_node) and bot_node.get_parent() == self:
bot_node.queue_free()
@rpc("call_local") @rpc("call_local")
func remove_bot(bot_id): func remove_bot(bot_id):
+25 -7
View File
@@ -6,6 +6,7 @@ extends Node3D
var enhanced_gridmap: EnhancedGridMap var enhanced_gridmap: EnhancedGridMap
@export var current_position: Vector2i @export var current_position: Vector2i
var is_player_moving: bool = false var is_player_moving: bool = false
var _verify_timer: float = 0.0
@export var cell_size: Vector3 = Vector3(2, 2, 2) @export var cell_size: Vector3 = Vector3(2, 2, 2)
@export var cell_offset: Vector3 = Vector3(0, 0, 0) @export var cell_offset: Vector3 = Vector3(0, 0, 0)
@@ -58,11 +59,10 @@ func _ready():
if main_scene: if main_scene:
enhanced_gridmap = main_scene.get_node("EnhancedGridMap") enhanced_gridmap = main_scene.get_node("EnhancedGridMap")
# Initialize behavior tree for bots
var behavior_tree = $BehaviorTree
# Early setup for bots # Early setup for bots
if is_bot == true or is_in_group("Bots"): if is_bot == true or is_in_group("Bots"):
# Initialize behavior tree for bots
var behavior_tree = $BehaviorTree
# Disable all input processing for bots immediately # Disable all input processing for bots immediately
set_process_input(false) set_process_input(false)
set_process_unhandled_input(false) set_process_unhandled_input(false)
@@ -135,6 +135,24 @@ func sync_bot_status(is_bot_status: bool):
behavior_tree.set_physics_process(false) behavior_tree.set_physics_process(false)
behavior_tree.set_process(false) behavior_tree.set_process(false)
func _process(delta):
if is_multiplayer_authority():
# Visual debugging - show connection status in name label
$Name.text = str(name) + "\n(Auth: " + str(get_multiplayer_authority()) + ")"
# Periodically verify our existence to others
_verify_timer += delta
if _verify_timer >= 3.0:
_verify_timer = 0.0
rpc("ping_existence")
@rpc("any_peer", "call_local")
func ping_existence():
# This just lets other clients know this player exists
# They can check if they have this node
pass
func _physics_process(_delta): func _physics_process(_delta):
if is_multiplayer_authority(): if is_multiplayer_authority():
rpc("remote_set_position", global_position) rpc("remote_set_position", global_position)
@@ -1065,11 +1083,11 @@ func update_visual_position():
rpc("sync_position", current_position) rpc("sync_position", current_position)
@rpc("any_peer", "call_local") @rpc("any_peer", "call_local")
func sync_position(pos: Vector2): func sync_position(pos: Vector2i):
current_position = pos current_position = pos
# Ensure proper grid-aligned positioning # Always update the visual position after position sync
global_position = Vector3( global_position = Vector3(
current_position.x * cell_size.x + cell_size.x * 0.5, current_position.x * cell_size.x + cell_size.x * 0.5,
1.0, cell_size.y,
current_position.y * cell_size.z + cell_size.z * 0.5 current_position.y * cell_size.z + cell_size.z * 0.5
) ) + cell_offset