2

I'm trying to write a tool that scans through our Unity (2017.4.22) prefabs and scene files to look for Monobehaviour properties that don't exist in a release build. I've created a c# console project (incorporating YamlDotNet 6.1.2), and from this project I refer to Unity's 'Assembly-CSharp-firstpass.dll' and 'Assembly-CSharp.dll' dlls.

I was wondering if anyone has been able to configure YamlDotNet to parse any given prefab/scene file into a generic key/value data structure (with an arbitrary number of nested levels) in memory, so I can iterate it and use reflection to determine if fields exist.

If you're wondering why I need to do this manually, it's because I'm scanning for fields that don't exist in release builds. The only way to do that is to recompile 'Assembly-CSharp-firstpass' and 'Assembly-CSharp' with UNITY_EDITOR removed (and all code from files within a 'Editor' subfolder) culled. I can't do this in-editor (obviously) so that's why this has to be a standalone tool.

Everything I've tried has resulted in crashes. Here's what I tried:

  1. I downloaded the YamlDotNet 6.1.2 source
  2. Tried to deserialize a prefab using Deserialize(...). Received this error: "Encountered an unresolved tag 'tag:unity3d.com,2011:1'"
  3. I then found this custom Type resolver, which I integrated: https://gist.github.com/derFunk/795d7a366627d59e0dbd
  4. I then started receiving this exception: "Exception during deserialization ---> System.InvalidOperationException: Failed to create an instance of type 'UnityEngine.GameObject'"

I'm guessing this is is happening because I'm trying to instantiate a GameObject in an environment that doesn't fully support GameObjects (I am in a standalone C# project after all).

But I don't actually need to instantiate any GameObjects. I just want to parse the values. Does this make sense to anyone? I found a few other questions here but they don't seem to handle YAML files that are at the same complexity as Unity's prefabs.

Thanks in advance, Jeff

1 Answers1

1

Your guess is correct. Because you are resolving the tag:unity3d.com,2011:* tags to UnityEngine.GameObject and related types, then the deserializer attempts to create an instance of the corresponding type when it encounters the tags.

You could opt to always resolve the tag to Dictionary<string, object> (or Dictionary<object, object> if the keys are not always strings). Then always get dictionaries.

In your case it is probably simpler to load the YAML stream using YamlDotNet.RepresentationModel.YamlStream. This will give you a representation of the YAML document that will be more suitable for your use case.

Here's the official example on how to do it: 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;
Antoine Aubry
  • 12,203
  • 10
  • 45
  • 74
  • 1
    Thanks! I had trouble sleeping last night and stumbled on exactly the sample code on your site. So now I'm a little embarrassed :D – Jeffery Chow Jul 30 '19 at 17:52