I have an AutoLoad node called MultiplayerDirector that handles creating peer and adding players. It also has MultiplayerSpawner which has player and Boxes™ in its Auto Spawn List with MultiplayerDirector as its Spawn Path. So when player creates Boxes™, MultiplayerSpawner sees that and creates Boxes™ for all the other players (or at least that how I’m understanding it works). But in actuality this happens only when the Host creates Boxes™ (see the video below).
The remote scene tree: 1 and 652996242 are Players, the RigidBody3D is the created Box™ from the Host
This is the snippet from the Director if server creation matters:
const PORT : int = 5357
var peer = ENetMultiplayerPeer.new()
func create_server():
peer.create_server(PORT)
multiplayer.multiplayer_peer = peer
multiplayer.server_relay = true
func create_client():
peer.create_client("localhost", PORT)
multiplayer.multiplayer_peer = peer
I tried setting multiplayer.server_relay to true from this topic, but it didn’t do anything.
The following video showcases the host on the left and other peer on the right. When host creates Boxes™, they appear for both players. When the other player creates Boxes™, they appear only on that player’s side, but not the host or other players’ (also tested with 3 separate game windows).
How to make it that Boxes™ are created from both players for all the other players?
In order to spawn a node from a peer the spawner needs to be authorized to the peer.
You could make an RPC function to request the host to spawn a node on its behalf. Or create a spawner that is authed to each peer.
Keep in mind the peer will need to manage the nodes it spawns.
Sharing authority is typically called peer-to-peer, as opposed to central authority which Godot is bent towards architecturally, with its authority concept. It usually makes it easier when one peer, the host, is responsible for state management.
To correct your understanding of the server_relay, it is meant to allow RPCs to be passed from one client to another. Usually with rpc_id, using the multiplayer_id of the client, and the target function would need to be annotated with an RPC attribute “any_peer”.
The server relay is on by default. In the mentioned post he was authorized the controlling to the peer. And only the host saw the movement but not the between clients. What the post doesn’t mention is is how he synchronizes state. So it’s hard to say why he had to manually turn it on or why it fixed his issue.
Thanks for the explanation! But I’m a bit puzzled right now. Do I need to establish full P2P or just send RPC requests to the host for it to spawn nodes for the other players, when player tries to create a node on their side? Or I can add MultiplayerSpawner for every other player upon that player connection and assigning them that player’s authority? (Don’t even know how that will work)
If I understood that correctly, I’ll try both methods and report if anything works, thanks again!
If you want to use a single spawner. I would setup a custom spawn that takes a configuration dictionary, builds the spawning node and returns the new node. You can write code for the host to spawn nodes this way, then provide an RPC for a client to send a configuration if they are not the server.
If you want multiple spawners, yes it does get complicated, but custom spawning also works here too. When a client joins you create all the client required nodes and authorize them to the client. Some call this a container scene and the host still manages these containers with a container spawner whenever a client joins or leaves.
Authority done with a single authority call since set_authority is recursive by default. It really depends on the tree layout on how many times you need to call set_authority.
Couple things to keep in mind, once a client has authority it is responsible for state management, and authority needs to be synchronized across all peers.
I finally did it! I used the RPC functions that create nodes on the host side in the Multiplayer autoload node which is then spawned on each other players side (or i think it does that like that)
@rpc("any_peer", "call_local", "reliable")
func add_box(box_type, normal, force_speed, global_position) -> void:
if not multiplayer.is_server():
return
///box creation code///