Difficulties with MultiplayerSynchronizer Visibility

Godot Version

Godot 4.2.1

Question

Hello, I am currently working on a P2P game and I am having trouble syncing the player objects in my game with the Multiplayer Synchronizer node.

With the way that my game is set up, the player instances take a few frames to load into the game for the client when they join. This causes a problem with the multiplayer synchronizer each player has to track their position. When the client joins, the instance on the server tries to sync with the instance on the client, and when the server instance cannot instantly find the corresponding player node, it throws the error:

E 0:00:12:0583   get_node: Node not found: "Game/Areas/AreaRef_-1_0/Entities/1/MultiplayerSynchronizer" (relative to "/root").
  <C++ Error>    Method/function failed. Returning: nullptr
  <C++ Source>   scene/main/node.cpp:1638 @ get_node()
E 0:00:12:0583   process_simplify_path: Parameter "node" is null.
  <C++ Source>   modules/multiplayer/scene_cache_interface.cpp:76 @ process_simplify_path()

Once, the multiplayer synchronizer cannot initially find it’s corresponding instance on the client, it refuses to synchronize no matter what I do. I know that the node paths are correct, because once both instances are loaded in, they respond to RPC calls. I have tried setting the public visibility for the synchronizer to false and then using set_visibility_for(), to try and get the player to sync once it has finished loading in, but it never seems to do anything.

I am not using MultiplayerSpawners because in my game, players will be able to be in different levels at the same time, meaning that clients will not have player instances that are on different levels loaded in. And to my knowledge there is not a good way to make the spawners only spawn to certain peers.

Is there a way to tell the MultiplayerSynchronizer when and when not to sync with peers or will I have to make a custom MultiplayerSync?

I never had any luck with set_visibility_for either (still not sure what I was missing). What worked for me was passing a filter to add_visibility_filter.

If you define the filter using variables that exist in an outer scope, then you’ll be able to change those variables to affect the filter without needing the call add_visibility_filter again.

Here’s an example of what the filter could look like:

@export var enable_filter := true


func filter(id: int) -> bool:
	return (
			not enable_filter  # Always return true if filter is disabled.
			or {whatever other condition you need}
	)