Multiplayer P2P - How to allow players to choose a different character

Godot Version

4.3

Hi guys!
I’m working to develop a small multiplayer game and I’ve followed a few tutorials and I’ve done and redone some tests with mock projects so I’m getting familiar with the basics.
So I can get a server running and a client connecting to it. Everything is synchronized and working as expected.
I still have trouble undestanding some stuff though but here is my question : I’d like the player to be able to choose between different characters (ships in my game) but I can’t get it done! I’ve tried several things but to no success.
Yesterday, I tried from a blank project and I got stuck again.
Here is my connection scene :

along with the main scene tree :

and the code :

extends Node

var peer
var port = 8080
var ip = "127.0.0.1"

var player_ship : String = "error"

@onready var ship_blue = preload("res://ship_blue.tscn")
@onready var ship_green = preload("res://ship_green.tscn")

@onready var level1 = preload("res://level_1.tscn")

func _ready() -> void:
	pass
	#multiplayer.peer_connected.connect(peer_connected.bind(player_ship))
	
func button_blue_ship() : 
	player_ship = "blue"
	if not multiplayer.peer_connected.is_connected(peer_connected) : 
		multiplayer.peer_connected.connect(peer_connected.bind(player_ship))
	else : 
		print("Already connected to signal")
	
func button_green_ship() : 
	player_ship = "green"
	if not multiplayer.peer_connected.is_connected(peer_connected) : 
		multiplayer.peer_connected.connect(peer_connected.bind(player_ship))
	else : 
		print("Already connected to signal")
	
func host() : 
	print("hosting")
	
	peer = ENetMultiplayerPeer.new()
	peer.create_server(port)
	
	multiplayer.multiplayer_peer = peer

func join() : 
	print("joining")
	
	peer = ENetMultiplayerPeer.new()
	peer.create_client(ip, port)
	
	multiplayer.multiplayer_peer = peer

func peer_connected(id, ship) : 
	print("Peer connected : ", id, " with ", ship )
	

As you can see, I’m just printing stuff and the result I get is the contrary of what I expect : Here is the output when I choose BlueShip for the Server and GreenShip for the client

hosting
Peer connected : 1718136004 with blue
joining
Peer connected : 1 with green

So what am I doing wrong?? What is the general way of doing that? Should the player choose their character after the connection was established or before?
Should I put the information in an autoload?
Is it even an Ok solution to put the signal connection in a button_press function?

Thanks a lot for your help!

I’ve continued working on the script and as I was doubtful about a signal connection in a button_press function, I rewrote it along with the _load_player function.

extends Node

var peer
var port = 8080
var ip = "127.0.0.1"

var player_ship : String = "error"

@onready var ship_blue = preload("res://ship_blue.tscn")
@onready var ship_green = preload("res://ship_green.tscn")

@onready var level1 = preload("res://level_1.tscn")

func _ready() -> void:

	pass
	#multiplayer.peer_connected.connect(peer_connected.bind(player_ship))
	
func choose_blue_ship() : 
	player_ship = "blue"
	
	
func choose_green_ship() : 
	player_ship = "green"
	
	
func host() : 
	print("hosting")
	
	peer = ENetMultiplayerPeer.new()
	var error = peer.create_server(port)
	
	if error != OK : 
		print("Can not create Server ", error)
		return
	
	multiplayer.multiplayer_peer = peer
	
	multiplayer.peer_connected.connect(peer_connected.bind(player_ship))

	_load_player(multiplayer.get_unique_id(),player_ship)
	print("Host_pressed : ", multiplayer.get_unique_id(), " ", player_ship)

func join() : 
	print("joining")
	
	peer = ENetMultiplayerPeer.new()
	peer.create_client(ip, port)
	
	multiplayer.multiplayer_peer = peer
	
func peer_connected(id, play_ship) : 
	print("Peer connected : ", id, " with ", play_ship )
	_load_player(id, play_ship)

func _load_player(id, ship) :
	if is_multiplayer_authority() : 
		var spawn_node = get_tree().current_scene.get_node("Player")
		var sh
		if ship == "error" : 
			print("ERROR : Choose a Ship")
			return
		if ship == "blue" : 
			sh = ship_blue.instantiate()
			sh.player_id = id
			sh.name = "Player_" + str(id)
			sh.global_position = Vector2(randi_range(50, 450),randi_range(50, 450) )
		elif ship == "green" : 
			sh = ship_green.instantiate()
			sh.player_id = id
			sh.name = "Player_" + str(id)
			sh.global_position = Vector2(randi_range(50, 450),randi_range(50, 450) )
			
		spawn_node.add_child(sh, true)

