Skip to content

conaman/ue4-uasset-tools

Repository files navigation

ue4-uasset-tools

Current release: 2026-05-12

ue4-uasset-tools is a small standalone Python toolkit for reviewing Unreal Engine 4.27 .uasset/.umap metadata, asset property changes, UMG widget changes, and map export changes as readable JSON.

It can:

  • Convert a .uasset or .umap file to readable metadata JSON.
  • Extract readable generic .uasset export properties, including many UDataAsset and UPrimaryDataAsset values, when Unreal saved them as tagged properties.
  • Extract UMG review properties such as slot padding, layout data, alignment, visibility, colors, widget styling, button/slider state, and custom primitive variables.
  • Extract readable .umap export properties such as actor labels, transforms, object references, component values, and custom primitive variables when Unreal saved them as tagged properties.
  • Print a compact UMG WidgetTree hierarchy with widget names and types.
  • Print 2-way and 3-way metadata JSON diffs for .uasset and .umap files.
  • Open Perforce P4Merge on generated metadata JSON files for visual comparison.

The parser reads UE4.27 package metadata plus supported asset/UMG/map tagged property values. It does not link against Unreal Engine.

Requirements

  • Python 3.9 or newer.
  • A UE4 .uasset or .umap file.
  • Perforce P4Merge is optional and only needed for uasset_p4merge.py.

No third-party Python packages are required.

Use Cases

  • Review UMG hierarchy changes in Perforce before accepting a changelist.
  • Review UMG layout changes such as padding, anchors, position, alignment, and parent/content slot relationships.
  • Review widget property changes on Button, CheckBox, Image, Border, Slider, ProgressBar, SizeBox, ScaleBox, ScrollBox, ComboBoxString, and common panel slot types.
  • Review TextBlock/RichTextBlock changes such as text source, localization key, font, color, shadow, wrapping, and justification.
  • See custom primitive fields serialized on widgets without maintaining a property-name filter.
  • Review UDataAsset values such as item names, numbers, enum selections, soft/object references, and simple structs before accepting a changelist.
  • Review .umap changes made by Unreal MCP or another LLM workflow before accepting the saved level.
  • Compare binary .uasset/.umap metadata without launching Unreal Editor.
  • Inspect imports, exports, dependencies, and soft package references.
  • Use P4Merge as a visual JSON diff viewer for UE4 assets.

Tools

Tool Purpose
uasset_to_text.py Convert .uasset or .umap to metadata JSON.
uasset_to_text.bat Windows wrapper for uasset_to_text.py.
uasset_umg_summary.py Print a UMG WidgetTree hierarchy from a .uasset or metadata JSON file.
uasset_diff.py Print a unified 2-way diff between two .uasset or .umap files.
uasset_diff3.py Print a structured 3-way diff report.
uasset_p4merge.py Convert .uasset files to metadata JSON, then open P4Merge.

Quick Start

Clone or download this repository, then run the scripts with Python 3.9 or newer. The scripts do not need Unreal Engine or third-party Python packages.

Convert a .uasset to metadata JSON:

./uasset_to_text.py /path/to/Asset.uasset

Convert a .umap to metadata JSON:

./uasset_to_text.py /path/to/Level.umap

On Windows:

uasset_to_text.bat "C:\path\to\Asset.uasset"

Print a compact UMG WidgetTree summary:

./uasset_umg_summary.py /path/to/Widget.uasset

On Windows:

uasset_umg_summary.bat "C:\path\to\Widget.uasset"

Compare two .uasset or .umap files as metadata JSON:

./uasset_diff.py /path/to/Old.uasset /path/to/New.uasset
./uasset_diff.py /path/to/Before.umap /path/to/After.umap

Open P4Merge on generated metadata JSON:

./uasset_p4merge.py /path/to/Old.uasset /path/to/New.uasset

Examples

Sample outputs generated from a UE4.27 UMG widget asset are available in examples/:

  • WidgetMenu.summary.txt: UMG WidgetTree summary output.
  • WidgetMenu.exports.json: compact export list with path and class fields.
  • WidgetMenu.metadata.json: full metadata JSON produced by uasset_to_text.py, including readable asset_properties where generic export payloads can be parsed.
  • DataAsset.asset_properties.json: focused asset_properties excerpt showing the kind of UDataAsset-style values that can appear in diffs.
  • WidgetMenu.review_properties.json: UMG review_properties excerpt showing every parsed export property and _raw_hex for unparsed values.
  • Snapshot_UI_VR.review_properties.json: focused UMG review_properties excerpt showing CanvasPanelSlot LayoutData position, anchors, alignment, and slot padding/alignment fields.
  • WidgetMenu.diff.txt: unified metadata diff between two widget revisions.

Usage

uasset_to_text.py

uasset_to_text.py writes parsed package metadata as readable JSON. The output is for inspection, summaries, and diff workflows. It is not an editing format and cannot be converted back into a modified .uasset or .umap file.

Default output path is ./Asset.json in the current directory:

./uasset_to_text.py /path/to/Asset.uasset

Common options:

./uasset_to_text.py /path/to/Asset.uasset --stdout
./uasset_to_text.py /path/to/Asset.uasset -o /tmp/Asset.json
./uasset_to_text.py /path/to/Asset.uasset --indent 4
./uasset_to_text.py /path/to/Asset.uasset --compact
./uasset_to_text.py /path/to/Asset.uasset --no-review-properties
./uasset_to_text.py /path/to/Asset.uasset --no-asset-properties
./uasset_to_text.py /path/to/Level.umap --no-map-properties

On Windows, use the batch wrapper from the tool folder. Extra options are passed through to Python:

uasset_to_text.bat "C:\path\to\Asset.uasset"
uasset_to_text.bat "C:\path\to\Asset.uasset" -o "C:\temp\Asset.json"
uasset_to_text.bat "C:\path\to\Asset.uasset" --exports-only
uasset_to_text.bat "C:\path\to\Level.umap" -o "C:\temp\Level.json"

Print a compact export list:

./uasset_to_text.py /path/to/Asset.uasset --exports-only

Example export entry:

{
  "path": "WidgetMenu.WidgetTree.ExitButton",
  "class": "/Script/UMG.Button",
  "super": null,
  "is_asset": false
}

uasset_umg_summary.py

uasset_umg_summary.py accepts a .uasset file directly. It uses the same parser as uasset_to_text.py internally, then prints a focused WidgetTree hierarchy without creating an intermediate JSON file.

./uasset_umg_summary.py /path/to/Widget.uasset

Example output:

Asset: WidgetMenu
UMG: WidgetBlueprint
ParentClass: /Script/UMG.UserWidget
Widgets: 6

WidgetTree
  Border_0: /Script/UMG.Border
    VerticalBox_48: /Script/UMG.VerticalBox
      RestartButton: /Script/UMG.Button
        Text_RestartButton: /Script/UMG.TextBlock
      ExitButton: /Script/UMG.Button
        Text_ExitButton: /Script/UMG.TextBlock

The default output shows Name: FullClassPath entries. This keeps custom Blueprint-generated widgets such as /Game/UI.CustomTextBlock_C traceable by their package path, which is useful when reviewing summaries directly or feeding them to an LLM. UMG slot exports are hidden by default. The hierarchy is restored from review_properties fields such as RootWidget, Slots, Parent, and Content. If those fields are unavailable, the tool falls back to a flat WidgetTree export list.

Common options:

./uasset_umg_summary.py /path/to/Widget.uasset --include-slots
./uasset_umg_summary.py /path/to/Widget.uasset --json
./uasset_umg_summary.py /path/to/Widget.uasset --show-paths

On Windows, the included batch wrapper accepts one input file:

uasset_umg_summary.bat "C:\path\to\Widget.uasset"

To run the summary from P4V's Tools menu, create a custom tool:

Name:
  UMG Summary

Application:
  C:\path\to\ue4-uasset-tools\uasset_umg_summary.bat

Arguments:
  %f

Run tool in terminal window:
  enabled

Use the lowercase %f argument so P4V passes one selected file at a time. Do not wrap %f in quotes here; the batch wrapper quotes the received path before calling Python.

Metadata JSON from uasset_to_text.py can also be used as input:

./uasset_to_text.py /path/to/Widget.uasset
./uasset_umg_summary.py Widget.json

If the input does not look like a UMG asset, the command prints an error and exits with a non-zero status.

uasset_diff.py

Print a unified metadata diff between two .uasset files:

./uasset_diff.py /path/to/Old.uasset /path/to/New.uasset

Common options:

./uasset_diff.py /path/to/Old.uasset /path/to/New.uasset --quiet
./uasset_diff.py /path/to/Old.uasset /path/to/New.uasset --keep-paths
./uasset_diff.py /path/to/Old.uasset /path/to/New.uasset --context-lines 8

Exit codes:

  • 0: no diff.
  • 1: differences found.
  • 2: error.

uasset_diff3.py

Print a structured 3-way JSON diff report:

