Skip to content

Latest commit

 

History

3 Commits

Folders and files

Repository files navigation

UAssetRegistry

基于 UAssetAPI(UnrealBinaryReader / UnrealBinaryWriter / FName / INameMap 等)的 Unreal Engine AssetRegistry.bin 解析与回写库。

解析逻辑移植自 CUE4Parse 的 UE4/AssetRegistry 模块,但底层类全部替换为 UAssetAPI 提供的类型(仅 FGuid、FSHAHash、FMD5Hash 等 UAssetAPI 缺失的必要结构自行实现)。

功能特性

  • ✅ 解析 AssetRegistry.bin(完整 FAssetRegistryState:资产数组 + 依赖节点 + 包数据)
  • ✅ 快速枚举(FPartialAssetRegistryState,只读核心字段,速度快)
  • ✅ 语义级回写(FAssetRegistryWriter:状态 → bin,格式镜像读取器,UE/CUE4Parse 均可读回)
  • ✅ 手动建表(FAssetData 手动构造函数 + FAssetRegistryState.AddAsset)
  • ✅ Tags 完整保留(FStore 解析:AnsiString / WideString / Name / ExportPath / LocalizedText)
  • ✅ FName 精确还原(含 number 后缀,如 ZenLogo_64)
  • ✅ 命令行演示工具(解析 / JSON 导出 / 简单版 JSON / 回写 / 手动构造测试)

依赖

  • .NET 10(net10.0)
  • UAssetAPI 1.1.0(NuGet)

快速开始

作为库引用

<ProjectReference Include="..\UAssetRegistry\UAssetRegistry.csproj" />
using UAssetRegistry;

// 解析
var state = AssetRegistryLoader.LoadFromFile("AssetRegistry.bin");
foreach (var asset in state.PreallocatedAssetDataBuffers)
{
    Console.WriteLine($"[{asset.AssetClass}] {asset.ObjectPath}");
    foreach (var (key, value) in asset.TagsAndValues)
        Console.WriteLine($"  {key} = {value}");
}

// 快速枚举(只读核心字段)
var partial = AssetRegistryLoader.LoadPartialFromFile("AssetRegistry.bin");
foreach (var p in partial.PreallocatedAssetDataBuffers)
    Console.WriteLine(p.ObjectPath);

// 语义级回写
AssetRegistryLoader.SaveToFile(state, "output.bin");

// 手动构造新表
var newState = new FAssetRegistryState
{
    Version = FAssetRegistryVersionType.ExternalActorToWorldIsEditorOnly,
    FilterEditorOnly = true
};
newState.AddAsset(new FAssetData(
    "/Game/X/BP_X", "/Game/X", "BP_X", "Blueprint",
    new Dictionary<string, string> { ["ParentClass"] = "Class'/Script/Engine.Actor'" },
    new[] { 0 }, EPackageFlags.PKG_Cooked));
AssetRegistryLoader.SaveToFile(newState, "manual.bin");

命令行

用法: UAssetRegistry <AssetRegistry.bin 路径> [--top N] [--out <json文件>] [--partial] [--simple] [--write <回写bin路径>] [--manual-test]
参数 说明
--top N 控制台显示条数(默认 10)
--out <文件> JSON 输出路径(默认 <输入>.json)
--partial 快速枚举模式(只输出核心字段)
--simple 简单版 JSON(无 Tags/ChunkIDs,无 PackageFlags,Tags 仅保留父类信息),默认 <输入>.simple.json
--write <bin路径> 解析后语义级回写为新 bin
--manual-test 手动构造资产 → 写回 → 读回验证(无需输入文件)

示例:

# 解析并导出完整 JSON
UAssetRegistry AssetRegistry.bin

# 简单版 JSON(仅核心字段 + 父类信息)
UAssetRegistry AssetRegistry.bin --simple

# 解析后回写
UAssetRegistry AssetRegistry.bin --write out.bin

# 手动构造测试
UAssetRegistry --manual-test

构造新项教程(SDK 用法)

把 UAssetRegistry 当 SDK 使用时,可以从零构造或在现有 bin 上增/改/删资产项,再写回。

① 从零构造一张新表

using UAssetRegistry;
using UAssetAPI.UnrealTypes;

