Getting "Node not found" error when instanciating a scene with a MultiplayerSynchronizer

As u can see by the title, I’m getting an error when instanciating a scene with a MultiplayerSynchronizer.
Older clients can see newer clients move but newer clients cannot see the updates.
I properly setup Both MultiplayerSynchronizer and MultiplayerSpawner:


Here’s my code:

Main.gd:

extends Node2D

var players := [ ]
var options := {"host": 1}
@export var player_scene: PackedScene

func _ready() -> void:
	var my_id = multiplayer.get_unique_id()
	if not players.has(my_id):
		players.append(my_id)
		_add_player(my_id, true)

	Server.player_request_join.connect(func(id:int):
		if not players.has(id):
			players.append(id)
			_add_player(id, false)
		_sync_players_to_all())

	_sync_players_to_all()

func _add_player(id:int, is_local_authority:bool) -> void:
	if $Players.has_node(str(id)):
		return
	var player = player_scene.instantiate()
	player.name = str(id)
	player.position = $Spawn.position
	$Players.call_deferred("add_child", player)
	if is_local_authority:
		player.set_multiplayer_authority(id)


func _sync_players_to_all() -> void:
	for player_id in players:
		rpc_id(player_id, "set_players", players, options)

@rpc("call_remote", "any_peer", "reliable")
func set_players(players_arr:Array, options_dict:Dictionary):
	options = options_dict
	players = players_arr
	for id in players_arr:
		if not $Players.has_node(str(id)):
			_add_player(id, multiplayer.get_unique_id() == id)

Player.gd:

extends CharacterBody2D

@export var speed := 130
var last_horizontal = 0
var last_vertical = 0
@onready var anim = $Anims
@onready var sprite = $Sprite


func _enter_tree() -> void:
	set_multiplayer_authority(name.to_int())
func _physics_process(delta):
	if is_multiplayer_authority():
		var left = Input.is_action_pressed("ui_left")
		var right = Input.is_action_pressed("ui_right")
		var up = Input.is_action_pressed("ui_up")
		var down = Input.is_action_pressed("ui_down")
		var horizontal = 0
		var vertical = 0
		if left and right:
			horizontal = last_horizontal
		elif left:
			horizontal = -1
		elif right:
			horizontal = 1

		if up and down:
			vertical = last_vertical
		elif up:
			vertical = -1
		elif down:
			vertical = 1
		if horizontal != 0:
			last_horizontal = horizontal
			sprite.flip_h = horizontal == -1
		if vertical != 0:
			last_vertical = vertical
		velocity = Vector2(horizontal, vertical)
		if velocity != Vector2.ZERO:
			velocity = velocity.normalized() * speed
		move_and_slide()
		if velocity.length() > 0:
			anim.play("walk")
		else:
			anim.play("RESET")

Clients shouldn’t be creating their own players, the MultiplayerSpawner needs to handle replicating all spawned players.

The MultiplayerSpawner does not replicate any properties but the node’s name, which I also believe must be added as a child with force_readable_name enabled, which is the second argument of add_child. So position and set_multiplayer_authority are not changed for everybody, though later you do use set_multiplayer_authority in the player.gd’s _enter_tree which will happen for every client as long as they have the same player with the same name.to_int().

$Players.add_child(player, true)
# or deferred, but I don't think you want deferred
$Players.add_child.call_deferred(player, true)

thanks ill try that later im going to the grocery store right now

can you help me i still cant solve the problem

Sure. A fairly basic set up would be to spawn the host’s player when the server starts, notice only the server ever calls _add_player, clients should not create players.

func _ready() -> void:
	if multiplayer.is_server():
		multiplayer.peer_connected.connect(_add_player)
		multiplayer.peer_disconnected.connect(_remove_player)

		_add_player(1)
1 Like

the problem is that im using a dedicated server for room codes etc.
I dont know if its even possible
but here’s Server.gd:

extends Node

var peer := WebSocketMultiplayerPeer.new()
var rooms := []
const PORT = 22023
signal server_error(err:String)
signal player_request_join(id:int)

func _ready() -> void:
	if OS.has_feature("dedicated_server"):
		peer.create_server(PORT)
		multiplayer.multiplayer_peer = peer
		print("Server hosted on port %s" % PORT)
		multiplayer.multiplayer_peer.peer_connected.connect(func(id:int):
			print("Client connected (%s)" % id)
		)
		multiplayer.multiplayer_peer.peer_disconnected.connect(func(id:int):
			print("Client disconnected (%s)" % id)
		)

@rpc("any_peer", "call_remote", "reliable")
func create_game(player_username:String, player_id:int = 0):
	randomize()
	var player_real = multiplayer.get_remote_sender_id() if player_id == 0 else player_id
	var room_code = str(snapped(randi(),100000)).left(6)
	for room in rooms:
		if int(room.code) == int(room_code):
			create_game(player_username, player_real)
			return
	print("Room hosted with code %s by %s (%s)" % [room_code, player_username, str(player_real)])
	rooms.append({
		"code": room_code,
		"host_username": player_username,
		"host_id": player_real,
		"players": [player_real]
	})
	rpc_id(player_real, "join_game", int(room_code), "brbfr", player_real)

@rpc("any_peer", "call_remote", "reliable")
func join_game(room_code:int, player_username:String, player_id:int=0):
	var player_real = multiplayer.get_remote_sender_id() if player_id == 0 else player_id
	print("Client trying to join: %s (%s)" % [room_code, player_real])
	for room in rooms:
		if int(room.code) == int(room_code):
			print("Player joined room %s (%s)" % [room_code, player_real])
			rpc_id(player_real, "player_joined_room", room_code)
			rpc_id(room.host_id, "add_player_to_lobby", player_real)
			return
	rpc_id(player_real, "send_err", "Room not found.")

@rpc("any_peer", "call_remote", "reliable")
func send_err(err:String):
	server_error.emit(err)

@rpc("any_peer", "call_remote", "reliable")
func host_joined_lobby():
	var id = multiplayer.get_remote_sender_id()
	for room in rooms:
		if room.host_id == id:
			print("Host joined the game.")
			return

@rpc("any_peer", "call_local", "reliable")
func player_joined_room(room_code:Variant):
	var id = multiplayer.get_remote_sender_id()
	for room in rooms:
		if int(room.code) == int(room_code):
			print("Player joined the game.")
			for player in room.players:
				rpc_id(int(player), "add_player_to_lobby", int(id))
			room.players.append(id)
			return

@rpc("any_peer", "call_remote", "reliable")
func add_player_to_lobby(id:int):
	player_request_join.emit(id)

basically i was making the server to tell the host to add the player which doesnt have the id 1 (of the server)

I see, I don’t think Godot’s high level multiplayer can handle multiple “sessions” easily if that’s what you hope to do with room codes, you may need excessive network “visibility” management for your Synchronizers.

The Server may not need a player, but it still needs to be solely in charge of spawning players. Your server and client’s scene tree must match for the high level multiplayer nodes to function properly, spawning new nodes must take place on the server with a readable name through the assigned MultiplayerSpawner node.

It certainly makes a program much more complicated to hold multiple game states, I believe most room-code online games do ask players to host on their machine and use a sort of STUN/TURN server to connect the two (through the room code).

1 Like

oh alright thanks anyway

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