ResourceLoader load issue with MultiplayerSpawner & Synchronizer

Godot Version

4.5.1

Question

From my Menu scene, client can join server (multiplayer)
Instead of loading scene with change_scene_to_file(), I want to use ResourceLoader

Problem is : My first player seems ok (Howerver, The multiplayerSynchronizer from one nested scene doesn’t work anymore) and then the second player joining spawn only from the view of the server and player 1. Player 2 doesn’t even see himself spawning in the game. His multiplayerSpawner doesn’t even sync. Not sure what is wrong with the code.

I put in the method “process2” the old way to load directly my scene, which is working

(it doesn’t make sens to put these line in the process method but it’s just to compare)

any idea how to fix this strange bug ?

extends Control

func _ready():
	if DisplayServer.get_name() == "headless":
		NetworkManager.host_game()

func _on_join():
	NetworkManager.playerName=%NameInput.text
	NetworkManager.join_game(%AddressInput.text)
	multiplayer.connected_to_server.connect(_on_connection_success)

func _on_connection_success():
	ResourceLoader.load_threaded_request(target_scene_path)
	loading = true
	%Loading.visible=loading

	
var loading = false
@export_file("*.tscn") var target_scene_path: String
var progress = []

func _process(_delta: float) :
	if loading :
		var status = ResourceLoader.load_threaded_get_status(target_scene_path, progress)
		%Loading.value = progress[0] * 100
		if status == ResourceLoader.THREAD_LOAD_LOADED:
			loading = false
			var new_scene = ResourceLoader.load_threaded_get(target_scene_path)
			get_tree().change_scene_to_packed(new_scene)
			%Loading.visible = loading
			

func _process2(_delta: float) :
	if loading :
		loading = false
		get_tree().change_scene_to_file("res://scenes/Game.tscn")

EDIT/NOTE : I got the same problem when using get_tree().change_scene_to_file(“res://scenes/Game.tscn”) just after :

if status == ResourceLoader.THREAD_LOAD_LOADED:

so it seems to come from ResourceLoader state ?

You are spending at least one frame where the two devices are connected, but the scene tree is totally different. At best you could threaded request the target scene before connecting, but for high level multiplayer to work you must have the same scene tree directly after the connection succeeds.

I tried to pre load the scene in the _ready() and it’s working, but honestly i don’t understand why

here is my code →

extends Control

var loading = false
@export_file("*.tscn") var target_scene_path: String
var progress = []

func _ready():
	ResourceLoader.load_threaded_request(target_scene_path, "",true,ResourceLoader.CACHE_MODE_REUSE)
	if DisplayServer.get_name() == "headless":
		NetworkManager.host_game()
		load_game()

func _on_join():
	NetworkManager.playerName=%NameInput.text
	NetworkManager.join_game(%AddressInput.text)
	multiplayer.connected_to_server.connect(load_game)

func load_game():
	loading = true
	%Loading.visible=loading
	
func _process(_delta: float) :
	if loading :
		var status = ResourceLoader.load_threaded_get_status(target_scene_path, progress)
		%Loading.value = progress[0] * 100
		if status == ResourceLoader.THREAD_LOAD_LOADED:
			loading = false
			#await get_tree().create_timer(2.0).timeout
			var new_scene = ResourceLoader.load_threaded_get(target_scene_path)
			get_tree().change_scene_to_packed(new_scene)
			%Loading.visible = loading

in the code if i uncomment :

#await get_tree().create_timer(2.0).timeout

it give me the same problem (problem with synchronizer and p2 not synced at all)

however i have the exact same scene tree between the server and p1 :

so it make me doubt about how to use ResourceLoader properly when i will need to switch between Lobby Scene, Game scene, end game scene etc…

EDIT : i noticed an error in the console :

get_node: Node not found: “Game/Teleporters/Teleporter/MultiplayerSynchronizer” (relative to “/root”).

while the MultiplayerSynchronizer is well present in the scene tree

so it make me think that the there is maybe a try to syncing before the object are well instantied (?)

You are still spending at least one frame not in the correct scene. As soon as you connect to the server you must load the next scene, no time for progress bars.

func load_game():
	var new_scene = ResourceLoader.load_threaded_get(target_scene_path)
	get_tree().change_scene_to_packed(new_scene)

Yes but why is it a problem ?

How to manage the following scenario :

  • Server launch and is in “lobby state”
  • Player 1 enter in the lobby
  • Player 2 enter in the lobby
  • Player 1 and 2 set parameter and profile customization (choose a caracther, spells, whatever…)
  • Both player are ready so they set “ready” in the lobby screen
  • Server see that p1 and p2 are ready so launch the game scene
  • Player 3 want to join the game (he is late) → connect to server → reach the lobby scene → join the game

How would you make this possible if i have to navigate through differents scenes not in same time for my player ?

The synchronizers and spawners run as soon as the player joins, they both expect to modify nodes by their scene tree path, if that path doesn’t match you will get errors.

Personally I have had success making a “Session” scene which has a multiplayer spawner for the lobby scene, this is deleted once the game starts and instantiates the main game scene through the same spawner.