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.
RepLayout handles differ from ClassNetCache field indices:
- Properties only (no functions)
- Struct expansion: structs without
NetSerializerflatten to sub-field handles - ArrayDim expansion: properties with
ArrayDim > 1produce multiple handles
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)
[*] 5523 classes, 5523 named
[*] Parsing properties & computing handle expansion...
[*] Struct types resolved: 65
[*] Built detail maps for 5523 classes
[*] Written 5523 classes → lyra_rep_layout_seed.json (49.9s)
Output format:
{
"stats": {
"total_classes": 5523,
"struct_types_resolved": 65,
"elapsed_sec": 49.9
},
"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 (235ms)
[*] Scanning 3834 packages...
[*] Scan complete: 292 BPs in 3834 packages (888ms)
[*] 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: Tested on UE 5.7. Other versions may work but are not verified.
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, 65 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
├── 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.