CCL : I still don’t get the result I’m looking for : the Client spawns the same ship character as the Server regardless of what I choose in the connection window…
Does it come from the signal connection line being in the host() function and the “player_ship” variable having been already passed through?
If that’s the case, how should I do it? What would be a standard procedure for that?

Hi, I continued my work and I finally found the solution which I post here in case someone is interested :


extends Node

var peer
var port = 8080
var ip = "127.0.0.1"

var player_ship : String = "error"

@onready var ship_blue = preload("res://ship_blue.tscn")
@onready var ship_green = preload("res://ship_green.tscn")
@onready var ship_class = preload("res://ShipClass.tscn")

@onready var level1 = preload("res://level_1.tscn")

func _ready() -> void:
	get_tree().paused = true


func host() : 
	print("hosting")
	
	$ConnectionUI/Panel/VBoxContainer/Join.disabled = true
	
	peer = ENetMultiplayerPeer.new()
	var error = peer.create_server(port)
	if error != OK : 
		print("Can not create Server ", error)
		return
	
	multiplayer.multiplayer_peer = peer
	
	multiplayer.peer_connected.connect(peer_connected)

	print("Host_pressed : ", multiplayer.get_unique_id())
	

func join() : 
	print("joining")
	
	$ConnectionUI/Panel/VBoxContainer/Host.disabled = true
	
	peer = ENetMultiplayerPeer.new()
	peer.create_client(ip, port)
	
	multiplayer.multiplayer_peer = peer
	
func peer_connected(id) : 
	print("Peer connected : ", id)


func choose_blue_ship() : 
	player_ship = "blue"
	
	await get_tree().create_timer(0.2).timeout
	
	print(multiplayer.get_unique_id())
	print(player_ship)
	
	if multiplayer.is_server() : 
		_load_player(multiplayer.get_unique_id(), player_ship)
	else : 
		_load_player.rpc(multiplayer.get_unique_id(), player_ship)

func choose_green_ship() : 
	player_ship = "green"
	
	await get_tree().create_timer(0.5).timeout
	
	print(multiplayer.get_unique_id())
	print(player_ship)
	
	if multiplayer.is_server() : 
		_load_player(multiplayer.get_unique_id(), player_ship)
	else : 
		_load_player.rpc(multiplayer.get_unique_id(), player_ship)

@rpc("any_peer")
func _load_player(id, ship) :
	if is_multiplayer_authority() : 
		var spawn_node = get_tree().current_scene.get_node("Player")
		var sh
		if ship != "blue" and ship != "green" : 
			print("ERROR : Choose a Ship")
			return
			
		if ship == "blue" : 
			sh = ship_blue.instantiate()
			sh.player_id = id
			sh.name = "Player_" + str(id)
			sh.global_position = Vector2(randi_range(50, 450),randi_range(50, 450) )
			
			print("Authority : ", sh.get_multiplayer_authority())
			print("Input Authority : ", sh.get_node("InputSynchronizer").get_multiplayer_authority())
			
			spawn_node.add_child(sh, true)
			
		elif ship == "green" : 
			sh = ship_green.instantiate()
			sh.player_id = id
			sh.name = "Player_" + str(id)
			sh.global_position = Vector2(randi_range(50, 450),randi_range(50, 450) )
			
			print("Authority : ", sh.get_multiplayer_authority())
			print("Input Authority : ", sh.get_node("InputSynchronizer").get_multiplayer_authority())

			spawn_node.add_child(sh, true)
			
func _on_connect_pressed() -> void:
	hide_ui.rpc()
	get_tree().paused = false

@rpc("any_peer", "call_local")
func hide_ui() : 
	$ConnectionUI.hide()

So I turned the _load_player function into an RPC which I call only on the client and I load the player in the Press_button functions now…
Well, everything works as intended now so I hope I won’t make the same mistake again!
I’m sure there are some better and more efficient way to do it but that’s the one I found by myself and it works so I’ll be happy for now.
Of course, if you have advice, don’t hesitate, I’'ll give my full attention!
Cheers