Extracts RepLayout handle assignments from Unreal Engine 5 games via static analysis of the PE binary and cooked .pak archives. RepLayout handles are required by netcode implementations that replicate UE5 property data outside the engine.
Pipeline:
- rep_layout_parser.py — Static analysis of the game binary (PE) to compute RepLayout handle assignments for all C++ native classes
- RepLayoutExtractor — Reads cooked
.pakarchives via CUE4Parse to extract data for Blueprint classes, then merges both into a single output
- Python 3.10+ with
pefile - .NET 8.0 SDK
git clone --recurse-submodules <repo-url>
cd rep_layout_extractor
dotnet build RepLayoutExtractor/RepLayoutExtractor.csproj -c Releasepython rep_layout_parser.py <Game.exe> [output.json] [--detail=Class1,Class2,...]
The --detail flag generates per-handle breakdowns with struct expansion, inheritance chain, and type info. Use --detail or --detail=* for all classes, or --detail=Class1,Class2,... for specific classes.
Example (Lyra Starter Game, UE 5.7):
python rep_layout_parser.py "LyraGame.exe" lyra_rep_layout_seed.json --detail
[*] Loading LyraGame.exe...
[*] ImageBase = 0x140000000
[*] ConstructUClass @ 0x142183CF0 (5523 classes, score=3)
[*] FClassParams bitfield @ 0x38 (deps=0x18 funcs=0x20 props=0x28)
[*] FFunctionParams.FunctionFlags @ 0x28 (score=62/66)
[*] FPropertyParamsBase: validated OK
[*] FStructParams: validated OK (e.g. struct 'StructCookedMetaDataStore')
[*] Detected offsets: ...
[*] 5523 classes, 5523 named
[*] Parsing properties & computing handle expansion...
[*] Struct types resolved: 116
[*] Built detail maps for 5523 classes
[*] Written 5523 classes -> lyra_rep_layout_seed.json (43.4s)
Output format:
{
"stats": {
"total_classes": 5523,
"struct_types_resolved": 116,
"elapsed_sec": 43.4
},
"handle_counts": {
"Actor": 15,
"Character": 53,
...
},
"handle_maps": {
"Actor": [
{ "h": 1, "name": "bReplicateMovement", "class": "Actor", "type": "bool" },
{ "h": 5, "name": "RemoteRole", "class": "Actor", "type": "byte" },
{ "h": 7, "name": "AttachmentReplication.LocationOffset", "class": "Actor", "type": "struct:Vector_NetQuantize100" },
{ "h": 12, "name": "ReplicatedMovement", "class": "Actor", "type": "struct:RepMovement" },
...
]
}
}RepLayoutExtractor <PaksDir> <SeedJson> [GameName] [UsmapPath] [OutputPath]
| Argument | Required | Description |
|---|---|---|
PaksDir |
Yes | Directory containing .pak / .utoc / .ucas files |
SeedJson |
Yes | Output from Step 1 |
GameName |
No | CUE4Parse EGame enum value (default: GAME_UE5_7) |
UsmapPath |
No | Path to .usmap mappings file, required for unversioned packages |
OutputPath |
No | Output JSON path (default: ./rep_layout.json) |
Example (Lyra Starter Game, UE 5.7):
dotnet run --project RepLayoutExtractor -c Release -- \
"LyraStarterGame/Content/Paks" \
lyra_rep_layout_seed.json \
GAME_UE5_7
[*] Loaded 5523 C++ seed classes, 5523 handle maps
[*] Mounted 6 containers, 9828 files (275ms)
[*] Scanning 3834 packages...
[*] Scan complete: 292 BPs in 3834 packages (2054ms)
[*] Skipped 3542 packages (no BP exports), 0 errors
[*] Resolved: 289, Unresolved: 0
[*] BP classes with own rep properties: 11
[*] Written 5812 classes (5523 C++ + 289 BP), 11 with own rep properties -> rep_layout.json
Output format:
{
"stats": {
"cpp_classes": 5523,
"bp_classes": 289,
"resolved": 289,
"unresolved": 0,
"with_rep_properties": 11,
"packages": 3834,
"skipped": 3542,
"errors": 0
},
"handle_counts": {
"AbilitySystemComponent": 57,
"Actor": 15,
"Character": 53,
...
},
"handle_maps": {
"Actor": [
{ "h": 1, "name": "bReplicateMovement", "class": "Actor", "type": "bool" },
{ "h": 6, "name": "AttachmentReplication.AttachParent", "class": "Actor", "type": "object" },
{ "h": 7, "name": "AttachmentReplication.LocationOffset", "class": "Actor", "type": "struct:Vector_NetQuantize100" },
{ "h": 12, "name": "ReplicatedMovement", "class": "Actor", "type": "struct:RepMovement" },
...
]
},
"parent_map": {
"B_HeroShooter_Mannequin_C": "LyraCharacter",
...
}
}- Unversioned packages: Most shipping builds use unversioned property serialization. In this case, a
.usmapmappings file is required for Step 2. Use UnrealMappingsDumper to generate one from a running process. - UE version support: Struct offsets are auto-detected from the binary. Tested on UE 5.7.
The example/ directory contains extraction results from Lyra Starter Game (UE 5.7):
lyra_rep_layout_seed.json— 5,523 C++ native classes (handle counts + detail maps for all classes, 116 struct types resolved)lyra_rep_layout.json— 5,812 merged classes (C++ + Blueprint, 11 BP classes with own rep properties)
├── pe_analyzer.py # Shared PE binary analysis module
├── layout_detector.py # Auto-detect struct offsets from Construct* code patterns
├── rep_layout_parser.py # Step 1: PE binary -> C++ seed data
├── RepLayoutExtractor/
│ ├── RepLayoutExtractor.csproj
│ └── Program.cs # Step 2: .pak archives → merged output
├── CUE4Parse/ # Git submodule
└── example/
├── lyra_rep_layout_seed.json
└── lyra_rep_layout.json
This project uses CUE4Parse (Apache-2.0) as a git submodule.