SpawnWeaver players are anonymous-first: no sign-up, no passwords. The first connect mints a stable player id; the SDK persists it so the same machine is the same player tomorrow.
How identity works
- On first connect, the server creates a new player id (
player_…) and returns a signed player token in the welcome. - The SDK stores that token on disk (
user://spawnweaver/identity.cfg) and presents it on every later connect — same token, sameplayer.id. - Every successful connect issues a fresh token (sliding expiration); the SDK always stores the newest one. As long as the player keeps playing occasionally, the identity never expires.
await SpawnWeaver.start()
print(SpawnWeaver.player.id) # "player_…" — stable across app restarts
There is nothing to build: no auth UI, no account database. If you later want real accounts, map your account ids to SpawnWeaver player ids in player storage.
Display names
Identity and display name are separate. Set the name other players see:
SpawnWeaver.set_display_name("Ada")
The name is applied on your next create/join/match — set it before entering a room (e.g. from a name field in your main menu). It is per-room, not stored server-side; to persist a chosen name across sessions, keep it in storage:
# Boot:
var saved := await SpawnWeaver.storage_get("display_name")
if saved.ok and saved.value != null:
SpawnWeaver.set_display_name(str(saved.value))
# When the player edits their name:
SpawnWeaver.set_display_name(new_name)
await SpawnWeaver.storage_set("display_name", new_name)
SWPlayer fields
Roster entries (and your own SpawnWeaver.player) are SWPlayer objects:
| Field / method | Type | Meaning |
|---|---|---|
id |
String |
Stable player id — survives reconnects and app restarts |
name |
String |
Display name given when creating/joining (may be empty) |
connected |
bool |
false while briefly disconnected (inside the grace window) |
is_local |
bool |
true when the entry is you |
display_name() |
String |
The name to show in UIs: name, or a short id fallback |
for p in SpawnWeaver.room.players:
print("%s%s%s" % [
p.display_name(),
" (you)" if p.is_local else "",
"" if p.connected else " — reconnecting…"])
Persistence across restarts
The token lives in Godot's user:// directory, so identity survives:
- app restarts and updates of your game,
- SDK upgrades,
- reconnects and network changes.
It does not survive the player clearing the game's user data, or switching machines — that machine is then a brand-new player. There is no cross-device identity in the current release; treat the player id as "this install of the game".
Multiple projects (and servers)
Identity is scoped per server URL + project key combination. The identity file holds one token per scope, so:
- Each of your games (different
pk_…) gets an independent player identity, even on the same machine. - The same game pointed at a local dev server and at production has two independent identities.
- Rotating your project's public key starts a new scope — existing installs get fresh identities.
For tools and tests that run several SDK clients in one process, the advanced
identity_scope property isolates identity persistence per client instance. Leave it
empty in games.
What resets identity
| Cause | Effect |
|---|---|
Player clears user:// data (or a fresh install on a new machine) |
New anonymous player on next connect |
| Token expires after long inactivity | Server rejects it; a new identity is needed |
| Project public key rotated | New identity scope per install |
SpawnWeaver.stop() / app quit |
No effect — identity persists |
Identity and the disconnect grace window
Because identity is stable, reconnecting players are recognized: if your connection
drops while in a room, the server keeps your seat for the grace window and the SDK's
automatic reconnect resumes it — same player.id, same entities. Other players see
player_disconnected then player_reconnected, not a leave/join. Details in
Rooms.
Common mistakes
| Mistake | What happens | Fix |
|---|---|---|
| Setting the display name after joining | Others see an empty name this session | Call set_display_name() before create/join/match |
Using name as a unique key |
Names collide and can be empty | Key everything by player.id |
| Expecting identity across devices | Each install is its own player | Layer your own account system on top if you need it, via storage |
| Testing "two players" with two rooms in one instance | One connection = one player = one room | Use Debug → Run Multiple Instances to run two clients side by side |
Next
- Player storage — persist data against the player id
- Rooms — rosters and the grace window