State Management¶
Manage in-game and persistent data in your mods.
Overview¶
Mods have access to two state systems:
| System | Scope | Use Cases |
|---|---|---|
modState |
Per-game | Teams, scores, cooldowns |
persistentStorage |
Cross-game | ELO, leaderboards, lifetime stats |
ModState (In-Game)¶
Temporary state that lives for one game session.
Setting State¶
// Simple values
this.modState.set('gameMode', 'team-battle');
// Objects
this.modState.set('teams', {
blue: ['player1', 'player2'],
red: ['player3', 'player4']
});
// Player-specific state
this.modState.set(`score_${playerId}`, 100);
Getting State¶
const teams = this.modState.get('teams');
const playerScore = this.modState.get(`score_${playerId}`);
Client Synchronization¶
Automatic Sync
All modState changes are automatically synchronized to connected clients. The frontend can read this state to update the UI.
Player Color Overrides¶
Set custom colors for players (useful for teams):
this.modState.setPlayerColor(playerId, {
fill: '#3b82f6', // Blue fill
border: '#1d4ed8' // Darker border
});
PersistentStorage (Cross-Game)¶
Permanent storage that persists across game sessions.
Incrementing Values¶
// Increment a player's win count
await this.persistentStorage.increment('players', oderId, 'wins', 1);
// Increment ELO
await this.persistentStorage.increment('players', oderId, 'elo', 25);
Getting Ordered Data¶
// Get top 10 players by ELO
const leaderboard = await this.persistentStorage.getOrderedDesc(
'players', // collection
'elo', // field to sort by
10 // limit
);
// Result: [{ oderId: '...', elo: 2100 }, ...]
Use Cases¶
- Leaderboards: Track lifetime wins, kills, territory conquered
- ELO Ratings: Matchmaking and skill tracking
- Achievements: Unlock conditions and completion status
- Clan Stats: Aggregate clan performance
Example: Team State Management¶
interface Teams {
blue: string[];
red: string[];
}
interface TeamStats {
blue: { kills: number; territory: number };
red: { kills: number; territory: number };
}
export default class TeamMod extends Mod {
onGameInit(game: Game, executor: Executor): void {
// Initialize team structure
this.modState.set('teams', { blue: [], red: [] } as Teams);
this.modState.set('stats', {
blue: { kills: 0, territory: 0 },
red: { kills: 0, territory: 0 }
} as TeamStats);
}
onPlayerAdded(player: Player): void {
const teams = this.modState.get('teams') as Teams;
// Assign to smaller team
const team = teams.blue.length <= teams.red.length ? 'blue' : 'red';
teams[team].push(player.id());
this.modState.set('teams', teams);
// Set team color
const colors = {
blue: { fill: '#3b82f6', border: '#1d4ed8' },
red: { fill: '#ef4444', border: '#dc2626' }
};
this.modState.setPlayerColor(player.id(), colors[team]);
}
async onGameEnd(game: Game, winnerId: string): Promise<void> {
const teams = this.modState.get('teams') as Teams;
const winningTeam = teams.blue.includes(winnerId) ? 'blue' : 'red';
// Award ELO to winning team
for (const oderId of teams[winningTeam]) {
await this.persistentStorage.increment('players', oderId, 'elo', 25);
await this.persistentStorage.increment('players', oderId, 'wins', 1);
}
}
}