Skip to main content

Identity Grains

Grains that manage user accounts, characters, sessions, and presence.

AccountGrain

Global account state that persists across all seasons.

Key: Guid (userId/accountId)

State

public class AccountGrainState
{
public Account? Account { get; set; }
public List<CharacterSummary> Characters { get; set; } = new();
}

Methods

MethodDescription
GetAccountAsync()Get account info (creates if not exists)
GetCharactersAsync()Get all character summaries
CreateCharacterAsync()Create new character in a season
UpdateCharacterSummaryAsync()Update character summary after migration
UnlockCosmeticAsync()Unlock a cosmetic
UnlockAchievementAsync()Unlock an achievement
HasCosmeticAsync()Check if cosmetic is unlocked
HasAchievementAsync()Check if achievement is unlocked
ExistsAsync()Check if account has been created
DeleteAsync()Delete account (for testing)

Account Creation Flow


CharacterGrain

Per-season character state. Uses compound key for season isolation.

Key: Guid (characterId) + string (seasonId)

State

public class CharacterGrainState
{
public Character? Character { get; set; }
public List<CharacterHistoryEntry> History { get; set; } = new();
}

Methods

MethodDescription
InitializeAsync()Create new character
GetCharacterAsync()Get character details
AddExperienceAsync()Add XP (may level up)
SetStatAsync()Set a stat value
GetChallengeProgressAsync()Get challenge progress
UpdateChallengeProgressAsync()Update challenge progress
DieAsync()Kill character (triggers migration for HC)
GetHistoryAsync()Get character history
MigrateAsync()Migrate to new season

Hardcore Death Flow


RefreshTokenGrain

Manages JWT refresh tokens per user. Supports multiple devices and token rotation.

Key: Guid (userId)

State

public class RefreshTokenState
{
public Dictionary<string, RefreshTokenInfo> Tokens { get; set; } = new();
}

Methods

MethodDescription
CreateTokenAsync()Create new refresh token
ConsumeTokenAsync()Use and invalidate token (rotation)
RevokeTokenAsync()Revoke specific token
RevokeAllTokensAsync()Revoke all tokens (security)
CleanupExpiredAsync()Remove expired tokens

Token Rotation


PlayerPresenceGrain

Tracks online status and active connections. In-memory only (not persisted).

Key: Guid (userId)

State

// In-memory only
private Dictionary<string, string> _connections = new(); // connectionId -> hubName

Methods

MethodDescription
RegisterConnectionAsync()Add connection (returns true if first)
UnregisterConnectionAsync()Remove connection (returns true if last)
GetActiveConnectionsAsync()Get all active connections
IsOnlineAsync()Check if user is online

SessionLogGrain

Persists session history for analytics and security.

Key: Guid (userId)

Methods

MethodDescription
StartSessionAsync(ip)Log session start with IP
EndSessionAsync()Log session end
GetSessionHistoryAsync()Get session history