var state = new FAssetRegistryState
{
    // 建议用 21(ExternalActorToWorldIsEditorOnly,与常见发布版一致)。
    // 注意:不要用 LatestVersion(24) —— 该版本启用 16 字节对齐,当前 writer 不产生对齐填充。
    Version = FAssetRegistryVersionType.ExternalActorToWorldIsEditorOnly,
    FilterEditorOnly = true
};

state.AddAsset(new FAssetData(
    packageName: "/Game/MyFolder/BP_Enemy",   // 完整包路径
    packagePath: "/Game/MyFolder",            // 目录路径
    assetName: "BP_Enemy",                    // 资产名
    assetClass: "Blueprint",                  // 资产类型
    tagsAndValues: new Dictionary<string, string>
    {
        ["ParentClass"] = "Class'/Script/Engine.Character'",
        ["NativeParentClass"] = "/Script/CoreUObject.Class'/Script/Engine.Character'"
    },
    chunkIDs: new[] { 0 },
    packageFlags: EPackageFlags.PKG_Cooked));

AssetRegistryLoader.SaveToFile(state, "new.bin");       // 写回 bin
byte[] bytes = AssetRegistryLoader.SaveToBytes(state);  // 或取字节

② 在现有 bin 上添加新项

var state = AssetRegistryLoader.LoadFromFile("existing.bin");

state.AddAsset(new FAssetData(
    "/Game/New/BP_New", "/Game/New", "BP_New", "Blueprint",
    new Dictionary<string, string> { ["ParentClass"] = "Class'/Script/Engine.Actor'" }));

AssetRegistryLoader.SaveToFile(state, "existing_updated.bin");
// 可选:LoadFromFile 读回验证 —— 新项应出现在资产列表里
var back = AssetRegistryLoader.LoadFromFile("existing_updated.bin");
Console.WriteLine(back.PreallocatedAssetDataBuffers.Length); // 原数量 + 1

③ 修改已有项的字段 / Tags

var state = AssetRegistryLoader.LoadFromFile("existing.bin");
var target = state.PreallocatedAssetDataBuffers.First(a => a.ObjectPath == "/Game/X/BP_X.BP_X");

// 修改已有 tag(key 是 FName,需先找到原 key)
var parentKey = target.TagsAndValues.Keys.First(k => k.ToString() == "ParentClass");
target.TagsAndValues[parentKey] = "Class'/Script/Engine.Pawn'";

// 新增 tag(key 用 UAssetAPI.FName 的 dummy 形式,值写入时自动收集)
var map = new RegistryNameMap();
target.TagsAndValues[FName.DefineDummy(map, "MyNewTag")] = "Hello 世界";

AssetRegistryLoader.SaveToFile(state, "existing_updated.bin");

④ 删除项

var state = AssetRegistryLoader.LoadFromFile("existing.bin");
var list = state.PreallocatedAssetDataBuffers.ToList();
list.RemoveAll(a => a.ObjectPath == "/Game/X/BP_X.BP_X");
state.PreallocatedAssetDataBuffers = list.ToArray();
AssetRegistryLoader.SaveToFile(state, "existing_updated.bin");

FAssetData 构造参数说明

参数 含义 示例
packageName 完整包路径(ObjectPath 的包部分) /Game/MyFolder/BP_Enemy
packagePath 资产所在目录 /Game/MyFolder
assetName 资产名 BP_Enemy
assetClass 资产类型(写回时存为 FTopLevelAssetPath 的 AssetName) Blueprint / Texture2D / Material
tagsAndValues tag 字典(key 属性名,value 字符串;ParentClass 等继承信息也放这里) ["ParentClass"] = "Class'/Script/Engine.Character'"
chunkIDs chunk 归属,通常 [0] new[] { 0 }
packageFlags EPackageFlags 组合 EPackageFlags.PKG_Cooked

注意事项

  • Version 不要用 LatestVersion(24):该版本启用 16 字节对齐,当前 FAssetRegistryWriter 不产生对齐填充,会导致读回错位。手动建表建议 21(或与目标引擎一致的无对齐版本)。
  • Tags 的 value 统一按 AnsiString 语义级编码,中文字符串(如 Hello 世界)可正常读写。
  • FName 字符串含 _N 时按普通字符原样保存(number=0);需真实 number 后缀请在解析出的资产上修改(读回的资产保留原始 number)。

