blind-review-data/StarCraftMotion
StarCraftMotion StarCraftMotion is a large-scale benchmark for agent simulation under adversarial and partial observability scenarios (built from StarCraft replays). Each example is a fixed-length scenario window (145 frames at 16 FPS, ~9 seconds) containing all unit states, dynamic map layers, and per-player economy time series. The released split is adversarial: scenarios are subsampled to overweight interaction-heavy windows (mutual-visibility and inter-player transitions)… See the full description on the dataset page: https://huggingface.co/datasets/blind-review-data/StarCraftMotion.
StarCraftMotion
StarCraftMotion is a large-scale benchmark for agent simulation under adversarial and partial observability scenarios (built from StarCraft replays). Each example is a fixed-length scenario window (145 frames at 16 FPS, ~9 seconds) containing all unit states, dynamic map layers, and per-player economy time series.
The released split is adversarial: scenarios are subsampled to overweight interaction-heavy windows (mutual-visibility and inter-player transitions), making it a stress test for multi-agent prediction under partial observability.
- Total scenarios: 469,187
- Train / Val / Test: 362,075 / 45,121 / 61,991
- Source replays: 64,327 replay-level HDF5 files (Blizzard
3.16.1-Pack_1-fix) - Maps (ID): AbyssalReefLE, AcolyteLE, AscensiontoAiurLE, InterloperLE, MechDepot_LE
- Maps (OOD, test only): CatallenaLE(Void), Odyssey_LE
- Splits are replay-level — windows from the same replay never cross splits.
Why parquet, and how to read
Each row is one scenario. All per-frame / per-unit array columns are stored as typed Arrow `large_list` arrays (e.g. LIST<float16>, LIST<bool>). n_timesteps = 145 and n_units varies per scenario (stored per row). The dynamic map layers (map_creep, map_fow_p1, map_fow_p2) are sampled every 16 frames, giving map_T = 10 snapshots per scenario. Spatial dimensions map_H and map_W are stored as explicit scalar columns per row (map-dependent; e.g. AbyssalReefLE is 176 × 200).
import numpy as np
from datasets import load_dataset
ds = load_dataset("blind-review-data/StarCraftMotion", split="train", streaming=True)
row = next(iter(ds))
T, N = row["n_timesteps"], row["n_units"]
map_T, map_H, map_W = row["map_T"], row["map_H"], row["map_W"]
coord = np.asarray(row["coordinate"], dtype=np.float16).reshape(T, N, 3)
alive = np.asarray(row["is_alive"], dtype=bool ).reshape(T, N)
owner = np.asarray(row["unit_owner"], dtype=np.uint8 ).reshape(N)
utype = np.asarray(row["unit_type"], dtype=np.uint32).reshape(T, N)
creep = np.asarray(row["map_creep"], dtype=bool ).reshape(map_T, map_H, map_W)Schema
Scalar fields
Map data — shape (map_T, map_H, map_W) where map_T = 10
map_H and map_W are map-specific (each StarCraft II ladder map has its own native grid). All three layers below share the same shape per scenario.
Player economy — shape (145, 2), column 0 = Player 1, column 1 = Player 2
Per-unit constants — shape (n_units,)
Per-frame, per-unit — shape (145, n_units) unless noted
visible_status = p1_state * 3 + p2_state, with each state in {0 = unseen, 1 = snapshot, 2 = visible}. Examples: 8 = visible to both, 6 = visible to P1 only, 2 = visible to P2 only.
Action labels
The ability_id column stores the raw SC2 ability ID as `uint32` (e.g. MOVE = 16, ATTACK_ATTACK = 23, HARVEST_GATHER_DRONE = 1183, ability_id == 0 means the unit has no active order). It is not class-indexed.
For action prediction tasks we provide an 11-class coarse mapping in the source repository at [sc2sensor/utils/coarse_action_mapping.py].
Sources for the mapping:
- Blizzard
s2client-apiABILITY_IDenum: https://blizzard.github.io/s2client-api/sc2_typeenums8h.html - Blizzard
s2client-protostableid.json: https://github.com/Blizzard/s2client-proto/blob/master/stableid.json
Coverage on the released split is 100% of all action occurrences (every ability_id either matches a Blizzard enum prefix, is one of 10 explicit stableid.json overrides, or is 0 / falls into UNKNOWN).
Applying the mapping
import numpy as np
from sc2sensor.utils.coarse_action_mapping import ABILITY_ID_TO_COARSE_ACTION
T, N = row["n_timesteps"], row["n_units"]
ability_id = np.frombuffer(row["ability_id"], dtype=np.uint32).reshape(T, N)
# Vectorized lookup via a dense uint8 table.
max_id = max(ABILITY_ID_TO_COARSE_ACTION) + 1
lut = np.full(max_id, 255, dtype=np.uint8)
for aid, label in ABILITY_ID_TO_COARSE_ACTION.items():
lut[aid] = label
coarse = np.where(ability_id < max_id, lut[np.clip(ability_id, 0, max_id - 1)], 255)Pipeline summary
- Replay extraction (
extract_replay_level.py): three SC2 engine passes (omniscient + per-player FOW) into one HDF5 per replay, preserving native coordinates, raw SC2 unit/ability IDs, and per-player visibility. - Scenario windowing (
split_scenarios.py): chunk into145-frame windows at16 FPS(1 s history + current + 8 s future). Drops replays withduration < 120 sor either player atAPM < 1. - Replay-level split (
create_dataset_split.py): 80/10/10 train/val/test over ID maps; OOD maps go to test only. Keeps10%of each replay's windows. - Adversarial weighting: window sampling weight is
log(1 + mutual_unit_sum) + log(1 + transition_cnt); zero-score windows are excluded.
Dataset statistics
Player-unit counts (units with owner != 16)
Race matchups
Mutual visibility (units with visible_status == 8 and is_alive)
Intended use
- Multi-agent simulation under adversarial partial observability.
- Benchmarks for fog-of-war handling, ID vs OOD-map generalization, and interaction-heavy scenes.
Limitations and ethical considerations
- Replay provenance: raw replays come from Blizzard's
3.16.1-Pack_1-fixdistribution. Per-replay curation, demographics of players, and any prior filtering performed by Blizzard are not documented. - MMR caveat: raw MMR values include sentinel-like negatives (down to
-36400) for some replays. League-tier bucketing should be recomputed rather than relied upon naively. - Single game version: all replays are SC2 build 3.16.1; balance and meta-game differ from current ladder versions.
- No personally identifying content is included beyond what Blizzard publishes in replay packs. Player names are not surfaced as columns.
- Game-balance / strategic bias: the corpus is whatever Blizzard released in the pack and is not a uniform sample of competitive play.
License
The released parquet artifacts are licensed under **Creative Commons Attribution-NonCommercial 4.0 International (CC-BY-NC-4.0)** (SPDX: CC-BY-NC-4.0).
The released parquet files are derivative ML features (float16 unit trajectories, fog-of-war and creep masks, per-player economy time series, and raw SC2 unit/ability identifiers) extracted from StarCraft II replays. The dataset does not redistribute raw .SC2Replay files, SC2 game maps, or any portion of the StarCraft II Software. Use of the underlying StarCraft II replays and the SC2 engine is separately governed by Blizzard's AI and Machine Learning License; that license explicitly permits use of derived ML data for personal or internal research and development.
Citation
Underlying replays:
@misc{blizzard_sc2_replaypacks,
title = {StarCraft II Replay Packs (3.16.1-Pack\_1-fix)},
author = {{Blizzard Entertainment}},
howpublished = {\url{https://blzdistsc2-a.akamaihd.net/ReplayPacks/3.16.1-Pack_1-fix.zip}}
}Acknowledgments
Built on top of DeepMind's pysc2 and Blizzard's StarCraft II AI/ML infrastructure.
