private static void DumpType(TypeSig typeSig, StringBuilder sb, ObjectReader reader, string name, int indent, bool isRoot = false) { var typeDef = typeSig.ToTypeDefOrRef().ResolveTypeDefThrow(); if (typeSig.IsPrimitive) { object value = null; switch (typeSig.TypeName) { case "Boolean": value = reader.ReadBoolean(); break; case "Byte": value = reader.ReadByte(); break; case "SByte": value = reader.ReadSByte(); break; case "Int16": value = reader.ReadInt16(); break; case "UInt16": value = reader.ReadUInt16(); break; case "Int32": value = reader.ReadInt32(); break; case "UInt32": value = reader.ReadUInt32(); break; case "Int64": value = reader.ReadInt64(); break; case "UInt64": value = reader.ReadUInt64(); break; case "Single": value = reader.ReadSingle(); break; case "Double": value = reader.ReadDouble(); break; case "Char": value = reader.ReadChar(); break; } reader.AlignStream(4); sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name} = {value}"); return; } if (typeSig.FullName == "System.String") { sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name} = \"{reader.ReadAlignedString()}\""); return; } if (typeSig.FullName == "System.Object") { return; } if (typeDef.IsDelegate) { return; } if (typeSig is ArraySigBase) { if (!typeDef.IsEnum && !IsBaseType(typeDef) && !IsAssignFromUnityObject(typeDef) && !IsEngineType(typeDef) && !typeDef.IsSerializable) { return; } var size = reader.ReadInt32(); sb.AppendLine($"{new string('\t', indent)}{typeSig.TypeName} {name}"); sb.AppendLine($"{new string('\t', indent + 1)}Array Array"); sb.AppendLine($"{new string('\t', indent + 1)}int size = {size}"); for (int i = 0; i < size; i++) { sb.AppendLine($"{new string('\t', indent + 2)}[{i}]"); DumpType(typeDef.ToTypeSig(), sb, reader, "data", indent + 2); } return; } if (!isRoot && typeSig is GenericInstSig genericInstSig) { if (genericInstSig.GenericArguments.Count == 1) { var type = genericInstSig.GenericArguments[0].ToTypeDefOrRef().ResolveTypeDefThrow(); if (!type.IsEnum && !IsBaseType(type) && !IsAssignFromUnityObject(type) && !IsEngineType(type) && !type.IsSerializable) { return; } var size = reader.ReadInt32(); sb.AppendLine($"{new string('\t', indent)}{typeSig.TypeName} {name}"); sb.AppendLine($"{new string('\t', indent + 1)}Array Array"); sb.AppendLine($"{new string('\t', indent + 1)}int size = {size}"); for (int i = 0; i < size; i++) { sb.AppendLine($"{new string('\t', indent + 2)}[{i}]"); DumpType(genericInstSig.GenericArguments[0], sb, reader, "data", indent + 2); } } return; } if (indent != -1 && IsAssignFromUnityObject(typeDef)) { var pptr = reader.ReadPPtr(); sb.AppendLine($"{new string('\t', indent)}PPtr<{typeDef.Name}> {name} = {{fileID: {pptr.m_FileID}, pathID: {pptr.m_PathID}}}"); return; } if (typeDef.IsEnum) { sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name} = {reader.ReadUInt32()}"); return; } if (indent != -1 && !IsEngineType(typeDef) && !typeDef.IsSerializable) { return; } if (typeDef.FullName == "UnityEngine.Rect") { sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}"); var rect = reader.ReadSingleArray(4); return; } if (typeDef.FullName == "UnityEngine.LayerMask") { sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}"); var value = reader.ReadInt32(); return; } if (typeDef.FullName == "UnityEngine.AnimationCurve") { sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}"); var animationCurve = new AnimationCurve <float>(reader, reader.ReadSingle); return; } if (typeDef.FullName == "UnityEngine.Gradient") { sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}"); if (reader.version[0] == 5 && reader.version[1] < 5) { reader.Position += 68; } else if (reader.version[0] == 5 && reader.version[1] < 6) { reader.Position += 72; } else { reader.Position += 168; } return; } if (typeDef.FullName == "UnityEngine.RectOffset") { sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}"); var left = reader.ReadSingle(); var right = reader.ReadSingle(); var top = reader.ReadSingle(); var bottom = reader.ReadSingle(); return; } if (typeDef.FullName == "UnityEngine.GUIStyle") //TODO { throw new NotSupportedException(); } if (typeDef.IsClass || typeDef.IsValueType) { if (name != null && indent != -1) { sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}"); } if (indent == -1 && typeDef.BaseType.FullName != "UnityEngine.Object") { DumpType(typeDef.BaseType.ToTypeSig(), sb, reader, null, indent, true); } if (indent != -1 && typeDef.BaseType.FullName != "System.Object") { DumpType(typeDef.BaseType.ToTypeSig(), sb, reader, null, indent, true); } foreach (var fieldDef in typeDef.Fields) { var access = fieldDef.Access & FieldAttributes.FieldAccessMask; if (access != FieldAttributes.Public) { if (fieldDef.CustomAttributes.Any(x => x.TypeFullName.Contains("SerializeField"))) { DumpType(fieldDef.FieldType, sb, reader, fieldDef.Name, indent + 1); } } else if ((fieldDef.Attributes & FieldAttributes.Static) == 0 && (fieldDef.Attributes & FieldAttributes.InitOnly) == 0 && (fieldDef.Attributes & FieldAttributes.NotSerialized) == 0) { DumpType(fieldDef.FieldType, sb, reader, fieldDef.Name, indent + 1); } } } }
private static void DumpType(TypeSig typeSig, StringBuilder sb, ObjectReader reader, string name, int indent, bool isRoot = false, bool align = true) { var typeDef = typeSig.ToTypeDefOrRef().ResolveTypeDefThrow(); if (typeSig.IsPrimitive) { object value = null; switch (typeSig.TypeName) { case "Boolean": value = reader.ReadBoolean(); break; case "Byte": value = reader.ReadByte(); break; case "SByte": value = reader.ReadSByte(); break; case "Int16": value = reader.ReadInt16(); break; case "UInt16": value = reader.ReadUInt16(); break; case "Int32": value = reader.ReadInt32(); break; case "UInt32": value = reader.ReadUInt32(); break; case "Int64": value = reader.ReadInt64(); break; case "UInt64": value = reader.ReadUInt64(); break; case "Single": value = reader.ReadSingle(); break; case "Double": value = reader.ReadDouble(); break; case "Char": value = reader.ReadChar(); break; } if (align) { reader.AlignStream(); } sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name} = {value}"); return; } if (typeSig.FullName == "System.String") { sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name} = \"{reader.ReadAlignedString()}\""); return; } if (typeSig.FullName == "System.Object") { return; } if (typeDef.IsDelegate) { return; } if (typeSig is ArraySigBase) { if (!typeDef.IsEnum && !IsBaseType(typeDef) && !IsAssignFromUnityObject(typeDef) && !IsEngineType(typeDef) && !typeDef.IsSerializable) { return; } var size = reader.ReadInt32(); sb.AppendLine($"{new string('\t', indent)}{typeSig.TypeName} {name}"); sb.AppendLine($"{new string('\t', indent + 1)}int size = {size}"); for (int i = 0; i < size; i++) { sb.AppendLine($"{new string('\t', indent + 2)}[{i}]"); DumpType(typeDef.ToTypeSig(), sb, reader, "data", indent + 2); } return; } if (!isRoot && typeSig is GenericInstSig genericInstSig) { if (genericInstSig.GenericArguments.Count == 1) { var genericType = genericInstSig.GenericType.ToTypeDefOrRef().ResolveTypeDefThrow(); var type = genericInstSig.GenericArguments[0].ToTypeDefOrRef().ResolveTypeDefThrow(); if (genericInstSig.GenericArguments[0] is ArraySigBase) { return; } if (!type.IsEnum && !IsBaseType(type) && !IsAssignFromUnityObject(type) && !IsEngineType(type) && !type.IsSerializable) { return; } sb.AppendLine($"{new string('\t', indent)}{typeSig.TypeName} {name}"); if (genericType.Interfaces.Any(x => x.Interface.FullName == "System.Collections.Generic.ICollection`1<T>")) //System.Collections.Generic.IEnumerable`1<T> { var size = reader.ReadInt32(); sb.AppendLine($"{new string('\t', indent + 1)}int size = {size}"); for (int i = 0; i < size; i++) { sb.AppendLine($"{new string('\t', indent + 2)}[{i}]"); DumpType(genericInstSig.GenericArguments[0], sb, reader, "data", indent + 2, false, false); } reader.AlignStream(); } else { DumpType(genericType.ToTypeSig(), sb, reader, "data", indent + 1); } } return; } if (indent != -1 && IsAssignFromUnityObject(typeDef)) { var pptr = new PPtr <Object>(reader); sb.AppendLine($"{new string('\t', indent)}PPtr<{typeDef.Name}> {name} = {{fileID: {pptr.m_FileID}, pathID: {pptr.m_PathID}}}"); return; } if (typeDef.IsEnum) { sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name} = {reader.ReadUInt32()}"); return; } if (!isRoot && !IsEngineType(typeDef) && !typeDef.IsSerializable) { return; } if (typeDef.FullName == "UnityEngine.Rect") { sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}"); var prefix = new string('\t', indent + 1); sb.AppendLine($"{prefix}float x = {reader.ReadSingle()}"); sb.AppendLine($"{prefix}float y = {reader.ReadSingle()}"); sb.AppendLine($"{prefix}float width = {reader.ReadSingle()}"); sb.AppendLine($"{prefix}float height = {reader.ReadSingle()}"); return; } if (typeDef.FullName == "UnityEngine.LayerMask") { sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}"); sb.AppendLine($"{new string('\t', indent + 1)}uint m_Bits = {reader.ReadUInt32()}"); return; } if (typeDef.FullName == "UnityEngine.AnimationCurve") { sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}"); sb.AppendLine($"{new string('\t', indent + 1)}<truncated>"); var animationCurve = new AnimationCurve <float>(reader, reader.ReadSingle); return; } if (typeDef.FullName == "UnityEngine.Gradient") { sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}"); sb.AppendLine($"{new string('\t', indent + 1)}<truncated>"); if (reader.version[0] == 5 && reader.version[1] < 5) { reader.Position += 68; } else if (reader.version[0] == 5 && reader.version[1] < 6) { reader.Position += 72; } else { reader.Position += 168; } return; } if (typeDef.FullName == "UnityEngine.RectOffset") { sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}"); var prefix = new string('\t', indent + 1); sb.AppendLine($"{prefix}float left = {reader.ReadSingle()}"); sb.AppendLine($"{prefix}float right = {reader.ReadSingle()}"); sb.AppendLine($"{prefix}float top = {reader.ReadSingle()}"); sb.AppendLine($"{prefix}float bottom = {reader.ReadSingle()}"); return; } if (typeDef.FullName == "UnityEngine.PropertyName") { sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}"); sb.AppendLine($"{new string('\t', indent + 1)}int id = {reader.ReadInt32()}"); return; } if (typeDef.FullName == "UnityEngine.Color32") { sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}"); var prefix = new string('\t', indent + 1); sb.AppendLine($"{prefix}byte r = {reader.ReadByte()}"); sb.AppendLine($"{prefix}byte g = {reader.ReadByte()}"); sb.AppendLine($"{prefix}byte b = {reader.ReadByte()}"); sb.AppendLine($"{prefix}byte a = {reader.ReadByte()}"); reader.AlignStream(); return; } if (typeDef.FullName == "UnityEngine.Vector2Int") { sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}"); var prefix = new string('\t', indent + 1); sb.AppendLine($"{prefix}int x = {reader.ReadInt32()}"); sb.AppendLine($"{prefix}int y = {reader.ReadInt32()}"); return; } if (typeDef.FullName == "UnityEngine.Vector3Int") { sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}"); var prefix = new string('\t', indent + 1); sb.AppendLine($"{prefix}int x = {reader.ReadInt32()}"); sb.AppendLine($"{prefix}int y = {reader.ReadInt32()}"); sb.AppendLine($"{prefix}int z = {reader.ReadInt32()}"); return; } if (typeDef.FullName == "UnityEngine.Bounds") { sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}"); sb.AppendLine($"{new string('\t', indent + 1)}<truncated>"); new AABB(reader); return; } if (typeDef.FullName == "UnityEngine.GUIStyle") //TODO { throw new NotSupportedException(); } if (typeDef.IsClass || typeDef.IsValueType) { if (name != null && indent != -1) { sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}"); } if (indent == -1 && typeDef.BaseType.FullName != "UnityEngine.Object") { DumpType(typeDef.BaseType.ToTypeSig(), sb, reader, null, indent, true); } if (indent != -1 && typeDef.BaseType.FullName != "System.Object") { DumpType(typeDef.BaseType.ToTypeSig(), sb, reader, null, indent, true); } foreach (var fieldDef in typeDef.Fields) { var flag = false; var access = fieldDef.Access & FieldAttributes.FieldAccessMask; if (access != FieldAttributes.Public) { if (fieldDef.CustomAttributes.Any(x => x.TypeFullName == "UnityEngine.SerializeField")) { flag = true; } } else if ((fieldDef.Attributes & FieldAttributes.Static) == 0 && (fieldDef.Attributes & FieldAttributes.InitOnly) == 0 && (fieldDef.Attributes & FieldAttributes.NotSerialized) == 0) { flag = true; } if (flag) { if (fieldDef.FieldType.IsGenericParameter) { for (var i = 0; i < typeDef.GenericParameters.Count; i++) { var g = typeDef.GenericParameters[i]; if (g.FullName == fieldDef.FieldType.FullName) { var type = ((GenericInstSig)typeSig).GenericArguments[i]; DumpType(type, sb, reader, fieldDef.Name, indent + 1); break; } } } else { DumpType(fieldDef.FieldType, sb, reader, fieldDef.Name, indent + 1); } } } } }