核心 API

类型 说明
AssetRegistryLoader 统一入口:LoadFromBytes/File/Stream、LoadPartialFromBytes/File、SaveToBytes/Stream/File
FAssetRegistryState 完整解析结果:PreallocatedAssetDataBuffers(资产)、PreallocatedDependsNodeDataBuffers(依赖)、PreallocatedPackageDataBuffers(包数据);Version/FilterEditorOnly;AddAsset
FPartialAssetRegistryState 部分解析结果(仅 FPartialAssetData[])
FAssetData 单资产:PackageName/PackagePath/AssetName/AssetClass/TagsAndValues/TaggedAssetBundles/ChunkIDs/PackageFlags/ObjectPath;含手动构造函数
FAssetIdentifier / FDependsNode / FAssetPackageData 依赖关系与包数据
FAssetRegistryReader / FNameTableArchiveReader 新版(FixedTags+)/ 旧版读取器
FAssetRegistryWriter 语义级回写器
FAssetRegistryHeader / FAssetRegistryVersionType 文件头与版本枚举(值对齐 UAssetAPI 的 FAssetRegistryVersion,并补全 UE 后续版本)
RegistryNameMap INameMap 实现,使 UAssetAPI 的 FName 直接使用 AssetRegistry 内嵌 name 表

文件布局(version ≥ FixedTags)

header (GUID + int32 version + int32 bFilterEditorOnly)
→ name batch(count + numStringBytes + hashVersion + hashes + 2B headers + name 数据)
→ 全局 FStore(magic + nums[11] + AnsiString/WideString 表 + Pairs + EndMagic)
→ FAssetData[](每个资产:FName 字段 + map 头(ulong) + bundles + ChunkIDs + PackageFlags)
→ dependencies(int64 sectionSize + 节点)
→ packages(int32 count + 包数据)

技术说明

版本枚举

FAssetRegistryVersionType 前 18 个值与 UAssetAPI CustomVersions.FAssetRegistryVersion 一致;UAssetAPI 1.1.0 缺少 UE 后续版本(18~24),已在 FAssetRegistryVersionType 中补全。

语义级回写

FAssetRegistryWriter 重建 name 表与 FStore(tag 值统一编码为 AnsiString 类型)。输出为标准合法的 AssetRegistry.bin(读回后全部资产与 tags 逐字段一致),字节与原文件不同。若需字节级一致,需在解析时额外保留原始 FValueId 类型。

校验说明

AssetRegistry.bin 无文件级/资产级校验和。存在的 magic 仅约束结构边界(header GUID、FStore EndMagic);FAssetPackageData 中的 CookedHash(MD5) / ChunkHashes(FIoHash) 是包内容哈希,且非所有文件都含包数据。

目录结构

UAssetRegistry/
├── UAssetRegistry.csproj     # net10.0,引用 UAssetAPI 1.1.0(Exe + 可引用)
├── Program.cs                # 命令行演示工具
├── README.md
└── AssetRegistry/            # 库源码(命名空间 UAssetRegistry)
    ├── AssetRegistryLoader.cs
    ├── FAssetRegistryState.cs / FPartialAssetRegistryState.cs
    ├── FAssetRegistryReader.cs / FNameTableArchiveReader.cs / FAssetRegistryArchive.cs
    ├── FAssetRegistryWriter.cs
    ├── FAssetRegistryHeader.cs / FAssetRegistryVersion.cs
    ├── FAssetData.cs / FAssetIdentifier.cs / FDependsNode.cs / FAssetPackageData.cs
    ├── FAssetBundleData.cs / FAssetBundleEntry.cs
    ├── FStore.cs / FValueHandle.cs / FValueId.cs
    ├── FNumberedPair.cs / FNumberlessPair.cs
    ├── FNumberlessExportPath.cs / FAssetRegistryExportPath.cs
    ├── FPartialAssetData.cs
    ├── FTopLevelAssetPath.cs / FSoftObjectPath.cs / FGuid.cs / FSHAHash.cs / FMD5Hash.cs / FPackageFileVersion.cs
    ├── ELoadOrder.cs
    └── RegistryNameMap.cs