add MonoScript to dump MonoBehaviour

This commit is contained in:
Perfare 2018-08-05 04:46:27 +08:00
parent 2bd4729fe7
commit 3e59a78376
9 changed files with 380 additions and 64 deletions

View File

@ -55,6 +55,10 @@
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<Reference Include="dnlib">
<HintPath>Library\dnlib.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="OpenTK, Version=2.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>Library\OpenTK.dll</HintPath>
@ -158,6 +162,7 @@
<Compile Include="Classes\AnimatorController.cs" />
<Compile Include="Classes\AnimatorOverrideController.cs" />
<Compile Include="Classes\Avatar.cs" />
<Compile Include="Classes\MonoScript.cs" />
<Compile Include="OpenFolderDialog.cs" />
<Compile Include="Classes\AssetBundle.cs" />
<Compile Include="Classes\MovieTexture.cs" />

View File

@ -55,6 +55,10 @@
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
</PropertyGroup>
<ItemGroup>
<Reference Include="dnlib">
<HintPath>Library\dnlib.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="OpenTK, Version=2.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>Library\OpenTK.dll</HintPath>
@ -146,6 +150,7 @@
<Compile Include="Brotli\Transform.cs" />
<Compile Include="Brotli\Utils.cs" />
<Compile Include="Brotli\WordTransformType.cs" />
<Compile Include="Classes\MonoScript.cs" />
<Compile Include="StudioClasses\SevenZipHelper.cs">
<SubType>Code</SubType>
</Compile>

View File

@ -778,8 +778,15 @@ namespace AssetStudio
}
case ClassIDReference.MonoBehaviour:
{
MonoBehaviour m_MonoBehaviour = new MonoBehaviour(asset, true);
textPreviewBox.Text = m_MonoBehaviour.serializedText;
var m_MonoBehaviour = new MonoBehaviour(asset);
if (asset.Type1 != asset.Type2 && asset.sourceFile.ClassStructures.ContainsKey(asset.Type1))
{
textPreviewBox.Text = asset.GetClassString();
}
else
{
textPreviewBox.Text = GetScriptString(asset);
}
textPreviewBox.Visible = true;
break;
@ -1685,6 +1692,9 @@ namespace AssetStudio
}
FMODreset();
moduleLoaded = false;
LoadedModuleDic.Clear();
}
private void assetListView_MouseClick(object sender, MouseEventArgs e)

View File

@ -7,38 +7,21 @@ namespace AssetStudio
{
class MonoBehaviour
{
public string serializedText;
public PPtr m_GameObject;
public byte m_Enabled;
public PPtr m_Script;
public string m_Name;
public MonoBehaviour(AssetPreloadData preloadData, bool readSwitch)
public MonoBehaviour(AssetPreloadData preloadData)
{
var sourceFile = preloadData.sourceFile;
var reader = preloadData.InitReader();
var m_GameObject = sourceFile.ReadPPtr();
var m_Enabled = reader.ReadByte();
m_GameObject = sourceFile.ReadPPtr();
m_Enabled = reader.ReadByte();
reader.AlignStream(4);
var m_Script = sourceFile.ReadPPtr();
var m_Name = reader.ReadAlignedString();
if (readSwitch)
{
if ((serializedText = preloadData.GetClassString()) == null)
{
var str = "PPtr<GameObject> m_GameObject\r\n";
str += "\tint m_FileID = " + m_GameObject.m_FileID + "\r\n";
str += "\tint64 m_PathID = " + m_GameObject.m_PathID + "\r\n";
str += "UInt8 m_Enabled = " + m_Enabled + "\r\n";
str += "PPtr<MonoScript> m_Script\r\n";
str += "\tint m_FileID = " + m_Script.m_FileID + "\r\n";
str += "\tint64 m_PathID = " + m_Script.m_PathID + "\r\n";
str += "string m_Name = \"" + m_Name + "\"\r\n";
serializedText = str;
}
}
else
{
preloadData.extension = ".txt";
preloadData.Text = m_Name;
}
m_Script = sourceFile.ReadPPtr();
m_Name = reader.ReadAlignedString();
}
}
}

