#Trying to Spawn Connecting Player

1 messages · Page 1 of 1 (latest)

maiden hamlet
#

Hello, and thank you for taking the time to view my issue.

I am currently trying to spawn a player character for first the host and then the connecting peer. The host is able to connect and spawn the character via .spawn(), but the connecting peer throws this error and does not spawn (as evident from the Remote tab). I'm new to multiplayer, so any help on this would be greatly appreciated.

Thanks!

near mortar
#

I think I might see the issue

#

normally the error message that is shown here is called when the spawner is called when not having multiplayer authority

#

what does client_create in this case do?

#

is that called when a client joins the server?

#

in that case the multiplayer authority/server should be receiving the player connected signal and creating a player for them, IIRC

#

alternatively, I set it up in a lobby system first, where the players are spawned in this way:

    var unique: Array = []

    for item in Network.connected_players:
        if not unique.has(item):
            unique.append(item)

    #below I get list of connected users from my global script and then I spawn(id) each of them. Seems to work great.
    for player in unique:
        print("from global script: "+str(player))
        data["id"] = player
        spawn_array.erase(player)    
        spawn(data)
maiden hamlet
# near mortar is that called when a client joins the server?

Thank you for response and apologies for the tardiness in mine.

#Create New Server
func server_create(username, _ip):
    var host = ENetMultiplayerPeer.new()
    host.create_server(port, max_players)
    multiplayer.multiplayer_peer = host
    player_info["name"] = username
    players[1] = player_info
    player_connected.emit(1, player_info)
    server_joined(username)
#Create Client Connection
func client_create(username, ip):
    var peer = ENetMultiplayerPeer.new()
    peer.create_client(ip, port)
    player_info["name"] = username
    multiplayer.multiplayer_peer = peer
    server_joined(username)
#Server Joined
func server_joined(username):
    var peer_id = multiplayer.get_unique_id()
    if peer_id == 1: print("Host Connected: ", username,  " [", peer_id, "]")
    else: print("Client Connected: ", username, " [", peer_id, "]")
    emit_signal("server_found", username)
    UI_NETWORK.set_deferred("visible", false)```
This is currently being called when a button gets pushed.
maiden hamlet
near mortar
#

I'd have to sit down and dig through your and my code though

#

I'll try to track something down later on or tomorrow

#

mine is relatively barebones by comparison lol

maiden hamlet
near mortar
#

basically, important thing is that only the server should be calling spawn on the multiplayerspawner

#

I don't believe you are checking for whether it is multiplayer_authority or is_server anywhere

#
func _ready():
    print(str(Network.connected_players))
    spawn_function = spawnPlayer
    if is_multiplayer_authority():
        #this line is important because it spawns the host in.
        spawn(data)
        #the lines below pretty much do nothing? I think due to the login changes
        multiplayer.peer_connected.connect(spawn)
        multiplayer.peer_disconnected.connect(removePlayer)
    
    spawn_array = Network.connected_players.duplicate(true)

    var unique: Array = []

    for item in Network.connected_players:
        if not unique.has(item):
            unique.append(item)

    #below I get list of connected users from my global script and then I spawn(id) each of them. Seems to work great.
    for player in unique:
        print("from global script: "+str(player))
        data["id"] = player
        

        spawn_array.erase(player)    
        
        
        #data["role"] = Permissions.Perms.BASIC
        spawn(data)
        
    
    pass # Replace with function body.
#

here is my very messy code for the actual Map itself (which has its own multiplayer_spawner for the players that connected prior in the lobby)

#

var is_host = false
var lobby_id = 0
var lobby_members : Array = []

var i_am_ready : bool = false

@onready var ms = $MultiplayerSpawner


func _ready() -> void:
    ms.spawn_function = spawn_level
    #in  order to connect all lobby callbacks
    multiplayer.peer_connected.connect(_on_player_connected)
    set_multiplayer_authority(1)
    print(str(get_multiplayer_authority()))
    if is_multiplayer_authority():
        $StartButton.visible = true

func _on_ready_button_toggled(toggled_on: bool) -> void:
    if toggled_on == true:
        rpc("readyup")
        i_am_ready = true
    elif toggled_on == false:
        rpc("unready")
        i_am_ready = false

func _on_player_connected(id: int):
    print("Peer connected: "+str(id))
    lobby_members.append(id)
    var but = CheckButton.new()
    but.text =  str(id)
    but.name = str(id)
    $VBoxContainer.add_child(but)
    rpc("add_to_list", id)
    Network.connected_players.append(id)

@rpc("any_peer")
func add_to_list(id : int):
    var but = CheckButton.new()
    but.text =  str(id)
    but.name = str(id)
    $VBoxContainer.add_child(but)
    

@rpc("any_peer","call_local")
func readyup():
    var children = $VBoxContainer.get_children()
    var id = multiplayer.get_remote_sender_id()
    print("called by id "+ str(id))
    for child in children:
        if child.name == str(id):
            child.button_pressed = true
    print(str(multiplayer.multiplayer_peer))

@rpc("any_peer","call_local")
func unready():
    var children = $VBoxContainer.get_children()
    var id = multiplayer.get_remote_sender_id()
    print("called by id "+ str(id))
    for child in children:
        if child.name == str(id):
            child.button_pressed = false


func _on_start_button_pressed() -> void:
    var children = $VBoxContainer.get_children()
    #check that all players are ready
    for child in children:
        if child.button_pressed == false:
            print("All players not ready.")
            return

    print("Starting game now.")
    #this does not get the other player to spawn in w their character. This is probably because technically
    #the connected (signal) does not fire again, since there is already a connection that was made...
    ms.spawn("res://addons/godot_aerodynamic_physics/demo/demo_scene.tscn")
    rpc("hide_lobby")
    self.hide()

@rpc("call_remote", "reliable", "authority")
func hide_lobby():
    self.hide()

func spawn_level(data):
    var a = (load(data) as PackedScene).instantiate()
    return a```
