Skip to main content

wows-replay-parser

A Python library for parsing World of Warships .wowsreplay files with dynamic schema loading. No hardcoded schemas — the binary format is derived at runtime from entity definition files, so new game patches require only a git pull on the gamedata repository.

GitHub: https://github.com/toalba/wows-replay-parser


Features

  • Decodes all BigWorld network packets from any .wowsreplay file
  • Dynamic schema generation from .def XML entity definitions — no manual updates on patches
  • Full entity state history with timestamp-indexed state_at() queries
  • Typed event stream: 20 event types covering positions, shots, torpedoes, damage, deaths, cap points, scores, vision, squadrons, ribbons, and more
  • Blowfish ECB decryption + zlib decompression of the packet stream
  • Auto-detection of type-ID to entity-name mapping from live packet data
  • Player roster enrichment with ship loadouts, clan info, and crew IDs
  • Server-authoritative ribbon extraction for the recording player
  • Structured JSON export with state snapshots
  • No data loss: unrecognized packets produce RawEvent rather than being silently dropped
  • CLI with five commands: info, parse, events, state, export

Quick Start

Install

# Core library
pip install wows-replay-parser

# With CLI support
pip install "wows-replay-parser[cli]"

Get gamedata

The parser needs the game's entity definition files (.def + alias.xml) to build binary schemas at runtime.

Get them from the public wows-render-gamedata repo:

git clone https://github.com/toalba/wows-render-gamedata.git wows-gamedata

Then point gamedata_path at ./wows-gamedata/data/scripts_entity/entity_defs. Tags follow v<build_id>; check out the tag matching your replay's WoWs build.

Parse a replay

from wows_replay_parser import parse_replay
from wows_replay_parser.events.models import ShotCreatedEvent, DeathEvent

replay = parse_replay(
    replay_path="battle.wowsreplay",
    gamedata_path="./wows-gamedata/data/scripts_entity/entity_defs",
)

print(replay.map_name)       # "spaces/42_Neighbors"
print(replay.game_version)   # "15.2.0"
print(replay.duration)       # 1243.6  (seconds)

for player in replay.players:
    print(player.name, player.ship_id, player.team_id)

shots = replay.events_of_type(ShotCreatedEvent)
deaths = replay.events_of_type(DeathEvent)

state = replay.state_at(120.5)
for entity_id, ship in state.ships.items():
    print(entity_id, ship.health, ship.position)

CLI Usage

All CLI commands require "wows-replay-parser[cli]" to be installed.

# Show metadata: map, version, player list, duration
wowsreplay info battle.wowsreplay

# Decode and print all packets as JSON
wowsreplay parse battle.wowsreplay \
    --gamedata ./wows-gamedata/data/scripts_entity/entity_defs

# Print typed event stream as JSON
wowsreplay events battle.wowsreplay \
    --gamedata ./wows-gamedata/data/scripts_entity/entity_defs

# Print entity state at a specific timestamp
wowsreplay state battle.wowsreplay \
    --gamedata ./wows-gamedata/data/scripts_entity/entity_defs \
    --time 120.5

# Export complete replay as structured JSON (with state snapshots)
wowsreplay export battle.wowsreplay \
    --gamedata ./wows-gamedata/data/scripts_entity/entity_defs \
    -o replay.json

API Reference

parse_replay(replay_path, gamedata_path) -> ParsedReplay

Top-level entry point. Loads gamedata, decrypts and decodes the replay, builds the event stream and state tracker, and returns a ParsedReplay.

ParsedReplay fields

Field Type Description
meta dict[str, Any] Raw JSON header from the replay file
players list[PlayerInfo] Player roster (name, ship, team, loadout, clan)
map_name str Map identifier, e.g. "spaces/42_Neighbors"
game_version str Game client version string
duration float Replay length in seconds
events list[GameEvent] All game events, sorted by timestamp
packets list[Packet] All decoded packets (raw access)

ParsedReplay methods

# Full game state snapshot at timestamp t
replay.state_at(t: float) -> GameState

# State for one ship at timestamp t
replay.ship_state(entity_id: int, t: float) -> ShipState

# Battle-level state (scores, timer, cap points) at timestamp t
replay.battle_state(t: float) -> BattleState

