Architecture
gem turns a raw .dem binary into structured Python objects in a single pass.
This page shows how the modules fit together and what each layer produces.
Pipeline
Data flows top to bottom in a single pass. The schema layer feeds two parallel consumers — event processing and the extractors — which both fan back into assembly.
Entry point
gem.parse() · gem.parse_to_dataframe()
Binary decoding
Outer demo frames → bits, bytes, and varints
Schema & state
Serializer tree, field decoders, string tables, entity deltas
Events
Game events & the combat log (S1 + S2)
Extractors
Players, objectives, wards, visibility, courier, draft, fights
Assembly
Combat aggregation → typed result assembly
Output
ParsedMatch → DataFrames · JSON · Parquet
Layers at a glance
Entry points
gem.parse()
gem.parse_to_dataframe()
gem.parse_to_json()
gem.parse_to_parquet()
Binary decoding
binary/stream.py
binary/packet.py
binary/reader.py
Schema decoding
schema/sendtable/
schema/field_decoder/
schema/field_path/
state/string_table.py
state/entities.py
Events
state/game_events.py
combat/log.py
Extractors
extractors/players.py
extractors/objectives.py
extractors/wards.py
extractors/visibility.py
extractors/courier.py
extractors/draft.py
extractors/fights.py
Assembly
combat/aggregator.py
results/assembly.py
Output
results/models.py · ParsedMatch
results/dataframes.py
Output model
gem.parse() returns a single ParsedMatch. Every field is either a scalar or
a list of typed dataclasses — no raw dicts, no untyped payloads.
| Field | Type | What it contains |
|---|---|---|
players |
list[ParsedPlayer] |
One entry per player — KDA, gold/XP series, purchases, runes, buybacks, positions |
draft |
list[DraftEvent] |
Chronological pick and ban events with hero name and team |
combat_log |
list[CombatLogEntry] |
Every damage, kill, heal, ability-use, and modifier event |
towers / barracks |
list[TowerKill / BarracksKill] |
Objective deaths with tick, team, and killer |
roshans |
list[RoshanKill] |
Roshan kills with kill number and killer slot |
tormentors / shrines |
list[TormentorKill / ShrineKill] |
Tormentor and Shrine of Wisdom destruction events |
wards |
list[WardEvent] |
Ward placements with exact map coordinates |
fights |
list[Fight] |
Detected fight windows with per-player damage, kills, and healing |
smoke_events |
list[SmokeEvent] |
Smoke activations with grouped heroes and centroid position |
hero_visibility_events |
list[HeroVisibilityEvent] |
Change-only, per-team visibility states for each canonical player hero |
entity_visibility_events |
list[EntityVisibilityEvent] |
Identity-safe visibility and lifecycle transitions for networked Dota NPCs |
aegis_events |
list[AegisEvent] |
Aegis pickups, steals, and denies |
courier_snapshots |
list[CourierSnapshot] |
Courier state sampled each tick |
chat |
list[ChatEntry] |
All-chat and team-chat messages |
radiant_gold_adv / radiant_xp_adv |
list[int] |
Per-minute Radiant gold and XP advantage curves |
For the full field listing see the Models reference and Full Match Data guide.