- C# 85%
- Python 15%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| tests | ||
| tools/Extractor | ||
| .gitattributes | ||
| .gitignore | ||
| AGENTS.md | ||
| manifest.json | ||
| packetIds.json | ||
| protos.proto | ||
| README.md | ||
wuwa-protos
Reconstruct named Wuthering Waves protobuf definitions and packet IDs from
the installed PC client's Aki.Protocol.dll. The extractor reads metadata and
serialization IL; it never loads or executes the game assembly.
The generated artifacts are at the repository root:
protos.proto: messages, fields, enums, oneofs, optional presence, maps, and repeated fields with their actual packing settings.packetIds.json: numeric packet ID to canonical message name, fromEMessageId.manifest.json: game/resource versions, assembly MVID, SHA-256 hashes, and counts.
The current snapshot targets game 3.8.0, resources 3.8.9.
Extract an update
Requires the .NET 10 SDK (or a newer SDK supporting net10.0) and protoc
on PATH. NuGet dependencies are pinned in tools/Extractor/packages.lock.json.
Use dotnet restore tools/Extractor --locked-mode for a locked restore.
From this repository:
dotnet run --project tools/Extractor -- --game 'C:/Games/Wuthering Waves/Client'
--game is the Client directory containing Content/Paks. The extractor
mounts base and downloaded patch archives and selects the latest protocol
assembly, comparing resource versions numerically. It infers the game and
resource versions from that archive. If the assembly is only in a base PAK,
provide --game-version explicitly.
PAK AES keys come from the public
wuwa-keys endpoint by default.
Use --keys keys.json or --keys <URL> to override it. The file format is
{"mainKey":"...","dynamicKeys":[{"guid":"...","key":"..."}]}.
Keys are never written to the outputs. Extraction stops if any archive cannot
be mounted, since an unreadable patch could contain a newer protocol.
An already extracted DLL also works, including the client's prefixed PE format:
dotnet run --project tools/Extractor -- --assembly Aki.Protocol.dll --game-version 3.8.0 --resource-version 3.8.9
--output <directory> changes the output directory. --protoc <path> or the
PROTOC environment variable selects the compiler. --check reconstructs,
compiles, and compares all three artifacts without replacing them. It needs
the same version/source arguments used for the snapshot; when using --game
these are inferred automatically:
dotnet run --project tools/Extractor -- --game 'C:/Games/Wuthering Waves/Client' --check
The extracted DLL is cached in .cache/ and is ignored by Git. DLLs, private
keys, and packet captures do not belong in this repository.
Stable naming and validation
Names come directly from managed type names, property names, and field-number
constants. Packet IDs are regenerated independently of those names. Scalar
types come from Write* and FieldCodec.For* calls, preserving distinctions
such as int32 versus sint32 or fixed32. The extractor checks serialized
field tags against the field constants. Oneof case enums identify membership;
Has<Field> properties identify optional presence.
Proto names are flattened for package-less consumers such as Spectrum.
Generated nested ENUMS types include their containing type in the name;
enum values are prefixed to satisfy protobuf's file-level enum scoping.
Namespace-qualified names resolve type collisions deterministically. Enums
missing zero get a synthetic zero value, and aliases are preserved.
Unsupported metadata, ambiguous names, invalid IDs, missing serialization evidence, tag disagreements, and protoc failures stop generation before the pinned artifacts are replaced. If a future client removes readable names or changes its code generator, update the extractor; it deliberately does not guess names from payload shapes. This tool does not extract RSA keys.
Mornye Tools
This repository is the data/wuwa-protos submodule in Mornye Tools. From the
Mornye Tools root, extract and publish its build snapshot with:
bun run update:protos --game 'C:/Games/Wuthering Waves/Client'
That command validates hashes and the schema, copies the three artifacts to
src-tauri/protocol/, and updates data/VERSION.json. Rust builds generate
packet constants from that snapshot, so consumers use message names instead
of hard-coded IDs. Normal app builds need neither this private checkout nor
.NET/the installed game. Changes to message semantics can still require app
converter changes.
Tests
python -S tests/run.py
The integration tests generate and compile a synthetic C# assembly using real protoc/Google.Protobuf. They check all scalar encodings, packing, maps, enums, oneofs, optional presence, prefixed assemblies, deterministic output, failed input preservation, and a simulated patch changing an ID and field number. No game installation or account capture is needed.