- Python 100%
Standing rule from the owner, 2026-09-19: no em dashes, anywhere. It is not
cosmetic. Blaze is Python 2.7 and refuses non-ASCII source without a PEP 263
declaration; it died on startup this morning with
SyntaxError: Non-ASCII character '\xe2' ... but no encoding declared
the first time the stack ran from the forge clones, because the legacy tree's
copies had been mojibaked down to ASCII and the CODA copies had not.
Swept every repo. 31,105 characters across 399 files: 10,184 em dashes, plus
en dashes, curly quotes, ellipses, arrows, section signs, box-drawing, math
symbols, check marks and emoji. Also repaired already-mojibaked sequences
(the 'a-EUR-quote' triples) in archived docs - those were corrupted em dashes
from an earlier encoding accident.
Deliberately NOT touched:
- anthem-api/localization and gameconfig, anthem-postgres/seed_data: the
accents in fr-fr.json and the game strings are CONTENT, and this pass would
have corrupted them.
- .json generally, for the same reason.
- Leading UTF-8 BOMs on MSBuild project files, vendored MinHook sources and
one SQL schema. Those are format markers, not typography; all 31 are
leading, none mid-file.
Verified after the sweep: every Blaze .py compiles under Python 2.7 and
'import BlazeMain_Client' succeeds; both registry YAMLs parse; the gameserver
suite is 1649 passed / 1 failed, the same single pre-existing failure
(test_damage_decode) as before; the DLL builds clean Release|x64; the launcher
still resolves 'repo : F:\anthem\coda\_stack\' with preflight ok.
|
||
|---|---|---|
| output | ||
| build_server_sdk_2026-08-12.py | ||
| README.md | ||
Anthem Server SDK - reference
Built 2026-08-11/12 from two full-memory dumps. Phase 1 of the master plan.
This is the consolidated reference. The derivation is spread across SS283-310 of
04-reverse-engineering/XBOX_VERIFICATION_OF_PRIOR_RE_2026-08-07.md; read that only if you need to
know how something was established. Everything needed to use the SDK is here.
1. What it is
A map from every reflected type in Anthem to its identity, its place in the class hierarchy, and its byte-level field layout - read out of a running process, not inferred.
types 32,129 named 10,083 (31%)
classes 11,688 with classId / lastSubclassId / superclass
types with layout 6,040 (every Class-category type that has fields)
fields 28,290 named 13,221 (47%), typed 23,495 (83%)
The artifacts
| file | size | what |
|---|---|---|
code/tools/output/anthem_server_sdk_2026-08-12.json |
13.9 MB | the SDK. Everything below, merged |
code/tools/output/anthem_types.h |
2.8 MB | 6,040 C structs, Ghidra-importable |
code/tools/ghidra_scripts/README_AnthemTypes.md |
- | how to import the header |
Inputs, kept because each is independently checkable:
| file | what |
|---|---|
anthem_typeguidmap_2026-08-11.json |
32,129 registry types (GUID, size, align, fieldCount) |
anthem_type_hierarchy_named_2026-08-11.json |
superclass links + the first 2,457 names |
anthem_classids_2026-08-11.json |
classId / lastSubclassId per class |
anthem_field_layouts_2026-08-12.json |
field arrays, Tarsis dump |
anthem_field_layouts_menu_2026-08-12.json |
same, menu dump - for diffing |
anthem_names_*_2026-08-12.json |
name candidates by source, with provenance |
Source dumps (not in git): /home/shinji/Projects/anthem_dumps/Anthem_mainmenu_2026-08-11.DMP
(5.0 GB) and Anthem_tarsis_2026-08-12.DMP (12.2 GB, from a second machine).
2. Schema
Keyed by descriptor VA (stable - the build has no ASLR, verified across two machines).
"0x144fd4ec0": {
"va": "0x144fd4ec0",
"guid": "86c9b59b640d75c180341a3dbb9f1cd7", // TypeInfoData +0x08
"nameHash": "0xab53fbda", // reflection hash, seed 1032
"name": "DofComponentData", // null if unnamed
"name_via": "dump_string", // provenance
"size": 240, // +0x06 totalSize
"align": 16, // +0x28
"fieldCount": 26, // +0x2a
"is_class": true,
"classId": 6918, // 1-based global DFS position
"lastSubclassId": 6944, // subtree end - see S4
"super_va": "0x144fc71b0",
"super_name": "ComponentData",
"offset_frame": "absolute_object", // <- READ THIS
"fields": [
{ "nameHash": "0x1f8a30c2", "name": "FocusDistance",
"offset": 8, "typeCode": 19, "typeName": "Float32", "typeSize": 4 }
]
}
(!) offset_frame: "absolute_object"
Offsets are absolute within the whole object - inherited members occupy the start. This is the frame the engine uses and the one you need to read bytes.
The older Xbox-derived anthem_type_sdk_named.json uses offsets relative to the declaring type.
The two disagree on every shared field (9,339 pairs, zero identical; the delta is the inherited
prefix, so it varies by which ancestor declares the field). Never mix them. The Xbox SDK's
offsets are deliberately not merged here.
3. Using it
Read a field out of an instance: value = instance_base + field.offset, field.typeSize bytes.
That is the whole contract.
Ghidra: File -> Parse C Source -> anthem_types.h, x86-64/Visual Studio profile. Then Ctrl+L on a
decompiler variable to apply a struct. 1,653 Class-typed members are real struct X *
cross-references, so following a pointer lands on a typed object.
Find a type by name:
sdk = json.load(open("code/tools/output/anthem_server_sdk_2026-08-12.json"))["types"]
by_name = {v["name"]: v for v in sdk.values() if v.get("name")}
by_name["NetObjectSystemSettings"]["fields"]
Types the project previously lacked and now has: NetObjectSystemSettings (13 fields - absent
from the Xbox SDK entirely), SpawnReferenceObjectData (20), SubWorldReferenceObjectData (15),
ReferenceObjectData (14), NetworkSettings (35), ClientSettings (51).
4. ClassIds
classId is a 1-based position in a global DFS of the class forest; lastSubclassId closes the
subtree. So isSubclassOf(a, b) is an interval test: b.classId <= a.classId <= b.lastSubclassId.
DataContainer [ 74, 7923] 7,850 descendants
GameObjectData [1900, 4346]
EntityData [1907, 3899]
11,688 classes, ids forming a gap-free bijection onto 1..11,688, 173 roots whose intervals tile the space with no gaps or overlaps.
(!) These ids are NOT on the ghost wire (S285). They are a property of the build, useful for hierarchy queries; do not expect to find one in a packet.
5. What is validated, and how
Four independent checks, each of which could have failed:
| check | constrains | result |
|---|---|---|
| natural alignment of every field | offsets | 21,232 constrained fields, 0 misaligned |
| zero overlap with real per-field sizes | offsets AND sizes | 0 of 28,290 collide |
| nameHash agreement vs the Xbox-derived SDK | two platform binaries | 1,925 of 1,927 |
| byte-identical layouts across two dumps | two machines, two worlds | 8,242 of 8,264 arrays |
The 22 that differed in the last check were the defect that found the typeCode bug (S305) - they
were non-Class descriptors misread as classes, and filtering to typeCode == 3 removed them.
(!) Not validated: a live decode. No check here demonstrates that pointing a layout at a real
object yields correct values. That is blocked on the absence of a vtable->type mapping - nothing in
TypeInfoData carries one, and RTTI is stripped for game classes (only 7 CRT/third-party
descriptors exist in the whole image). Closing it needs per-class constructor analysis. See SS307-308.
6. Limits
| limit | why |
|---|---|
| 31% of types named, 47% of field names | source-exhausted. A PC memory dump and an Xbox decompilation converge on the same ~10,000 names; the Xbox corpus added 2 (S309). Needs a build with reflection names compiled in |
| 26,089 types have no struct | enums, primitives, arrays - no ClassInfoData, so no field array |
| engine classes absent | StreamManagerGhost, LevelSetup, BlueprintOwner are not reflected DataContainer types and were never in the registry |
| enum members absent | the enum descriptor's member table is not at the offsets a Class uses; needs fresh RE, capped payoff (S310) |
| function names | out of scope - reflection names types and fields, never functions |
7. Regenerating
In order. Each step needs the previous.
D=/home/shinji/Projects/anthem_dumps/Anthem_tarsis_2026-08-12.DMP
python3 code/tools/mdmp_gonogo_2026-08-11.py "$D" # PASS before anything else
python3 code/tools/enumerate_typeguidmap_2026-08-12.py "$D"
python3 code/tools/sweep_classids_2026-08-12.py "$D"
python3 code/tools/extract_field_layouts_2026-08-12.py "$D"
python3 code/tools/name_by_string_harvest_2026-08-12.py "$D" --all-memory
python3 code/tools/name_combined_2026-08-12.py
python3 code/tools/build_server_sdk_2026-08-12.py
python3 code/tools/emit_ghidra_types_2026-08-12.py
python3 code/tools/validate_sdk_alignment_2026-08-12.py # must report 0 misaligned
mdmp_reader_2026-08-11.py is the shared minidump reader - mmap + bisect, and it self-tests VA
translation against the reflection size table at 0x14372e060. Run it standalone on any new dump
first.
8. Traps that cost time building this
Each of these cost at least one wrong conclusion:
- Read the value at the address the code actually uses.
*DAT_144713698is a pointer to the table; reading0x144713698itself gives the pointer cell and its neighbours (S298). - Filter by
typeCode == 3before treating a descriptor as aClassInfoData. Array/ValueType/ Enum descriptors have different layouts, and+0x30/+0x38mean something else on them (SS297, 301). - A field's type comes from its
TypeInfo*, not from theFieldInfoDataflags. The documented(flags>>5)&0x1freads 0 for 93% of fields (S305). - Ask what a check would report if the thing were wrong. The
sizeofassertions in S304 passed by construction and constrained nothing. - Diff two captures of the same build. It is the cheapest defect detector available and found what a 1,925-type agreement missed (S301).
- Vtables hold thunks. Searching for a function's VA finds nothing; scan for
jmp rel32to it, then search for the thunk (S294).