./uasset_diff3.py /path/to/Base.uasset /path/to/Ours.uasset /path/to/Theirs.uasset

The report separates non-conflicting changes from conflicts.

Common options:

./uasset_diff3.py Base.uasset Ours.uasset Theirs.uasset --quiet
./uasset_diff3.py Base.uasset Ours.uasset Theirs.uasset --keep-paths
./uasset_diff3.py Base.uasset Ours.uasset Theirs.uasset --indent 4

Exit codes:

  • 0: no changes.
  • 1: non-conflicting changes found.
  • 2: conflicts found.
  • 3: error.

uasset_p4merge.py

uasset_p4merge.py converts .uasset files to temporary metadata JSON files, then opens Perforce P4Merge.

Use two files for a 2-way compare:

./uasset_p4merge.py /path/to/Old.uasset /path/to/New.uasset

Use three files for a 3-way view. The command accepts base ours theirs:

./uasset_p4merge.py /path/to/Base.uasset /path/to/Ours.uasset /path/to/Theirs.uasset

Internally, P4Merge is invoked in Perforce's expected order:

base theirs yours result

Common options:

./uasset_p4merge.py A.uasset B.uasset --tool "open -a p4merge --args"
./uasset_p4merge.py A.uasset B.uasset --keep-paths
./uasset_p4merge.py A.uasset B.uasset --delete-temp
./uasset_p4merge.py Base.uasset Ours.uasset Theirs.uasset --result /tmp/Merged.json
./uasset_p4merge.py Base.uasset Ours.uasset Theirs.uasset --overwrite-result

P4Merge Tool Path

The script looks for P4Merge in this order:

  • --tool
  • P4MERGE
  • MERGE
  • p4merge, p4merge.exe, P4Merge.exe, launchp4merge, or launchp4merge.exe on PATH
  • common Windows Perforce install paths
  • common macOS P4Merge app paths

Tool path examples:

./uasset_p4merge.py A.uasset B.uasset --tool "open -a p4merge --args"
./uasset_p4merge.py A.uasset B.uasset --tool "/Applications/p4merge.app/Contents/Resources/launchp4merge"

On Windows, this README assumes python and p4merge are both on PATH:

python uasset_p4merge.py A.uasset B.uasset

If p4merge is installed but not found, try the explicit .exe command:

python uasset_p4merge.py A.uasset B.uasset --tool p4merge.exe

For a full path with spaces, quote the executable path:

python uasset_p4merge.py A.uasset B.uasset --tool "C:\Program Files\Perforce\p4merge.exe"

Registering in P4V

P4V can register external diff and merge applications by file type. In P4V, open Preferences, then configure Diff and Merge applications for the .uasset extension.

P4V diff placeholders:

  • %1: first file.
  • %2: second file.

P4V merge placeholders:

  • %b: base file.
  • %1: their/source file.
  • %2: your/target file.
  • %r: result file.

uasset_p4merge.py expects 3-way input as base ours theirs, so P4V merge arguments must use %b %2 %1 %r. The fourth %r argument is required by P4V for merge result handling, but this tool ignores it.

macOS or Linux, when the script is executable:

Diff application:
  /path/to/ue4-uasset-tools/uasset_p4merge.py

Diff arguments:
  %1 %2

Merge application:
  /path/to/ue4-uasset-tools/uasset_p4merge.py

Merge arguments:
  %b %2 %1 %r

Windows, assuming python is on PATH, use the included P4V wrapper files. Configure P4V for the .uasset file type like this:

Diff application:
  C:\path\to\ue4-uasset-tools\uasset_p4v_diff.bat

Diff arguments:
  %1 %2

Merge application:
  C:\path\to\ue4-uasset-tools\uasset_p4v_merge.bat

Merge arguments:
  %b %2 %1 %r

The wrapper files call uasset_p4merge.py from the same directory, so the P4V configuration does not need to include the Python script path in the arguments. uasset_p4v_merge.bat expects P4V to pass merge arguments as %b %2 %1 %r, then forwards the first three arguments to uasset_p4merge.py as base ours theirs.

Important: this merge registration opens a metadata JSON 3-way view. It does not write a merged .uasset result back to P4V. Pass P4V's %r placeholder as the fourth merge argument, but do not pass it to --result, because %r is normally the original .uasset merge target and uasset_p4merge.py intentionally only allows .json review result files.

Result Files

For 3-way P4Merge runs, the merge result is a generated .json review file. When the result file is kept and --quiet is not used, its path is printed to stdout as a single line:

result_json=$(./uasset_p4merge.py Base.uasset Ours.uasset Theirs.uasset)
echo "$result_json"

Status and temp directory messages are printed to stderr.

You can choose a result path:

./uasset_p4merge.py Base.uasset Ours.uasset Theirs.uasset --result /tmp/Merged.json

Safety rules:

  • Original .uasset inputs are never used as merge result targets.
  • --result must be a .json review path.
  • Existing result files are preserved unless --overwrite-result is used.
  • Generated temp JSON files are kept by default because some GUI launchers return before P4Merge finishes reading the files.

Delete temp files after P4Merge exits:

./uasset_p4merge.py Base.uasset Ours.uasset Theirs.uasset --delete-temp

Use --delete-temp only with a P4Merge invocation that waits for the GUI to close. Launchers such as open -a p4merge --args may return immediately.

What This Tool Parses

The metadata object can include:

  • file: input path and file size.
  • summary: package file summary fields and version data.
  • imports: imported object table with Name references expanded to strings.
  • exports: exported object table with Name references expanded to strings and asset_properties on readable generic .uasset exports, review_properties on supported UMG exports, or map_properties on .umap exports when readable payload data is found.
  • depends: export dependency map.
  • soft_package_references: soft package references.
  • preload_dependencies: cooked preload dependency indexes.

UMG Review Coverage

review_properties is emitted for UMG and WidgetTree exports when the parser can read the tagged property stream. Property names are not filtered, so custom primitive fields on widgets can show up too.

  • hierarchy references: Parent, Content, Slot, Slots
  • layout: Canvas LayoutData, Padding, alignment, size, row/column/layer, SizeBox/ScaleBox settings, and major panel slot settings
  • appearance: Brush, Background, WidgetStyle, colors, visibility, render opacity, and render transform
  • interaction/state: Button and CheckBox methods/focus/state, Slider values, ProgressBar percent/fill, ScrollBox and ComboBox behavior
  • text: TextBlock, RichTextBlock, EditableText, and EditableTextBox content, font, color, shadow, wrapping, justification, and virtual keyboard options
  • custom values: supported primitive properties such as bool, int, float, string, text, name, enum, object/class references, and arrays of those values

WidgetTree custom widgets are checked too. For example, a CustomButton can show inherited Button fields, and a CustomTextBlock can show inherited TextBlock fields. A ModuleWidget can also show custom primitive fields that are serialized in the parent widget instance.

When a property is present but its value is not decoded yet, it is kept as _unparsed with _raw_hex. That means the diff can still show that a value changed, even when this tool cannot name every field inside that value.

Asset Review Coverage

When the input path ends in .uasset, asset_properties is emitted for non-UMG exports whose payload starts with a readable tagged property stream. This is meant for review-friendly assets such as UDataAsset, UPrimaryDataAsset, and project-specific asset classes that store values as normal UPROPERTY tags.

Common values that can appear include bool, int, float, string, text, name, enum, object/class references, soft references, vectors, rotators, colors, margins, simple nested structs, arrays of supported primitive values, and custom primitive fields. UMG exports keep using review_properties, so the same value is not shown twice.

Use --no-asset-properties when you only want package metadata and do not want generic asset payload values in the JSON.

UMAP Review Coverage

When the input path ends in .umap, map_properties is emitted for exports whose payload starts with a readable tagged property stream. This is intended for before/after reviews when an LLM or Unreal MCP saves a level.

Common changes that can appear include actor labels, relative location, rotation, scale, object references, component settings, visibility/state flags, numeric values, strings, names, enums, and custom primitive fields.

Some map exports use native or custom serializers before their tagged properties. Those exports may only show metadata changes, or may keep an unsupported value as _unparsed with _raw_hex when the property tag itself can be identified.

Limitations

This tool focuses on package metadata tables, supported asset/UMG/map tagged property values, and visual review diffs. It is not a full UObject property serializer.

Unsupported custom serializers are marked as _unparsed with _raw_hex instead of guessed. Default-valued properties may not appear if Unreal did not serialize them into the asset.

Struct arrays can be reported as _unparsed when the asset stream only says the array contains StructProperty values and does not include the concrete struct type name needed to decode each element safely.

uasset_p4merge.py is a JSON comparison launcher. Even if P4Merge saves a merged JSON result, the original .uasset files are not modified.

The implementation targets Unreal Engine 4.27 package layout. Older UE4 assets may work when their package metadata matches the layouts this parser handles, but the parser is intentionally conservative when it sees unsupported or implausible data.

About

Inspect UE4.27 .uasset metadata as JSON, summarize UMG WidgetTrees, and diff via P4Merge.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors