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
.uassetor.umapfile to readable metadata JSON. - Extract readable generic
.uassetexport properties, including manyUDataAssetandUPrimaryDataAssetvalues, 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
.umapexport 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
.uassetand.umapfiles. - 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.
- Python 3.9 or newer.
- A UE4
.uassetor.umapfile. - Perforce P4Merge is optional and only needed for
uasset_p4merge.py.
No third-party Python packages are required.
- 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
.umapchanges made by Unreal MCP or another LLM workflow before accepting the saved level. - Compare binary
.uasset/.umapmetadata without launching Unreal Editor. - Inspect imports, exports, dependencies, and soft package references.
- Use P4Merge as a visual JSON diff viewer for UE4 assets.
| 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. |
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.uassetConvert a .umap to metadata JSON:
./uasset_to_text.py /path/to/Level.umapOn Windows:
uasset_to_text.bat "C:\path\to\Asset.uasset"Print a compact UMG WidgetTree summary:
./uasset_umg_summary.py /path/to/Widget.uassetOn 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.umapOpen P4Merge on generated metadata JSON:
./uasset_p4merge.py /path/to/Old.uasset /path/to/New.uassetSample 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 byuasset_to_text.py, including readableasset_propertieswhere generic export payloads can be parsed.DataAsset.asset_properties.json: focusedasset_propertiesexcerpt showing the kind of UDataAsset-style values that can appear in diffs.WidgetMenu.review_properties.json: UMGreview_propertiesexcerpt showing every parsed export property and_raw_hexfor unparsed values.Snapshot_UI_VR.review_properties.json: focused UMGreview_propertiesexcerpt showing CanvasPanelSlotLayoutDataposition, anchors, alignment, and slot padding/alignment fields.WidgetMenu.diff.txt: unified metadata diff between two widget revisions.
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.uassetCommon 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-propertiesOn 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-onlyExample export entry:
{
"path": "WidgetMenu.WidgetTree.ExitButton",
"class": "/Script/UMG.Button",
"super": null,
"is_asset": false
}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.uassetExample 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-pathsOn 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.jsonIf the input does not look like a UMG asset, the command prints an error and exits with a non-zero status.
Print a unified metadata diff between two .uasset files:
./uasset_diff.py /path/to/Old.uasset /path/to/New.uassetCommon 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 8Exit codes:
0: no diff.1: differences found.2: error.
Print a structured 3-way JSON diff report:
./uasset_diff3.py /path/to/Base.uasset /path/to/Ours.uasset /path/to/Theirs.uassetThe 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 4Exit codes:
0: no changes.1: non-conflicting changes found.2: conflicts found.3: error.
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.uassetUse 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.uassetInternally, 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-resultThe script looks for P4Merge in this order:
--toolP4MERGEMERGEp4merge,p4merge.exe,P4Merge.exe,launchp4merge, orlaunchp4merge.exeonPATH- 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.uassetIf p4merge is installed but not found, try the explicit .exe command:
python uasset_p4merge.py A.uasset B.uasset --tool p4merge.exeFor a full path with spaces, quote the executable path:
python uasset_p4merge.py A.uasset B.uasset --tool "C:\Program Files\Perforce\p4merge.exe"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.
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.jsonSafety rules:
- Original
.uassetinputs are never used as merge result targets. --resultmust be a.jsonreview path.- Existing result files are preserved unless
--overwrite-resultis 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-tempUse --delete-temp only with a P4Merge invocation that waits for the GUI to
close. Launchers such as open -a p4merge --args may return immediately.
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 andasset_propertieson readable generic.uassetexports,review_propertieson supported UMG exports, ormap_propertieson.umapexports when readable payload data is found.depends: export dependency map.soft_package_references: soft package references.preload_dependencies: cooked preload dependency indexes.
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.
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.
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.
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.