# Optimized sequential iteration for rendering (O(delta) per frame)
replay.iter_states(timestamps: list[float]) -> Iterator[GameState]

# Server-authoritative ribbons for the recording player
replay.recording_player_ribbons() -> list[RibbonEvent]

# Filter events by type
replay.events_of_type(ShotCreatedEvent) -> list[ShotCreatedEvent]

# Events in a time window (inclusive)
replay.events_in_range(start: float, end: float) -> list[GameEvent]

PlayerInfo fields

Field Type Description
account_id int WG account ID
name str Player name
ship_id int GameParams ship ID
team_id int Team index
relation int 0=self, 1=ally, 2=enemy
entity_id int In-battle entity ID
clan_tag str Clan abbreviation
clan_color int Clan tag display color as packed RGB (0 = no custom color)
max_health int Ship max health
is_bot bool Whether player is a bot
ship_config ShipConfig | None Parsed ship loadout (modules, upgrades, signals, camo)
crew_id int GameParams ID of the captain

Event Types

All events inherit from GameEvent(timestamp, entity_id, raw_data).

Event class Key fields Source
PositionEvent x y z yaw speed is_alive Position packet (0x0A)
DamageEvent target_id damage damage_type ammo_id attacker_id receiveDamagesOnShip
DamageReceivedStatEvent target_id attacker_id damage weapon_type receiveDamageStat
DeathEvent victim_id killer_id death_reason kill / receiveVehicleDeath
ShotEvent owner_id params_id salvo_id shot_count receiveArtilleryShots
ShotCreatedEvent shot_id owner_id spawn_x/y/z target_x/y/z speed server_time_left Per-shell from salvo
ShotDestroyedEvent shot_id owner_id hit_type impact_x/y/z receiveShotKills
TorpedoCreatedEvent shot_id owner_id x y z direction_x/y/z armed receiveTorpedoes
CapturePointUpdateEvent zone_entity_id team_id radius capture_points capture_speed InteractiveZone property
ScoreUpdateEvent battle_stage time_left teams BattleLogic property
ChatEvent sender_id channel message onChatMessage
ConsumableEvent vehicle_id consumable_id consumable_type is_used work_time_left onConsumableUsed
AchievementEvent player_id achievement_id onAchievementEarned
MinimapVisionEvent entity_id x z heading is_visible updateMinimapVisionInfo
ScoutingDamageEvent victim_id spotter_id amount weapon_type Avatar stats methods
CapContestEvent cap_index vehicle_id is_entering Avatar stats methods
SquadronEvent squadron_id action owner_id plane_type Avatar receive_* squadron methods
AirSupportEvent vehicle_id params_id position activateAirSupport
RibbonEvent ribbon_id ribbon_name count derived privateVehicleState.ribbons / derived
PropertyUpdateEvent entity_type property_name value Any entity property change
RawEvent packet_type method_name property_name Unmatched packets

ShotCreatedEvent and ShotDestroyedEvent share a shot_id for correlation.


State Tracking

The GameStateTracker records every entity property change with its timestamp. State queries reconstruct a snapshot by replaying the change history up to time t.

# Full snapshot: all ships + battle state at t=120s
state = replay.state_at(120.0)
state.timestamp            # 120.0
state.ships                # dict[entity_id, ShipState]
state.battle.time_left     # seconds remaining
state.battle.team_scores   # {0: 450, 1: 320}
state.battle.capture_points  # list[CapturePointState]

# Single ship
ship = replay.ship_state(entity_id=511260, t=120.0)
ship.health                # current HP
ship.max_health            # maximum HP
ship.regeneration_health   # HP recoverable by Repair Party
ship.is_alive              # bool
ship.position              # (x, y, z) world coordinates
ship.yaw                   # heading in radians
ship.speed                 # current speed
ship.team_id
ship.burning_flags         # bitmask of active fire zones
ship.visibility_flags      # spotted status bitmask

# Battle state only
battle = replay.battle_state(120.0)
battle.time_left
battle.team_scores         # {team_id: score}
battle.battle_stage
battle.battle_result_winner

Position interpolation is not built into ship_state() — the returned position is the last known value at or before t. If you need smooth interpolation, query positions from PositionEvent objects directly.


Architecture

wows-gamedata/
  entity_defs/*.def + alias.xml
        |
        v
  AliasRegistry        (resolves Simple/FIXED_DICT/ARRAY/TUPLE/USER_TYPE aliases)
        |
  DefLoader            (parses .def XML, merges interfaces)
        |
  EntityRegistry       (indexes entities, methods, properties; sort_size)
        |
  SchemaBuilder        (builds construct binary parsers on demand)
        |
.wowsreplay file
        |
        v
  ReplayReader         (extracts JSON headers, Blowfish ECB decrypt, zlib decompress)
        |
  PacketDecoder        (12-byte header: payload_size u32 + packet_type u32 + clock f32)
        |       \
        |     GameStateTracker  (property history per entity, state_at() queries)
        |
  EventStream          (method + property factories → typed GameEvent objects)
        |
  ParsedReplay         (meta, players, events, packets, state queries)

Packet header format (verified): payload_size(u32 LE) + packet_type(u32 LE) + clock(f32 LE) — 12 bytes.


Gamedata

The parser reads entity definitions from wows-render-gamedata, a public companion repository with the game-data subset needed at runtime.

git clone https://github.com/toalba/wows-render-gamedata.git wows-gamedata

Key paths used by the parser:

Path Contents
data/scripts_entity/entity_defs/ .def XML files (14 entities, 22 interfaces) + alias.xml
data/spaces/<map_name>/space.settings Map world bounds (minX/maxX/minY/maxY)
data/content/GameParams.data Ship stats and names (Blowfish-encrypted pickle)
data/projectiles.json / data/ship_consumables.json / data/arena_key_maps.json Curated enrichment data; parser falls back gracefully if absent

Tags follow v<build_id> (matching the WoWs client build). gamedata_sync.sync_gamedata() checks out the closest tag to a replay's game version automatically.

Patch pipeline

The repository is regenerated automatically by an upstream extraction pipeline whenever WoWs ships a new build. Because the parser derives all schemas from the .def files at runtime, no code changes are needed when WoWs updates — a git pull on the gamedata repo is sufficient.


Development

# Clone and install in dev mode (uv recommended)
git clone https://github.com/toalba/wows-replay-parser.git
cd wows-replay-parser
uv pip install -e ".[dev,cli]"

# Run tests
pytest

# Lint
ruff check src/

# Type check
mypy src/

Requirements: Python >= 3.11

Dependencies: construct, lxml, pycryptodome

Dev dependencies: pytest, ruff, mypy


Contributing

Bug reports, patches, and new event types welcome. See .github/CONTRIBUTING.md for dev setup and .github/CODE_OF_CONDUCT.md for expectations. Security issues: see SECURITY.md.


Related projects

Other community projects in the World of Warships replay-parsing space:


License

Apache 2.0 — see LICENSE.

Metadata

Release files for wows-replay-parser 0.1.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for wows-replay-parser 0.1.4
File Size Uploaded
wows_replay_parser-0.1.4.tar.gz 259.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for wows-replay-parser 0.1.4
File Interpreter ABI Platform
wows_replay_parser-0.1.4-py3-none-any.whl Python 3 none any Details

Total release size: 411.0 kB

Release files / wows_replay_parser-0.1.4.tar.gz

Download URL wows_replay_parser-0.1.4.tar.gz
Size 259.6 kB
Tags Source
SHA-256 checksum
How to use checksums
5cf2476d6c64666077dc62141efc5bdf43630ee8d780df94eeaa6740afaa04fc
BLAKE2b-256 checksum
How to use checksums
5cfa5e3dbb3389a1d7f108aded8f5f136ae5b5c484f97c5f3a79b96b090f359c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 18, 2026.

Transparency log

Release files / wows_replay_parser-0.1.4-py3-none-any.whl

Download URL wows_replay_parser-0.1.4-py3-none-any.whl
Size 151.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2f2bcd009a7c8eb41a6f95177f89c48dd43764fc11626323b3203afb4ea5227a
BLAKE2b-256 checksum
How to use checksums
a384830e6fe6b0ed5910bcb5a29853cb29bab804e0804f42c30cf9fe2a815031
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 18, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.4 This release

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page