#

here is full lobby code

#

basically I check for is-multiplayer_authority()
and only make start button callable from there. The Start Button is what actually calls the spawner to then create the level in this case

maiden hamlet
#

Thank you for your time, checking for multiplayer_authority() has gotten me a bit further.

near mortar
#

awesome, glad to hear it - still running into errors?

maiden hamlet
#

I've altered my code a bit to test for the ids, but it seems to be overwriting the clients player_info with the servers.

#

Fixed that one... The quest continues!

maiden hamlet
#

I think I'm almost there... I'm just stuck in one spot...

#

I essentially just need to take this player and throw it in front of is_multiplayer_authority, I think. But I'm unsure how to exactly do that since I called the Callable from set_spawn_function.

#

Trying to Spawn Connecting Client

#

Trying to Spawn Connecting Player

solar crest
#

I’m gonna forward this here, main thing is the last point, but you’ll run into issues due to the others once this is resolved

maiden hamlet
#

You’re completely ignoring the param passed to your custom spawn function, is that intentional?

This is essentially what I'm trying to get. I'm not familiar with the syntax for Callables like this.

You don’t need to check the player’s authority, checking the spawners authority before calling spawn() is good enough, since the spawn call will be replicated to all clients

I thought I tried this, and it just threw an error. I'll experiment more with it.

exotic fulcrum
#

A callable is just another name for a function. Anything in brackets is information you need to pass to that function.


func my_callable( number: int ) -> void:
    print( number ) ## prints '5'```
#

If you don't need any info to be passed you can just use open and close brackets - ()

iron wasp
maiden hamlet
#

I'm going to sleep. I'll tackle this later. @.@

willow delta
exotic fulcrum
maiden hamlet
#

After a full night's rest and not having a screaming baby in my ear, it seems I was able to work it all out switching my spawning approach from .spawn() to add_child() and condensing my code. In further research, I think .spawn() would be more useful to me as an enemy spawner, rather than the players. Thank you all for your help, I'm marking this as solved.

#
func _ready() -> void:
    BUTTON_SPAWN.connect("spawn_requested", spawn_requested.rpc)
    NETWORK.connect("server_found", server_found)

@rpc("any_peer", "call_local")
func spawn_requested():
    for id in NETWORK.players:
        var player_scene = preload("res://source/03 - Entities/00 - Humanoid/01 - Player/Entity_Player.tscn")
        var player = player_scene.instantiate()
        player.set_multiplayer_authority(id)
        player.name = str(id)
        if id == 1: player.global_position = object_plinths.get_node("Markers/Marker_Host").global_position
        else: player.global_position = object_plinths.get_node("Markers/Marker_Guest1").global_position
        spawner_players.call_deferred("add_child", player)

func server_found(username): print(username, ": Found the World!")```