Found the solution here. As this is a bit of a mess of functions I’ll go into a bit of detail here in case anyone else is trying to connect Godot, Steam, and Nakama together in the future.
For context: I am using the GodotSteam plugin for Godot 3.5.3. I’m sure this would work the same or similarly for the Steam-built editor.
The core issue I was running into was stepping on the toes of the callbacks and signals.
During the game start, I check if Steam is enabled and logged in. If it is, I make a single function call to my ServerConnection singleton which calls Steam.getAuthSessionTicket().
func initiate_steam_connect() -> void:
print("Fetching ticket")
_auth_ticket = steam.Steam.getAuthSessionTicket()
This triggers _on_get_auth_session_ticket_response which if successful (result is 1), the validate_auth_session function is called.
func _on_get_auth_session_ticket_response(this_auth_ticket: int, result: int) -> void:
print("Auth session result: %s" % result)
print("Auth session ticket handle: %s" % this_auth_ticket)
if result == 1:
validate_auth_session(_auth_ticket, steam.Steam.getSteamID())
I modified the validate_auth_session function as below.
func validate_auth_session(ticket: Dictionary, steam_id: int) -> void:
#_auth_ticket = steam.Steam.getAuthSessionTicket()
var auth_response: int = steam.Steam.beginAuthSession(_auth_ticket.buffer, _auth_ticket.size, steam_id)
# Get a verbose response; unnecessary but useful in this example
var verbose_response: String
match auth_response:
0: verbose_response = "Ticket is valid for this game and this Steam ID."
1: verbose_response = "The ticket is invalid."
2: verbose_response = "A ticket has already been submitted for this Steam ID."
3: verbose_response = "Ticket is from an incompatible interface version."
4: verbose_response = "Ticket is not for this game."
5: verbose_response = "Ticket has expired."
print("Auth verifcation response: %s" % verbose_response)
if auth_response == 0:
print("Validation successful, adding user to client_auth_tickets")
_client_auth_tickets.append({"id": steam_id, "ticket": _auth_ticket.id})
var auth_ticket_string := ''
for i in range(_auth_ticket['size']):
auth_ticket_string += "%02x" % _auth_ticket['buffer'][i]
print("Got auth ticket: %s" % auth_ticket_string)
var response = yield(_authenticator.authenticate_steam_async(auth_ticket_string), "completed")
if response == 0:
_storage_worker = StorageWorker.new(_authenticator.session, _client, _exception_handler)
emit_signal("steam_connected")
else:
print("Auth error: %s" % response)
While I don’t use the function for anything in this case, _on_validate_auth_ticket_response is where I believe you would send the ticket onwards for validation by clients in a P2P scenario.
func _on_validate_auth_ticket_response(auth_id: int, response: int, owner_id: int) -> void:
print("Ticket Owner: %s" % auth_id)
# Make the response more verbose, highly unnecessary but good for this example
var verbose_response: String
match response:
0: verbose_response = "Steam has verified the user is online, the ticket is valid and ticket has not been reused."
1: verbose_response = "The user in question is not connected to Steam."
2: verbose_response = "The user doesn't have a license for this App ID or the ticket has expired."
3: verbose_response = "The user is VAC banned for this game."
4: verbose_response = "The user account has logged in elsewhere and the session containing the game instance has been disconnected."
5: verbose_response = "VAC has been unable to perform anti-cheat checks on this user."
6: verbose_response = "The ticket has been canceled by the issuer."
7: verbose_response = "This ticket has already been used, it is not valid."
8: verbose_response = "This ticket is not from a user instance currently connected to steam."
9: verbose_response = "The user is banned for this game. The ban came via the Web API and not VAC."
print("Auth response: %s" % verbose_response)
print("Game owner ID: %s" % owner_id)
Hope this helps anyone else who comes across this issue.