Skip to content

modules/multiplayer/scene_replication_interface @243 throws error perhaps change this check to a warning? #98104

Open
@KyleLevi

Description

@KyleLevi

Tested versions

4.3 release (not C#)

System information

Godot v4.3.stable.mono - Windows 10.0.22631 - Vulkan (Forward+) - dedicated NVIDIA GeForce RTX 3090 (NVIDIA; 32.0.15.6094) - AMD Ryzen 9 5900X 12-Core Processor (24 Threads)

Issue description

Hopefully this issue is a nice break from the others, it's kind of like a reverse-bug where an error is thrown, but the correct behavior is observed.

I'm following an implementation pattern similar to this blog post: https://godotengine.org/article/multiplayer-in-godot-4-0-scene-replication/

Essentially, when a Node is spawned, and the multiplayer authority of a child MultiplayerSynchronizer node is changed during _ready() or _enter_tree(), this error is thrown:

E 0:00:06:0613   on_replication_start: The MultiplayerSynchronizer at path "/root/Lobby/Spawns/676522849/MultiplayerSynchronizer" is unable to process the pending spawn since it has no network ID. This might happen when changing the multiplayer authority during the "_ready" callback. Make sure to only change the authority of multiplayer synchronizers during "_enter_tree" or the "_spawn_custom" callback of their multiplayer spawner.
  <C++ Error>    Condition "pending_sync_net_ids.is_empty()" is true. Returning: ERR_INVALID_DATA
  <C++ Source>   modules/multiplayer/scene_replication_interface.cpp:243 @ on_replication_start()

But if the node is inspected in the remote scene trees, the correct multiplayer authority is displayed for all clients. The error is repeated again when a new client joins, for every current client. (i.e. first client join sees 1 error, second client join is 4 total errors, third client brings the total to 9, ...)

The error is NOT thrown if a base Node is used instead of a MultiplayerSynchronizer - so I'm worried there may still be something behind the error going wrong I'm not aware of.

I've also tried adding a timed delay after the player joins, and the player node is instantiated, but before it is added to the scene by parenting to the Spawn node - so I believe this is unrelated to spawning a player node too soon after a player connects.

Steps to reproduce

I've created a micro example if anyone wants to try, you only need to make two scenes:

Lobby.tscn (default start scene)

  • Add MultiplayerSynchronizer as child of this Node
  • Add Node as child, name it Spawns
  • Add the following script to the Lobby:
extends Node

@onready var spawns: Node = $Spawns
@onready var spawner: Node = $MultiplayerSpawner

const PORT = 7000
const DEFAULT_SERVER_IP = "127.0.0.1"
var Player = preload("res://player.tscn")

func _ready() -> void:
    spawner.spawn_path = spawns.get_path()
    spawner.add_spawnable_scene("res://player.tscn")
    create_buttons()

func create_game():
    print('Creating Game')
    var peer = ENetMultiplayerPeer.new()
    peer.create_server(PORT)
    multiplayer.multiplayer_peer = peer
    multiplayer.peer_connected.connect(add_player)

func join_game():
    print('Joining Game')
    var peer = ENetMultiplayerPeer.new()
    peer.create_client(DEFAULT_SERVER_IP, PORT)
    multiplayer.multiplayer_peer = peer

func add_player(peer_id):
    print('Adding Player, Peer ID: %s' % [str(peer_id)])
    # await get_tree().create_timer(2.0).timeout
    # print('Timeout Done')
    var player = Player.instantiate()
    player.name = str(peer_id)
    spawns.add_child(player, true)

func create_buttons():
    var vbox = VBoxContainer.new()
    add_child(vbox)

    var host_button = Button.new()
    host_button.text = "HOST"
    host_button.connect("pressed", create_game)
    vbox.add_child(host_button)

    var join_button = Button.new()
    join_button.text = "JOIN"
    join_button.connect("pressed", join_game)
    vbox.add_child(join_button)

player.tscn

  • Add MultiplayerSynchronizer as child
  • Add this script to the MultiplayerSynchronizer:
extends MultiplayerSynchronizer

func _enter_tree() -> void:
    print("NetID: %s is setting multiplayer authority to %s" % [str(multiplayer.get_unique_id()), str(get_parent().name)])
    set_multiplayer_authority(get_parent().name.to_int())
    print("NetID: %s sees authority: %s" % [str(multiplayer.get_unique_id()), str(get_multiplayer_authority())])

Now to test it, you should see an error like:

E 0:00:06:0613   on_replication_start: The MultiplayerSynchronizer at path "/root/Lobby/Spawns/676522849/MultiplayerSynchronizer" is unable to process the pending spawn since it has no network ID. This might happen when changing the multiplayer authority during the "_ready" callback. Make sure to only change the authority of multiplayer synchronizers during "_enter_tree" or the "_spawn_custom" callback of their multiplayer spawner.
  <C++ Error>    Condition "pending_sync_net_ids.is_empty()" is true. Returning: ERR_INVALID_DATA
  <C++ Source>   modules/multiplayer/scene_replication_interface.cpp:243 @ on_replication_start()

and output in the terminal like:

Creating Game
Joining Game
Adding Player, Peer ID: 622658096
NetID: 1 is setting multiplayer authority to 622658096
NetID: 1 sees authority: 622658096
NetID: 622658096 is setting multiplayer authority to 622658096
NetID: 622658096 sees authority: 622658096

And if you inspect the MultiplayerSynchronizer node in the Scene -> Remote panel, both sessions will show the correct authority.

Minimal reproduction project (MRP)

multiplayer_synchronizer_MRP.zip

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions