首页 > 解决方案 > 将 Unity 预制件/场景反序列化为键/值对的嵌套哈希表

问题描述

我正在尝试编写一个工具来扫描我们的 Unity (2017.4.22) 预制件和场景文件,以查找发布版本中不存在的 Monobehaviour 属性。我创建了 ac# 控制台项目(包含 YamlDotNet 6.1.2),并且从这个项目中我参考了 Unity 的“Assembly-CSharp-firstpass.dll”和“Assembly-CSharp.dll”dll。

我想知道是否有人能够配置 YamlDotNet 将任何给定的预制/场景文件解析为内存中的通用键/值数据结构(具有任意数量的嵌套级别),因此我可以对其进行迭代并使用反射来确定是否字段存在。

如果您想知道为什么我需要手动执行此操作,那是因为我正在扫描发布版本中不存在的字段。唯一的方法是重新编译“Assembly-CSharp-firstpass”和“Assembly-CSharp”,删除 UNITY_EDITOR(以及“Editor”子文件夹中文件的所有代码)。我不能在编辑器中执行此操作(显然),所以这就是为什么它必须是一个独立的工具。

我尝试过的一切都导致崩溃。这是我尝试过的:

  1. 我下载了 YamlDotNet 6.1.2 源码
  2. 尝试使用 Deserialize(...) 反序列化预制件。收到此错误:“遇到未解析的标签 'tag:unity3d.com,2011:1'”
  3. 然后我找到了我集成的这个自定义类型解析器:https ://gist.github.com/derFunk/795d7a366627d59e0dbd
  4. 然后我开始收到这个异常:“反序列化过程中的异常---> System.InvalidOperationException:无法创建'UnityEngine.GameObject'类型的实例”

我猜这是因为我试图在一个不完全支持 GameObjects 的环境中实例化一个 GameObject(毕竟我在一个独立的 C# 项目中)。

但我实际上不需要实例化任何游戏对象。我只想解析这些值。这对任何人都有意义吗?我在这里发现了一些其他问题,但它们似乎无法处理与 Unity 预制件具有相同复杂性的 YAML 文件。

在此先感谢,杰夫

标签: unity3dyamldotnet

解决方案


你的猜测是正确的。因为您将tag:unity3d.com,2011:*标签解析为UnityEngine.GameObject相关类型,所以反序列化器在遇到标签时会尝试创建相应类型的实例。

您可以选择始终将标签解析为Dictionary<string, object>(或者Dictionary<object, object>如果键并不总是字符串)。然后总是得到字典。

在您的情况下,使用加载 YAML 流可能更简单YamlDotNet.RepresentationModel.YamlStream。这将为您提供更适合您的用例的 YAML 文档的表示形式。

这是有关如何执行此操作的官方示例:https ://github.com/aaubry/YamlDotNet/wiki/Samples.LoadingAYamlStream

// Load the stream
var yaml = new YamlStream();
yaml.Load(input);

// Examine the stream
var mapping = (YamlMappingNode)yaml.Documents[0].RootNode;

推荐阅读