static unsafe void ExportStructDump()
        {
            Directory.CreateDirectory(OutputDirectory);
            var flags = TransferInstructionFlags.SerializeGameRelease;

            using var tw = new StreamWriter(Path.Combine(OutputDirectory, "structs.dump"));

            for (int i = 0; i < RuntimeTypes.Count; i++)
            {
                var type        = RuntimeTypes.Types[i];
                var iter        = type;
                var inheritance = string.Empty;

                while (true)
                {
                    inheritance += Marshal.PtrToStringAnsi(iter->ClassName);

                    if (iter->Base == null)
                    {
                        break;
                    }

                    inheritance += " <- ";
                    iter         = iter->Base;
                }

                tw.WriteLine("\n// classID{{{0}}}: {1}", (int)type->PersistentTypeID, inheritance);

                iter = type;
                while (iter->IsAbstract)
                {
                    tw.WriteLine("// {0} is abstract", Marshal.PtrToStringAnsi(iter->ClassName));

                    if (iter->Base == null)
                    {
                        break;
                    }

                    iter = iter->Base;
                }

                var obj = NativeObject.GetOrProduce(*iter);

                if (obj == null)
                {
                    continue;
                }

                var tree = new TypeTree();
                tree.Init();
                if (obj->GetTypeTree(flags, ref tree))
                {
                    TypeTreeUtility.CreateTextDump(tree, tw);
                }

                NativeObject.DestroyIfNotSingletonOrPersistent(obj);
            }
        }
        static unsafe void ExportStructData()
        {
            Directory.CreateDirectory(OutputDirectory);
            var flags = TransferInstructionFlags.SerializeGameRelease;

            using var bw = new BinaryWriter(File.OpenWrite(Path.Combine(OutputDirectory, "structs.dat")));

            foreach (char c in Application.unityVersion)
            {
                bw.Write((byte)c);
            }
            bw.Write((byte)0);

            bw.Write((int)Application.platform);
            bw.Write((byte)1); // hasTypeTrees
            var countPosition = (int)bw.BaseStream.Position;
            var typeCount     = 0;

            for (int i = 0; i < RuntimeTypes.Count; i++)
            {
                var type = RuntimeTypes.Types[i];
                var iter = type;

                while (iter->IsAbstract)
                {
                    if (iter->Base == null)
                    {
                        goto NextType;
                    }

                    iter = iter->Base;
                }

                var obj = NativeObject.GetOrProduce(*iter);

                if (obj == null)
                {
                    continue;
                }

                var tree = new TypeTree();
                tree.Init();
                if (obj->GetTypeTree(flags, ref tree))
                {
                    // Shouldn't this write type.PersistentTypeID instead?
                    // I'm leaving it as iter.PersistentTypeID for consistency
                    // with existing C++ code that generates structs.dat
                    bw.Write((int)iter->PersistentTypeID);

                    // GUID
                    for (int j = 0, n = (int)iter->PersistentTypeID < 0 ? 0x20 : 0x10; j < n; ++j)
                    {
                        bw.Write((byte)0);
                    }

                    TypeTreeUtility.CreateBinaryDump(tree, bw);
                    typeCount++;
                }

                NativeObject.DestroyIfNotSingletonOrPersistent(obj);

NextType:
                continue;
            }

            bw.Seek(countPosition, SeekOrigin.Begin);
            bw.Write(typeCount);
        }