Skip to content

Extracts RepLayout data from UE5 binaries and cooked packages

Notifications You must be signed in to change notification settings

Mokocoder/UE5_RepLayout_Extractor

Repository files navigation

UE5 RepLayout Extractor

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:

  1. rep_layout_parser.py — Static analysis of the game binary (PE) to compute RepLayout handle assignments for all C++ native classes
  2. RepLayoutExtractor — Reads cooked .pak archives via CUE4Parse to extract data for Blueprint classes, then merges both into a single output

Requirements

  • Python 3.10+ with pefile
  • .NET 8.0 SDK

Build

git clone --recurse-submodules <repo-url>
cd rep_layout_extractor
dotnet build RepLayoutExtractor/RepLayoutExtractor.csproj -c Release

Usage

Step 1: Extract C++ Seed Data

python 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" },
      ...
    ]
  }
}

Step 2: Merge Blueprint Data

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",
    ...
  }
}

Notes

  • Unversioned packages: Most shipping builds use unversioned property serialization. In this case, a .usmap mappings 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.

Example Output

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)

Project Structure

├── 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

License

This project uses CUE4Parse (Apache-2.0) as a git submodule.

About

Extracts RepLayout data from UE5 binaries and cooked packages

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published