Skip to main content

Season Grains

Grains that manage seasons (leagues) and character migration.

SeasonRegistryGrain​

Singleton registry for season definitions.

Key: string ("default")

Methods​

MethodDescription
GetAllSeasonsAsync()Get all seasons
GetSeasonAsync(id)Get specific season
GetCurrentSeasonAsync()Get active temporary season
CreateSeasonAsync()Create new season
UpdateSeasonStatusAsync()Update season status
EndSeasonAsync()End season, trigger migration

Season Model​

{
seasonId: string; // e.g., "standard", "season-1"
name: string; // Display name
description?: string;
status: SeasonStatus;
isPermanent: boolean; // true for "standard", "void"
targetSeasonId?: string; // Where characters migrate to
startedAt?: string;
endsAt?: string; // null for permanent
}

Built-in Seasons​

Season IDTypeMigration TargetDescription
standardPermanent-Default permanent league
voidPermanent-Items don't migrate (Void League)
season-NTemporarystandardTemporary challenge league

SeasonMigrationGrain​

Manages character migration when seasons end.

Key: string (seasonId)

State​

public class SeasonMigrationState
{
public MigrationStatus Status { get; set; }
public List<Guid> PendingCharacters { get; set; }
public List<Guid> CompletedCharacters { get; set; }
public List<MigrationError> Errors { get; set; }
}

Methods​

MethodDescription
GetStatusAsync()Get migration status
StartMigrationAsync()Begin migration process
MigrateCharacterAsync()Migrate single character
CancelMigrationAsync()Cancel in-progress migration

Migration Flow​

Hardcore Character Migration​

When a hardcore character dies:

The character:

  1. Is marked as dead
  2. Is migrated to the permanent league
  3. Keeps the Hardcore flag (for display)
  4. Cannot be used for trading (dead)

Void League​

For "Void League" seasons, characters migrate to the void season where:

  • Characters exist but can't interact with the economy
  • Items don't enter the permanent league
  • Used for experimental league mechanics
var voidSeason = new Season
{
SeasonId = "void",
Name = "Void",
IsPermanent = true,
// No targetSeasonId - nothing leaves the void
};

Season Lifecycle​