I’ve been doing Steam integration with GodotSteam and made a tricky mistake. It’s not an issue with GodotSteam in particular, but a pattern that is fairly common in GDScript. So, I thought I’d share.
Mistake
GodotSteam API looks sort of like this (pseudocode):
1class_name Steam
2
3signal leaderboard_find_result(handle: int, found: int)
4
5func findLeaderboard(lb_name: String) -> void:
6 ...
You call findLeaderboard, which is a long I/O bound operation, so you need to connect to leaderboard_find_result to get the result.
Because I didn’t really care to block anything, I wrote code like this:
1Steam.findLeaderboard("highscore")
2var result = await Steam.leaderboard_find_result
Do you see a problem here?
What about here:
1Steam.findLeaderboard("highscore")
2await get_tree().create_timer(5.0).timeout
3var result = await Steam.leaderboard_find_result
If leaderboard is found within the 5 second timeout, you may never get the handle you expect to get.
It may sound obvious, but you need to connect to a signal before making a function call. So awaiting with this API may not be the best option.
Solution
So your options are either avoiding awaits entirely
1func fetch() -> void:
2 Steam.leaderboard_find_result.connect(_on_leaderboard_find_result, CONNECT_ONE_SHOT)
3 Steam.findLeaderboard("highscore")
4
5func _on_leaderboard_find_result(handle: int, found: int) -> void:
6 # process result
7 pass
or using call_deferred.
1
2func fetch() -> void:
3 Steam.findLeaderboard.call_deferred("highscore")
4 var result = await Steam.leaderboard_find_result
In latter case Steam.findLeaderboard will be called at the end of the frame, i.e. after we have already started awaiting for Steam.leaderboard_find_result.