View File

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace AssetStudio
{
class MonoScript
{
public string m_Name;
public string m_ClassName;
public string m_Namespace = string.Empty;
public string m_AssemblyName;
public MonoScript(AssetPreloadData preloadData)
{
var sourceFile = preloadData.sourceFile;
var reader = preloadData.InitReader();
var version = sourceFile.version;
m_Name = reader.ReadAlignedString();
if (version[0] > 3 || (version[0] == 3 && version[1] >= 4))
{
var m_ExecutionOrder = reader.ReadAlignedString();
}
if (version[0] < 5)
{
var m_PropertiesHash = reader.ReadUInt32();
}
else
{
var m_PropertiesHash = reader.ReadBytes(16);
}
if (version[0] < 3)
{
var m_PathName = reader.ReadAlignedString();
}
m_ClassName = reader.ReadAlignedString();
if (version[0] >= 3)
{
m_Namespace = reader.ReadAlignedString();
}
m_AssemblyName = reader.ReadAlignedString();
if (version[0] < 2018 || (version[0] == 2018 && version[1] < 2))
{
var m_IsEditorScript = reader.ReadBoolean();
}
}
}
}

Binary file not shown.

View File

@ -8,32 +8,19 @@ namespace AssetStudio
{
class OpenFolderDialog
{
/// <summary>
/// Gets/sets folder in which dialog will be open.
/// </summary>
public string InitialFolder { get; set; }
/// <summary>
/// Gets/sets directory in which dialog will be open if there is no recent directory available.
/// </summary>
public string DefaultFolder { get; set; }
/// <summary>
/// Gets selected folder.
/// </summary>
public string Folder { get; private set; }
public string Title { get; set; }
internal DialogResult ShowDialog(IWin32Window owner)
internal DialogResult ShowDialog(IWin32Window owner = null)
{
if (Environment.OSVersion.Version.Major >= 6)
{
return ShowVistaDialog(owner);
}
else
{
return ShowLegacyDialog(owner);
}
return ShowLegacyDialog(owner);
}
private DialogResult ShowVistaDialog(IWin32Window owner)
@ -42,24 +29,26 @@ namespace AssetStudio
frm.GetOptions(out var options);
options |= NativeMethods.FOS_PICKFOLDERS | NativeMethods.FOS_FORCEFILESYSTEM | NativeMethods.FOS_NOVALIDATE | NativeMethods.FOS_NOTESTFILECREATE | NativeMethods.FOS_DONTADDTORECENT;
frm.SetOptions(options);
if (this.InitialFolder != null)
if (Title != null)
frm.SetTitle(Title);
if (InitialFolder != null)
{
var riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); //IShellItem
if (NativeMethods.SHCreateItemFromParsingName(this.InitialFolder, IntPtr.Zero, ref riid, out var directoryShellItem) == NativeMethods.S_OK)
if (NativeMethods.SHCreateItemFromParsingName(InitialFolder, IntPtr.Zero, ref riid, out var directoryShellItem) == NativeMethods.S_OK)
{
frm.SetFolder(directoryShellItem);
}
}
if (this.DefaultFolder != null)
if (DefaultFolder != null)
{
var riid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); //IShellItem
if (NativeMethods.SHCreateItemFromParsingName(this.DefaultFolder, IntPtr.Zero, ref riid, out var directoryShellItem) == NativeMethods.S_OK)
if (NativeMethods.SHCreateItemFromParsingName(DefaultFolder, IntPtr.Zero, ref riid, out var directoryShellItem) == NativeMethods.S_OK)
{
frm.SetDefaultFolder(directoryShellItem);
}
}
if (frm.Show(owner.Handle) == NativeMethods.S_OK)
if ((owner == null ? frm.Show() : frm.Show(owner.Handle)) == NativeMethods.S_OK)
{
if (frm.GetResult(out var shellItem) == NativeMethods.S_OK)
{
@ -69,7 +58,7 @@ namespace AssetStudio
{
try
{
this.Folder = Marshal.PtrToStringAuto(pszString);
Folder = Marshal.PtrToStringAuto(pszString);
return DialogResult.OK;
}
finally
@ -87,16 +76,17 @@ namespace AssetStudio
{
using (var frm = new FolderBrowserDialog())
{
if (this.InitialFolder != null) { frm.SelectedPath = this.InitialFolder; }
if (frm.ShowDialog(owner) == DialogResult.OK)
if (InitialFolder != null)
{
this.Folder = Path.GetDirectoryName(frm.SelectedPath);
frm.SelectedPath = InitialFolder;
}
if ((owner == null ? frm.ShowDialog() : frm.ShowDialog(owner)) == DialogResult.OK)
{
Folder = Path.GetDirectoryName(frm.SelectedPath);
return DialogResult.OK;
}
else
{
return DialogResult.Cancel;
}
return DialogResult.Cancel;
}
}
}

View File

@ -145,11 +145,20 @@ namespace AssetStudio
public static bool ExportMonoBehaviour(AssetPreloadData asset, string exportPath)
{
var m_MonoBehaviour = new MonoBehaviour(asset, true);
var exportFullName = exportPath + asset.Text + asset.extension;
var exportFullName = exportPath + asset.Text + ".txt";
if (ExportFileExists(exportFullName))
return false;
File.WriteAllText(exportFullName, m_MonoBehaviour.serializedText);
var m_MonoBehaviour = new MonoBehaviour(asset);
string str;
if (asset.Type1 != asset.Type2 && asset.sourceFile.ClassStructures.ContainsKey(asset.Type1))
{
str = asset.GetClassString();
}
else
{
str = Studio.GetScriptString(asset);
}
File.WriteAllText(exportFullName, str);
return true;
}

View File

@ -4,8 +4,10 @@ using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using dnlib.DotNet;
using static AssetStudio.Exporter;
namespace AssetStudio
@ -21,6 +23,8 @@ namespace AssetStudio
public static Dictionary<string, SortedDictionary<int, ClassStruct>> AllClassStructures = new Dictionary<string, SortedDictionary<int, ClassStruct>>();
public static string mainPath;
public static string productName = "";
public static bool moduleLoaded;
public static Dictionary<string, ModuleDef> LoadedModuleDic = new Dictionary<string, ModuleDef>();
//UI
public static Action<int> SetProgressBarValue;
@ -218,9 +222,17 @@ namespace AssetStudio
}
case ClassIDReference.MonoBehaviour:
{
var m_MonoBehaviour = new MonoBehaviour(asset, false);
if (asset.Type1 != asset.Type2 && assetsFile.ClassStructures.ContainsKey(asset.Type1))
exportable = true;
var m_MonoBehaviour = new MonoBehaviour(asset);
if (m_MonoBehaviour.m_Name == "" && assetsfileList.TryGetPD(m_MonoBehaviour.m_Script, out var script))
{
var m_Script = new MonoScript(script);
asset.Text = m_Script.m_ClassName;
}
else
{
asset.Text = m_MonoBehaviour.m_Name;
}
exportable = true;
break;
}
case ClassIDReference.Font:
@ -722,5 +734,257 @@ namespace AssetStudio
}
}
}
public static string GetScriptString(AssetPreloadData assetPreloadData)
{
if (!moduleLoaded)
{
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
}
}
moduleLoaded = true;
}
var m_MonoBehaviour = new MonoBehaviour(assetPreloadData);
var sb = new StringBuilder();
sb.AppendLine("PPtr<GameObject> 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<MonoScript> 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}\"");
if (assetsfileList.TryGetPD(m_MonoBehaviour.m_Script, out var script))
{
var m_Script = new MonoScript(script);
if (!LoadedModuleDic.TryGetValue(m_Script.m_AssemblyName, out var module))
{
/*using (var openFileDialog = new OpenFileDialog())
{
openFileDialog.Title = $"Select {m_Script.m_AssemblyName}";
openFileDialog.FileName = m_Script.m_AssemblyName;
openFileDialog.Filter = $"{m_Script.m_AssemblyName}|{m_Script.m_AssemblyName}";
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
var moduleContext = new ModuleContext();
var asmResolver = new AssemblyResolver(moduleContext, true);
var resolver = new Resolver(asmResolver);
moduleContext.AssemblyResolver = asmResolver;
moduleContext.Resolver = resolver;
module = ModuleDefMD.Load(openFileDialog.FileName, moduleContext);
LoadedModule.Add(m_Script.m_AssemblyName, module);
}
else
{
return sb.ToString();
}
}*/
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, assetPreloadData.sourceFile, null, -1, true);
}
catch
{
sb = new StringBuilder();
sb.AppendLine("PPtr<GameObject> 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<MonoScript> 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.ToString();
}
private static void DumpType(TypeSig typeSig, StringBuilder sb, AssetsFile assetsFile, string name, int indent, bool isRoot = false)
{
var typeDef = typeSig.ToTypeDefOrRef().ResolveTypeDefThrow();
var reader = assetsFile.reader;
if (typeDef.IsPrimitive)
{
object value = null;
switch (typeDef.Name)
{
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;
}
reader.AlignStream(4);
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name} = {value}");
return;
}
if (typeDef.FullName == "System.String")
{
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name} = \"{reader.ReadAlignedString()}\"");
return;
}
if (typeDef.IsEnum)
{
sb.AppendLine($"{new string('\t', indent)}{typeDef.Name} {name} = {reader.ReadUInt32()}");
return;
}
if (typeSig is ArraySigBase)
{
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, assetsFile, "data", indent + 2);
}
return;
}
if (!isRoot && typeSig is GenericInstSig genericInstSig)
{
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}");
if (genericInstSig.GenericArguments.Count == 1) //vector
{
for (int i = 0; i < size; i++)
{
sb.AppendLine($"{new string('\t', indent + 2)}[{i}]");
DumpType(genericInstSig.GenericArguments[0], sb, assetsFile, "data", indent + 2);
}
}
else if (genericInstSig.GenericArguments.Count == 2) //map
{
for (int i = 0; i < size; i++)
{
sb.AppendLine($"{new string('\t', indent + 2)}[{i}]");
DumpType(genericInstSig.GenericArguments[0], sb, assetsFile, "first", indent + 2);
DumpType(genericInstSig.GenericArguments[1], sb, assetsFile, "second", indent + 2);
}
}
return;
}
if (indent != -1 && typeDef.FullName == "UnityEngine.Object")
{
var pptr = assetsFile.ReadPPtr();
sb.AppendLine($"{new string('\t', indent)}PPtr<{typeDef.Name}> {name} = {{fileID: {pptr.m_FileID}, pathID: {pptr.m_PathID}}}");
return;
}
if (indent != -1 && typeDef.BaseType != null && typeDef.BaseType.FullName != "System.Object")
{
var flag = false;
var type = typeDef;
while (true)
{
if (type.BaseType.FullName == "UnityEngine.Object")
{
flag = true;
break;
}
type = type.BaseType.ResolveTypeDefThrow();
if (type.BaseType == null)
{
break;
}
}
if (flag)
{
var pptr = assetsFile.ReadPPtr();
sb.AppendLine($"{new string('\t', indent)}PPtr<{typeDef.Name}> {name} = {{fileID: {pptr.m_FileID}, pathID: {pptr.m_PathID}}}");
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, assetsFile, null, indent, true);
}
if (indent != -1 && typeDef.BaseType.FullName != "System.Object")
{
DumpType(typeDef.BaseType.ToTypeSig(), sb, assetsFile, null, indent, true);
}
/*if (typeDef.FullName == "UnityEngine.AnimationCurve") //TODO
{
var AnimationCurve = new AnimationCurve<float>(reader, reader.ReadSingle, assetsFile.version);
}*/
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, assetsFile, fieldDef.Name, indent + 1);
}
}
else if ((fieldDef.Attributes & FieldAttributes.Static) == 0 && (fieldDef.Attributes & FieldAttributes.InitOnly) == 0)
{
DumpType(fieldDef.FieldType, sb, assetsFile, fieldDef.Name, indent + 1);
}
}
}
}
}
}