s2protocol-rs
A nom parser for the Starcraft 2 Protocol Replay format. Provides Iterators to transist a minimal state machine through the game loops Keeping track of unit groups, upgrades, targets, etc.
Motivation
The goal is to learn how to parse binary files format with nom
and to learn
how the Starcraft 2 Replay file is so incredibly small for the amount of
information it packs.
From the available data, analytics, visualizations and generative art can be created, for example by using
- jupyter notebook in s2-polars-data-analysis
- rerun : See the repo swarmy
- yew cooper
- eframe/egui: See repo eframes-c2
- bevyengine/bevy can be used to see:
- An Enhanced Replay Minimap
- Additional statistics.
Consuming events
Transition Iterators
These are different ways to consume the events:
SC2EventIterator
collects both TrackerEvents and GameEvents. Events are provided as they appear, be them Tracker or GameTrackerEventIterator
allows consuming only Tracker EventsGameEventIterator
allows consuming only the Game Events
Event changes transist a minimal state machine that updates:
- names
- positions
- Attack events
- etc.
The iterators returns a tuple (SC2EventType, UnitChangeHint)
The first item contains the event itself as it was deserialized from the SC2Replay.
The second item hints the consumers of the iterator about the changes performed to the state machine due to this event.
For example, units may have been deleted, added, changed position, etc.
let source: PathBuf = new;
let res = new?;
for in res.into_iter
Interacting with polars
Generating the IPC Arrow datasets
In the directory ipcs/ one .ipc file will be created per implemented data type.
The --source
is the directory that contains the replay directory (Or a single file).
Files are processed using parallel operations.
For 3600 files (500 MBs) it takes 30 seconds to transform/split them. YMMV
This is behind a feature flag arrow
.
Jupyter Notebooks
The jupyter notebook with examples on how to interact with the data are available in s2-polars-data-analysis
polars-cli
|
)
)
)
)
)
)
)
Status
- Replay Tracker, Game Events and Chat Message Events for protocol75689
- Replay Tracker, Game Events and Chat Message Events for protocol84643
- Replay Tracker, Game Events and Chat Message Events for protocol87702
- Replay Tracker, Game Events and Chat Message Events for protocol88500
- Replay Tracker, Game Events and Chat Message Events for protocol89634
- Replay Tracker, Game Events and Chat Message Events for protocol89720
- Replay Tracker, Game Events and Chat Message Events for protocol90136
- Replay Tracker, Game Events and Chat Message Events for protocol90779
- Replay Tracker, Game Events and Chat Message Events for protocol90870
- Parsing unit movement is done.
- Decoding the tag/recycle done to match Game Events.
- Game Events are parsed (tho some that seem irrelevant are skipped).
- Read the version and from the version call the correct module so that we can support multiple modules.
- Support for MPQ embedded file:
replay.initData
- Add the remaining Tracker/Game event types.
- Support for MPQ embedded file:
replay.gamemetadata.json
- Support for MPQ embedded file:
replay.attributes.events
version compatibility.
After a bit of testing, it seems most of the types are compatible between versions, so only when they differ would they make part of the protocol version. Since I started this exercise on protocol87702, all types would be relative to it. That is, most modules would re-use protocol87702 as much as possible. This explains why old-er versions such as 75689 would still reference 87702 as much as possible.
The generator above thus would show example code S2ProtoResult
created in favour of unwrapping/panic'ing.
Generating protocol-specific code:
The rust code for the protocols versions available were generated using: This would now be compared with ./src/versions/protocol99999.template file and from there we can analyze what has changed. Notably, the number of bits used for the Chat Message is still miscalculated to 3 so it needs to be dismissed.
RUST_LOG_SPAN_EVENTS=full RUST_LOG=debug
# Add the new module to src/versions/mod.rs
# Run rust format on the new src/versions/protocol87702/mod.rs file
# cargo check, cargo build, etc
# Additionally some code to transform from Protocol-Specific to Protocol-Agnostic was added, TODO: Add to generator.rs