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
| Method | Description |
|---|---|
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
| Method | Description |
|---|---|
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
| Method | Description |
|---|---|
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
| Method | Description |
|---|---|
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
| Method | Description |
|---|---|
StartSessionAsync(ip) | Log session start with IP |
EndSessionAsync() | Log session end |
GetSessionHistoryAsync() | Get session history |