LESSON 05 OF 07 · RACING TUTORIAL
Turn bumps into rivals
Receive eligible visitors and give them a role in your game.
1. Load visitors after connecting
WeBumpAPI calls load_visitors() after connection. The title screen refreshes approximately every ten seconds with one refresh in flight. Reuse this rather than adding a second loop. A new game can refresh on focus or before a session. See the request-budget example before choosing a polling interval.
func _ready() -> void:
WeBumpAPI.visitors_updated.connect(_visitors_changed)
func _visitors_changed(cards: Array) -> void:
$Status.text = "%d available visitors" % cards.size()
# The demo’s RivalRoster chooses up to three for the next race.
GET /v1/me/visitors returns eligible people bumped, including verifiable recent history synced by weBump, once the bump is unwrapped in weBump and the visitor’s profile delay has passed. They must still allow sharing. The player does not approve every visit or press a second transfer button. The API’s optional explicit handoff is a separate feature.
Wait for the first load before a session starts. The first load after connecting takes a few seconds, because it fetches the list and then each rival’s shared replay. A race that takes its roster snapshot before that finishes starts with no visitors, and the player races practice drivers even though their bumps arrived moments later. In the demo, WeBumpAPI.visitors_ready becomes true when the first load finishes, whether or not it succeeded. The title screen shows Loading rivals… until then, and unlocks after 12 seconds anyway so a slow or rate-limited request never blocks play.
func _can_start_race() -> bool:
return WeBumpAPI.visitors_ready or _waited_seconds >= 12.0
2. Use the card, not a global identity
A card includes a temporary project-scoped reference, display_name and theme_color. capsule holds the encounter snapshot; stats contains currently permitted capsule values. A visitor can share a basic card without playing your game, so stats and selected data may be absent.
scripts/rival_roster.gd prioritizes valid shared recordings, then uses ordinary AI for other rivals. It takes a roster snapshot for the race. Adapt that decision point: a visitor might become a customer or contribute a cosmetic decoration in your game.
Cards also include visitor_id: an opaque ID for recognizing the same visitor within this game and receiving player. Different recipients and games receive different IDs, and name/color changes do not affect it. Group repeat cards by that field, keeping a valid reference for API reads. The ID itself cannot fetch anything. Never infer identity from name and color; older cards without the field can only be deduplicated by exact reference.
Recognition continues while unexpired seven-day receipts link the pair. Polling does not extend it. An expiry gap, visitor opt-out or game exclusion, block, explicit game disconnect/revocation or deletion resets the affected relationship. Unblocking does not restore old references. A new installation is a new identity.
3. Publish small public values separately
The demo’s save_public_highscore() calls put_capsule() and put_showcase() with the reviewed integer fields from its definition. That is separate from saving the private replay.
# Example in this demo, with its reviewed fields:
WeBumpAPI.save_public_highscore(96.0, 31.0)
Capsule values can accompany eligible visits when the player allows sharing. Showcase values can appear under Games on the player’s profile when they enable that visibility. The app renders reviewed icons, labels and fields dynamically. Saving a value does not enable a player’s sharing toggle.
4. Handle unavailable visitors
Revalidate references before a new session. Drop personal data after expiry, withdrawal or a 410; do not replay it indefinitely from a cache. If only a shared document is unavailable, a still-authorized basic card can use an AI fallback. If the card itself is unavailable, use an anonymous practice driver.
The demo omits cards it cannot revalidate. A network outage is not proof of revocation, so don’t tell players that a rival opted out just because a request failed. Keep retries bounded and obey Retry-After.
If your game awards rewards
Temporary references and scoped visitor IDs are not permanent global player IDs. Persist reward deduplication with the local save, and update the reward and processed receipt together. This prevents ordinary duplicate processing; client-side saves and public-client OAuth cannot make cash-value rewards or competitive results cheat-proof.
Checkpoint
Mock rivals appear in the editor. For a live test, connect before a fresh bump between test players and wait for the reveal delay. An empty list immediately after connecting is normal. Synthetic playground visitors do not populate a production account.
