diff --git a/AssetStudio/Classes/Sprite.cs b/AssetStudio/Classes/Sprite.cs index ea9e273..e970099 100644 --- a/AssetStudio/Classes/Sprite.cs +++ b/AssetStudio/Classes/Sprite.cs @@ -174,7 +174,8 @@ namespace AssetStudio m_PixelsToUnits = reader.ReadSingle(); if (version[0] > 5 || (version[0] == 5 && version[1] > 4) - || (version[0] == 5 && version[1] == 4 && version[2] >= 2)) //5.4.2 and up + || (version[0] == 5 && version[1] == 4 && version[2] >= 2) + || (version[0] == 5 && version[1] == 4 && version[2] == 1 && buildType.IsPatch && version[3] >= 3)) //5.4.1p3 and up { m_Pivot = reader.ReadVector2(); } diff --git a/AssetStudio/Extensions/BinaryReaderExtensions.cs b/AssetStudio/Extensions/BinaryReaderExtensions.cs index 84d1d35..a84c2b5 100644 --- a/AssetStudio/Extensions/BinaryReaderExtensions.cs +++ b/AssetStudio/Extensions/BinaryReaderExtensions.cs @@ -36,12 +36,20 @@ namespace AssetStudio return ""; } - public static string ReadStringToNull(this BinaryReader reader) + public static string ReadStringToNull(this BinaryReader reader, int maxLength = 32767) { var bytes = new List(); - byte b; - while (reader.BaseStream.Position != reader.BaseStream.Length && (b = reader.ReadByte()) != 0) + int count = 0; + while (reader.BaseStream.Position != reader.BaseStream.Length && count < maxLength) + { + var b = reader.ReadByte(); + if (b == 0) + { + break; + } bytes.Add(b); + count++; + } return Encoding.UTF8.GetString(bytes.ToArray()); } diff --git a/AssetStudio/ImportHelper.cs b/AssetStudio/ImportHelper.cs index 440ce71..c3ea046 100644 --- a/AssetStudio/ImportHelper.cs +++ b/AssetStudio/ImportHelper.cs @@ -70,7 +70,7 @@ namespace AssetStudio private static FileType CheckFileType(EndianBinaryReader reader) { - var signature = reader.ReadStringToNull(); + var signature = reader.ReadStringToNull(20); reader.Position = 0; switch (signature) { diff --git a/AssetStudio/Libraries/dnlib.dll b/AssetStudio/Libraries/dnlib.dll index 718b4bf..6265fdb 100644 Binary files a/AssetStudio/Libraries/dnlib.dll and b/AssetStudio/Libraries/dnlib.dll differ diff --git a/AssetStudioGUI/AssetStudioGUI.csproj b/AssetStudioGUI/AssetStudioGUI.csproj index 575ca1b..7b5b023 100644 --- a/AssetStudioGUI/AssetStudioGUI.csproj +++ b/AssetStudioGUI/AssetStudioGUI.csproj @@ -73,11 +73,6 @@ MinimumRecommendedRules.ruleset - - False - ..\AssetStudio\Libraries\dnlib.dll - False - False ..\AssetStudio\Libraries\OpenTK.dll diff --git a/AssetStudioGUI/AssetStudioGUIForm.cs b/AssetStudioGUI/AssetStudioGUIForm.cs index 0968bc7..848e9ae 100644 --- a/AssetStudioGUI/AssetStudioGUIForm.cs +++ b/AssetStudioGUI/AssetStudioGUIForm.cs @@ -1707,12 +1707,8 @@ namespace AssetStudioGUI FMODreset(); - ModuleLoaded = false; - foreach (var pair in LoadedModuleDic) - { - pair.Value.Dispose(); - } - LoadedModuleDic.Clear(); + scriptDumper.Dispose(); + scriptDumper = null; } private void assetListView_MouseClick(object sender, MouseEventArgs e) diff --git a/AssetStudioGUI/Studio.cs b/AssetStudioGUI/Studio.cs index c2fc32a..c0f385e 100644 --- a/AssetStudioGUI/Studio.cs +++ b/AssetStudioGUI/Studio.cs @@ -7,7 +7,6 @@ using System.Linq; using System.Threading; using System.Windows.Forms; using AssetStudio; -using dnlib.DotNet; using static AssetStudioGUI.Exporter; using Object = AssetStudio.Object; @@ -16,10 +15,9 @@ namespace AssetStudioGUI internal static class Studio { public static AssetsManager assetsManager = new AssetsManager(); + public static ScriptDumper scriptDumper = new ScriptDumper(); public static List exportableAssets = new List(); public static List visibleAssets = new List(); - public static bool ModuleLoaded; - public static Dictionary LoadedModuleDic = new Dictionary(); public static void ExtractFile(string[] fileNames) { @@ -614,36 +612,21 @@ namespace AssetStudioGUI public static string GetScriptString(ObjectReader reader) { - if (!ModuleLoaded) + if (scriptDumper == null) { var openFolderDialog = new OpenFolderDialog(); openFolderDialog.Title = "Select Assembly Folder"; if (openFolderDialog.ShowDialog() == DialogResult.OK) { - var files = Directory.GetFiles(openFolderDialog.Folder, "*.dll"); - var moduleContext = new ModuleContext(); - var asmResolver = new AssemblyResolver(moduleContext, true); - var resolver = new Resolver(asmResolver); - moduleContext.AssemblyResolver = asmResolver; - moduleContext.Resolver = resolver; - try - { - foreach (var file in files) - { - var module = ModuleDefMD.Load(file, moduleContext); - LoadedModuleDic.Add(Path.GetFileName(file), module); - } - } - catch - { - // ignored - } + scriptDumper = new ScriptDumper(openFolderDialog.Folder); + } + else + { + scriptDumper = new ScriptDumper(); } - - ModuleLoaded = true; } - return ScriptHelper.GetScriptString(reader, LoadedModuleDic); + return scriptDumper.DumpScript(reader); } } } diff --git a/AssetStudioUtility/AssetStudioUtility.csproj b/AssetStudioUtility/AssetStudioUtility.csproj index bf0950a..a579872 100644 --- a/AssetStudioUtility/AssetStudioUtility.csproj +++ b/AssetStudioUtility/AssetStudioUtility.csproj @@ -82,7 +82,7 @@ - + diff --git a/AssetStudioUtility/ScriptHelper.cs b/AssetStudioUtility/ScriptDumper.cs similarity index 64% rename from AssetStudioUtility/ScriptHelper.cs rename to AssetStudioUtility/ScriptDumper.cs index ec4d565..22fd143 100644 --- a/AssetStudioUtility/ScriptHelper.cs +++ b/AssetStudioUtility/ScriptDumper.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using dnlib.DotNet; @@ -7,9 +8,37 @@ using dnlib.DotNet; namespace AssetStudio { //TODO unfinished - public static class ScriptHelper + //Separate, EngineType read + public class ScriptDumper : IDisposable { - public static string GetScriptString(ObjectReader reader, Dictionary moduleDic) + 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); @@ -25,16 +54,32 @@ namespace AssetStudio 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() + { + foreach (var pair in moduleDic) + { + pair.Value.Dispose(); + } + moduleDic.Clear(); + moduleDic = null; + } + private static StringBuilder CreateMonoBehaviourHeader(MonoBehaviour m_MonoBehaviour) { var sb = new StringBuilder(); @@ -49,7 +94,7 @@ namespace AssetStudio return sb; } - private static void DumpType(TypeSig typeSig, StringBuilder sb, ObjectReader reader, string name, int indent, bool isRoot = false) + 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) @@ -94,7 +139,8 @@ namespace AssetStudio value = reader.ReadChar(); break; } - reader.AlignStream(); + if (align) + reader.AlignStream(); sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name} = {value}"); return; } @@ -131,18 +177,27 @@ namespace AssetStudio { if (genericInstSig.GenericArguments.Count == 1) { + var genericType = genericInstSig.GenericType.ToTypeDefOrRef().ResolveTypeDefThrow(); 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)}int size = {size}"); - for (int i = 0; i < size; i++) + if (genericType.Interfaces.Any(x => x.Interface.FullName == "System.Collections.Generic.ICollection`1")) //System.Collections.Generic.IEnumerable`1 { - sb.AppendLine($"{new string('\t', indent + 2)}[{i}]"); - DumpType(genericInstSig.GenericArguments[0], sb, reader, "data", indent + 2); + 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; @@ -158,31 +213,37 @@ namespace AssetStudio sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name} = {reader.ReadUInt32()}"); return; } - if (indent != -1 && !IsEngineType(typeDef) && !typeDef.IsSerializable) + if (!isRoot && !IsEngineType(typeDef) && !typeDef.IsSerializable) { return; } if (typeDef.FullName == "UnityEngine.Rect") { sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name}"); - var rect = reader.ReadSingleArray(4); + 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}"); - var value = reader.ReadInt32(); + 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)}"); var animationCurve = new AnimationCurve(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)}"); if (reader.version[0] == 5 && reader.version[1] < 5) reader.Position += 68; else if (reader.version[0] == 5 && reader.version[1] < 6) @@ -194,10 +255,52 @@ namespace AssetStudio 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(); + 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)}"); + new AABB(reader); return; } if (typeDef.FullName == "UnityEngine.GUIStyle") //TODO @@ -230,7 +333,22 @@ namespace AssetStudio } 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); + if (fieldDef.FieldType.IsGenericParameter) + { + foreach (var g in typeDef.GenericParameters) + { + if (g.FullName == fieldDef.FieldType.FullName) + { + var type = ((GenericInstSig)typeSig).GenericArguments[0]; + DumpType(type, sb, reader, fieldDef.Name, indent + 1); + break; + } + } + } + else + { + DumpType(fieldDef.FieldType, sb, reader, fieldDef.Name, indent + 1); + } } } } @@ -308,6 +426,7 @@ namespace AssetStudio case "UnityEngine.Vector3": case "UnityEngine.Vector3Int": case "UnityEngine.Vector4": + case "UnityEngine.PropertyName": return true; default: return false;