diff --git a/AssetStudio/Classes/MonoScript.cs b/AssetStudio/Classes/MonoScript.cs index 9c696f8..cea9e89 100644 --- a/AssetStudio/Classes/MonoScript.cs +++ b/AssetStudio/Classes/MonoScript.cs @@ -8,7 +8,7 @@ namespace AssetStudio public sealed class MonoScript : NamedObject { public string m_ClassName; - public string m_Namespace = string.Empty; + public string m_Namespace; public string m_AssemblyName; public MonoScript(ObjectReader reader) : base(reader) diff --git a/AssetStudio/Classes/Object.cs b/AssetStudio/Classes/Object.cs index 039bd57..835b5bf 100644 --- a/AssetStudio/Classes/Object.cs +++ b/AssetStudio/Classes/Object.cs @@ -43,7 +43,6 @@ namespace AssetStudio public string Dump() { - reader.Reset(); if (serializedType?.m_Nodes != null) { var sb = new StringBuilder(); diff --git a/AssetStudio/TypeTreeHelper.cs b/AssetStudio/TypeTreeHelper.cs index 6f28bdf..8b66325 100644 --- a/AssetStudio/TypeTreeHelper.cs +++ b/AssetStudio/TypeTreeHelper.cs @@ -1,19 +1,23 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; -using System.Linq; using System.Text; namespace AssetStudio { public static class TypeTreeHelper { - public static void ReadTypeString(StringBuilder sb, List members, BinaryReader reader) + public static void ReadTypeString(StringBuilder sb, List members, ObjectReader reader) { + reader.Reset(); for (int i = 0; i < members.Count; i++) { ReadStringValue(sb, members, reader, ref i); } + var readed = reader.Position - reader.byteStart; + if (readed != reader.byteSize) + { + Logger.Error($"Error while read type, read {readed} bytes but expected {reader.byteSize} bytes"); + } } private static void ReadStringValue(StringBuilder sb, List members, BinaryReader reader, ref int i) diff --git a/AssetStudio/TypeTreeNode.cs b/AssetStudio/TypeTreeNode.cs index 642612e..f2e5aea 100644 --- a/AssetStudio/TypeTreeNode.cs +++ b/AssetStudio/TypeTreeNode.cs @@ -18,5 +18,15 @@ namespace AssetStudio public uint m_TypeStrOffset; public uint m_NameStrOffset; public ulong m_RefTypeHash; + + public TypeTreeNode() { } + + public TypeTreeNode(string type, string name, int level, bool align) + { + m_Type = type; + m_Name = name; + m_Level = level; + m_MetaFlag = align ? 0x4000 : 0; + } } } diff --git a/AssetStudioGUI/AssetStudioGUIForm.cs b/AssetStudioGUI/AssetStudioGUIForm.cs index be1b5ec..89d624d 100644 --- a/AssetStudioGUI/AssetStudioGUIForm.cs +++ b/AssetStudioGUI/AssetStudioGUIForm.cs @@ -930,7 +930,7 @@ namespace AssetStudioGUI private void PreviewMonoBehaviour(MonoBehaviour m_MonoBehaviour) { - PreviewText(m_MonoBehaviour.Dump() ?? GetScriptString(m_MonoBehaviour.reader)); + PreviewText(m_MonoBehaviour.Dump() ?? DeserializeMonoBehaviour(m_MonoBehaviour)); } private void PreviewFont(Font m_Font) @@ -1192,6 +1192,7 @@ namespace AssetStudioGUI { Text = $"AssetStudioGUI v{Application.ProductVersion}"; assetsManager.Clear(); + assemblyLoader.Clear(); exportableAssets.Clear(); visibleAssets.Clear(); sceneTreeView.Nodes.Clear(); @@ -1221,12 +1222,6 @@ namespace AssetStudioGUI } FMODreset(); - - if (scriptDumper != null) - { - scriptDumper.Dispose(); - scriptDumper = null; - } } private void assetListView_MouseClick(object sender, MouseEventArgs e) diff --git a/AssetStudioGUI/Exporter.cs b/AssetStudioGUI/Exporter.cs index c24f133..fd7a9b1 100644 --- a/AssetStudioGUI/Exporter.cs +++ b/AssetStudioGUI/Exporter.cs @@ -116,7 +116,7 @@ namespace AssetStudioGUI if (!TryExportFile(exportPath, item, ".txt", out var exportFullPath)) return false; var m_MonoBehaviour = (MonoBehaviour)item.Asset; - var str = m_MonoBehaviour.Dump() ?? Studio.GetScriptString(item.Asset.reader); + var str = m_MonoBehaviour.Dump() ?? Studio.DeserializeMonoBehaviour(m_MonoBehaviour); File.WriteAllText(exportFullPath, str); return true; } diff --git a/AssetStudioGUI/Studio.cs b/AssetStudioGUI/Studio.cs index d0fb49f..ae5706c 100644 --- a/AssetStudioGUI/Studio.cs +++ b/AssetStudioGUI/Studio.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; +using System.Text; using System.Threading; using System.Windows.Forms; using static AssetStudioGUI.Exporter; @@ -22,7 +23,7 @@ namespace AssetStudioGUI internal static class Studio { public static AssetsManager assetsManager = new AssetsManager(); - public static ScriptDumper scriptDumper = new ScriptDumper(); + public static AssemblyLoader assemblyLoader = new AssemblyLoader(); public static List exportableAssets = new List(); public static List visibleAssets = new List(); internal static Action StatusStripUpdate = x => { }; @@ -614,23 +615,29 @@ namespace AssetStudioGUI } } - public static string GetScriptString(ObjectReader reader) + public static string DeserializeMonoBehaviour(MonoBehaviour m_MonoBehaviour) { - if (scriptDumper == null) + if (!assemblyLoader.Loaded) { var openFolderDialog = new OpenFolderDialog(); openFolderDialog.Title = "Select Assembly Folder"; if (openFolderDialog.ShowDialog() == DialogResult.OK) { - scriptDumper = new ScriptDumper(openFolderDialog.Folder); + assemblyLoader.Load(openFolderDialog.Folder); } else { - scriptDumper = new ScriptDumper(); + assemblyLoader.Loaded = true; } } - - return scriptDumper.DumpScript(reader); + var nodes = m_MonoBehaviour.ConvertToTypeTreeNode(assemblyLoader); + if (nodes != null) + { + var sb = new StringBuilder(); + TypeTreeHelper.ReadTypeString(sb, nodes, m_MonoBehaviour.reader); + return sb.ToString(); + } + return null; } } } diff --git a/AssetStudioUtility/AssemblyLoader.cs b/AssetStudioUtility/AssemblyLoader.cs new file mode 100644 index 0000000..9958b25 --- /dev/null +++ b/AssetStudioUtility/AssemblyLoader.cs @@ -0,0 +1,53 @@ +using Mono.Cecil; +using System.Collections.Generic; +using System.IO; + +namespace AssetStudio +{ + public class AssemblyLoader + { + public bool Loaded; + private Dictionary moduleDic = new Dictionary(); + + public void Load(string path) + { + var files = Directory.GetFiles(path, "*.dll"); + var resolver = new MyAssemblyResolver(); + var readerParameters = new ReaderParameters(); + readerParameters.AssemblyResolver = resolver; + try + { + foreach (var file in files) + { + var assembly = AssemblyDefinition.ReadAssembly(file, readerParameters); + resolver.Register(assembly); + moduleDic.Add(assembly.MainModule.Name, assembly.MainModule); + } + } + catch + { + // ignored + } + Loaded = true; + } + + public TypeDefinition GetTypeDefinition(string assemblyName, string fullName) + { + if (moduleDic.TryGetValue(assemblyName, out var module)) + { + return module.GetType(fullName); + } + return null; + } + + public void Clear() + { + foreach (var pair in moduleDic) + { + pair.Value.Dispose(); + } + moduleDic.Clear(); + Loaded = false; + } + } +} diff --git a/AssetStudioUtility/AssetStudioUtility.csproj b/AssetStudioUtility/AssetStudioUtility.csproj index 4e0635a..dd4072a 100644 --- a/AssetStudioUtility/AssetStudioUtility.csproj +++ b/AssetStudioUtility/AssetStudioUtility.csproj @@ -34,9 +34,6 @@ MinimumRecommendedRules.ruleset - - ..\packages\dnlib.3.3.2\lib\net45\dnlib.dll - @@ -46,8 +43,18 @@ + + Libraries\Unity.Cecil.dll + + + Libraries\Unity.CecilTools.dll + + + Libraries\Unity.SerializationLogic.dll + + @@ -64,8 +71,11 @@ + + + + - @@ -93,8 +103,5 @@ Texture2DDecoderWrapper - - - \ No newline at end of file diff --git a/AssetStudioUtility/Libraries/Unity.Cecil.dll b/AssetStudioUtility/Libraries/Unity.Cecil.dll new file mode 100644 index 0000000..4166cfc Binary files /dev/null and b/AssetStudioUtility/Libraries/Unity.Cecil.dll differ diff --git a/AssetStudioUtility/Libraries/Unity.CecilTools.dll b/AssetStudioUtility/Libraries/Unity.CecilTools.dll new file mode 100644 index 0000000..2c1ce70 Binary files /dev/null and b/AssetStudioUtility/Libraries/Unity.CecilTools.dll differ diff --git a/AssetStudioUtility/Libraries/Unity.SerializationLogic.dll b/AssetStudioUtility/Libraries/Unity.SerializationLogic.dll new file mode 100644 index 0000000..7af54d9 Binary files /dev/null and b/AssetStudioUtility/Libraries/Unity.SerializationLogic.dll differ diff --git a/AssetStudioUtility/MonoBehaviourConverter.cs b/AssetStudioUtility/MonoBehaviourConverter.cs new file mode 100644 index 0000000..34b9fdf --- /dev/null +++ b/AssetStudioUtility/MonoBehaviourConverter.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; + +namespace AssetStudio +{ + public static class MonoBehaviourConverter + { + public static List ConvertToTypeTreeNode(this MonoBehaviour m_MonoBehaviour, AssemblyLoader assemblyLoader) + { + var nodes = new List(); + var helper = new SerializedTypeHelper(m_MonoBehaviour.version); + helper.AddMonoBehaviour(nodes, 0); + if (m_MonoBehaviour.m_Script.TryGet(out var m_Script)) + { + var typeDef = assemblyLoader.GetTypeDefinition(m_Script.m_AssemblyName, string.IsNullOrEmpty(m_Script.m_Namespace) ? m_Script.m_ClassName : $"{m_Script.m_Namespace}.{m_Script.m_ClassName}"); + if (typeDef != null) + { + var typeDefinitionConverter = new TypeDefinitionConverter(typeDef, helper, 1); + nodes.AddRange(typeDefinitionConverter.ConvertToTypeTreeNode()); + } + } + return nodes; + } + } +} diff --git a/AssetStudioUtility/MyAssemblyResolver.cs b/AssetStudioUtility/MyAssemblyResolver.cs new file mode 100644 index 0000000..fb5a20f --- /dev/null +++ b/AssetStudioUtility/MyAssemblyResolver.cs @@ -0,0 +1,12 @@ +using Mono.Cecil; + +namespace AssetStudio +{ + public class MyAssemblyResolver : DefaultAssemblyResolver + { + public void Register(AssemblyDefinition assembly) + { + RegisterAssembly(assembly); + } + } +} diff --git a/AssetStudioUtility/ScriptDumper.cs b/AssetStudioUtility/ScriptDumper.cs deleted file mode 100644 index c8d61fa..0000000 --- a/AssetStudioUtility/ScriptDumper.cs +++ /dev/null @@ -1,492 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using dnlib.DotNet; - -namespace AssetStudio -{ - //TODO to json file - public sealed class ScriptDumper : IDisposable - { - private Dictionary moduleDic = new Dictionary(); - - public ScriptDumper() { } - - public ScriptDumper(string path) - { - var files = Directory.GetFiles(path, "*.dll"); - var moduleContext = new ModuleContext(); - var asmResolver = new AssemblyResolver(moduleContext); - var resolver = new Resolver(asmResolver); - moduleContext.AssemblyResolver = asmResolver; - moduleContext.Resolver = resolver; - try - { - foreach (var file in files) - { - var module = ModuleDefMD.Load(file, moduleContext); - asmResolver.AddToCache(module); - moduleDic.Add(Path.GetFileName(file), module); - } - } - catch - { - // ignored - } - } - - public string DumpScript(ObjectReader reader) - { - var m_MonoBehaviour = new MonoBehaviour(reader); - var sb = CreateMonoBehaviourHeader(m_MonoBehaviour); - if (m_MonoBehaviour.m_Script.TryGet(out var m_Script)) - { - if (!moduleDic.TryGetValue(m_Script.m_AssemblyName, out var module)) - { - return sb.ToString(); - } - var typeDef = module.Assembly.Find(m_Script.m_Namespace != "" ? $"{m_Script.m_Namespace}.{m_Script.m_ClassName}" : m_Script.m_ClassName, false); - if (typeDef != null) - { - try - { - DumpType(typeDef.ToTypeSig(), sb, reader, null, -1, true); - var readed = reader.Position - reader.byteStart; - if (readed != reader.byteSize) - { - Logger.Error($"Error while dump type, read {readed} bytes but expected {reader.byteSize} bytes"); - } - } - catch - { - sb = CreateMonoBehaviourHeader(m_MonoBehaviour); - Logger.Error("Error while dump type"); - } - } - } - return sb.ToString(); - } - - public void Dispose() - { - if (moduleDic != null) - { - foreach (var pair in moduleDic) - { - pair.Value.Dispose(); - } - moduleDic.Clear(); - moduleDic = null; - } - } - - private static StringBuilder CreateMonoBehaviourHeader(MonoBehaviour m_MonoBehaviour) - { - var sb = new StringBuilder(); - sb.AppendLine("PPtr m_GameObject"); - sb.AppendLine($"\tint m_FileID = {m_MonoBehaviour.m_GameObject.m_FileID}"); - sb.AppendLine($"\tint64 m_PathID = {m_MonoBehaviour.m_GameObject.m_PathID}"); - sb.AppendLine($"UInt8 m_Enabled = {m_MonoBehaviour.m_Enabled}"); - sb.AppendLine("PPtr m_Script"); - sb.AppendLine($"\tint m_FileID = {m_MonoBehaviour.m_Script.m_FileID}"); - sb.AppendLine($"\tint64 m_PathID = {m_MonoBehaviour.m_Script.m_PathID}"); - sb.AppendLine($"string m_Name = \"{m_MonoBehaviour.m_Name}\""); - return sb; - } - - 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")) //System.Collections.Generic.IEnumerable`1 - { - 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(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.AnimationCurve") - { - sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}"); - sb.AppendLine($"{new string('\t', indent + 1)}"); - var animationCurve = new AnimationCurve(reader, reader.ReadSingle); - return; - } - if (typeDef.FullName == "UnityEngine.Bounds") - { - sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}"); - sb.AppendLine($"{new string('\t', indent + 1)}"); - new AABB(reader); - return; - } - if (typeDef.FullName == "UnityEngine.BoundsInt") - { - sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}"); - sb.AppendLine($"{new string('\t', indent + 1)}"); - reader.Position += 24; - 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.Gradient") - { - sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}"); - sb.AppendLine($"{new string('\t', indent + 1)}"); - 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.GUIStyle") //TODO - { - throw new NotSupportedException(); - } - 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.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.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.RectInt") - { - 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 width = {reader.ReadInt32()}"); - sb.AppendLine($"{prefix}int height = {reader.ReadInt32()}"); - 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.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.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 if (fieldDef.FieldType is GenericInstSig genericSig && genericSig.GenericArguments.Count == 1 && genericSig.GenericArguments[0].IsGenericParameter) - { - for (var i = 0; i < typeDef.GenericParameters.Count; i++) - { - var g = typeDef.GenericParameters[i]; - if (g.FullName == genericSig.GenericArguments[0].FullName) - { - var type = ((GenericInstSig)typeSig).GenericArguments[i]; - var fieldTypeDef = fieldDef.FieldType.ToTypeDefOrRef().ResolveTypeDefThrow(); - if (fieldTypeDef.Interfaces.Any(x => x.Interface.FullName == "System.Collections.Generic.ICollection`1")) //System.Collections.Generic.IEnumerable`1 - { - var size = reader.ReadInt32(); - sb.AppendLine($"{new string('\t', indent + 1)}int size = {size}"); - for (int j = 0; j < size; j++) - { - sb.AppendLine($"{new string('\t', indent + 2)}[{i}]"); - DumpType(type, sb, reader, "data", indent + 2, false, false); - } - } - else - { - DumpType(fieldDef.FieldType, sb, reader, fieldDef.Name, indent + 1); - } - } - } - } - else - { - DumpType(fieldDef.FieldType, sb, reader, fieldDef.Name, indent + 1); - } - } - } - } - } - - private static bool IsAssignFromUnityObject(TypeDef typeDef) - { - if (typeDef.FullName == "UnityEngine.Object") - { - return true; - } - if (typeDef.BaseType != null) - { - if (typeDef.BaseType.FullName == "UnityEngine.Object") - { - return true; - } - while (true) - { - typeDef = typeDef.BaseType.ResolveTypeDefThrow(); - if (typeDef.BaseType == null) - { - break; - } - if (typeDef.BaseType.FullName == "UnityEngine.Object") - { - return true; - } - } - } - return false; - } - - private static bool IsBaseType(IFullName typeDef) - { - switch (typeDef.FullName) - { - case "System.Boolean": - case "System.Byte": - case "System.SByte": - case "System.Int16": - case "System.UInt16": - case "System.Int32": - case "System.UInt32": - case "System.Int64": - case "System.UInt64": - case "System.Single": - case "System.Double": - case "System.String": - return true; - default: - return false; - } - } - - private static bool IsEngineType(IFullName typeDef) - { - switch (typeDef.FullName) - { - case "UnityEngine.AnimationCurve": - case "UnityEngine.Bounds": - case "UnityEngine.BoundsInt": - case "UnityEngine.Color": - case "UnityEngine.Color32": - case "UnityEngine.Gradient": - case "UnityEngine.GUIStyle": - case "UnityEngine.LayerMask": - case "UnityEngine.Matrix4x4": - case "UnityEngine.PropertyName": - case "UnityEngine.Quaternion": - case "UnityEngine.Rect": - case "UnityEngine.RectInt": - case "UnityEngine.RectOffset": - case "UnityEngine.Vector2": - case "UnityEngine.Vector2Int": - case "UnityEngine.Vector3": - case "UnityEngine.Vector3Int": - case "UnityEngine.Vector4": - return true; - default: - return false; - } - } - } -} diff --git a/AssetStudioUtility/SerializedTypeHelper.cs b/AssetStudioUtility/SerializedTypeHelper.cs new file mode 100644 index 0000000..5d2fc8a --- /dev/null +++ b/AssetStudioUtility/SerializedTypeHelper.cs @@ -0,0 +1,281 @@ +using System.Collections.Generic; + +namespace AssetStudio +{ + public class SerializedTypeHelper + { + private readonly int[] version; + + public SerializedTypeHelper(int[] version) + { + this.version = version; + } + + public void AddMonoBehaviour(List nodes, int indent) + { + nodes.Add(new TypeTreeNode("MonoBehaviour", "Base", indent, false)); + AddPPtr(nodes, "GameObject", "m_GameObject", indent + 1); + nodes.Add(new TypeTreeNode("UInt8", "m_Enabled", indent + 1, true)); + AddPPtr(nodes, "MonoScript", "m_Script", indent + 1); + AddString(nodes, "m_Name", indent + 1); + } + + public void AddPPtr(List nodes, string type, string name, int indent) + { + nodes.Add(new TypeTreeNode($"PPtr<{type}>", name, indent, false)); + nodes.Add(new TypeTreeNode("int", "m_FileID", indent + 1, false)); + if (version[0] >= 5) //5.0 and up + { + nodes.Add(new TypeTreeNode("SInt64", "m_PathID", indent + 1, false)); + } + else + { + nodes.Add(new TypeTreeNode("int", "m_PathID", indent + 1, false)); + } + } + + public void AddString(List nodes, string name, int indent) + { + nodes.Add(new TypeTreeNode("string", name, indent, false)); + nodes.Add(new TypeTreeNode("Array", "Array", indent + 1, true)); + nodes.Add(new TypeTreeNode("int", "size", indent + 2, false)); + nodes.Add(new TypeTreeNode("char", "data", indent + 2, false)); + } + + public void AddArray(List nodes, int indent) + { + nodes.Add(new TypeTreeNode("Array", "Array", indent, false)); + nodes.Add(new TypeTreeNode("int", "size", indent + 1, false)); + } + + public void AddAnimationCurve(List nodes, string name, int indent) + { + nodes.Add(new TypeTreeNode("AnimationCurve", name, indent, false)); + nodes.Add(new TypeTreeNode("vector", "m_Curve", indent + 1, false)); + AddArray(nodes, indent + 2); //TODO 2017 and up Array align but no effect + nodes.Add(new TypeTreeNode("Keyframe", "data", indent + 3, false)); + nodes.Add(new TypeTreeNode("float", "time", indent + 4, false)); + nodes.Add(new TypeTreeNode("float", "value", indent + 4, false)); + nodes.Add(new TypeTreeNode("float", "inSlope", indent + 4, false)); + nodes.Add(new TypeTreeNode("float", "outSlope", indent + 4, false)); + if (version[0] >= 2018) //2018 and up + { + nodes.Add(new TypeTreeNode("int", "weightedMode", indent + 4, false)); + nodes.Add(new TypeTreeNode("float", "inWeight", indent + 4, false)); + nodes.Add(new TypeTreeNode("float", "outWeight", indent + 4, false)); + } + nodes.Add(new TypeTreeNode("int", "m_PreInfinity", indent + 1, false)); + nodes.Add(new TypeTreeNode("int", "m_PostInfinity", indent + 1, false)); + if (version[0] > 5 || (version[0] == 5 && version[1] >= 3)) //5.3 and up + { + nodes.Add(new TypeTreeNode("int", "m_RotationOrder", indent + 1, false)); + } + } + + public void AddGradient(List nodes, string name, int indent) + { + nodes.Add(new TypeTreeNode("Gradient", name, indent, false)); + if (version[0] > 5 || (version[0] == 5 && version[1] >= 6)) //5.6 and up + { + AddColorRGBA(nodes, "key0", indent + 1); + AddColorRGBA(nodes, "key1", indent + 1); + AddColorRGBA(nodes, "key2", indent + 1); + AddColorRGBA(nodes, "key3", indent + 1); + AddColorRGBA(nodes, "key4", indent + 1); + AddColorRGBA(nodes, "key5", indent + 1); + AddColorRGBA(nodes, "key6", indent + 1); + AddColorRGBA(nodes, "key7", indent + 1); + } + else + { + AddColor32(nodes, "key0", indent + 1); + AddColor32(nodes, "key1", indent + 1); + AddColor32(nodes, "key2", indent + 1); + AddColor32(nodes, "key3", indent + 1); + AddColor32(nodes, "key4", indent + 1); + AddColor32(nodes, "key5", indent + 1); + AddColor32(nodes, "key6", indent + 1); + AddColor32(nodes, "key7", indent + 1); + } + nodes.Add(new TypeTreeNode("UInt16", "ctime0", indent + 1, false)); + nodes.Add(new TypeTreeNode("UInt16", "ctime1", indent + 1, false)); + nodes.Add(new TypeTreeNode("UInt16", "ctime2", indent + 1, false)); + nodes.Add(new TypeTreeNode("UInt16", "ctime3", indent + 1, false)); + nodes.Add(new TypeTreeNode("UInt16", "ctime4", indent + 1, false)); + nodes.Add(new TypeTreeNode("UInt16", "ctime5", indent + 1, false)); + nodes.Add(new TypeTreeNode("UInt16", "ctime6", indent + 1, false)); + nodes.Add(new TypeTreeNode("UInt16", "ctime7", indent + 1, false)); + nodes.Add(new TypeTreeNode("UInt16", "atime0", indent + 1, false)); + nodes.Add(new TypeTreeNode("UInt16", "atime1", indent + 1, false)); + nodes.Add(new TypeTreeNode("UInt16", "atime2", indent + 1, false)); + nodes.Add(new TypeTreeNode("UInt16", "atime3", indent + 1, false)); + nodes.Add(new TypeTreeNode("UInt16", "atime4", indent + 1, false)); + nodes.Add(new TypeTreeNode("UInt16", "atime5", indent + 1, false)); + nodes.Add(new TypeTreeNode("UInt16", "atime6", indent + 1, false)); + nodes.Add(new TypeTreeNode("UInt16", "atime7", indent + 1, false)); + if (version[0] > 5 || (version[0] == 5 && version[1] >= 5)) //5.5 and up + { + nodes.Add(new TypeTreeNode("int", "m_Mode", indent + 1, false)); + } + nodes.Add(new TypeTreeNode("UInt8", "m_NumColorKeys", indent + 1, false)); + nodes.Add(new TypeTreeNode("UInt8", "m_NumAlphaKeys", indent + 1, true)); + } + + public void AddGUIStyle(List nodes, string name, int indent) + { + nodes.Add(new TypeTreeNode("GUIStyle", name, indent, false)); + AddString(nodes, "m_Name", indent + 1); + AddGUIStyleState(nodes, "m_Normal", indent + 1); + AddGUIStyleState(nodes, "m_Hover", indent + 1); + AddGUIStyleState(nodes, "m_Active", indent + 1); + AddGUIStyleState(nodes, "m_Focused", indent + 1); + AddGUIStyleState(nodes, "m_OnNormal", indent + 1); + AddGUIStyleState(nodes, "m_OnHover", indent + 1); + AddGUIStyleState(nodes, "m_OnActive", indent + 1); + AddGUIStyleState(nodes, "m_OnFocused", indent + 1); + AddRectOffset(nodes, "m_Border", indent + 1); + if (version[0] >= 4) //4 and up + { + AddRectOffset(nodes, "m_Margin", indent + 1); + AddRectOffset(nodes, "m_Padding", indent + 1); + } + else + { + AddRectOffset(nodes, "m_Padding", indent + 1); + AddRectOffset(nodes, "m_Margin", indent + 1); + } + AddRectOffset(nodes, "m_Overflow", indent + 1); + AddPPtr(nodes, "Font", "m_Font", indent + 1); + if (version[0] >= 4) //4 and up + { + nodes.Add(new TypeTreeNode("int", "m_FontSize", indent + 1, false)); + nodes.Add(new TypeTreeNode("int", "m_FontStyle", indent + 1, false)); + nodes.Add(new TypeTreeNode("int", "m_Alignment", indent + 1, false)); + nodes.Add(new TypeTreeNode("bool", "m_WordWrap", indent + 1, false)); + nodes.Add(new TypeTreeNode("bool", "m_RichText", indent + 1, true)); + nodes.Add(new TypeTreeNode("int", "m_TextClipping", indent + 1, false)); + nodes.Add(new TypeTreeNode("int", "m_ImagePosition", indent + 1, false)); + AddVector2f(nodes, "m_ContentOffset", indent + 1); + nodes.Add(new TypeTreeNode("float", "m_FixedWidth", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "m_FixedHeight", indent + 1, false)); + nodes.Add(new TypeTreeNode("bool", "m_StretchWidth", indent + 1, false)); + nodes.Add(new TypeTreeNode("bool", "m_StretchHeight", indent + 1, true)); + } + else + { + nodes.Add(new TypeTreeNode("int", "m_ImagePosition", indent + 1, false)); + nodes.Add(new TypeTreeNode("int", "m_Alignment", indent + 1, false)); + nodes.Add(new TypeTreeNode("bool", "m_WordWrap", indent + 1, true)); + nodes.Add(new TypeTreeNode("int", "m_TextClipping", indent + 1, false)); + AddVector2f(nodes, "m_ContentOffset", indent + 1); + AddVector2f(nodes, "m_ClipOffset", indent + 1); + nodes.Add(new TypeTreeNode("float", "m_FixedWidth", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "m_FixedHeight", indent + 1, false)); + if (version[0] >= 3) //3 and up + { + nodes.Add(new TypeTreeNode("int", "m_FontSize", indent + 1, false)); + nodes.Add(new TypeTreeNode("int", "m_FontStyle", indent + 1, false)); + } + nodes.Add(new TypeTreeNode("bool", "m_StretchWidth", indent + 1, true)); + nodes.Add(new TypeTreeNode("bool", "m_StretchHeight", indent + 1, true)); + } + } + + public void AddGUIStyleState(List nodes, string name, int indent) + { + nodes.Add(new TypeTreeNode("GUIStyleState", name, indent, false)); + AddPPtr(nodes, "Texture2D", "m_Background", indent + 1); + AddColorRGBA(nodes, "m_TextColor", indent + 1); + } + + public void AddVector2f(List nodes, string name, int indent) + { + nodes.Add(new TypeTreeNode("Vector2f", name, indent, false)); + nodes.Add(new TypeTreeNode("float", "x", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "y", indent + 1, false)); + } + + public void AddRectOffset(List nodes, string name, int indent) + { + nodes.Add(new TypeTreeNode("RectOffset", name, indent, false)); + nodes.Add(new TypeTreeNode("int", "m_Left", indent + 1, false)); + nodes.Add(new TypeTreeNode("int", "m_Right", indent + 1, false)); + nodes.Add(new TypeTreeNode("int", "m_Top", indent + 1, false)); + nodes.Add(new TypeTreeNode("int", "m_Bottom", indent + 1, false)); + } + + public void AddColorRGBA(List nodes, string name, int indent) + { + nodes.Add(new TypeTreeNode("ColorRGBA", name, indent, false)); + nodes.Add(new TypeTreeNode("float", "r", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "g", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "b", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "a", indent + 1, false)); + } + + public void AddColor32(List nodes, string name, int indent) + { + nodes.Add(new TypeTreeNode("ColorRGBA", name, indent, false)); + nodes.Add(new TypeTreeNode("unsigned int", "rgba", indent + 1, false)); + } + + public void AddMatrix4x4(List nodes, string name, int indent) + { + nodes.Add(new TypeTreeNode("Matrix4x4f", name, indent, false)); + nodes.Add(new TypeTreeNode("float", "e00", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "e01", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "e02", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "e03", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "e10", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "e11", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "e12", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "e13", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "e20", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "e21", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "e22", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "e23", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "e30", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "e31", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "e32", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "e33", indent + 1, false)); + } + + public void AddSphericalHarmonicsL2(List nodes, string name, int indent) + { + nodes.Add(new TypeTreeNode("SphericalHarmonicsL2", name, indent, false)); + nodes.Add(new TypeTreeNode("float", "sh[ 0]", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "sh[ 1]", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "sh[ 2]", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "sh[ 3]", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "sh[ 4]", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "sh[ 5]", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "sh[ 6]", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "sh[ 7]", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "sh[ 8]", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "sh[ 9]", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "sh[10]", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "sh[11]", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "sh[12]", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "sh[13]", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "sh[14]", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "sh[15]", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "sh[16]", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "sh[17]", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "sh[18]", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "sh[19]", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "sh[20]", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "sh[21]", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "sh[22]", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "sh[23]", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "sh[24]", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "sh[25]", indent + 1, false)); + nodes.Add(new TypeTreeNode("float", "sh[26]", indent + 1, false)); + } + + public void AddPropertyName(List nodes, string name, int indent) + { + nodes.Add(new TypeTreeNode("PropertyName", name, indent, false)); + AddString(nodes, "id", indent + 1); + } + } +} diff --git a/AssetStudioUtility/TypeDefinitionConverter.cs b/AssetStudioUtility/TypeDefinitionConverter.cs new file mode 100644 index 0000000..3892ea3 --- /dev/null +++ b/AssetStudioUtility/TypeDefinitionConverter.cs @@ -0,0 +1,307 @@ +using Mono.Cecil; +using System; +using System.Collections.Generic; +using System.Linq; +using Unity.CecilTools; +using Unity.SerializationLogic; + +namespace AssetStudio +{ + public class TypeDefinitionConverter + { + private readonly TypeDefinition TypeDef; + private readonly TypeResolver TypeResolver; + private readonly SerializedTypeHelper Helper; + private readonly int Indent; + + public TypeDefinitionConverter(TypeDefinition typeDef, SerializedTypeHelper helper, int indent) + { + TypeDef = typeDef; + TypeResolver = new TypeResolver(null); + Helper = helper; + Indent = indent; + } + + public List ConvertToTypeTreeNode() + { + var nodes = new List(); + + Stack baseTypes = new Stack(); + TypeReference baseType = TypeDef.BaseType; + while (!UnitySerializationLogic.IsNonSerialized(baseType)) + { + GenericInstanceType genericInstanceType = baseType as GenericInstanceType; + if (genericInstanceType != null) + { + TypeResolver.Add(genericInstanceType); + } + baseTypes.Push(baseType); + baseType = baseType.Resolve().BaseType; + } + while (baseTypes.Count > 0) + { + TypeReference typeReference = baseTypes.Pop(); + TypeDefinition typeDefinition = typeReference.Resolve(); + foreach (var fieldDefinition in typeDefinition.Fields.Where(WillUnitySerialize)) + { + if (!IsHiddenByParentClass(baseTypes, fieldDefinition, TypeDef)) + { + nodes.AddRange(ProcessingFieldRef(ResolveGenericFieldReference(fieldDefinition))); + } + } + + var genericInstanceType2 = typeReference as GenericInstanceType; + if (genericInstanceType2 != null) + { + TypeResolver.Remove(genericInstanceType2); + } + } + foreach (FieldDefinition fieldDefinition2 in FilteredFields()) + { + nodes.AddRange(ProcessingFieldRef(fieldDefinition2)); + } + + return nodes; + } + + private bool WillUnitySerialize(FieldDefinition fieldDefinition) + { + bool result; + try + { + TypeReference typeReference = TypeResolver.Resolve(fieldDefinition.FieldType); + if (UnitySerializationLogic.ShouldNotTryToResolve(typeReference)) + { + result = false; + } + else + { + if (!UnityEngineTypePredicates.IsUnityEngineObject(typeReference)) + { + if (typeReference.FullName == fieldDefinition.DeclaringType.FullName) + { + return false; + } + } + result = UnitySerializationLogic.WillUnitySerialize(fieldDefinition, TypeResolver); + } + } + catch (Exception ex) + { + throw new Exception(string.Format("Exception while processing {0} {1}, error {2}", fieldDefinition.FieldType.FullName, fieldDefinition.FullName, ex.Message)); + } + return result; + } + + private static bool IsHiddenByParentClass(IEnumerable parentTypes, FieldDefinition fieldDefinition, TypeDefinition processingType) + { + return processingType.Fields.Any((FieldDefinition f) => f.Name == fieldDefinition.Name) || parentTypes.Any((TypeReference t) => t.Resolve().Fields.Any((FieldDefinition f) => f.Name == fieldDefinition.Name)); + } + + private IEnumerable FilteredFields() + { + foreach (var f in TypeDef.Fields.Where(WillUnitySerialize)) + { + if (UnitySerializationLogic.IsSupportedCollection(f.FieldType) || !f.FieldType.IsGenericInstance || UnitySerializationLogic.ShouldImplementIDeserializable(f.FieldType.Resolve())) + { + yield return f; + } + } + + yield break; + } + + private FieldReference ResolveGenericFieldReference(FieldReference fieldRef) + { + FieldReference field = new FieldReference(fieldRef.Name, fieldRef.FieldType, ResolveDeclaringType(fieldRef.DeclaringType)); + return TypeDef.Module.ImportReference(field); + } + + private TypeReference ResolveDeclaringType(TypeReference declaringType) + { + TypeDefinition typeDefinition = declaringType.Resolve(); + TypeReference result; + if (typeDefinition == null || !typeDefinition.HasGenericParameters) + { + result = typeDefinition; + } + else + { + GenericInstanceType genericInstanceType = new GenericInstanceType(typeDefinition); + foreach (GenericParameter item in typeDefinition.GenericParameters) + { + genericInstanceType.GenericArguments.Add(item); + } + result = TypeResolver.Resolve(genericInstanceType); + } + return result; + } + + private List ProcessingFieldRef(FieldReference fieldDef) + { + var typeRef = TypeResolver.Resolve(fieldDef.FieldType); + return TypeRefToTypeTreeNodes(typeRef, fieldDef.Name, Indent); + } + + private static bool IsStruct(TypeReference typeRef) + { + return typeRef.IsValueType && !IsEnum(typeRef) && !typeRef.IsPrimitive; + } + + private static bool IsEnum(TypeReference typeRef) + { + return !typeRef.IsArray && typeRef.Resolve().IsEnum; + } + + private static bool RequiresAlignment(TypeReference typeRef) + { + bool result; + switch (typeRef.MetadataType) + { + case MetadataType.Boolean: + case MetadataType.Char: + case MetadataType.SByte: + case MetadataType.Byte: + case MetadataType.Int16: + case MetadataType.UInt16: + result = true; + break; + default: + result = (UnitySerializationLogic.IsSupportedCollection(typeRef) && RequiresAlignment(CecilUtils.ElementTypeOfCollection(typeRef))); + break; + } + return result; + } + + private static bool IsSystemString(TypeReference typeRef) + { + return typeRef.FullName == "System.String"; + } + + private List TypeRefToTypeTreeNodes(TypeReference typeRef, string name, int indent) + { + var align = false; + + if (!IsStruct(TypeDef) || !UnityEngineTypePredicates.IsUnityEngineValueType(TypeDef)) + { + if (IsStruct(typeRef) || RequiresAlignment(typeRef)) + { + align = true; + } + } + + var nodes = new List(); + if (typeRef.IsPrimitive) + { + var primitiveName = typeRef.Name; + switch (primitiveName) + { + case "Boolean": + primitiveName = "bool"; + break; + case "Byte": + primitiveName = "UInt8"; + break; + case "SByte": + primitiveName = "SInt8"; + break; + case "Int16": + primitiveName = "SInt16"; + break; + case "UInt16": + primitiveName = "UInt16"; + break; + case "Int32": + primitiveName = "SInt32"; + break; + case "UInt32": + primitiveName = "UInt32"; + break; + case "Int64": + primitiveName = "SInt64"; + break; + case "UInt64": + primitiveName = "UInt64"; + break; + case "Char": + primitiveName = "char"; + break; + case "Double": + primitiveName = "double"; + break; + case "Single": + primitiveName = "float"; + break; + default: + throw new NotSupportedException(); + } + nodes.Add(new TypeTreeNode(primitiveName, name, indent, align)); + } + else if (IsSystemString(typeRef)) + { + Helper.AddString(nodes, name, indent); + } + else if (IsEnum(typeRef)) + { + nodes.Add(new TypeTreeNode("SInt32", name, indent, align)); + } + else if (CecilUtils.IsGenericList(typeRef)) + { + var elementRef = CecilUtils.ElementTypeOfCollection(typeRef); + nodes.Add(new TypeTreeNode(typeRef.Name, name, indent, align)); + Helper.AddArray(nodes, indent + 1); + nodes.AddRange(TypeRefToTypeTreeNodes(elementRef, "data", indent + 2)); + } + else if (typeRef.IsArray) + { + var elementRef = typeRef.GetElementType(); + nodes.Add(new TypeTreeNode(typeRef.Name, name, indent, align)); + Helper.AddArray(nodes, indent + 1); + nodes.AddRange(TypeRefToTypeTreeNodes(elementRef, "data", indent + 2)); + } + else if (UnityEngineTypePredicates.IsUnityEngineObject(typeRef)) + { + Helper.AddPPtr(nodes, typeRef.Name, name, indent); + } + else if (UnityEngineTypePredicates.IsSerializableUnityClass(typeRef) || UnityEngineTypePredicates.IsSerializableUnityStruct(typeRef)) + { + switch (typeRef.FullName) + { + case "UnityEngine.AnimationCurve": + Helper.AddAnimationCurve(nodes, name, indent + 1); + break; + case "UnityEngine.Gradient": + Helper.AddGradient(nodes, name, indent + 1); + break; + case "UnityEngine.GUIStyle": + Helper.AddGUIStyle(nodes, name, indent + 1); + break; + case "UnityEngine.RectOffset": + Helper.AddRectOffset(nodes, name, indent + 1); + break; + case "UnityEngine.Color32": + Helper.AddColor32(nodes, name, indent + 1); + break; + case "UnityEngine.Matrix4x4": + Helper.AddMatrix4x4(nodes, name, indent + 1); + break; + case "UnityEngine.Rendering.SphericalHarmonicsL2": + Helper.AddSphericalHarmonicsL2(nodes, name, indent + 1); + break; + case "UnityEngine.PropertyName": + Helper.AddPropertyName(nodes, name, indent + 1); + break; + } + } + else + { + nodes.Add(new TypeTreeNode(typeRef.Name, name, indent, align)); + var typeDef = typeRef.Resolve(); + var typeDefinitionConverter = new TypeDefinitionConverter(typeDef, Helper, indent + 1); + nodes.AddRange(typeDefinitionConverter.ConvertToTypeTreeNode()); + } + + return nodes; + } + } +} diff --git a/AssetStudioUtility/packages.config b/AssetStudioUtility/packages.config deleted file mode 100644 index 99bb478..0000000 --- a/AssetStudioUtility/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file