Synchronizing Existing Objects with MultiplayerSpawner

Godot Version

4.4-dev2

Scenario

I’m creating a basic platformer that has coins and mobs at certain locations in the level. I’d like to synchronize the coins and mobs using a MultiplayerSpawner so that I can handle destroying them on the server when the player collects the coins or kills the mobs and have that be synchronized to all clients.

Question

MultiplayerSpawner works great when you spawn objects after clients have connected (like spawning a Player object when a new client connects), but how can it work with pre-existing objects (coins/mobs that are already on the map)?

If I just set up a MultiplayerSpawner with the Coin scene in the Auto Spawn List and Spawn Path set to the parent of some coins in the scene, it will cause this error to appear when a client connects because the client already has the coins when the server tries to sync them:

SceneReplicationInterface::on_spawn_receive: Condition “parent->has_node(name)” is true. Returning: ERR_INVALID_DATA

Possible Solution 1

I’ve tried deleting objects from clients before they’re synchronized, but queue_free() isn’t called until after the MultiplayerSpawner tries to sync objects, so it results in the same error.

Possible Solution 2

I’ve tried renaming objects (and later deleting them) on clients before they’re synchronized, but that seemed to break synchronization and the coins were not recreated by clients when the server tried to sync.

Possible Solution 3

Would the best solution be to create a placeholder object for coins/mobs for level creation and then, at runtime, delete the placeholder and have the server replace them with coins/mobs to synchronize to clients? This sounds like it would work, but would be less convenient for level design.

Please let me know what you think the best solution would be in this situation or if there is a better solution than the ones that I have listed. Thank you!

The MultiplayerSpawner isnt really customizable and I think what you will want to use is a good ole RPC function to have the clients queue_free() everything.

Example if the server is also a player:

@rpc("any_peer", "call_local")
func delete_coins(coin):
     queue_free(coin)

If the server is NOT a player:

@rpc("any_peer", "call_remote")
func delete_coins(coin):
     queue_free(coin)

You can call this function from wherever you know you want to delete your coin like this and it will be called on all clients:

delete_coins.rpc(coin)

Hope this helps.

I ended up having the coin parent remove its coin children on clients in _enter_tree() and that seemed to remove the coins before the MultiplayerSpawner syncs, so that clients get a synchronized copy of the coins from the server properly:

func _enter_tree() -> void:
	if <this is client>:
		for child in get_children():
			remove_child(child)
			child.queue_free()

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