Migrating to SDK 3
SDK 3 adds production queues, construction timers, unit health, hero mana, and MMR for Battle.net and W3Champions. This guide covers the breaking changes and how to use the new data in your app.
Already using SDK 3.0? The SDK 3.1 guide covers illusion filtering and hero order. Updating from 3.0 is optional and keeps protocol 3.0.
Upgrade your app
- Update
@w3booster/sdkto version 3 and update your lockfile. - Regenerate your app binding after updating its requested scopes.
- Apply the model changes below, then rebuild and redeploy your app.
SDK 3 requires platform protocol 3. An SDK 2 bundle cannot connect to that platform; upgrading the package without rebuilding the bundle is not enough.
Entity identity and collections
| SDK 2 usage | SDK 3 replacement |
|---|---|
Hero rawcode in hero.id |
hero.typeId; hero.id is an opaque instance ID |
| Hero arrays | player.heroes is an instance map; units and buildings have their own maps |
hero.name / required hero.level |
Display text comes from app metadata keyed by typeId; level is optional until observed |
modeInfo(mode).stats |
modeInfo(mode).ladderMode identifies the exact ladder mode |
| A rawcode as a rendering key | (match.id, entity.id); rawcodes can repeat or change on transformation |
Legacy solo/team statistics and preferredStats |
player.stats.status, player.stats.records, statsForMode(player, mode, options) |
Cooldown total, remaining, elapsed |
totalSeconds, remainingSeconds; derive elapsed if both are known |
| Research start/finish timestamps | TimedProgress; missing observations use null timers |
The maps contain observations, not authoritative army totals. Missing collections mean unavailable; an observed empty map or production queue means empty. Queued items have a type and a snapshot slot, not an already spawned unit instance ID.
Health, mana, and positions
Unit.hitpoints and hero mana expose { current, max } in player-facing units.
Use the unit/building/hero selectors or Object.values(collection ?? {}).
Hero vitals use the fast hero update cadence; other health and hero positions
use 200 ms sampling. Structures retain their first observed position. Ordinary
units omit position. Updates are sent on change; don't create another polling
connection. Snapshots remain immutable.
Production and countdowns
Building.production.queue and Building.construction expose progress
(completed fraction 0–1), totalSeconds, and remainingSeconds. Unknown timers
are null, including waiting slots. They use game time: never advance through
pauses on a wall clock. Ability cooldown helpers use the same fields but remain
estimates from standard-game metadata and observed ability activation.
Scopes and visibility
Request units:read, buildings:read, and production:read as needed.
Construction needs both buildings and production access. Production, hero data,
and research are PRO in self-play and free in observer/replay modes. Ordinary
unit/building observations in self-play cover the local player; observer/replay
observations cover non-neutral players. Opponent control groups are unavailable
in self-play. Always honor delivered capabilities and optional fields.
| Data | Self-play | Observer / replay |
|---|---|---|
| Ordinary units and building identity, health and position where supplied | All plans | All plans |
| Hero data, including health and mana | PRO | All plans |
| Training queues and construction progress | PRO | All plans |
| Research and upgrades | PRO | All plans |
| Player stats, including MMR, rank and league | All plans | All plans |
The required scopes and visibility rules still apply. See field-level plan tags.
MMR, ranks, and loading states
player.stats separates loading, ready, and unavailable. Each record identifies
its provider, mode, queue, and optional season/race/team. Use statsForMode with
an exact team ID for arranged teams; ambiguous selections return undefined.
mmr, rank, placement state, and league can be absent; never substitute zero.
Battle.net and W3Champions share this shape. match.realm identifies the game
service; isReforged only selects graphics. Battle.net division artwork is
available through /assets helpers, separate from W3Champions league IDs.
Use the delivered statistics; your app does not need a separate profile integration.
Match results
Read the terminal local-player result from match.result. It can arrive after
the first finished snapshot. Deduplicate by match ID before updating a score;
your app still decides which matches count.
Observer and replay results are absent. An absent result is unknown, not a loss. For self-play, the platform reports a recorded victory as won and otherwise reports lost when the match ends; a loss is not independent defeat confirmation.
Example: a player panel
The example below reads hero vitals, building queues, and the selected ladder record from one snapshot. It leaves missing observations absent and displays unknown countdowns explicitly. For an arranged team, pass the actual team ID as shown in the comment; do not substitute an individual ladder record.
import type { Player, Match, TimedProgress } from '@w3booster/sdk';
import { playerHeroes, playerBuildings } from '@w3booster/sdk/selectors';
import { statsForMode } from '@w3booster/sdk/standard-game';
export function playerPanel(player: Player, match: Match) {
return {
heroes: playerHeroes(player).map(hero => ({
key: `${match.id}:${hero.id}`, typeId: hero.typeId,
health: hero.hitpoints, mana: hero.mana,
})),
buildings: playerBuildings(player).map(building => ({
key: `${match.id}:${building.id}`, typeId: building.typeId,
construction: building.construction,
queue: building.production?.queue,
})),
statsStatus: player.stats?.status,
// For arranged teams, pass { queue: 'arranged', teamId: actualTeamId }.
stats: statsForMode(player, match.mode, { queue: 'individual' }),
};
}
export function remainingLabel(timer: TimedProgress): string {
return timer.remainingSeconds === null ? 'Unavailable'
: `${Math.ceil(timer.remainingSeconds)}s`;
}
Browse the complete SDK 3 API reference
See the Match Vision update for the features built with this data.