ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

AssetRipper 数据库拆解:看懂存储与查询只需这 4 个抽象

AssetRipper 数据库拆解:看懂存储与查询只需这 4 个抽象 AssetRipper 数据库拆解看懂存储与查询只需这 4 个抽象【免费下载链接】AssetRipperGUI application to analyze game files项目地址: https://gitcode.com/GitHub_Trending/as/AssetRipperAssetRipper 数据库并不是真正的数据库引擎而是这个 Unity 资产提取工具藏在源码深处的一套键值存储与查询机制。下面从一条真实配置的落盘过程切入把 AssetRipper 数据存储子系统拆开讲清楚读完你能独立给项目加一条新配置。一条配置是怎么变成文件里的字符串的先看这条配置是怎么落进存储的。你在 GUI 里把脚本导入级别从 2 调到 0内存里变化的其实是一个 ImportSettings 对象但保存设置文件时磁盘上写的是一段 JSON 文本。为什么存成字符串而不是直接写对象因为整个存储层是文件无关的DataEntry 这一层所有条目的共同根类不关心内容最终以什么形式存在它只规定每个条目必须能被 Clear() 清空字符串化这件事被统一推后到 Text 属性上完成。 所以三层抽象的分工很干脆DataEntry 是根DataInstance 管单值一个对象DataSet 管序列一组值可直接遍历。真正值得记死的是 DataInstance 里的 Text 属性public T Value { get; set; } public sealed override string Text { get serializer.Serialize(Value); // 读取时才序列化 set Value serializer.Deserialize(value); // 写入时才反序列化 }也就是说反序列化发生在有人给 Text 赋值的那一步从文件读进内存序列化发生在有人读 Text 的那一步从内存写回文件内存里始终持有对象本身。整个子系统的结构大致如下全部实现集中在 Source/AssetRipper.Configuration/ 目录十几个文件一次能读完。三种序列化怎么选纯文本、可解析类型、结构化对象⚙️ 上面那个 serializer 字段就是分叉口。基类 DataSerializer 只要求三个方法负责把 T 和 string 互转public abstract class DataSerializerT { public abstract T Deserialize(string text); public abstract string Serialize(T value); public abstract T CreateNew(); }存裸文本时用 StringDataSerializer它就是恒等映射适合 README 这类纯说明文本、不需要任何解释的原始内容。CoreConfiguration 的调试数据里就有一条这样的字符串条目走的是这条最轻的路径。存可解析类型时用 ParsableDataSerializer前提是 T 实现 IParsable 能靠 T.TryParse 从一行字符串还原自己int、Guid 都算。它的 Deserialize 是容错的解析失败不抛异常而是回落到 CreateNew() 给一个默认值坏文本不会把整个加载流程打断。存结构化对象时用 JsonDataSerializerImportSettings 这种嵌套对象走这条线构造时传入 System.Text.Json 的 JsonTypeInfo 可理解为编译期就绑定好的类型信息省掉运行时反射反序列化同样包着 try/catch坏数据退回 new T()。把选型压缩成一句话内容是一坨不需要解释的文本用字符串序列化内容能用一行字符串完整表达用可解析类型内容是有字段层次的 POCO用 JSON。这篇 AssetRipper 源码解析到此可以下结论两个容错分支都会静默回落这条特性后面避坑时还会再提。如何写入一条配置、如何读回它✅ 调用侧其实比内部简单得多。配置管理走 CoreConfiguration 的属性封装键名直接用类型名var settings new CoreConfiguration(); // 写入配置属性 setter 内部执行 SetStoredValue settings.ImportSettings.ScriptContentLevel ScriptContentLevel.Level0; // 读取配置键不存在或类型不符时返回 false不抛异常 settings.SingletonData.TryGetStoredValueImportSettings( nameof(ImportSettings), out ImportSettings? imported);CoreConfiguration.cs 的构造函数里能看到默认值是怎么放进去的SingletonData.Add(nameof(ImportSettings), new JsonDataInstanceImportSettings(...))导出侧的 ProcessingSettings、ExportSettings 则是 FullConfiguration.cs 用同一招补进去的。资产依赖列表这类一组值走 ListDataStorage。它的 Add 重载按元素类型自动挑选容器字符串列表装箱为 StringDataSet满足 IParsable 的类型装箱为 ParsableDataSet 。// 写入列表int 满足 IParsableint自动用 ParsableDataSetint settings.ListData.Add(Fibonacci, new Listint { 1, 1, 2, 3, 5, 8 }); // 读回经基类取出再用字符串视图遍历 DataSet set settings.ListData.GetValueDataSet(Fibonacci); foreach (string item in set.Strings) { Console.WriteLine(item); // 1 1 2 3 5 8 }保存动作本身发生在设置页ConfigurationFilesPage.cs 把编辑器里的内容整体赋给某个条目的 .Text保存文件就等价于把 Text 序列化后写盘。进阶与避坑遇到 X 就考虑 Y️ 读源码到一半你可能会撞上这几个情况对应的解法项目里都已经写好了遇到界面要编辑一个尚不存在的键别手动 TryGet 再加用 GUI 侧现成的 GetOrAdd 扩展DataExtensions.csGameFileLoader.Settings.SingletonData.GetOrAdd(key).Text content;遇到按名字高频查找同一个列表元素DataSet 是线性遍历自己维护一份Dictionarystring, int索引即可别指望存储层替你建索引。遇到想改配置但不想重建实例SetStoredValue 会原地修改已存在 DataInstance 的 Value前提是键已存在否则抛 KeyNotFoundException。遇到配置文件坏了但程序没报错回想前面说的容错解析——坏文本会静默回落成 CreateNew() 的默认值。设置突然变回默认时先查文件内容别怀疑代码逻辑。遇到多线程并发写DataStorage 底层就是 Dictionary没有任何锁。GUI 当前单线程使用没问题自己写插件或工具若要跨线程共享同一份配置同步得自己加。行动建议与延伸阅读如果只带走一条建议给 AssetRipper 加新配置时永远走键 DataInstance /DataSet 对应序列化器这个组合别绕过 Text 直接往字典里塞字符串否则读回时拿不到类型化对象。延伸阅读按依赖顺序走一遍就通了 DataSerializer.cs → DataInstance.cs → CoreConfiguration.cs → FullConfiguration.cs → ConfigurationFilesPage.cs看完在自己的分支里加一个配置键是最快的检验方式。【免费下载链接】AssetRipperGUI application to analyze game files项目地址: https://gitcode.com/GitHub_Trending/as/AssetRipper创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表