MultiplayerSpawner : name conflict on spawned projectiles

Godot Version

4.1.3

Question

I want to spawn a projectile across network with a multiplayer spawner.
Sometimes the spawn does not take place on the client, and I can see this error :

E 0:00:37:0471   on_spawn_receive: Condition "parent->has_node(name)" is true. Returning: ERR_INVALID_DATA
  <Source C++>   modules/multiplayer/scene_replication_interface.cpp:596 @ on_spawn_receive()

So I think it’s a naming conlict on the spawned projectile.

Questions :
_ How does the MultiplayerSpawner synchronize spawned node’s name?
_ Is it a good practice to handle name synchronization myself ?
_ Should I avoid to send StringName across network (it’s the type of node’s name) ?

Error Breakdown:

The error “ERR_INVALID_DATA” indicates that the client received invalid data during the spawn process. Specifically, the on_spawn_receive function in modules/multiplayer/scene_replication_interface.cpp checks if the parent node (parent->has_node(name)) already has a child with the same name (name) as the spawned projectile. If so, the spawning fails. This suggests a naming conflict on the client-side.

MultiplayerSpawner Synchronization:

The MultiplayerSpawner node itself doesn’t directly synchronize the spawned node’s name. It replicates the entire scene hierarchy, including the node’s properties at the time of spawning. By default, Godot uses Remote Procedure Calls (RPCs) to send this information across the network.

Recommendations:

Unique Naming Strategy

To avoid naming conflicts, it’s highly recommended to implement a unique naming strategy for spawned projectiles. Here are two common approaches:

  • Prefix with Network ID: Prepend the projectile’s unique network ID (obtained from MultiplayerAPI.rpc_id) to its base name. This ensures uniqueness across clients.
  • Centralized Naming: Consider having a server-side script that generates unique names and assigns them to projectiles during spawning. This centralizes name management and avoids potential conflicts.

Code Example (Unique Naming with Network ID Prefix)

# Server-side spawning code (e.g., in a player script)
func spawn_projectile():
    var projectile = preload("res://path/to/projectile.tscn").instance()  # Load projectile scene
    var network_id = MultiplayerAPI.rpc_id  # Get unique network ID
    projectile.name = network_id + "_projectile"  # Prepend network ID to name
    var spawn_path = get_node("SpawnPoint").global_position  # Spawn location
    # Use RPC to spawn on clients
    var result = rpc_id(REMOTE_SPAWN_METHOD, spawn_path, projectile)

# Remote method on clients for replicating projectile
func remote_spawn(spawn_path, projectile_data):
    var projectile = projectile_data.instance()  # Instantiate projectile scene
    projectile.name = projectile_data.name  # Set name received from server
    add_child(projectile)  # Add projectile to scene
    projectile.global_position = spawn_path  # Set spawn position

Additional Considerations

  • Make sure your REMOTE_SPAWN_METHOD RPC is set up correctly on clients to handle the received data (spawn path and projectile data).
  • Consider error handling on the client-side in case the RPC fails or the projectile cannot be spawned.

Thanks for your answer.

  • Indeed, MultiplayerSpawner seems to replicate all properties of the given node to all clients. This is an important information which is not in the documentation.
  • I could not find the MultiplayerAPI.rpc_id property on my version of Godot (4.1.3). But indeed it would have been handy if it existed.
  • So I solved my problem by setting up a unique name ("projectile_[peer_id]_[projectile_id]") on the server, which is autmatically replicated on clients.

There is strange things in your answer (projectile.global_position = spawn_path). No offense, but have you written your answer with ChatGPT ? By the way it’s a good idea, shame I have not thought about it.

2 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.