Passing Host in P2P game

Godot Version

v4.4.1.stable.custom_build [d4efbbd1d]- Godot Steam

Question

` I am attempting to pass the host to another client when the host leaves the lobby. Currently when the host leaves the scene is “closed” and a grey screen appears. I create the lobby and handle joining through my main.gd:

extends Node2D

Variables for Logger

var scriptName = “main.gd”

var peer = SteamMultiplayerPeer.new()
@onready var ms: MultiplayerSpawner = $MultiplayerSpawner

func _ready() → void:
var function = “_ready”
Logger.log(scriptName, function, “Log”, Globals.startLog)

ms.spawn_function = spawn_level
peer.lobby_created.connect(_on_lobby_created)
Steam.lobby_match_list.connect(_on_lobby_match_list)
open_lobby_list()

Logger.log(scriptName, function, "Log", Globals.endLog)

func spawn_level(data):
var function = “spawn_level”
Logger.log(scriptName, function, “Log”, Globals.startLog)

var a = (load(data) as PackedScene).instantiate()

Logger.log(scriptName, function, "Log", Globals.endLog)

return a

func _on_host_pressed() → void:
var function = “_on_host_pressed”
Logger.log(scriptName, function, “Log”, Globals.startLog)
Logger.log(scriptName, function, “Log”, “Host button has been pressed.”)

Globals.isHost = true
peer.create_lobby(SteamMultiplayerPeer.LOBBY_TYPE_PUBLIC)
multiplayer.multiplayer_peer = peer
ms.spawn("res://scene/level.tscn")
$Host.hide()
$LobbyContainer/Lobbies.hide()
$Refresh.hide()

Logger.log(scriptName, function, "Log", Globals.endLog)

func join_lobby(id):
var function = “join_lobby”
Logger.log(scriptName, function, “Log”, Globals.startLog)

peer.connect_lobby(id)
multiplayer.multiplayer_peer = peer
Globals.LOBBY_ID = id
$Host.hide()
$LobbyContainer/Lobbies.hide()
$Refresh.hide()

Logger.log(scriptName, function, "Log", "Joining Lobby : " + str(Globals.LOBBY_ID))
Logger.log(scriptName, function, "Log", Globals.endLog)

func _on_lobby_created(connect, id):
var function = “_on_lobby_created”
Logger.log(scriptName, function, “Log”, Globals.startLog)

if connect:
	Globals.LOBBY_ID = id
	Steam.setLobbyData(Globals.LOBBY_ID, "name", str(Steam.getPersonaName() + "'s Lobby"))
	Steam.setLobbyJoinable(Globals.LOBBY_ID, true)
	
	Logger.log(scriptName, function, "Log", "Lobby Created with ID : " + str(Globals.LOBBY_ID))
	Logger.log(scriptName, function, "Log", Globals.endLog)

func open_lobby_list():
var function = “open_lobby_list”
Logger.log(scriptName, function, “Log”, Globals.startLog)

Steam.addRequestLobbyListDistanceFilter(Steam.LOBBY_DISTANCE_FILTER_WORLDWIDE)
Steam.requestLobbyList()

Logger.log(scriptName, function, "Log", Globals.endLog)

func _on_lobby_match_list(lobbies):
var function = “_on_lobby_match_list”
Logger.log(scriptName, function, “Log”, Globals.startLog)

for lobby in lobbies:
	var lobby_name = Steam.getLobbyData(lobby, "name")
	var memb_count = Steam.getNumLobbyMembers(lobby)
	
	var but = Button.new()
	but.set_text(str(lobby_name, "| Player Count: ", memb_count))
	but.set_size(Vector2(100, 5))
	but.connect("pressed", Callable(self, "join_lobby").bind(lobby))
	
	$LobbyContainer/Lobbies.add_child(but)
	
Logger.log(scriptName, function, "Log", Globals.endLog)

func _on_refresh_pressed() → void:
var function = “_on_refresh_pressed”
Logger.log(scriptName, function, “Log”, Globals.startLog)

if $LobbyContainer/Lobbies.get_child_count() > 0:
	for n in $LobbyContainer/Lobbies.get_children():
		n.queue_free()
		
open_lobby_list()

Logger.log(scriptName, function, "Log", Globals.endLog)

Further functionality is handled in multiplayer_spawner.gd :

extends MultiplayerSpawner

@export var playerScene : PackedScene
var scriptName = “multiplayer_spawner.gd”
var players = {}

Server Prep

func _ready() → void:
var function = “_ready”
Logger.log(scriptName, function, “Log”, Globals.startLog)
Logger.log(scriptName, function, “Log”, "isHost = " + str(Globals.isHost))

Steam.lobby_chat_update.connect(_on_lobby_chat_update)
spawn_function = spawnPlayer

if Globals.isHost:
	spawn(1)
	
multiplayer.peer_connected.connect(spawn)
multiplayer.peer_disconnected.connect(removePlayer)

Logger.log(scriptName, function, "Log", Globals.endLog)

Server Functions

func spawnPlayer(data):
var function = “spawnPlayer”
Logger.log(scriptName, function, “Log”, Globals.startLog)

var p = playerScene.instantiate()
p.set_multiplayer_authority(data)
players[data] = p

Logger.log(scriptName, function, "Log", Globals.endLog)

return p

func removePlayer(data):
var function = “removePlayer”
Logger.log(scriptName, function, “Log”, Globals.startLog)

var ownerID = Steam.getLobbyOwner(Globals.LOBBY_ID)
if Globals.STEAM_ID == ownerID:
	Globals.isHost = true
	
players[data].queue_free()
players.erase(data)

Logger.log(scriptName, function, "Log", Globals.endLog)

func lobbyMessage(message):
var function = “lobbyMessage”
Logger.log(scriptName, function, “Log”, Globals.startLog)

for data in players:
	print("Loop : " + str(players[data]))
	players[data].get_node("ServerMessage").text = message
	
Logger.log(scriptName, function, "Log", "message = " + message)
Logger.log(scriptName, function, "Log", Globals.endLog)

Steam Event Connects

func _on_lobby_chat_update(_this_lobby_id: int, change_id: int, _making_change_id: int, chat_state: int):
var function = “_on_lobby_chat_update”
Logger.log(scriptName, function, “Log”, Globals.startLog)

var changerName: String = Steam.getFriendPersonaName(change_id)
var message

Logger.log(scriptName, function, "Log", "changerName = " + changerName)

if chat_state == Steam.CHAT_MEMBER_STATE_CHANGE_ENTERED:
	message = changerName + " has joined the lobby!"
	
elif chat_state == Steam.CHAT_MEMBER_STATE_CHANGE_LEFT:
	message = changerName + " has left the lobby!"
	
Logger.log(scriptName, function, "Log", "message = " + message)
Logger.log(scriptName, function, "Log", Globals.endLog)	
	
lobbyMessage(message)

I believe the issue may lie in main.gd _on_host_pressed(). I’m spawning the level only by the host. - ms.spawn(“res://scene/level.tscn”)
I think the issue is when the host leaves, other players no longer have access to the level. I there a way to pass the current state of the level to the new host assigned by the Steam lobby?
Sorry for my incompetence’s, first time trying this and am having trouble finding resources surrounding this.

Sorry to be blunt but you NEED to format the code in your post if you want me to read it. It’s incredibly tiring to read without it.

Use the </> button to create a code field within which you can paste your code. If you do this, I would have no problem reading your post.

However, do be warned that networked code can be harder to debug - especially from an outside perspective. There is no guarantee that I will be able to help you.

1 Like

Seconded. You should use three tick marks (```) at the top and bottom of each individual script, and tell us the name of each script since you’re not using class_name.

On the plus side I am literally working on Godot networking code right now and am interested in this problem . . . so help us help you.

1 Like