Skip to content

基于AssetStudio修改的适配AssetsTools.NET v3的导出工具

Notifications You must be signed in to change notification settings

SwingCosmic/AssetStudioExporter

Repository files navigation

AssetStudioExporter

适配 AssetsTools.NET V3(AT3) 的AssetBundle导出工具,基于AssetStudio进行修改

本仓库是生成的是.NET库,用于简化使用AssetsTools.NET编写解包代码的逻辑,并不是一个独立的可执行文件,请先使用其他工具探索AssetBundle(AB)的结构并定位所需内容


特性

  • 同时支持AssetFile和AssetBundle文件
  • 经过简单的封装,以简单的方式导出Texture2D, AudioClip, Font等各类资源
  • 更好的Texture2D
    • 全面的图片纹理格式支持,能导出几乎所有种类的Texture2D
    • 同时带有AssetRipper的解码器和AssetStudio自己的解码器,两者有各自的特点,可根据实际情况自由切换
  • 支持反序列化MonoBehaviour,只需要提供由Il2CppDumper/Cpp2Il生成的dummy DLL,调一个简单方法即可导出JSON
  • 直接的资源类型抽象,以及简单的导出参数配置,可以方便地实现新的导出方法,并灵活控制封装程度,不会对编写解包代码产生较大的侵入性和限制
  • 简单的跨平台
    • 同时带有Windows/Mac/Linux的x86/x64第三方库二进制,无分平台包,无需判断平台和重新编译,编译一次到处运行

开始使用

本仓库包含了对AssetsTools.NET V3(AT3)的封装,使用前先阅读AT3的开发文档

添加引用

  1. 添加对AssetsTools.NETAssetsTools.NET.Texture(如果需要处理图片)的nuget包
  2. 克隆本仓库并作为项目依赖添加

定位Asset

具体参考AT3的文档

var am = new AssetsManager();
am.LoadClassPackage(Path.Combine(AppContext.BaseDirectory, "classdata.tpk"));

var root = new DirectoryInfo("path/to/ab");
foreach (var file in root.EnumerateFiles("*.bundle", SearchOption.AllDirectories))
{
  var bf = am.LoadBundleFile(file.FullName, true);
  var inst = am.LoadAssetsFileFromBundle(bf, 0, true);

  foreach (var info in inst.file.AssetInfos) {
    var needExport = false;
    // 尝试定位到所需的资源
    // ...
    if(needExport) {
      // 使用Exporter进行导出
    }
  }
}

导出资源

  • 如果只是想简单的导出符合要求的资源,可以根据asset的AssetClassID来使用不同的导出类。可以使用ExporterSetting.Default来设置全局默认导出设置。
IAssetTypeExporter? exporter = null;
switch (info.TypeId)
{
  case (int)AssetClassID.Texture2D:
    exporter = Texture2D.Read(baseField);
    break;
  case (int)AssetClassID.AudioClip:
    exporter = AudioClip.Read(baseField);
    break;
  case (int)AssetClassID.TextAsset:
    exporter = TextAsset.Read(baseField);
    break;
  case (int)AssetClassID.Font:
    exporter = Font.Read(baseField);
    break;
  // 检查其他类型
  // ...
  default:
    break;
}

if (exporter is not null) 
{
  exporter.Export(inst, "path/to/exported/file");
}
  • 对于需要更精细控制的asset,也可以手动传入参数
if (info.TypeId == (int)AssetClassID.Texture2D) 
{
  var texture2D = Texture2D.Read(baseField);
  var fileName = Path.Combind("path/to/export", texture2D.m_Name + ".webp");
  using (var fs = File.Open(fileName, FileMode.Create, FileAccess.ReadWrite)) 
  { 
    // 使用webp导出并写入流
    texture2D.Export(inst, fs, ImageFormat.Webp);
  }
}

反序列化MonoBehavoiur

读取MonoBehavoiur是一件十分复杂的操作,但如果只需要简单地读取指定GameObject中存储的数据的结构(例如反序列化并生成JSON),使用提供的方法可以进行很大程度的简化

if (info.TypeId == (int)AssetClassID.GameObject) 
{
  // 确保加载了GameObject的依赖
  // ...

  // 读取该GameObject上包含的所有MonoBehaviour并筛选出需要的那个
  var assetFile = info
    .ReadAllMonoBehaviours(inst, am)
    .First(m => m.m_Script.m_ClassName == "YourClass" && m.m_Script.m_Namespace == "YourNamespace")
    .assetFile!;

  // dump出的dummy DLL所在目录
  var managedDir = "path/to/bin/Data/Managed";
  var monoBehaviour = MonoDeserializer.GetMonoBaseField(am, inst, assetFile, managedDir);

  // 将monoBehaviour的字段信息转换为对象,
  // 该对象和原始的类结构类似,且生成JSON的内容一致,
  // 但并不是原来的类的实例,而是由字典、数组和基本类型等组成的复杂结构
  dynamic? obj = AssetDataUtil.DeserializeMonoBehaviour(monoBehaviour);
  var json = JsonSerializer.Serialize(obj);
  Console.WriteLine(json);
}

一些工具方法

读取资产路径

部分资产在打包时包含路径信息,在AssetStudio中会显示为 "Container" 列,可以通过扩展方法AssetsFileInstance.GetContainers获取当前文件里的所有路径信息。

Dictionary<string, AssetPPtr> containers = inst.GetContainers(am);
foreach (var (name, pptr) in containers) 
{
  Console.WriteLine($"{name}: FileId={pptr.FileId}, PathId={pptr.PathId}");
  // 根据PPtr找到对应的资产对象
}

About

基于AssetStudio修改的适配AssetsTools.NET v3的导出工具

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages