diff --git a/AssetStudio/AssetStudio.csproj b/AssetStudio/AssetStudio.csproj index 23e4f76..559390f 100644 --- a/AssetStudio/AssetStudio.csproj +++ b/AssetStudio/AssetStudio.csproj @@ -62,6 +62,8 @@ + + @@ -135,7 +137,6 @@ - diff --git a/AssetStudio/AssetsManager.cs b/AssetStudio/AssetsManager.cs index 0fdf0c1..01ca153 100644 --- a/AssetStudio/AssetsManager.cs +++ b/AssetStudio/AssetsManager.cs @@ -38,6 +38,7 @@ namespace AssetStudio importFiles.Add(file); importFilesHash.Add(Path.GetFileName(file).ToUpper()); } + Progress.Reset(); //use a for loop because list size can change for (var i = 0; i < importFiles.Count; i++) @@ -45,9 +46,13 @@ namespace AssetStudio LoadFile(importFiles[i]); Progress.Report(i + 1, importFiles.Count); } + importFiles.Clear(); importFilesHash.Clear(); assetsfileListHash.Clear(); + + ReadAssets(); + ProcessGameObject(); } private void LoadFile(string fullName) @@ -118,7 +123,6 @@ namespace AssetStudio var fileName = Path.GetFileName(fullName); if (!assetsfileListHash.Contains(fileName.ToUpper())) { - Logger.Info($"Loading {fileName}"); var assetsFile = new SerializedFile(this, fullName, reader); if (assetsFile.valid) { @@ -127,6 +131,7 @@ namespace AssetStudio { assetsFile.SetVersion(unityVersion); } + assetsFileList.Add(assetsFile); assetsfileListHash.Add(assetsFile.upperFileName); } @@ -140,7 +145,7 @@ namespace AssetStudio private void LoadBundleFile(string fullName, EndianBinaryReader reader, string parentPath = null) { var fileName = Path.GetFileName(fullName); - Logger.Info("Decompressing " + fileName); + Logger.Info("Loading " + fileName); var bundleFile = new BundleFile(reader, fullName); reader.Dispose(); foreach (var file in bundleFile.fileList) @@ -178,15 +183,166 @@ namespace AssetStudio { foreach (var assetsFile in assetsFileList) { + assetsFile.Objects.Clear(); assetsFile.reader.Close(); } assetsFileList.Clear(); + foreach (var resourceFileReader in resourceFileReaders) { resourceFileReader.Value.Close(); } resourceFileReaders.Clear(); + assetsFileIndexCache.Clear(); } + + private void ReadAssets() + { + Logger.Info("Read assets..."); + + var progressCount = assetsFileList.Sum(x => x.m_Objects.Count); + int i = 0; + Progress.Reset(); + foreach (var assetsFile in assetsFileList) + { + assetsFile.Objects = new Dictionary(assetsFile.m_Objects.Count); + foreach (var objectInfo in assetsFile.m_Objects) + { + var objectReader = new ObjectReader(assetsFile.reader, assetsFile, objectInfo); + switch (objectReader.type) + { + case ClassIDType.Animation: + assetsFile.Objects.Add(objectInfo.m_PathID, new Animation(objectReader)); + break; + case ClassIDType.AnimationClip: + assetsFile.Objects.Add(objectInfo.m_PathID, new AnimationClip(objectReader)); + break; + case ClassIDType.Animator: + assetsFile.Objects.Add(objectInfo.m_PathID, new Animator(objectReader)); + break; + case ClassIDType.AnimatorController: + assetsFile.Objects.Add(objectInfo.m_PathID, new AnimatorController(objectReader)); + break; + case ClassIDType.AnimatorOverrideController: + assetsFile.Objects.Add(objectInfo.m_PathID, new AnimatorOverrideController(objectReader)); + break; + case ClassIDType.AssetBundle: + assetsFile.Objects.Add(objectInfo.m_PathID, new AssetBundle(objectReader)); + break; + case ClassIDType.AudioClip: + assetsFile.Objects.Add(objectInfo.m_PathID, new AudioClip(objectReader)); + break; + case ClassIDType.Avatar: + assetsFile.Objects.Add(objectInfo.m_PathID, new Avatar(objectReader)); + break; + case ClassIDType.Font: + assetsFile.Objects.Add(objectInfo.m_PathID, new Font(objectReader)); + break; + case ClassIDType.GameObject: + assetsFile.Objects.Add(objectInfo.m_PathID, new GameObject(objectReader)); + break; + case ClassIDType.Material: + assetsFile.Objects.Add(objectInfo.m_PathID, new Material(objectReader)); + break; + case ClassIDType.Mesh: + assetsFile.Objects.Add(objectInfo.m_PathID, new Mesh(objectReader)); + break; + case ClassIDType.MeshFilter: + assetsFile.Objects.Add(objectInfo.m_PathID, new MeshFilter(objectReader)); + break; + case ClassIDType.MeshRenderer: + assetsFile.Objects.Add(objectInfo.m_PathID, new MeshRenderer(objectReader)); + break; + case ClassIDType.MonoBehaviour: + assetsFile.Objects.Add(objectInfo.m_PathID, new MonoBehaviour(objectReader)); + break; + case ClassIDType.MonoScript: + assetsFile.Objects.Add(objectInfo.m_PathID, new MonoScript(objectReader)); + break; + case ClassIDType.MovieTexture: + assetsFile.Objects.Add(objectInfo.m_PathID, new MovieTexture(objectReader)); + break; + case ClassIDType.PlayerSettings: + assetsFile.Objects.Add(objectInfo.m_PathID, new PlayerSettings(objectReader)); + break; + case ClassIDType.RectTransform: + assetsFile.Objects.Add(objectInfo.m_PathID, new RectTransform(objectReader)); + break; + case ClassIDType.Shader: + assetsFile.Objects.Add(objectInfo.m_PathID, new Shader(objectReader)); + break; + case ClassIDType.SkinnedMeshRenderer: + assetsFile.Objects.Add(objectInfo.m_PathID, new SkinnedMeshRenderer(objectReader)); + break; + case ClassIDType.Sprite: + assetsFile.Objects.Add(objectInfo.m_PathID, new Sprite(objectReader)); + break; + case ClassIDType.SpriteAtlas: + assetsFile.Objects.Add(objectInfo.m_PathID, new SpriteAtlas(objectReader)); + break; + case ClassIDType.TextAsset: + assetsFile.Objects.Add(objectInfo.m_PathID, new TextAsset(objectReader)); + break; + case ClassIDType.Texture2D: + assetsFile.Objects.Add(objectInfo.m_PathID, new Texture2D(objectReader)); + break; + case ClassIDType.Transform: + assetsFile.Objects.Add(objectInfo.m_PathID, new Transform(objectReader)); + break; + case ClassIDType.VideoClip: + assetsFile.Objects.Add(objectInfo.m_PathID, new VideoClip(objectReader)); + break; + default: + assetsFile.Objects.Add(objectInfo.m_PathID, new Object(objectReader)); + break; + } + + Progress.Report(++i, progressCount); + } + } + } + + private void ProcessGameObject() + { + Logger.Info("Process GameObject..."); + + foreach (var assetsFile in assetsFileList) + { + foreach (var obj in assetsFile.Objects.Values) + { + if (obj is GameObject m_GameObject) + { + foreach (var pptr in m_GameObject.m_Components) + { + if (pptr.TryGet(out var m_Component)) + { + switch (m_Component) + { + case Transform m_Transform: + m_GameObject.m_Transform = m_Transform; + break; + case MeshRenderer m_MeshRenderer: + m_GameObject.m_MeshRenderer = m_MeshRenderer; + break; + case MeshFilter m_MeshFilter: + m_GameObject.m_MeshFilter = m_MeshFilter; + break; + case SkinnedMeshRenderer m_SkinnedMeshRenderer: + m_GameObject.m_SkinnedMeshRenderer = m_SkinnedMeshRenderer; + break; + case Animator m_Animator: + m_GameObject.m_Animator = m_Animator; + break; + case Animation m_Animation: + m_GameObject.m_Animation = m_Animation; + break; + } + } + } + } + } + } + } } -} +} \ No newline at end of file diff --git a/AssetStudio/Classes/Animation.cs b/AssetStudio/Classes/Animation.cs index f206a6e..624fbe1 100644 --- a/AssetStudio/Classes/Animation.cs +++ b/AssetStudio/Classes/Animation.cs @@ -7,16 +7,16 @@ namespace AssetStudio { public sealed class Animation : Behaviour { - public List m_Animations; + public List> m_Animations; public Animation(ObjectReader reader) : base(reader) { - var m_Animation = reader.ReadPPtr(); + var m_Animation = new PPtr(reader); int numAnimations = reader.ReadInt32(); - m_Animations = new List(numAnimations); + m_Animations = new List>(numAnimations); for (int i = 0; i < numAnimations; i++) { - m_Animations.Add(reader.ReadPPtr()); + m_Animations.Add(new PPtr(reader)); } } } diff --git a/AssetStudio/Classes/AnimationClip.cs b/AssetStudio/Classes/AnimationClip.cs index 38f9559..6bdc653 100644 --- a/AssetStudio/Classes/AnimationClip.cs +++ b/AssetStudio/Classes/AnimationClip.cs @@ -293,7 +293,7 @@ namespace AssetStudio public string attribute; public string path; public int classID; - public PPtr script; + public PPtr script; public FloatCurve(ObjectReader reader) @@ -302,20 +302,20 @@ namespace AssetStudio attribute = reader.ReadAlignedString(); path = reader.ReadAlignedString(); classID = reader.ReadInt32(); - script = reader.ReadPPtr(); + script = new PPtr(reader); } } public class PPtrKeyframe { public float time; - public PPtr value; + public PPtr value; public PPtrKeyframe(ObjectReader reader) { time = reader.ReadSingle(); - value = reader.ReadPPtr(); + value = new PPtr(reader); } } @@ -325,7 +325,7 @@ namespace AssetStudio public string attribute; public string path; public int classID; - public PPtr script; + public PPtr script; public PPtrCurve(ObjectReader reader) @@ -340,7 +340,7 @@ namespace AssetStudio attribute = reader.ReadAlignedString(); path = reader.ReadAlignedString(); classID = reader.ReadInt32(); - script = reader.ReadPPtr(); + script = new PPtr(reader); } } @@ -757,7 +757,7 @@ namespace AssetStudio { public uint path; public uint attribute; - public PPtr script; + public PPtr script; public ClassIDType typeID; public byte customType; public byte isPPtrCurve; @@ -767,7 +767,7 @@ namespace AssetStudio var version = reader.version; path = reader.ReadUInt32(); attribute = reader.ReadUInt32(); - script = reader.ReadPPtr(); + script = new PPtr(reader); if (version[0] > 5 || (version[0] == 5 && version[1] >= 6)) //5.6 and up { typeID = (ClassIDType)reader.ReadInt32(); @@ -785,7 +785,7 @@ namespace AssetStudio public class AnimationClipBindingConstant { public List genericBindings; - public List pptrCurveMapping; + public List> pptrCurveMapping; public AnimationClipBindingConstant(ObjectReader reader) { @@ -797,10 +797,10 @@ namespace AssetStudio } int numMappings = reader.ReadInt32(); - pptrCurveMapping = new List(numMappings); + pptrCurveMapping = new List>(numMappings); for (int i = 0; i < numMappings; i++) { - pptrCurveMapping.Add(reader.ReadPPtr()); + pptrCurveMapping.Add(new PPtr(reader)); } } diff --git a/AssetStudio/Classes/Animator.cs b/AssetStudio/Classes/Animator.cs index 1acc45e..2e97717 100644 --- a/AssetStudio/Classes/Animator.cs +++ b/AssetStudio/Classes/Animator.cs @@ -7,14 +7,14 @@ namespace AssetStudio { public sealed class Animator : Behaviour { - public PPtr m_Avatar; - public PPtr m_Controller; + public PPtr m_Avatar; + public PPtr m_Controller; public bool m_HasTransformHierarchy; public Animator(ObjectReader reader) : base(reader) { - m_Avatar = reader.ReadPPtr(); - m_Controller = reader.ReadPPtr(); + m_Avatar = new PPtr(reader); + m_Controller = new PPtr(reader); var m_CullingMode = reader.ReadInt32(); if (version[0] > 4 || (version[0] == 4 && version[1] >= 5)) //4.5 and up diff --git a/AssetStudio/Classes/AnimatorController.cs b/AssetStudio/Classes/AnimatorController.cs index 7bbacfd..958978b 100644 --- a/AssetStudio/Classes/AnimatorController.cs +++ b/AssetStudio/Classes/AnimatorController.cs @@ -531,9 +531,9 @@ namespace AssetStudio } } - public sealed class AnimatorController : NamedObject + public sealed class AnimatorController : RuntimeAnimatorController { - public PPtr[] m_AnimationClips; + public PPtr[] m_AnimationClips; public AnimatorController(ObjectReader reader) : base(reader) { @@ -548,10 +548,10 @@ namespace AssetStudio } int numClips = reader.ReadInt32(); - m_AnimationClips = new PPtr[numClips]; + m_AnimationClips = new PPtr[numClips]; for (int i = 0; i < numClips; i++) { - m_AnimationClips[i] = reader.ReadPPtr(); + m_AnimationClips[i] = new PPtr(reader); } } } diff --git a/AssetStudio/Classes/AnimatorOverrideController.cs b/AssetStudio/Classes/AnimatorOverrideController.cs index 6f7d095..c55e0a8 100644 --- a/AssetStudio/Classes/AnimatorOverrideController.cs +++ b/AssetStudio/Classes/AnimatorOverrideController.cs @@ -7,24 +7,24 @@ namespace AssetStudio { public class AnimationClipOverride { - public PPtr m_OriginalClip; - public PPtr m_OverrideClip; + public PPtr m_OriginalClip; + public PPtr m_OverrideClip; public AnimationClipOverride(ObjectReader reader) { - m_OriginalClip = reader.ReadPPtr(); - m_OverrideClip = reader.ReadPPtr(); + m_OriginalClip = new PPtr(reader); + m_OverrideClip = new PPtr(reader); } } - public class AnimatorOverrideController : NamedObject + public sealed class AnimatorOverrideController : RuntimeAnimatorController { - public PPtr m_Controller; + public PPtr m_Controller; public List m_Clips; public AnimatorOverrideController(ObjectReader reader) : base(reader) { - m_Controller = reader.ReadPPtr(); + m_Controller = new PPtr(reader); int numOverrides = reader.ReadInt32(); m_Clips = new List(numOverrides); diff --git a/AssetStudio/Classes/AssetBundle.cs b/AssetStudio/Classes/AssetBundle.cs index 5ab7db1..116e765 100644 --- a/AssetStudio/Classes/AssetBundle.cs +++ b/AssetStudio/Classes/AssetBundle.cs @@ -9,28 +9,28 @@ namespace AssetStudio { public int preloadIndex; public int preloadSize; - public PPtr asset; + public PPtr asset; public AssetInfo(ObjectReader reader) { preloadIndex = reader.ReadInt32(); preloadSize = reader.ReadInt32(); - asset = reader.ReadPPtr(); + asset = new PPtr(reader); } } public sealed class AssetBundle : NamedObject { - public List m_PreloadTable; + public List> m_PreloadTable; public List> m_Container; public AssetBundle(ObjectReader reader) : base(reader) { var m_PreloadTableSize = reader.ReadInt32(); - m_PreloadTable = new List(m_PreloadTableSize); + m_PreloadTable = new List>(m_PreloadTableSize); for (int i = 0; i < m_PreloadTableSize; i++) { - m_PreloadTable.Add(reader.ReadPPtr()); + m_PreloadTable.Add(new PPtr(reader)); } var m_ContainerSize = reader.ReadInt32(); diff --git a/AssetStudio/Classes/AudioClip.cs b/AssetStudio/Classes/AudioClip.cs index 74d49cc..bbfdf50 100644 --- a/AssetStudio/Classes/AudioClip.cs +++ b/AssetStudio/Classes/AudioClip.cs @@ -29,9 +29,9 @@ namespace AssetStudio public string m_Source; public long m_Offset; public long m_Size; - public byte[] m_AudioData; + public Lazy m_AudioData; - public AudioClip(ObjectReader reader, bool readData) : base(reader) + public AudioClip(ObjectReader reader) : base(reader) { if (version[0] < 5) { @@ -49,7 +49,7 @@ namespace AssetStudio if (reader.byteSize + reader.byteStart - reader.Position != tsize) { m_Offset = reader.ReadInt32(); - m_Source = sourceFile.fullName + ".resS"; + m_Source = assetsFile.fullName + ".resS"; } } else @@ -79,18 +79,16 @@ namespace AssetStudio m_CompressionFormat = (AudioCompressionFormat)reader.ReadInt32(); } - if (readData) + ResourceReader resourceReader; + if (!string.IsNullOrEmpty(m_Source)) { - if (!string.IsNullOrEmpty(m_Source)) - { - m_AudioData = ResourcesHelper.GetData(m_Source, sourceFile, m_Offset, (int)m_Size); - } - else - { - if (m_Size > 0) - m_AudioData = reader.ReadBytes((int)m_Size); - } + resourceReader = new ResourceReader(m_Source, assetsFile, m_Offset, (int)m_Size); } + else + { + resourceReader = new ResourceReader(reader, reader.BaseStream.Position, (int)m_Size); + } + m_AudioData = new Lazy(resourceReader.GetData); } } diff --git a/AssetStudio/Classes/Component.cs b/AssetStudio/Classes/Component.cs index 7a03952..99f30e7 100644 --- a/AssetStudio/Classes/Component.cs +++ b/AssetStudio/Classes/Component.cs @@ -7,11 +7,11 @@ namespace AssetStudio { public abstract class Component : EditorExtension { - public PPtr m_GameObject; + public PPtr m_GameObject; protected Component(ObjectReader reader) : base(reader) { - m_GameObject = reader.ReadPPtr(); + m_GameObject = new PPtr(reader); } } } diff --git a/AssetStudio/Classes/EditorExtension.cs b/AssetStudio/Classes/EditorExtension.cs index 7554588..1605f2c 100644 --- a/AssetStudio/Classes/EditorExtension.cs +++ b/AssetStudio/Classes/EditorExtension.cs @@ -11,8 +11,8 @@ namespace AssetStudio { if (platform == BuildTarget.NoTarget) { - var m_PrefabParentObject = reader.ReadPPtr(); - var m_PrefabInternal = reader.ReadPPtr(); + var m_PrefabParentObject = new PPtr(reader); + var m_PrefabInternal = new PPtr(reader); //PPtr } } } diff --git a/AssetStudio/Classes/Font.cs b/AssetStudio/Classes/Font.cs index ed0e06e..bc1091e 100644 --- a/AssetStudio/Classes/Font.cs +++ b/AssetStudio/Classes/Font.cs @@ -14,9 +14,9 @@ namespace AssetStudio if ((version[0] == 5 && version[1] >= 5) || version[0] > 5)//5.5 and up { var m_LineSpacing = reader.ReadSingle(); - var m_DefaultMaterial = reader.ReadPPtr(); + var m_DefaultMaterial = new PPtr(reader); var m_FontSize = reader.ReadSingle(); - var m_Texture = reader.ReadPPtr(); + var m_Texture = new PPtr(reader); int m_AsciiStartOffset = reader.ReadInt32(); var m_Tracking = reader.ReadSingle(); var m_CharacterSpacing = reader.ReadInt32(); @@ -68,7 +68,7 @@ namespace AssetStudio } int m_ConvertCase = reader.ReadInt32(); - PPtr m_DefaultMaterial = reader.ReadPPtr(); + var m_DefaultMaterial = new PPtr(reader); int m_CharacterRects_size = reader.ReadInt32(); for (int i = 0; i < m_CharacterRects_size; i++) @@ -93,7 +93,7 @@ namespace AssetStudio } } - PPtr m_Texture = reader.ReadPPtr(); + var m_Texture = new PPtr(reader); int m_KerningValues_size = reader.ReadInt32(); for (int i = 0; i < m_KerningValues_size; i++) diff --git a/AssetStudio/Classes/GameObject.cs b/AssetStudio/Classes/GameObject.cs index 104f56c..62fdc59 100644 --- a/AssetStudio/Classes/GameObject.cs +++ b/AssetStudio/Classes/GameObject.cs @@ -7,28 +7,30 @@ namespace AssetStudio { public sealed class GameObject : EditorExtension { - public List m_Components; + public List> m_Components; public string m_Name; - public PPtr m_Transform; - public PPtr m_MeshRenderer; - public PPtr m_MeshFilter; - public PPtr m_SkinnedMeshRenderer; - public PPtr m_Animator; + + public Transform m_Transform; + public MeshRenderer m_MeshRenderer; + public MeshFilter m_MeshFilter; + public SkinnedMeshRenderer m_SkinnedMeshRenderer; + public Animator m_Animator; + public Animation m_Animation; public GameObject(ObjectReader reader) : base(reader) { int m_Component_size = reader.ReadInt32(); - m_Components = new List(m_Component_size); + m_Components = new List>(m_Component_size); for (int j = 0; j < m_Component_size; j++) { - if ((version[0] == 5 && version[1] >= 5) || version[0] > 5)//5.5.0 and up + if ((version[0] == 5 && version[1] >= 5) || version[0] > 5) //5.5.0 and up { - m_Components.Add(reader.ReadPPtr()); + m_Components.Add(new PPtr(reader)); } else { int first = reader.ReadInt32(); - m_Components.Add(reader.ReadPPtr()); + m_Components.Add(new PPtr(reader)); } } diff --git a/AssetStudio/Classes/Material.cs b/AssetStudio/Classes/Material.cs index e9fd858..1706524 100644 --- a/AssetStudio/Classes/Material.cs +++ b/AssetStudio/Classes/Material.cs @@ -8,7 +8,7 @@ namespace AssetStudio public class TexEnv { public string name; - public PPtr m_Texture; + public PPtr m_Texture; public float[] m_Scale; public float[] m_Offset; } @@ -27,7 +27,7 @@ namespace AssetStudio public sealed class Material : NamedObject { - public PPtr m_Shader; + public PPtr m_Shader; public string[] m_ShaderKeywords; public int m_CustomRenderQueue; public TexEnv[] m_TexEnvs; @@ -36,7 +36,7 @@ namespace AssetStudio public Material(ObjectReader reader) : base(reader) { - m_Shader = reader.ReadPPtr(); + m_Shader = new PPtr(reader); if (version[0] == 4 && (version[1] >= 2 || (version[1] == 1 && !buildType.IsAlpha))) { @@ -84,7 +84,7 @@ namespace AssetStudio TexEnv m_TexEnv = new TexEnv() { name = reader.ReadAlignedString(), - m_Texture = reader.ReadPPtr(), + m_Texture = new PPtr(reader), m_Scale = new[] { reader.ReadSingle(), reader.ReadSingle() }, m_Offset = new[] { reader.ReadSingle(), reader.ReadSingle() } }; diff --git a/AssetStudio/Classes/Mesh.cs b/AssetStudio/Classes/Mesh.cs index 4469017..43f33c4 100644 --- a/AssetStudio/Classes/Mesh.cs +++ b/AssetStudio/Classes/Mesh.cs @@ -351,7 +351,7 @@ namespace AssetStudio bool m_IsReadable = reader.ReadBoolean(); bool m_KeepVertices = reader.ReadBoolean(); bool m_KeepIndices = reader.ReadBoolean(); - if (reader.HasStructMember("m_UsedForStaticMeshColliderOnly")) + if (HasStructMember("m_UsedForStaticMeshColliderOnly")) { var m_UsedForStaticMeshColliderOnly = reader.ReadBoolean(); } diff --git a/AssetStudio/Classes/MeshFilter.cs b/AssetStudio/Classes/MeshFilter.cs index 95ea684..5db6140 100644 --- a/AssetStudio/Classes/MeshFilter.cs +++ b/AssetStudio/Classes/MeshFilter.cs @@ -8,11 +8,11 @@ namespace AssetStudio public sealed class MeshFilter : Component { public long preloadIndex; - public PPtr m_Mesh; + public PPtr m_Mesh; public MeshFilter(ObjectReader reader) : base(reader) { - m_Mesh = reader.ReadPPtr(); + m_Mesh = new PPtr(reader); } } } diff --git a/AssetStudio/Classes/MonoBehaviour.cs b/AssetStudio/Classes/MonoBehaviour.cs index 5e3d931..7657919 100644 --- a/AssetStudio/Classes/MonoBehaviour.cs +++ b/AssetStudio/Classes/MonoBehaviour.cs @@ -7,12 +7,12 @@ namespace AssetStudio { public sealed class MonoBehaviour : Behaviour { - public PPtr m_Script; + public PPtr m_Script; public string m_Name; public MonoBehaviour(ObjectReader reader) : base(reader) { - m_Script = reader.ReadPPtr(); + m_Script = new PPtr(reader); m_Name = reader.ReadAlignedString(); } } diff --git a/AssetStudio/Classes/MovieTexture.cs b/AssetStudio/Classes/MovieTexture.cs index 7c7bcd3..9cdc42f 100644 --- a/AssetStudio/Classes/MovieTexture.cs +++ b/AssetStudio/Classes/MovieTexture.cs @@ -8,13 +8,13 @@ namespace AssetStudio public sealed class MovieTexture : Texture { public byte[] m_MovieData; + public PPtr m_AudioClip; public MovieTexture(ObjectReader reader) : base(reader) { var m_Loop = reader.ReadBoolean(); reader.AlignStream(4); - //PPtr - reader.ReadPPtr(); + m_AudioClip = new PPtr(reader); m_MovieData = reader.ReadBytes(reader.ReadInt32()); } } diff --git a/AssetStudio/Classes/NamedObject.cs b/AssetStudio/Classes/NamedObject.cs index c91b2ce..d43db4e 100644 --- a/AssetStudio/Classes/NamedObject.cs +++ b/AssetStudio/Classes/NamedObject.cs @@ -9,7 +9,7 @@ namespace AssetStudio { public string m_Name; - public NamedObject(ObjectReader reader) : base(reader) + protected NamedObject(ObjectReader reader) : base(reader) { m_Name = reader.ReadAlignedString(); } diff --git a/AssetStudio/Classes/Object.cs b/AssetStudio/Classes/Object.cs index 0b9aa67..039bd57 100644 --- a/AssetStudio/Classes/Object.cs +++ b/AssetStudio/Classes/Object.cs @@ -5,27 +5,58 @@ using System.Text; namespace AssetStudio { - public abstract class Object + public class Object { - protected SerializedFile sourceFile; + public SerializedFile assetsFile; public ObjectReader reader; + public long m_PathID; public int[] version; protected BuildType buildType; public BuildTarget platform; + public ClassIDType type; + public SerializedType serializedType; + public uint byteSize; - protected Object(ObjectReader reader) + public Object(ObjectReader reader) { this.reader = reader; reader.Reset(); - sourceFile = reader.assetsFile; + assetsFile = reader.assetsFile; + type = reader.type; + m_PathID = reader.m_PathID; version = reader.version; buildType = reader.buildType; platform = reader.platform; + serializedType = reader.serializedType; + byteSize = reader.byteSize; if (platform == BuildTarget.NoTarget) { var m_ObjectHideFlags = reader.ReadUInt32(); } } + + protected bool HasStructMember(string name) + { + return serializedType?.m_Nodes != null && serializedType.m_Nodes.Any(x => x.m_Name == name); + } + + public string Dump() + { + reader.Reset(); + if (serializedType?.m_Nodes != null) + { + var sb = new StringBuilder(); + TypeTreeHelper.ReadTypeString(sb, serializedType.m_Nodes, reader); + return sb.ToString(); + } + return null; + } + + public byte[] GetRawData() + { + reader.Reset(); + return reader.ReadBytes((int)byteSize); + } } } diff --git a/AssetStudio/Classes/PPtr.cs b/AssetStudio/Classes/PPtr.cs index 69536e9..c84139a 100644 --- a/AssetStudio/Classes/PPtr.cs +++ b/AssetStudio/Classes/PPtr.cs @@ -1,12 +1,19 @@ namespace AssetStudio { - public class PPtr + public sealed class PPtr where T : Object { public int m_FileID; public long m_PathID; - public SerializedFile assetsFile; - public int index = -2; //-2 - Prepare, -1 - Missing + private SerializedFile assetsFile; + private int index = -2; //-2 - Prepare, -1 - Missing + + public PPtr(ObjectReader reader) + { + m_FileID = reader.ReadInt32(); + m_PathID = reader.m_Version < 14 ? reader.ReadInt32() : reader.ReadInt64(); + assetsFile = reader.assetsFile; + } private bool TryGetAssetsFile(out SerializedFile result) { @@ -20,7 +27,7 @@ if (m_FileID > 0 && m_FileID - 1 < assetsFile.m_Externals.Count) { var assetsManager = assetsFile.assetsManager; - var assetsfileList = assetsManager.assetsFileList; + var assetsFileList = assetsManager.assetsFileList; var assetsFileIndexCache = assetsManager.assetsFileIndexCache; if (index == -2) @@ -29,14 +36,14 @@ var name = m_External.fileName.ToUpper(); if (!assetsFileIndexCache.TryGetValue(name, out index)) { - index = assetsfileList.FindIndex(x => x.upperFileName == name); + index = assetsFileList.FindIndex(x => x.upperFileName == name); assetsFileIndexCache.Add(name, index); } } if (index >= 0) { - result = assetsfileList[index]; + result = assetsFileList[index]; return true; } } @@ -44,45 +51,39 @@ return false; } - public bool TryGet(out ObjectReader result) + public bool TryGet(out T result) { + if (TryGetAssetsFile(out var sourceFile)) + { + if (sourceFile.Objects.TryGetValue(m_PathID, out var obj)) + { + if (obj is T variable) + { + result = variable; + return true; + } + } + } + result = null; - if (TryGetAssetsFile(out var sourceFile)) - { - if (sourceFile.ObjectReaders.TryGetValue(m_PathID, out result)) - { - return true; - } - } - return false; } - public bool TryGetTransform(out Transform m_Transform) + public bool TryGet(out T2 result) where T2 : Object { if (TryGetAssetsFile(out var sourceFile)) { - if (sourceFile.Transforms.TryGetValue(m_PathID, out m_Transform)) + if (sourceFile.Objects.TryGetValue(m_PathID, out var obj)) { - return true; + if (obj is T2 variable) + { + result = variable; + return true; + } } } - m_Transform = null; - return false; - } - - public bool TryGetGameObject(out GameObject m_GameObject) - { - if (TryGetAssetsFile(out var sourceFile)) - { - if (sourceFile.GameObjects.TryGetValue(m_PathID, out m_GameObject)) - { - return true; - } - } - - m_GameObject = null; + result = null; return false; } } diff --git a/AssetStudio/Classes/Renderer.cs b/AssetStudio/Classes/Renderer.cs index 662c20e..2321031 100644 --- a/AssetStudio/Classes/Renderer.cs +++ b/AssetStudio/Classes/Renderer.cs @@ -13,7 +13,7 @@ namespace AssetStudio public abstract class Renderer : Component { - public PPtr[] m_Materials; + public PPtr[] m_Materials; public StaticBatchInfo m_StaticBatchInfo; public uint[] m_SubsetIndices; @@ -51,10 +51,10 @@ namespace AssetStudio reader.Position += 16;//Vector4f m_LightmapTilingOffsetDynamic } - m_Materials = new PPtr[reader.ReadInt32()]; + m_Materials = new PPtr[reader.ReadInt32()]; for (int m = 0; m < m_Materials.Length; m++) { - m_Materials[m] = reader.ReadPPtr(); + m_Materials[m] = new PPtr(reader); } if (version[0] < 3) @@ -77,12 +77,12 @@ namespace AssetStudio m_SubsetIndices = reader.ReadUInt32Array(numSubsetIndices); } - var m_StaticBatchRoot = reader.ReadPPtr(); + var m_StaticBatchRoot = new PPtr(reader); if ((version[0] == 5 && version[1] >= 4) || version[0] > 5)//5.4.0 and up { - var m_ProbeAnchor = reader.ReadPPtr(); - var m_LightProbeVolumeOverride = reader.ReadPPtr(); + var m_ProbeAnchor = new PPtr(reader); + var m_LightProbeVolumeOverride = new PPtr(reader); } else if (version[0] >= 4 || (version[0] == 3 && version[1] >= 5))//3.5 - 5.3 { @@ -92,7 +92,7 @@ namespace AssetStudio { int m_ReflectionProbeUsage = reader.ReadInt32(); } - var m_LightProbeAnchor = reader.ReadPPtr(); + var m_LightProbeAnchor = new PPtr(reader); } if (version[0] >= 5 || (version[0] == 4 && version[1] >= 3))//4.3 and up diff --git a/AssetStudio/Classes/RuntimeAnimatorController.cs b/AssetStudio/Classes/RuntimeAnimatorController.cs new file mode 100644 index 0000000..5b6be8f --- /dev/null +++ b/AssetStudio/Classes/RuntimeAnimatorController.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace AssetStudio +{ + public abstract class RuntimeAnimatorController : NamedObject + { + protected RuntimeAnimatorController(ObjectReader reader) : base(reader) + { + + } + } +} diff --git a/AssetStudio/Classes/SkinnedMeshRenderer.cs b/AssetStudio/Classes/SkinnedMeshRenderer.cs index 8bf6dda..6e8c5c3 100644 --- a/AssetStudio/Classes/SkinnedMeshRenderer.cs +++ b/AssetStudio/Classes/SkinnedMeshRenderer.cs @@ -7,8 +7,8 @@ namespace AssetStudio { public sealed class SkinnedMeshRenderer : Renderer { - public PPtr m_Mesh; - public PPtr[] m_Bones; + public PPtr m_Mesh; + public PPtr[] m_Bones; public List m_BlendShapeWeights; public SkinnedMeshRenderer(ObjectReader reader) : base(reader) @@ -20,15 +20,15 @@ namespace AssetStudio if (version[0] == 2 && version[1] < 6)//2.6 down { - var m_DisableAnimationWhenOffscreen = reader.ReadPPtr(); + var m_DisableAnimationWhenOffscreen = new PPtr(reader); } - m_Mesh = reader.ReadPPtr(); + m_Mesh = new PPtr(reader); - m_Bones = new PPtr[reader.ReadInt32()]; + m_Bones = new PPtr[reader.ReadInt32()]; for (int b = 0; b < m_Bones.Length; b++) { - m_Bones[b] = reader.ReadPPtr(); + m_Bones[b] = new PPtr(reader); } if (version[0] < 3) diff --git a/AssetStudio/Classes/Sprite.cs b/AssetStudio/Classes/Sprite.cs index 1b7b28c..7b0c071 100644 --- a/AssetStudio/Classes/Sprite.cs +++ b/AssetStudio/Classes/Sprite.cs @@ -50,8 +50,8 @@ namespace AssetStudio public float m_PixelsToUnits; public Vector2 m_Pivot; public Tuple m_RenderDataKey; - public PPtr texture; - public PPtr m_SpriteAtlas; + public PPtr texture; + public PPtr m_SpriteAtlas; public RectangleF textureRect; public SpriteSettings settingsRaw; public PointF[][] m_PhysicsShape; //Vector2[][] @@ -98,16 +98,16 @@ namespace AssetStudio } //PPtr m_SpriteAtlas - m_SpriteAtlas = reader.ReadPPtr(); + m_SpriteAtlas = new PPtr(reader); } //SpriteRenderData m_RD // PPtr texture - texture = reader.ReadPPtr(); + texture = new PPtr(reader); // PPtr alphaTexture if (version[0] > 5 || (version[0] == 5 && version[1] >= 2)) //5.2 and up { - var alphaTexture = reader.ReadPPtr(); + var alphaTexture = new PPtr(reader); } if (version[0] > 5 || (version[0] == 5 && version[1] >= 6)) //5.6 and up diff --git a/AssetStudio/Classes/SpriteAtlas.cs b/AssetStudio/Classes/SpriteAtlas.cs index a5c0ca3..0f52ea3 100644 --- a/AssetStudio/Classes/SpriteAtlas.cs +++ b/AssetStudio/Classes/SpriteAtlas.cs @@ -9,8 +9,8 @@ namespace AssetStudio { public class SpriteAtlasData { - public PPtr texture; - public PPtr alphaTexture; + public PPtr texture; + public PPtr alphaTexture; public System.Drawing.RectangleF textureRect; public Vector2 textureRectOffset; public Vector2 atlasRectOffset; @@ -21,8 +21,8 @@ namespace AssetStudio public SpriteAtlasData(ObjectReader reader) { var version = reader.version; - texture = reader.ReadPPtr(); - alphaTexture = reader.ReadPPtr(); + texture = new PPtr(reader); + alphaTexture = new PPtr(reader); textureRect = reader.ReadRectangleF(); textureRectOffset = reader.ReadVector2(); if (version[0] > 2017 || (version[0] == 2017 && version[1] >= 2)) //2017.2 and up @@ -44,7 +44,7 @@ namespace AssetStudio var m_PackedSpritesSize = reader.ReadInt32(); for (int i = 0; i < m_PackedSpritesSize; i++) { - reader.ReadPPtr(); //PPtr data + new PPtr(reader); } var m_PackedSpriteNamesToIndexSize = reader.ReadInt32(); diff --git a/AssetStudio/Classes/Texture2D.cs b/AssetStudio/Classes/Texture2D.cs index 8db39d5..89c6574 100644 --- a/AssetStudio/Classes/Texture2D.cs +++ b/AssetStudio/Classes/Texture2D.cs @@ -28,13 +28,13 @@ namespace AssetStudio public int m_ColorSpace; //image dataa public int image_data_size; - public byte[] image_data; + public Lazy image_data; //m_StreamData public uint offset; public uint size; public string path; - public Texture2D(ObjectReader reader, bool readData) : base(reader) + public Texture2D(ObjectReader reader) : base(reader) { m_Width = reader.ReadInt32(); m_Height = reader.ReadInt32(); @@ -58,11 +58,11 @@ namespace AssetStudio { var m_StreamingMipmapsPriority = reader.ReadInt32(); } - else if (reader.HasStructMember("m_StreamingMipmapsPriority")) //will fix in some patch version bundle + else if (HasStructMember("m_StreamingMipmapsPriority")) //will fix in some patch version bundle { var m_StreamingMipmapsPriority = reader.ReadInt32(); } - if (reader.HasStructMember("m_StreamingGroupID")) //What the hell is this? + if (HasStructMember("m_StreamingGroupID")) //What the hell is this? { var m_StreamingGroupID = reader.ReadUInt32(); } @@ -101,17 +101,16 @@ namespace AssetStudio path = reader.ReadAlignedString(); } - if (readData) + ResourceReader resourceReader; + if (!string.IsNullOrEmpty(path)) { - if (!string.IsNullOrEmpty(path)) - { - image_data = ResourcesHelper.GetData(path, sourceFile, offset, image_data_size); - } - else - { - image_data = reader.ReadBytes(image_data_size); - } + resourceReader = new ResourceReader(path, assetsFile, offset, image_data_size); } + else + { + resourceReader = new ResourceReader(reader, reader.BaseStream.Position, image_data_size); + } + image_data = new Lazy(resourceReader.GetData); } } diff --git a/AssetStudio/Classes/Transform.cs b/AssetStudio/Classes/Transform.cs index a6eeb1d..0f64f25 100644 --- a/AssetStudio/Classes/Transform.cs +++ b/AssetStudio/Classes/Transform.cs @@ -11,8 +11,8 @@ namespace AssetStudio public float[] m_LocalRotation; public float[] m_LocalPosition; public float[] m_LocalScale; - public List m_Children; - public PPtr m_Father; + public List> m_Children; + public PPtr m_Father; public Transform(ObjectReader reader) : base(reader) { @@ -20,12 +20,12 @@ namespace AssetStudio m_LocalPosition = new[] { reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle() }; m_LocalScale = new[] { reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle() }; int m_ChildrenCount = reader.ReadInt32(); - m_Children = new List(m_ChildrenCount); + m_Children = new List>(m_ChildrenCount); for (int j = 0; j < m_ChildrenCount; j++) { - m_Children.Add(reader.ReadPPtr()); + m_Children.Add(new PPtr(reader)); } - m_Father = reader.ReadPPtr(); + m_Father = new PPtr(reader); } } } diff --git a/AssetStudio/Classes/VideoClip.cs b/AssetStudio/Classes/VideoClip.cs index 59d8fb4..df69452 100644 --- a/AssetStudio/Classes/VideoClip.cs +++ b/AssetStudio/Classes/VideoClip.cs @@ -8,12 +8,12 @@ namespace AssetStudio { public sealed class VideoClip : NamedObject { - public byte[] m_VideoData; + public Lazy m_VideoData; public string m_OriginalPath; public string m_Source; public ulong m_Size; - public VideoClip(ObjectReader reader, bool readData) : base(reader) + public VideoClip(ObjectReader reader) : base(reader) { m_OriginalPath = reader.ReadAlignedString(); var m_ProxyWidth = reader.ReadUInt32(); @@ -47,18 +47,16 @@ namespace AssetStudio m_Size = reader.ReadUInt64(); var m_HasSplitAlpha = reader.ReadBoolean(); - if (readData) + ResourceReader resourceReader; + if (!string.IsNullOrEmpty(m_Source)) { - if (!string.IsNullOrEmpty(m_Source)) - { - m_VideoData = ResourcesHelper.GetData(m_Source, sourceFile, (long)m_Offset, (int)m_Size); - } - else - { - if (m_Size > 0) - m_VideoData = reader.ReadBytes((int)m_Size); - } + resourceReader = new ResourceReader(m_Source, assetsFile, (long)m_Offset, (int)m_Size); } + else + { + resourceReader = new ResourceReader(reader, reader.BaseStream.Position, (int)m_Size); + } + m_VideoData = new Lazy(resourceReader.GetData); } } } diff --git a/AssetStudio/ObjectInfo.cs b/AssetStudio/ObjectInfo.cs index 20644ad..c84876d 100644 --- a/AssetStudio/ObjectInfo.cs +++ b/AssetStudio/ObjectInfo.cs @@ -11,9 +11,7 @@ namespace AssetStudio public uint byteSize; public int typeID; public int classID; - public ushort isDestroyed; - //custom public long m_PathID; public SerializedType serializedType; } diff --git a/AssetStudio/ObjectReader.cs b/AssetStudio/ObjectReader.cs index 952ec21..50b5e4a 100644 --- a/AssetStudio/ObjectReader.cs +++ b/AssetStudio/ObjectReader.cs @@ -15,7 +15,7 @@ namespace AssetStudio public ClassIDType type; public SerializedType serializedType; public BuildTarget platform; - private uint m_Version; + public uint m_Version; public int[] version => assetsFile.version; public BuildType buildType => assetsFile.buildType; @@ -43,38 +43,5 @@ namespace AssetStudio { Position = byteStart; } - - public string Dump() - { - Reset(); - if (serializedType?.m_Nodes != null) - { - var sb = new StringBuilder(); - TypeTreeHelper.ReadTypeString(sb, serializedType.m_Nodes, this); - return sb.ToString(); - } - return null; - } - - public bool HasStructMember(string name) - { - return serializedType?.m_Nodes != null && serializedType.m_Nodes.Any(x => x.m_Name == name); - } - - public PPtr ReadPPtr() - { - return new PPtr - { - m_FileID = ReadInt32(), - m_PathID = m_Version < 14 ? ReadInt32() : ReadInt64(), - assetsFile = assetsFile - }; - } - - public byte[] GetRawData() - { - Reset(); - return ReadBytes((int)byteSize); - } } } diff --git a/AssetStudio/ResourceReader.cs b/AssetStudio/ResourceReader.cs new file mode 100644 index 0000000..86c9f8e --- /dev/null +++ b/AssetStudio/ResourceReader.cs @@ -0,0 +1,69 @@ +using System.IO; + +namespace AssetStudio +{ + public class ResourceReader + { + private bool needSearch; + private string path; + private SerializedFile assetsFile; + private long offset; + private int size; + private BinaryReader reader; + + + public ResourceReader(string path, SerializedFile assetsFile, long offset, int size) + { + needSearch = true; + this.path = path; + this.assetsFile = assetsFile; + this.offset = offset; + this.size = size; + } + + public ResourceReader(BinaryReader reader, long offset, int size) + { + this.reader = reader; + this.offset = offset; + this.size = size; + } + + public byte[] GetData() + { + if (needSearch) + { + var resourceFileName = Path.GetFileName(path); + + if (assetsFile.assetsManager.resourceFileReaders.TryGetValue(resourceFileName.ToUpper(), out var reader)) + { + reader.Position = offset; + return reader.ReadBytes(size); + } + + var currentDirectory = Path.GetDirectoryName(assetsFile.fullName); + var resourceFilePath = currentDirectory + "\\" + resourceFileName; + if (!File.Exists(resourceFilePath)) + { + var findFiles = Directory.GetFiles(currentDirectory, resourceFileName, SearchOption.AllDirectories); + if (findFiles.Length > 0) + { + resourceFilePath = findFiles[0]; + } + } + if (File.Exists(resourceFilePath)) + { + using (var resourceReader = new BinaryReader(File.OpenRead(resourceFilePath))) + { + resourceReader.BaseStream.Position = offset; + return resourceReader.ReadBytes(size); + } + } + + throw new FileNotFoundException($"Can't find the resource file {resourceFileName}"); + } + + reader.BaseStream.Position = offset; + return reader.ReadBytes(size); + } + } +} diff --git a/AssetStudio/ResourcesHelper.cs b/AssetStudio/ResourcesHelper.cs deleted file mode 100644 index bdc5e24..0000000 --- a/AssetStudio/ResourcesHelper.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; - -namespace AssetStudio -{ - internal static class ResourcesHelper - { - public static byte[] GetData(string path, SerializedFile assetsFile, long offset, int size) - { - var resourceFileName = Path.GetFileName(path); - - if (assetsFile.assetsManager.resourceFileReaders.TryGetValue(resourceFileName.ToUpper(), out var reader)) - { - reader.Position = offset; - return reader.ReadBytes(size); - } - - var currentDirectory = Path.GetDirectoryName(assetsFile.fullName); - var resourceFilePath = currentDirectory + "\\" + resourceFileName; - if (!File.Exists(resourceFilePath)) - { - var findFiles = Directory.GetFiles(currentDirectory, resourceFileName, SearchOption.AllDirectories); - if (findFiles.Length > 0) - { - resourceFilePath = findFiles[0]; - } - } - if (File.Exists(resourceFilePath)) - { - using (var resourceReader = new BinaryReader(File.OpenRead(resourceFilePath))) - { - resourceReader.BaseStream.Position = offset; - return resourceReader.ReadBytes(size); - } - } - - throw new FileNotFoundException($"Can't find the resource file {resourceFileName}"); - } - } -} diff --git a/AssetStudio/SerializedFile.cs b/AssetStudio/SerializedFile.cs index f64095c..9d1bdab 100644 --- a/AssetStudio/SerializedFile.cs +++ b/AssetStudio/SerializedFile.cs @@ -17,9 +17,7 @@ namespace AssetStudio public int[] version = { 0, 0, 0, 0 }; public BuildType buildType; public bool valid; - public Dictionary ObjectReaders = new Dictionary(); - public Dictionary GameObjects = new Dictionary(); - public Dictionary Transforms = new Dictionary(); + public Dictionary Objects; public SerializedFileHeader header; private EndianType m_FileEndianess; @@ -27,7 +25,7 @@ namespace AssetStudio public BuildTarget m_TargetPlatform = BuildTarget.UnknownPlatform; private bool m_EnableTypeTree = true; public List m_Types; - private List m_Objects; + public List m_Objects; private List m_ScriptTypes; public List m_Externals; @@ -118,7 +116,7 @@ namespace AssetStudio { objectInfo.classID = reader.ReadUInt16(); objectInfo.serializedType = m_Types.Find(x => x.classID == objectInfo.typeID); - objectInfo.isDestroyed = reader.ReadUInt16(); + var isDestroyed = reader.ReadUInt16(); } else { @@ -131,10 +129,6 @@ namespace AssetStudio var stripped = reader.ReadByte(); } m_Objects.Add(objectInfo); - - //Create Reader - var objectReader = new ObjectReader(reader, this, objectInfo); - ObjectReaders.Add(objectInfo.m_PathID, objectReader); } if (header.m_Version >= 11) diff --git a/AssetStudio/TypeTreeHelper.cs b/AssetStudio/TypeTreeHelper.cs index f85546b..3391844 100644 --- a/AssetStudio/TypeTreeHelper.cs +++ b/AssetStudio/TypeTreeHelper.cs @@ -8,7 +8,7 @@ namespace AssetStudio { public static class TypeTreeHelper { - public static void ReadTypeString(StringBuilder sb, List members, EndianBinaryReader reader) + public static void ReadTypeString(StringBuilder sb, List members, BinaryReader reader) { for (int i = 0; i < members.Count; i++) { @@ -16,7 +16,7 @@ namespace AssetStudio } } - private static void ReadStringValue(StringBuilder sb, List members, EndianBinaryReader reader, ref int i) + private static void ReadStringValue(StringBuilder sb, List members, BinaryReader reader, ref int i) { var member = members[i]; var level = member.m_Level; @@ -153,7 +153,7 @@ namespace AssetStudio reader.AlignStream(4); } - public static Dictionary ReadBoxingType(List members, EndianBinaryReader reader) + public static Dictionary ReadBoxingType(List members, BinaryReader reader) { var obj = new Dictionary(); for (int i = 0; i < members.Count; i++) @@ -165,7 +165,7 @@ namespace AssetStudio return obj; } - private static object ReadValue(List members, EndianBinaryReader reader, ref int i) + private static object ReadValue(List members, BinaryReader reader, ref int i) { var member = members[i]; var level = member.m_Level; diff --git a/AssetStudioGUI/AssetStudioGUIForm.cs b/AssetStudioGUI/AssetStudioGUIForm.cs index d18b82e..635c155 100644 --- a/AssetStudioGUI/AssetStudioGUIForm.cs +++ b/AssetStudioGUI/AssetStudioGUIForm.cs @@ -15,6 +15,8 @@ using OpenTK; using OpenTK.Graphics.OpenGL; using AssetStudio; using static AssetStudioGUI.Studio; +using Object = AssetStudio.Object; +using Font = AssetStudio.Font; namespace AssetStudioGUI { @@ -134,13 +136,13 @@ namespace AssetStudioGUI } var productName = string.Empty; - var tempDic = new Dictionary(); + var tempDic = new Dictionary(); if (!dontLoadAssetsMenuItem.Checked) { BuildAssetList(tempDic, displayAll.Checked, displayOriginalName.Checked, out productName); } - List treeNodeCollection = null; + List treeNodeCollection = null; if (!dontBuildHierarchyMenuItem.Checked) { treeNodeCollection = BuildTreeStructure(tempDic); @@ -651,457 +653,459 @@ namespace AssetStudioGUI } } - private void PreviewAsset(AssetItem asset) + private void PreviewAsset(AssetItem assetItem) { - var reader = asset.reader; try { - switch (asset.Type) + switch (assetItem.Asset) { - case ClassIDType.Texture2D: + case Texture2D m_Texture2D: + PreviewTexture2D(assetItem, m_Texture2D); + break; + case AudioClip m_AudioClip: + PreviewAudioClip(assetItem, m_AudioClip); + break; + case Shader m_Shader: + PreviewShader(m_Shader); + break; + case TextAsset m_TextAsset: + PreviewTextAsset(m_TextAsset); + break; + case MonoBehaviour m_MonoBehaviour: + PreviewMonoBehaviour(m_MonoBehaviour); + break; + case Font m_Font: + PreviewFont(m_Font); + break; + case Mesh m_Mesh: + PreviewMesh(m_Mesh); + break; + case VideoClip _: + case MovieTexture _: + StatusStripUpdate("Only supported export."); + break; + case Sprite m_Sprite: + PreviewSprite(assetItem, m_Sprite); + break; + case Animator _: + StatusStripUpdate("Can be exported to FBX file."); + break; + case AnimationClip _: + StatusStripUpdate("Can be exported with Animator or Objects"); + break; + default: + var str = assetItem.Asset.Dump(); + if (str != null) { - imageTexture?.Dispose(); - var m_Texture2D = new Texture2D(reader, true); - - //Info - asset.InfoText = $"Width: {m_Texture2D.m_Width}\nHeight: {m_Texture2D.m_Height}\nFormat: {m_Texture2D.m_TextureFormat}"; - switch (m_Texture2D.m_FilterMode) - { - case 0: asset.InfoText += "\nFilter Mode: Point "; break; - case 1: asset.InfoText += "\nFilter Mode: Bilinear "; break; - case 2: asset.InfoText += "\nFilter Mode: Trilinear "; break; - } - asset.InfoText += $"\nAnisotropic level: {m_Texture2D.m_Aniso}\nMip map bias: {m_Texture2D.m_MipBias}"; - switch (m_Texture2D.m_WrapMode) - { - case 0: asset.InfoText += "\nWrap mode: Repeat"; break; - case 1: asset.InfoText += "\nWrap mode: Clamp"; break; - } - - var converter = new Texture2DConverter(m_Texture2D); - imageTexture = converter.ConvertToBitmap(true); - if (imageTexture != null) - { - previewPanel.BackgroundImage = imageTexture; - if (imageTexture.Width > previewPanel.Width || imageTexture.Height > previewPanel.Height) - previewPanel.BackgroundImageLayout = ImageLayout.Zoom; - else - previewPanel.BackgroundImageLayout = ImageLayout.Center; - } - else - { - StatusStripUpdate("Unsupported image for preview"); - } - break; - } - case ClassIDType.AudioClip: - { - var m_AudioClip = new AudioClip(reader, true); - - //Info - asset.InfoText = "Compression format: "; - if (m_AudioClip.version[0] < 5) - { - switch (m_AudioClip.m_Type) - { - case AudioType.ACC: - asset.InfoText += "Acc"; - break; - case AudioType.AIFF: - asset.InfoText += "AIFF"; - break; - case AudioType.IT: - asset.InfoText += "Impulse tracker"; - break; - case AudioType.MOD: - asset.InfoText += "Protracker / Fasttracker MOD"; - break; - case AudioType.MPEG: - asset.InfoText += "MP2/MP3 MPEG"; - break; - case AudioType.OGGVORBIS: - asset.InfoText += "Ogg vorbis"; - break; - case AudioType.S3M: - asset.InfoText += "ScreamTracker 3"; - break; - case AudioType.WAV: - asset.InfoText += "Microsoft WAV"; - break; - case AudioType.XM: - asset.InfoText += "FastTracker 2 XM"; - break; - case AudioType.XMA: - asset.InfoText += "Xbox360 XMA"; - break; - case AudioType.VAG: - asset.InfoText += "PlayStation Portable ADPCM"; - break; - case AudioType.AUDIOQUEUE: - asset.InfoText += "iPhone"; - break; - default: - asset.InfoText += "Unknown"; - break; - } - } - else - { - switch (m_AudioClip.m_CompressionFormat) - { - case AudioCompressionFormat.PCM: - asset.InfoText += "PCM"; - break; - case AudioCompressionFormat.Vorbis: - asset.InfoText += "Vorbis"; - break; - case AudioCompressionFormat.ADPCM: - asset.InfoText += "ADPCM"; - break; - case AudioCompressionFormat.MP3: - asset.InfoText += "MP3"; - break; - case AudioCompressionFormat.VAG: - asset.InfoText += "PlayStation Portable ADPCM"; - break; - case AudioCompressionFormat.HEVAG: - asset.InfoText += "PSVita ADPCM"; - break; - case AudioCompressionFormat.XMA: - asset.InfoText += "Xbox360 XMA"; - break; - case AudioCompressionFormat.AAC: - asset.InfoText += "AAC"; - break; - case AudioCompressionFormat.GCADPCM: - asset.InfoText += "Nintendo 3DS/Wii DSP"; - break; - case AudioCompressionFormat.ATRAC9: - asset.InfoText += "PSVita ATRAC9"; - break; - default: - asset.InfoText += "Unknown"; - break; - } - } - - if (m_AudioClip.m_AudioData == null) - break; - FMOD.CREATESOUNDEXINFO exinfo = new FMOD.CREATESOUNDEXINFO(); - - exinfo.cbsize = Marshal.SizeOf(exinfo); - exinfo.length = (uint)m_AudioClip.m_Size; - - var result = system.createSound(m_AudioClip.m_AudioData, FMOD.MODE.OPENMEMORY | loopMode, ref exinfo, out sound); - if (ERRCHECK(result)) { break; } - - result = sound.getSubSound(0, out var subsound); - if (result == FMOD.RESULT.OK) - { - sound = subsound; - } - - result = sound.getLength(out FMODlenms, FMOD.TIMEUNIT.MS); - if (ERRCHECK(result)) { break; } - - result = system.playSound(sound, null, true, out channel); - if (ERRCHECK(result)) { break; } - - FMODpanel.Visible = true; - - result = channel.getFrequency(out var frequency); - if (ERRCHECK(result)) { break; } - - FMODinfoLabel.Text = frequency + " Hz"; - FMODtimerLabel.Text = $"0:0.0 / {FMODlenms / 1000 / 60}:{FMODlenms / 1000 % 60}.{FMODlenms / 10 % 100}"; - break; - } - case ClassIDType.Shader: - { - var m_Shader = new Shader(reader); - var str = ShaderConverter.Convert(m_Shader); - textPreviewBox.Text = str == null ? "Serialized Shader can't be read" : str.Replace("\n", "\r\n"); + textPreviewBox.Text = str; textPreviewBox.Visible = true; - break; } - case ClassIDType.TextAsset: + else { - TextAsset m_TextAsset = new TextAsset(reader); - - string m_Script_Text = Encoding.UTF8.GetString(m_TextAsset.m_Script); - m_Script_Text = Regex.Replace(m_Script_Text, "(? 0) - { - fontPreviewBox.SelectionStart = 0; - fontPreviewBox.SelectionLength = 80; - fontPreviewBox.SelectionFont = new System.Drawing.Font(pfc.Families[0], 16, FontStyle.Regular); - fontPreviewBox.SelectionStart = 81; - fontPreviewBox.SelectionLength = 56; - fontPreviewBox.SelectionFont = new System.Drawing.Font(pfc.Families[0], 12, FontStyle.Regular); - fontPreviewBox.SelectionStart = 138; - fontPreviewBox.SelectionLength = 56; - fontPreviewBox.SelectionFont = new System.Drawing.Font(pfc.Families[0], 18, FontStyle.Regular); - fontPreviewBox.SelectionStart = 195; - fontPreviewBox.SelectionLength = 56; - fontPreviewBox.SelectionFont = new System.Drawing.Font(pfc.Families[0], 24, FontStyle.Regular); - fontPreviewBox.SelectionStart = 252; - fontPreviewBox.SelectionLength = 56; - fontPreviewBox.SelectionFont = new System.Drawing.Font(pfc.Families[0], 36, FontStyle.Regular); - fontPreviewBox.SelectionStart = 309; - fontPreviewBox.SelectionLength = 56; - fontPreviewBox.SelectionFont = new System.Drawing.Font(pfc.Families[0], 48, FontStyle.Regular); - fontPreviewBox.SelectionStart = 366; - fontPreviewBox.SelectionLength = 56; - fontPreviewBox.SelectionFont = new System.Drawing.Font(pfc.Families[0], 60, FontStyle.Regular); - fontPreviewBox.SelectionStart = 423; - fontPreviewBox.SelectionLength = 55; - fontPreviewBox.SelectionFont = new System.Drawing.Font(pfc.Families[0], 72, FontStyle.Regular); - fontPreviewBox.Visible = true; - } - } - break; - } - } - StatusStripUpdate("Unsupported font for preview. Try to export."); - break; - } - case ClassIDType.Mesh: - { - var m_Mesh = new Mesh(reader); - if (m_Mesh.m_VertexCount > 0) - { - viewMatrixData = Matrix4.CreateRotationY(-(float)Math.PI / 4) * Matrix4.CreateRotationX(-(float)Math.PI / 6); - #region Vertices - if (m_Mesh.m_Vertices == null || m_Mesh.m_Vertices.Length == 0) - { - StatusStripUpdate("Mesh can't be previewed."); - return; - } - int count = 3; - if (m_Mesh.m_Vertices.Length == m_Mesh.m_VertexCount * 4) - { - count = 4; - } - vertexData = new Vector3[m_Mesh.m_VertexCount]; - // Calculate Bounding - float[] min = new float[3]; - float[] max = new float[3]; - for (int i = 0; i < 3; i++) - { - min[i] = m_Mesh.m_Vertices[i]; - max[i] = m_Mesh.m_Vertices[i]; - } - for (int v = 0; v < m_Mesh.m_VertexCount; v++) - { - for (int i = 0; i < 3; i++) - { - min[i] = Math.Min(min[i], m_Mesh.m_Vertices[v * count + i]); - max[i] = Math.Max(max[i], m_Mesh.m_Vertices[v * count + i]); - } - vertexData[v] = new Vector3( - m_Mesh.m_Vertices[v * count], - m_Mesh.m_Vertices[v * count + 1], - m_Mesh.m_Vertices[v * count + 2]); - } - - // Calculate modelMatrix - Vector3 dist = Vector3.One, offset = Vector3.Zero; - for (int i = 0; i < 3; i++) - { - dist[i] = max[i] - min[i]; - offset[i] = (max[i] + min[i]) / 2; - } - float d = Math.Max(1e-5f, dist.Length); - modelMatrixData = Matrix4.CreateTranslation(-offset) * Matrix4.CreateScale(2f / d); - #endregion - #region Indicies - indiceData = new int[m_Mesh.m_Indices.Count]; - for (int i = 0; i < m_Mesh.m_Indices.Count; i = i + 3) - { - indiceData[i] = (int)m_Mesh.m_Indices[i]; - indiceData[i + 1] = (int)m_Mesh.m_Indices[i + 1]; - indiceData[i + 2] = (int)m_Mesh.m_Indices[i + 2]; - } - #endregion - #region Normals - if (m_Mesh.m_Normals != null && m_Mesh.m_Normals.Length > 0) - { - if (m_Mesh.m_Normals.Length == m_Mesh.m_VertexCount * 3) - count = 3; - else if (m_Mesh.m_Normals.Length == m_Mesh.m_VertexCount * 4) - count = 4; - normalData = new Vector3[m_Mesh.m_VertexCount]; - for (int n = 0; n < m_Mesh.m_VertexCount; n++) - { - normalData[n] = new Vector3( - m_Mesh.m_Normals[n * count], - m_Mesh.m_Normals[n * count + 1], - m_Mesh.m_Normals[n * count + 2]); - } - } - else - normalData = null; - // calculate normal by ourself - normal2Data = new Vector3[m_Mesh.m_VertexCount]; - int[] normalCalculatedCount = new int[m_Mesh.m_VertexCount]; - for (int i = 0; i < m_Mesh.m_VertexCount; i++) - { - normal2Data[i] = Vector3.Zero; - normalCalculatedCount[i] = 0; - } - for (int i = 0; i < m_Mesh.m_Indices.Count; i = i + 3) - { - Vector3 dir1 = vertexData[indiceData[i + 1]] - vertexData[indiceData[i]]; - Vector3 dir2 = vertexData[indiceData[i + 2]] - vertexData[indiceData[i]]; - Vector3 normal = Vector3.Cross(dir1, dir2); - normal.Normalize(); - for (int j = 0; j < 3; j++) - { - normal2Data[indiceData[i + j]] += normal; - normalCalculatedCount[indiceData[i + j]]++; - } - } - for (int i = 0; i < m_Mesh.m_VertexCount; i++) - { - if (normalCalculatedCount[i] == 0) - normal2Data[i] = new Vector3(0, 1, 0); - else - normal2Data[i] /= normalCalculatedCount[i]; - } - #endregion - #region Colors - if (m_Mesh.m_Colors != null && m_Mesh.m_Colors.Length == m_Mesh.m_VertexCount * 3) - { - colorData = new Vector4[m_Mesh.m_VertexCount]; - for (int c = 0; c < m_Mesh.m_VertexCount; c++) - { - colorData[c] = new Vector4( - m_Mesh.m_Colors[c * 3], - m_Mesh.m_Colors[c * 3 + 1], - m_Mesh.m_Colors[c * 3 + 2], - 1.0f); - } - } - else if (m_Mesh.m_Colors != null && m_Mesh.m_Colors.Length == m_Mesh.m_VertexCount * 4) - { - colorData = new Vector4[m_Mesh.m_VertexCount]; - for (int c = 0; c < m_Mesh.m_VertexCount; c++) - { - colorData[c] = new Vector4( - m_Mesh.m_Colors[c * 4], - m_Mesh.m_Colors[c * 4 + 1], - m_Mesh.m_Colors[c * 4 + 2], - m_Mesh.m_Colors[c * 4 + 3]); - } - } - else - { - colorData = new Vector4[m_Mesh.m_VertexCount]; - for (int c = 0; c < m_Mesh.m_VertexCount; c++) - { - colorData[c] = new Vector4(0.5f, 0.5f, 0.5f, 1.0f); - } - } - #endregion - glControl1.Visible = true; - createVAO(); - } - StatusStripUpdate("Using OpenGL Version: " + GL.GetString(StringName.Version) + "\n" - + "'Mouse Left'=Rotate | 'Mouse Right'=Move | 'Mouse Wheel'=Zoom \n" - + "'Ctrl W'=Wireframe | 'Ctrl S'=Shade | 'Ctrl N'=ReNormal "); + StatusStripUpdate("Only supported export the raw file."); } break; - case ClassIDType.VideoClip: - case ClassIDType.MovieTexture: - { - StatusStripUpdate("Only supported export."); - break; - } - case ClassIDType.Sprite: - { - imageTexture?.Dispose(); - imageTexture = SpriteHelper.GetImageFromSprite(new Sprite(reader)); - if (imageTexture != null) - { - asset.InfoText = $"Width: {imageTexture.Width}\nHeight: {imageTexture.Height}\n"; - previewPanel.BackgroundImage = imageTexture; - if (imageTexture.Width > previewPanel.Width || imageTexture.Height > previewPanel.Height) - previewPanel.BackgroundImageLayout = ImageLayout.Zoom; - else - previewPanel.BackgroundImageLayout = ImageLayout.Center; - } - else - { - StatusStripUpdate("Unsupported sprite for preview."); - } - break; - } - case ClassIDType.Animator: - { - StatusStripUpdate("Can be exported to FBX file."); - break; - } - case ClassIDType.AnimationClip: - { - StatusStripUpdate("Can be exported with Animator or objects"); - break; - } - default: - { - var str = reader.Dump(); - if (str != null) - { - textPreviewBox.Text = str; - textPreviewBox.Visible = true; - } - else - StatusStripUpdate("Only supported export the raw file."); - break; - } } } catch (Exception e) { - MessageBox.Show($"Preview {asset.Type}:{asset.Text} error\r\n{e.Message}\r\n{e.StackTrace}"); + MessageBox.Show($"Preview {assetItem.Type}:{assetItem.Text} error\r\n{e.Message}\r\n{e.StackTrace}"); } } + private void PreviewTexture2D(AssetItem assetItem, Texture2D m_Texture2D) + { + var converter = new Texture2DConverter(m_Texture2D); + var bitmap = converter.ConvertToBitmap(true); + if (bitmap != null) + { + assetItem.InfoText = $"Width: {m_Texture2D.m_Width}\nHeight: {m_Texture2D.m_Height}\nFormat: {m_Texture2D.m_TextureFormat}"; + switch (m_Texture2D.m_FilterMode) + { + case 0: assetItem.InfoText += "\nFilter Mode: Point "; break; + case 1: assetItem.InfoText += "\nFilter Mode: Bilinear "; break; + case 2: assetItem.InfoText += "\nFilter Mode: Trilinear "; break; + } + assetItem.InfoText += $"\nAnisotropic level: {m_Texture2D.m_Aniso}\nMip map bias: {m_Texture2D.m_MipBias}"; + switch (m_Texture2D.m_WrapMode) + { + case 0: assetItem.InfoText += "\nWrap mode: Repeat"; break; + case 1: assetItem.InfoText += "\nWrap mode: Clamp"; break; + } + + PreviewTexture(bitmap); + } + else + { + StatusStripUpdate("Unsupported image for preview"); + } + } + + private void PreviewAudioClip(AssetItem assetItem, AudioClip m_AudioClip) + { + //Info + assetItem.InfoText = "Compression format: "; + if (m_AudioClip.version[0] < 5) + { + switch (m_AudioClip.m_Type) + { + case AudioType.ACC: + assetItem.InfoText += "Acc"; + break; + case AudioType.AIFF: + assetItem.InfoText += "AIFF"; + break; + case AudioType.IT: + assetItem.InfoText += "Impulse tracker"; + break; + case AudioType.MOD: + assetItem.InfoText += "Protracker / Fasttracker MOD"; + break; + case AudioType.MPEG: + assetItem.InfoText += "MP2/MP3 MPEG"; + break; + case AudioType.OGGVORBIS: + assetItem.InfoText += "Ogg vorbis"; + break; + case AudioType.S3M: + assetItem.InfoText += "ScreamTracker 3"; + break; + case AudioType.WAV: + assetItem.InfoText += "Microsoft WAV"; + break; + case AudioType.XM: + assetItem.InfoText += "FastTracker 2 XM"; + break; + case AudioType.XMA: + assetItem.InfoText += "Xbox360 XMA"; + break; + case AudioType.VAG: + assetItem.InfoText += "PlayStation Portable ADPCM"; + break; + case AudioType.AUDIOQUEUE: + assetItem.InfoText += "iPhone"; + break; + default: + assetItem.InfoText += "Unknown"; + break; + } + } + else + { + switch (m_AudioClip.m_CompressionFormat) + { + case AudioCompressionFormat.PCM: + assetItem.InfoText += "PCM"; + break; + case AudioCompressionFormat.Vorbis: + assetItem.InfoText += "Vorbis"; + break; + case AudioCompressionFormat.ADPCM: + assetItem.InfoText += "ADPCM"; + break; + case AudioCompressionFormat.MP3: + assetItem.InfoText += "MP3"; + break; + case AudioCompressionFormat.VAG: + assetItem.InfoText += "PlayStation Portable ADPCM"; + break; + case AudioCompressionFormat.HEVAG: + assetItem.InfoText += "PSVita ADPCM"; + break; + case AudioCompressionFormat.XMA: + assetItem.InfoText += "Xbox360 XMA"; + break; + case AudioCompressionFormat.AAC: + assetItem.InfoText += "AAC"; + break; + case AudioCompressionFormat.GCADPCM: + assetItem.InfoText += "Nintendo 3DS/Wii DSP"; + break; + case AudioCompressionFormat.ATRAC9: + assetItem.InfoText += "PSVita ATRAC9"; + break; + default: + assetItem.InfoText += "Unknown"; + break; + } + } + + var m_AudioData = m_AudioClip.m_AudioData.Value; + if (m_AudioData == null || m_AudioData.Length == 0) + return; + FMOD.CREATESOUNDEXINFO exinfo = new FMOD.CREATESOUNDEXINFO(); + + exinfo.cbsize = Marshal.SizeOf(exinfo); + exinfo.length = (uint)m_AudioClip.m_Size; + + var result = system.createSound(m_AudioData, FMOD.MODE.OPENMEMORY | loopMode, ref exinfo, out sound); + if (ERRCHECK(result)) return; + + result = sound.getSubSound(0, out var subsound); + if (result == FMOD.RESULT.OK) + { + sound = subsound; + } + + result = sound.getLength(out FMODlenms, FMOD.TIMEUNIT.MS); + if (ERRCHECK(result)) return; + + result = system.playSound(sound, null, true, out channel); + if (ERRCHECK(result)) return; + + FMODpanel.Visible = true; + + result = channel.getFrequency(out var frequency); + if (ERRCHECK(result)) return; + + FMODinfoLabel.Text = frequency + " Hz"; + FMODtimerLabel.Text = $"0:0.0 / {FMODlenms / 1000 / 60}:{FMODlenms / 1000 % 60}.{FMODlenms / 10 % 100}"; + } + + private void PreviewShader(Shader m_Shader) + { + var str = ShaderConverter.Convert(m_Shader); + PreviewText(str == null ? "Serialized Shader can't be read" : str.Replace("\n", "\r\n")); + } + + private void PreviewTextAsset(TextAsset m_TextAsset) + { + var text = Encoding.UTF8.GetString(m_TextAsset.m_Script); + PreviewText(text.Replace("\n", "\r\n")); + } + + private void PreviewMonoBehaviour(MonoBehaviour m_MonoBehaviour) + { + PreviewText(m_MonoBehaviour.Dump() ?? GetScriptString(m_MonoBehaviour.reader)); + } + + private void PreviewFont(Font m_Font) + { + if (m_Font.m_FontData != null) + { + var data = Marshal.AllocCoTaskMem(m_Font.m_FontData.Length); + Marshal.Copy(m_Font.m_FontData, 0, data, m_Font.m_FontData.Length); + + uint cFonts = 0; + var re = AddFontMemResourceEx(data, (uint)m_Font.m_FontData.Length, IntPtr.Zero, ref cFonts); + if (re != IntPtr.Zero) + { + using (var pfc = new PrivateFontCollection()) + { + pfc.AddMemoryFont(data, m_Font.m_FontData.Length); + Marshal.FreeCoTaskMem(data); + if (pfc.Families.Length > 0) + { + fontPreviewBox.SelectionStart = 0; + fontPreviewBox.SelectionLength = 80; + fontPreviewBox.SelectionFont = new System.Drawing.Font(pfc.Families[0], 16, FontStyle.Regular); + fontPreviewBox.SelectionStart = 81; + fontPreviewBox.SelectionLength = 56; + fontPreviewBox.SelectionFont = new System.Drawing.Font(pfc.Families[0], 12, FontStyle.Regular); + fontPreviewBox.SelectionStart = 138; + fontPreviewBox.SelectionLength = 56; + fontPreviewBox.SelectionFont = new System.Drawing.Font(pfc.Families[0], 18, FontStyle.Regular); + fontPreviewBox.SelectionStart = 195; + fontPreviewBox.SelectionLength = 56; + fontPreviewBox.SelectionFont = new System.Drawing.Font(pfc.Families[0], 24, FontStyle.Regular); + fontPreviewBox.SelectionStart = 252; + fontPreviewBox.SelectionLength = 56; + fontPreviewBox.SelectionFont = new System.Drawing.Font(pfc.Families[0], 36, FontStyle.Regular); + fontPreviewBox.SelectionStart = 309; + fontPreviewBox.SelectionLength = 56; + fontPreviewBox.SelectionFont = new System.Drawing.Font(pfc.Families[0], 48, FontStyle.Regular); + fontPreviewBox.SelectionStart = 366; + fontPreviewBox.SelectionLength = 56; + fontPreviewBox.SelectionFont = new System.Drawing.Font(pfc.Families[0], 60, FontStyle.Regular); + fontPreviewBox.SelectionStart = 423; + fontPreviewBox.SelectionLength = 55; + fontPreviewBox.SelectionFont = new System.Drawing.Font(pfc.Families[0], 72, FontStyle.Regular); + fontPreviewBox.Visible = true; + } + } + return; + } + } + StatusStripUpdate("Unsupported font for preview. Try to export."); + } + + private void PreviewMesh(Mesh m_Mesh) + { + if (m_Mesh.m_VertexCount > 0) + { + viewMatrixData = Matrix4.CreateRotationY(-(float)Math.PI / 4) * Matrix4.CreateRotationX(-(float)Math.PI / 6); + #region Vertices + if (m_Mesh.m_Vertices == null || m_Mesh.m_Vertices.Length == 0) + { + StatusStripUpdate("Mesh can't be previewed."); + return; + } + int count = 3; + if (m_Mesh.m_Vertices.Length == m_Mesh.m_VertexCount * 4) + { + count = 4; + } + vertexData = new Vector3[m_Mesh.m_VertexCount]; + // Calculate Bounding + float[] min = new float[3]; + float[] max = new float[3]; + for (int i = 0; i < 3; i++) + { + min[i] = m_Mesh.m_Vertices[i]; + max[i] = m_Mesh.m_Vertices[i]; + } + for (int v = 0; v < m_Mesh.m_VertexCount; v++) + { + for (int i = 0; i < 3; i++) + { + min[i] = Math.Min(min[i], m_Mesh.m_Vertices[v * count + i]); + max[i] = Math.Max(max[i], m_Mesh.m_Vertices[v * count + i]); + } + vertexData[v] = new Vector3( + m_Mesh.m_Vertices[v * count], + m_Mesh.m_Vertices[v * count + 1], + m_Mesh.m_Vertices[v * count + 2]); + } + + // Calculate modelMatrix + Vector3 dist = Vector3.One, offset = Vector3.Zero; + for (int i = 0; i < 3; i++) + { + dist[i] = max[i] - min[i]; + offset[i] = (max[i] + min[i]) / 2; + } + float d = Math.Max(1e-5f, dist.Length); + modelMatrixData = Matrix4.CreateTranslation(-offset) * Matrix4.CreateScale(2f / d); + #endregion + #region Indicies + indiceData = new int[m_Mesh.m_Indices.Count]; + for (int i = 0; i < m_Mesh.m_Indices.Count; i = i + 3) + { + indiceData[i] = (int)m_Mesh.m_Indices[i]; + indiceData[i + 1] = (int)m_Mesh.m_Indices[i + 1]; + indiceData[i + 2] = (int)m_Mesh.m_Indices[i + 2]; + } + #endregion + #region Normals + if (m_Mesh.m_Normals != null && m_Mesh.m_Normals.Length > 0) + { + if (m_Mesh.m_Normals.Length == m_Mesh.m_VertexCount * 3) + count = 3; + else if (m_Mesh.m_Normals.Length == m_Mesh.m_VertexCount * 4) + count = 4; + normalData = new Vector3[m_Mesh.m_VertexCount]; + for (int n = 0; n < m_Mesh.m_VertexCount; n++) + { + normalData[n] = new Vector3( + m_Mesh.m_Normals[n * count], + m_Mesh.m_Normals[n * count + 1], + m_Mesh.m_Normals[n * count + 2]); + } + } + else + normalData = null; + // calculate normal by ourself + normal2Data = new Vector3[m_Mesh.m_VertexCount]; + int[] normalCalculatedCount = new int[m_Mesh.m_VertexCount]; + for (int i = 0; i < m_Mesh.m_VertexCount; i++) + { + normal2Data[i] = Vector3.Zero; + normalCalculatedCount[i] = 0; + } + for (int i = 0; i < m_Mesh.m_Indices.Count; i = i + 3) + { + Vector3 dir1 = vertexData[indiceData[i + 1]] - vertexData[indiceData[i]]; + Vector3 dir2 = vertexData[indiceData[i + 2]] - vertexData[indiceData[i]]; + Vector3 normal = Vector3.Cross(dir1, dir2); + normal.Normalize(); + for (int j = 0; j < 3; j++) + { + normal2Data[indiceData[i + j]] += normal; + normalCalculatedCount[indiceData[i + j]]++; + } + } + for (int i = 0; i < m_Mesh.m_VertexCount; i++) + { + if (normalCalculatedCount[i] == 0) + normal2Data[i] = new Vector3(0, 1, 0); + else + normal2Data[i] /= normalCalculatedCount[i]; + } + #endregion + #region Colors + if (m_Mesh.m_Colors != null && m_Mesh.m_Colors.Length == m_Mesh.m_VertexCount * 3) + { + colorData = new Vector4[m_Mesh.m_VertexCount]; + for (int c = 0; c < m_Mesh.m_VertexCount; c++) + { + colorData[c] = new Vector4( + m_Mesh.m_Colors[c * 3], + m_Mesh.m_Colors[c * 3 + 1], + m_Mesh.m_Colors[c * 3 + 2], + 1.0f); + } + } + else if (m_Mesh.m_Colors != null && m_Mesh.m_Colors.Length == m_Mesh.m_VertexCount * 4) + { + colorData = new Vector4[m_Mesh.m_VertexCount]; + for (int c = 0; c < m_Mesh.m_VertexCount; c++) + { + colorData[c] = new Vector4( + m_Mesh.m_Colors[c * 4], + m_Mesh.m_Colors[c * 4 + 1], + m_Mesh.m_Colors[c * 4 + 2], + m_Mesh.m_Colors[c * 4 + 3]); + } + } + else + { + colorData = new Vector4[m_Mesh.m_VertexCount]; + for (int c = 0; c < m_Mesh.m_VertexCount; c++) + { + colorData[c] = new Vector4(0.5f, 0.5f, 0.5f, 1.0f); + } + } + #endregion + glControl1.Visible = true; + createVAO(); + } + StatusStripUpdate("Using OpenGL Version: " + GL.GetString(StringName.Version) + "\n" + + "'Mouse Left'=Rotate | 'Mouse Right'=Move | 'Mouse Wheel'=Zoom \n" + + "'Ctrl W'=Wireframe | 'Ctrl S'=Shade | 'Ctrl N'=ReNormal "); + } + + private void PreviewSprite(AssetItem assetItem, Sprite m_Sprite) + { + var bitmap = SpriteHelper.GetImageFromSprite(m_Sprite); + if (bitmap != null) + { + assetItem.InfoText = $"Width: {imageTexture.Width}\nHeight: {imageTexture.Height}\n"; + + PreviewTexture(bitmap); + } + else + { + StatusStripUpdate("Unsupported sprite for preview."); + } + } + + private void PreviewTexture(Bitmap bitmap) + { + imageTexture?.Dispose(); + imageTexture = bitmap; + previewPanel.BackgroundImage = imageTexture; + if (imageTexture.Width > previewPanel.Width || imageTexture.Height > previewPanel.Height) + previewPanel.BackgroundImageLayout = ImageLayout.Zoom; + else + previewPanel.BackgroundImageLayout = ImageLayout.Center; + } + + private void PreviewText(string text) + { + textPreviewBox.Text = text; + textPreviewBox.Visible = true; + } + private void FMODinit() { FMODreset(); @@ -1683,6 +1687,7 @@ namespace AssetStudioGUI classesListView.Items.Clear(); classesListView.Groups.Clear(); previewPanel.BackgroundImage = Properties.Resources.preview; + imageTexture?.Dispose(); previewPanel.BackgroundImageLayout = ImageLayout.Center; assetInfoLabel.Visible = false; assetInfoLabel.Text = null; @@ -1757,7 +1762,7 @@ namespace AssetStudioGUI private void showOriginalFileToolStripMenuItem_Click(object sender, EventArgs e) { var selectasset = (AssetItem)assetListView.Items[assetListView.SelectedIndices[0]]; - var args = $"/select, \"{selectasset.sourceFile.originalPath ?? selectasset.sourceFile.fullName}\""; + var args = $"/select, \"{selectasset.SourceFile.originalPath ?? selectasset.SourceFile.fullName}\""; var pfi = new ProcessStartInfo("explorer.exe", args); Process.Start(pfi); } diff --git a/AssetStudioGUI/Components/AssetItem.cs b/AssetStudioGUI/Components/AssetItem.cs index 452fee6..1245cd7 100644 --- a/AssetStudioGUI/Components/AssetItem.cs +++ b/AssetStudioGUI/Components/AssetItem.cs @@ -5,21 +5,22 @@ namespace AssetStudioGUI { internal class AssetItem : ListViewItem { - public SerializedFile sourceFile; - public ObjectReader reader; + public Object Asset; + public SerializedFile SourceFile; public long FullSize; public ClassIDType Type; public string TypeString; + public string InfoText; public string UniqueID; public GameObjectTreeNode TreeNode; - public AssetItem(ObjectReader reader) + public AssetItem(Object asset) { - sourceFile = reader.assetsFile; - this.reader = reader; - FullSize = reader.byteSize; - Type = reader.type; + Asset = asset; + SourceFile = asset.assetsFile; + FullSize = asset.byteSize; + Type = asset.type; TypeString = Type.ToString(); } } diff --git a/AssetStudioGUI/Exporter.cs b/AssetStudioGUI/Exporter.cs index a99455e..284ab58 100644 --- a/AssetStudioGUI/Exporter.cs +++ b/AssetStudioGUI/Exporter.cs @@ -11,10 +11,7 @@ namespace AssetStudioGUI { public static bool ExportTexture2D(AssetItem item, string exportPathName) { - var m_Texture2D = new Texture2D(item.reader, true); - if (m_Texture2D.image_data == null || m_Texture2D.image_data.Length == 0) - return false; - var converter = new Texture2DConverter(m_Texture2D); + var converter = new Texture2DConverter((Texture2D)item.Asset); var convertTexture = (bool)Properties.Settings.Default["convertTexture"]; if (convertTexture) { @@ -54,8 +51,9 @@ namespace AssetStudioGUI public static bool ExportAudioClip(AssetItem item, string exportPath) { - var m_AudioClip = new AudioClip(item.reader, true); - if (m_AudioClip.m_AudioData == null) + var m_AudioClip = (AudioClip)item.Asset; + var m_AudioData = m_AudioClip.m_AudioData.Value; + if (m_AudioData == null || m_AudioData.Length == 0) return false; var convertAudio = (bool)Properties.Settings.Default["convertAudio"]; var converter = new AudioClipConverter(m_AudioClip); @@ -74,25 +72,24 @@ namespace AssetStudioGUI var exportFullName = exportPath + item.Text + converter.GetExtensionName(); if (ExportFileExists(exportFullName)) return false; - File.WriteAllBytes(exportFullName, m_AudioClip.m_AudioData); + File.WriteAllBytes(exportFullName, m_AudioData); } return true; } public static bool ExportShader(AssetItem item, string exportPath) { - var m_Shader = new Shader(item.reader); var exportFullName = exportPath + item.Text + ".shader"; if (ExportFileExists(exportFullName)) return false; - var str = ShaderConverter.Convert(m_Shader); + var str = ShaderConverter.Convert((Shader)item.Asset); File.WriteAllText(exportFullName, str ?? "Serialized Shader can't be read"); return true; } public static bool ExportTextAsset(AssetItem item, string exportPath) { - var m_TextAsset = new TextAsset(item.reader); + var m_TextAsset = (TextAsset)(item.Asset); var exportFullName = exportPath + item.Text + ".txt"; if (ExportFileExists(exportFullName)) return false; @@ -105,23 +102,15 @@ namespace AssetStudioGUI var exportFullName = exportPath + item.Text + ".txt"; if (ExportFileExists(exportFullName)) return false; - var reader = item.reader; - string str; - if (reader.serializedType?.m_Nodes != null) - { - str = reader.Dump(); - } - else - { - str = Studio.GetScriptString(reader); - } + var m_MonoBehaviour = (MonoBehaviour)item.Asset; + var str = m_MonoBehaviour.Dump() ?? Studio.GetScriptString(item.Asset.reader); File.WriteAllText(exportFullName, str); return true; } public static bool ExportFont(AssetItem item, string exportPath) { - var m_Font = new Font(item.reader); + var m_Font = (Font)item.Asset; if (m_Font.m_FontData != null) { var extension = ".ttf"; @@ -140,7 +129,7 @@ namespace AssetStudioGUI public static bool ExportMesh(AssetItem item, string exportPath) { - var m_Mesh = new Mesh(item.reader); + var m_Mesh = (Mesh)item.Asset; if (m_Mesh.m_VertexCount <= 0) return false; var exportFullName = exportPath + item.Text + ".obj"; @@ -221,13 +210,14 @@ namespace AssetStudioGUI public static bool ExportVideoClip(AssetItem item, string exportPath) { - var m_VideoClip = new VideoClip(item.reader, true); - if (m_VideoClip.m_VideoData != null) + var m_VideoClip = (VideoClip)item.Asset; + var m_VideoData = m_VideoClip.m_VideoData.Value; + if (m_VideoData != null && m_VideoData.Length != 0) { var exportFullName = exportPath + item.Text + Path.GetExtension(m_VideoClip.m_OriginalPath); if (ExportFileExists(exportFullName)) return false; - File.WriteAllBytes(exportFullName, m_VideoClip.m_VideoData); + File.WriteAllBytes(exportFullName, m_VideoData); return true; } return false; @@ -235,7 +225,7 @@ namespace AssetStudioGUI public static bool ExportMovieTexture(AssetItem item, string exportPath) { - var m_MovieTexture = new MovieTexture(item.reader); + var m_MovieTexture = (MovieTexture)item.Asset; var exportFullName = exportPath + item.Text + ".ogv"; if (ExportFileExists(exportFullName)) return false; @@ -262,7 +252,7 @@ namespace AssetStudioGUI var exportFullName = exportPath + item.Text + "." + type.ToLower(); if (ExportFileExists(exportFullName)) return false; - var bitmap = SpriteHelper.GetImageFromSprite(new Sprite(item.reader)); + var bitmap = SpriteHelper.GetImageFromSprite((Sprite)item.Asset); if (bitmap != null) { bitmap.Save(exportFullName, format); @@ -277,7 +267,7 @@ namespace AssetStudioGUI var exportFullName = exportPath + item.Text + ".dat"; if (ExportFileExists(exportFullName)) return false; - File.WriteAllBytes(exportFullName, item.reader.GetRawData()); + File.WriteAllBytes(exportFullName, item.Asset.GetRawData()); return true; } @@ -293,15 +283,15 @@ namespace AssetStudioGUI public static bool ExportAnimator(AssetItem item, string exportPath, List animationList = null) { - var m_Animator = new Animator(item.reader); - var convert = animationList != null ? new ModelConverter(m_Animator, animationList.Select(x => x.reader).ToArray()) : new ModelConverter(m_Animator); + var m_Animator = (Animator)item.Asset; + var convert = animationList != null ? new ModelConverter(m_Animator, animationList.Select(x => (AnimationClip)x.Asset).ToArray()) : new ModelConverter(m_Animator); exportPath = exportPath + item.Text + ".fbx"; return ExportFbx(convert, exportPath); } public static bool ExportGameObject(GameObject gameObject, string exportPath, List animationList = null) { - var convert = animationList != null ? new ModelConverter(gameObject, animationList.Select(x => x.reader).ToArray()) : new ModelConverter(gameObject); + var convert = animationList != null ? new ModelConverter(gameObject, animationList.Select(x => (AnimationClip)x.Asset).ToArray()) : new ModelConverter(gameObject); exportPath = exportPath + Studio.FixFileName(gameObject.m_Name) + ".fbx"; return ExportFbx(convert, exportPath); } diff --git a/AssetStudioGUI/Studio.cs b/AssetStudioGUI/Studio.cs index 50bd9f5..f10c593 100644 --- a/AssetStudioGUI/Studio.cs +++ b/AssetStudioGUI/Studio.cs @@ -9,6 +9,7 @@ using System.Windows.Forms; using AssetStudio; using dnlib.DotNet; using static AssetStudioGUI.Exporter; +using Object = AssetStudio.Object; namespace AssetStudioGUI { @@ -92,135 +93,89 @@ namespace AssetStudioGUI return extractedCount; } - public static void BuildAssetList(Dictionary tempDic, bool displayAll, bool displayOriginalName, out string productName) + public static void BuildAssetList(Dictionary tempDic, bool displayAll, bool displayOriginalName, out string productName) { Logger.Info("Building asset list..."); productName = string.Empty; var assetsNameHash = new HashSet(); - var progressCount = assetsManager.assetsFileList.Sum(x => x.ObjectReaders.Count); + var progressCount = assetsManager.assetsFileList.Sum(x => x.Objects.Count); int j = 0; Progress.Reset(); foreach (var assetsFile in assetsManager.assetsFileList) { var tempExportableAssets = new List(); AssetBundle ab = null; - foreach (var objectReader in assetsFile.ObjectReaders.Values) + foreach (var asset in assetsFile.Objects.Values) { - var assetItem = new AssetItem(objectReader); - tempDic.Add(objectReader, assetItem); + var assetItem = new AssetItem(asset); + tempDic.Add(asset, assetItem); assetItem.UniqueID = " #" + j; var exportable = false; - switch (assetItem.Type) + switch (asset) { - case ClassIDType.GameObject: + case GameObject m_GameObject: + assetItem.Text = m_GameObject.m_Name; + break; + case Texture2D m_Texture2D: + if (!string.IsNullOrEmpty(m_Texture2D.path)) + assetItem.FullSize = asset.byteSize + m_Texture2D.size; + assetItem.Text = m_Texture2D.m_Name; + exportable = true; + break; + case AudioClip m_AudioClip: + if (!string.IsNullOrEmpty(m_AudioClip.m_Source)) + assetItem.FullSize = asset.byteSize + m_AudioClip.m_Size; + assetItem.Text = m_AudioClip.m_Name; + exportable = true; + break; + case VideoClip m_VideoClip: + if (!string.IsNullOrEmpty(m_VideoClip.m_OriginalPath)) + assetItem.FullSize = asset.byteSize + (long)m_VideoClip.m_Size; + assetItem.Text = m_VideoClip.m_Name; + exportable = true; + break; + case Shader m_Shader: + assetItem.Text = m_Shader.m_ParsedForm?.m_Name ?? m_Shader.m_Name; + exportable = true; + break; + case Mesh _: + case TextAsset _: + case AnimationClip _: + case Font _: + case MovieTexture _: + case Sprite _: + assetItem.Text = ((NamedObject)asset).m_Name; + exportable = true; + break; + case Animator m_Animator: + if (m_Animator.m_GameObject.TryGet(out var gameObject)) { - var m_GameObject = new GameObject(objectReader); - assetItem.Text = m_GameObject.m_Name; - assetsFile.GameObjects.Add(objectReader.m_PathID, m_GameObject); - break; + assetItem.Text = gameObject.m_Name; } - case ClassIDType.Transform: + exportable = true; + break; + case MonoBehaviour m_MonoBehaviour: + if (m_MonoBehaviour.m_Name == "" && m_MonoBehaviour.m_Script.TryGet(out var m_Script)) { - var m_Transform = new Transform(objectReader); - assetsFile.Transforms.Add(objectReader.m_PathID, m_Transform); - break; + assetItem.Text = m_Script.m_ClassName; } - case ClassIDType.RectTransform: + else { - var m_Rect = new RectTransform(objectReader); - assetsFile.Transforms.Add(objectReader.m_PathID, m_Rect); - break; - } - case ClassIDType.Texture2D: - { - var m_Texture2D = new Texture2D(objectReader, false); - if (!string.IsNullOrEmpty(m_Texture2D.path)) - assetItem.FullSize = objectReader.byteSize + m_Texture2D.size; - assetItem.Text = m_Texture2D.m_Name; - exportable = true; - break; - } - case ClassIDType.AudioClip: - { - var m_AudioClip = new AudioClip(objectReader, false); - if (!string.IsNullOrEmpty(m_AudioClip.m_Source)) - assetItem.FullSize = objectReader.byteSize + m_AudioClip.m_Size; - assetItem.Text = m_AudioClip.m_Name; - exportable = true; - break; - } - case ClassIDType.VideoClip: - { - var m_VideoClip = new VideoClip(objectReader, false); - if (!string.IsNullOrEmpty(m_VideoClip.m_OriginalPath)) - assetItem.FullSize = objectReader.byteSize + (long)m_VideoClip.m_Size; - assetItem.Text = m_VideoClip.m_Name; - exportable = true; - break; - } - case ClassIDType.Shader: - { - var m_Shader = new Shader(objectReader); - assetItem.Text = m_Shader.m_ParsedForm?.m_Name ?? m_Shader.m_Name; - exportable = true; - break; - } - case ClassIDType.Mesh: - case ClassIDType.TextAsset: - case ClassIDType.AnimationClip: - case ClassIDType.Font: - case ClassIDType.MovieTexture: - case ClassIDType.Sprite: - { - var obj = new NamedObject(objectReader); - assetItem.Text = obj.m_Name; - exportable = true; - break; - } - case ClassIDType.Avatar: - case ClassIDType.AnimatorController: - case ClassIDType.AnimatorOverrideController: - case ClassIDType.Material: - case ClassIDType.MonoScript: - case ClassIDType.SpriteAtlas: - { - var obj = new NamedObject(objectReader); - assetItem.Text = obj.m_Name; - break; - } - case ClassIDType.Animator: - { - exportable = true; - break; - } - case ClassIDType.MonoBehaviour: - { - var m_MonoBehaviour = new MonoBehaviour(objectReader); - if (m_MonoBehaviour.m_Name == "" && m_MonoBehaviour.m_Script.TryGet(out var script)) - { - var m_Script = new MonoScript(script); - assetItem.Text = m_Script.m_ClassName; - } - else - { - assetItem.Text = m_MonoBehaviour.m_Name; - } - exportable = true; - break; - } - case ClassIDType.PlayerSettings: - { - var plSet = new PlayerSettings(objectReader); - productName = plSet.productName; - break; - } - case ClassIDType.AssetBundle: - { - ab = new AssetBundle(objectReader); - assetItem.Text = ab.m_Name; - break; + assetItem.Text = m_MonoBehaviour.m_Name; } + exportable = true; + break; + case PlayerSettings m_PlayerSettings: + productName = m_PlayerSettings.productName; + break; + case AssetBundle m_AssetBundle: + ab = m_AssetBundle; + assetItem.Text = ab.m_Name; + break; + case NamedObject m_NamedObject: + assetItem.Text = m_NamedObject.m_Name; + break; } if (assetItem.Text == "") { @@ -247,18 +202,18 @@ namespace AssetStudioGUI } if (displayOriginalName && ab != null) { - foreach (var asset in tempExportableAssets) + foreach (var item in tempExportableAssets) { - var originalPath = ab.m_Container.Find(y => y.Value.asset.m_PathID == asset.reader.m_PathID).Key; + var originalPath = ab.m_Container.Find(y => y.Value.asset.m_PathID == item.Asset.m_PathID).Key; if (!string.IsNullOrEmpty(originalPath)) { var extension = Path.GetExtension(originalPath); - if (!string.IsNullOrEmpty(extension) && asset.Type == ClassIDType.TextAsset) + if (!string.IsNullOrEmpty(extension) && item.Type == ClassIDType.TextAsset) { //asset.Extension = extension; //TODO } - asset.Text = Path.GetDirectoryName(originalPath) + "\\" + asset.Text; + item.Text = Path.GetDirectoryName(originalPath) + "\\" + item.Text; } } } @@ -270,21 +225,22 @@ namespace AssetStudioGUI assetsNameHash.Clear(); } - public static List BuildTreeStructure(Dictionary tempDic) + public static List BuildTreeStructure(Dictionary tempDic) { - var treeNodeCollection = new List(); - var gameObjectCount = assetsManager.assetsFileList.Sum(x => x.GameObjects.Count); - if (gameObjectCount > 0) - { - Logger.Info("Building tree structure..."); - var treeNodeDictionary = new Dictionary(); - int i = 0; - Progress.Reset(); - foreach (var assetsFile in assetsManager.assetsFileList) - { - var fileNode = new GameObjectTreeNode(assetsFile.fileName); //RootNode + Logger.Info("Building tree structure..."); - foreach (var m_GameObject in assetsFile.GameObjects.Values) + var treeNodeCollection = new List(); + var treeNodeDictionary = new Dictionary(); + var progressCount = assetsManager.assetsFileList.Count; + int i = 0; + Progress.Reset(); + foreach (var assetsFile in assetsManager.assetsFileList) + { + var fileNode = new GameObjectTreeNode(assetsFile.fileName); //RootNode + + foreach (var obj in assetsFile.Objects.Values) + { + if (obj is GameObject m_GameObject) { if (!treeNodeDictionary.TryGetValue(m_GameObject, out var currentNode)) { @@ -292,68 +248,31 @@ namespace AssetStudioGUI treeNodeDictionary.Add(m_GameObject, currentNode); } - foreach (var m_Component in m_GameObject.m_Components) + if (m_GameObject.m_MeshFilter != null) { - if (m_Component.TryGet(out var asset)) + if (m_GameObject.m_MeshFilter.m_Mesh.TryGet(out var m_Mesh)) { - switch (asset.type) - { - case ClassIDType.Transform: - { - m_GameObject.m_Transform = m_Component; - break; - } - case ClassIDType.MeshRenderer: - { - m_GameObject.m_MeshRenderer = m_Component; - break; - } - case ClassIDType.MeshFilter: - { - m_GameObject.m_MeshFilter = m_Component; - if (m_Component.TryGet(out var objectReader)) - { - var m_MeshFilter = new MeshFilter(objectReader); - if (m_MeshFilter.m_Mesh.TryGet(out objectReader)) - { - var item = tempDic[objectReader]; - item.TreeNode = currentNode; - } - } - break; - } - case ClassIDType.SkinnedMeshRenderer: - { - m_GameObject.m_SkinnedMeshRenderer = m_Component; - if (m_Component.TryGet(out var objectReader)) - { - var m_SkinnedMeshRenderer = new SkinnedMeshRenderer(objectReader); - if (m_SkinnedMeshRenderer.m_Mesh.TryGet(out objectReader)) - { - var item = tempDic[objectReader]; - item.TreeNode = currentNode; - } - } - break; - } - case ClassIDType.Animator: - { - m_GameObject.m_Animator = m_Component; - var item = tempDic[asset]; - item.Text = tempDic[m_GameObject.reader].Text; - break; - } - } + var item = tempDic[m_Mesh]; + item.TreeNode = currentNode; + } + } + + if (m_GameObject.m_SkinnedMeshRenderer != null) + { + if (m_GameObject.m_SkinnedMeshRenderer.m_Mesh.TryGet(out var m_Mesh)) + { + var item = tempDic[m_Mesh]; + item.TreeNode = currentNode; } } var parentNode = fileNode; - if (m_GameObject.m_Transform != null && m_GameObject.m_Transform.TryGetTransform(out var m_Transform)) + if (m_GameObject.m_Transform != null) { - if (m_Transform.m_Father.TryGetTransform(out var m_Father)) + if (m_GameObject.m_Transform.m_Father.TryGet(out var m_Father)) { - if (m_Father.m_GameObject.TryGetGameObject(out var parentGameObject)) + if (m_Father.m_GameObject.TryGet(out var parentGameObject)) { if (!treeNodeDictionary.TryGetValue(parentGameObject, out parentNode)) { @@ -365,19 +284,19 @@ namespace AssetStudioGUI } parentNode.Nodes.Add(currentNode); - - Progress.Report(++i, gameObjectCount); - } - - if (fileNode.Nodes.Count > 0) - { - treeNodeCollection.Add(fileNode); } } - treeNodeDictionary.Clear(); + if (fileNode.Nodes.Count > 0) + { + treeNodeCollection.Add(fileNode); + } + + Progress.Report(++i, progressCount); } + treeNodeDictionary.Clear(); + return treeNodeCollection; } @@ -435,7 +354,7 @@ namespace AssetStudioGUI var exportpath = savePath + "\\"; if (assetGroupSelectedIndex == 1) { - exportpath += Path.GetFileNameWithoutExtension(asset.sourceFile.fullName) + "_export\\"; + exportpath += Path.GetFileNameWithoutExtension(asset.SourceFile.fullName) + "_export\\"; } else if (assetGroupSelectedIndex == 0) { diff --git a/AssetStudioTools/AudioClipConverter.cs b/AssetStudioTools/AudioClipConverter.cs index ec6452e..6ddb2fa 100644 --- a/AssetStudioTools/AudioClipConverter.cs +++ b/AssetStudioTools/AudioClipConverter.cs @@ -15,6 +15,9 @@ namespace AssetStudio public byte[] ConvertToWav() { + var m_AudioData = m_AudioClip.m_AudioData.Value; + if (m_AudioData == null || m_AudioData.Length == 0) + return null; var exinfo = new FMOD.CREATESOUNDEXINFO(); var result = FMOD.Factory.System_Create(out var system); if (result != FMOD.RESULT.OK) @@ -24,7 +27,7 @@ namespace AssetStudio return null; exinfo.cbsize = Marshal.SizeOf(exinfo); exinfo.length = (uint)m_AudioClip.m_Size; - result = system.createSound(m_AudioClip.m_AudioData, FMOD.MODE.OPENMEMORY, ref exinfo, out var sound); + result = system.createSound(m_AudioData, FMOD.MODE.OPENMEMORY, ref exinfo, out var sound); if (result != FMOD.RESULT.OK) return null; result = sound.getSubSound(0, out var subsound); diff --git a/AssetStudioTools/ModelConverter.cs b/AssetStudioTools/ModelConverter.cs index 68893b6..89af1a8 100644 --- a/AssetStudioTools/ModelConverter.cs +++ b/AssetStudioTools/ModelConverter.cs @@ -19,29 +19,27 @@ namespace AssetStudio private Avatar avatar; private Dictionary morphChannelInfo = new Dictionary(); - private HashSet animationClipHashSet = new HashSet(); + private HashSet animationClipHashSet = new HashSet(); private Dictionary bonePathHash = new Dictionary(); - private Dictionary textureNameDictionary = new Dictionary(); + private Dictionary textureNameDictionary = new Dictionary(); public ModelConverter(GameObject m_GameObject) { - if (m_GameObject.m_Animator != null && m_GameObject.m_Animator.TryGet(out var m_Animator)) + if (m_GameObject.m_Animator != null) { - var animator = new Animator(m_Animator); - InitWithAnimator(animator); - CollectAnimationClip(animator); + InitWithAnimator(m_GameObject.m_Animator); + CollectAnimationClip(m_GameObject.m_Animator); } else InitWithGameObject(m_GameObject); ConvertAnimations(); } - public ModelConverter(GameObject m_GameObject, ObjectReader[] animationList) + public ModelConverter(GameObject m_GameObject, AnimationClip[] animationList) { - if (m_GameObject.m_Animator != null && m_GameObject.m_Animator.TryGet(out var m_Animator)) + if (m_GameObject.m_Animator != null) { - var animator = new Animator(m_Animator); - InitWithAnimator(animator); + InitWithAnimator(m_GameObject.m_Animator); } else InitWithGameObject(m_GameObject); @@ -59,7 +57,7 @@ namespace AssetStudio ConvertAnimations(); } - public ModelConverter(Animator m_Animator, ObjectReader[] animationList) + public ModelConverter(Animator m_Animator, AnimationClip[] animationList) { InitWithAnimator(m_Animator); foreach (var animationClip in animationList) @@ -72,27 +70,26 @@ namespace AssetStudio private void InitWithAnimator(Animator m_Animator) { if (m_Animator.m_Avatar.TryGet(out var m_Avatar)) - avatar = new Avatar(m_Avatar); + avatar = m_Avatar; - m_Animator.m_GameObject.TryGetGameObject(out var m_GameObject); + m_Animator.m_GameObject.TryGet(out var m_GameObject); InitWithGameObject(m_GameObject, m_Animator.m_HasTransformHierarchy); } private void InitWithGameObject(GameObject m_GameObject, bool hasTransformHierarchy = true) { - m_GameObject.m_Transform.TryGetTransform(out var m_Transform); - var rootTransform = m_Transform; + var m_Transform = m_GameObject.m_Transform; if (!hasTransformHierarchy) { - var rootFrame = ConvertFrame(rootTransform); + var rootFrame = ConvertFrame(m_Transform); FrameList.Add(rootFrame); DeoptimizeTransformHierarchy(); } else { var frameList = new List(); - var tempTransform = rootTransform; - while (tempTransform.m_Father.TryGetTransform(out var m_Father)) + var tempTransform = m_Transform; + while (tempTransform.m_Father.TryGet(out var m_Father)) { frameList.Add(ConvertFrame(m_Father)); tempTransform = m_Father; @@ -113,7 +110,7 @@ namespace AssetStudio ConvertFrames(m_Transform, null); } - CreateBonePathHash(rootTransform); + CreateBonePathHash(m_Transform); } ConvertMeshRenderer(m_Transform); @@ -121,83 +118,68 @@ namespace AssetStudio private void ConvertMeshRenderer(Transform m_Transform) { - m_Transform.m_GameObject.TryGetGameObject(out var m_GameObject); - foreach (var m_Component in m_GameObject.m_Components) + m_Transform.m_GameObject.TryGet(out var m_GameObject); + + if (m_GameObject.m_MeshRenderer != null) { - if (m_Component.TryGet(out var objectReader)) + ConvertMeshRenderer(m_GameObject.m_MeshRenderer); + } + + if (m_GameObject.m_SkinnedMeshRenderer != null) + { + ConvertMeshRenderer(m_GameObject.m_SkinnedMeshRenderer); + } + + if (m_GameObject.m_Animation != null) + { + foreach (var animation in m_GameObject.m_Animation.m_Animations) { - switch (objectReader.type) + if (animation.TryGet(out var animationClip)) { - case ClassIDType.MeshRenderer: - { - var m_Renderer = new MeshRenderer(objectReader); - ConvertMeshRenderer(m_Renderer); - break; - } - case ClassIDType.SkinnedMeshRenderer: - { - var m_SkinnedMeshRenderer = new SkinnedMeshRenderer(objectReader); - ConvertMeshRenderer(m_SkinnedMeshRenderer); - break; - } - case ClassIDType.Animation: - { - var m_Animation = new Animation(objectReader); - foreach (var animation in m_Animation.m_Animations) - { - if (animation.TryGet(out var animationClip)) - { - animationClipHashSet.Add(animationClip); - } - } - break; - } + animationClipHashSet.Add(animationClip); } } } + foreach (var pptr in m_Transform.m_Children) { - if (pptr.TryGetTransform(out var child)) + if (pptr.TryGet(out var child)) ConvertMeshRenderer(child); } } private void CollectAnimationClip(Animator m_Animator) { - if (m_Animator.m_Controller.TryGet(out var objectReader)) + if (m_Animator.m_Controller.TryGet(out var m_Controller)) { - if (objectReader.type == ClassIDType.AnimatorOverrideController) + switch (m_Controller) { - var m_AnimatorOverrideController = new AnimatorOverrideController(objectReader); - if (m_AnimatorOverrideController.m_Controller.TryGet(out objectReader)) - { - var m_AnimatorController = new AnimatorController(objectReader); - foreach (var m_AnimationClip in m_AnimatorController.m_AnimationClips) + case AnimatorOverrideController m_AnimatorOverrideController: { - if (m_AnimationClip.TryGet(out objectReader)) + if (m_AnimatorOverrideController.m_Controller.TryGet(out var m_AnimatorController)) { - animationClipHashSet.Add(objectReader); + foreach (var pptr in m_AnimatorController.m_AnimationClips) + { + if (pptr.TryGet(out var m_AnimationClip)) + { + animationClipHashSet.Add(m_AnimationClip); + } + } } + break; } - } - /*foreach (var clip in m_AnimatorOverrideController.m_Clips) - { - if (assetsfileList.TryGetPD(clip[1], out assetPreloadData)) + + case AnimatorController m_AnimatorController: { - animationList.Add(new AnimationClip(assetPreloadData)); + foreach (var pptr in m_AnimatorController.m_AnimationClips) + { + if (pptr.TryGet(out var m_AnimationClip)) + { + animationClipHashSet.Add(m_AnimationClip); + } + } + break; } - }*/ - } - else if (objectReader.type == ClassIDType.AnimatorController) - { - var m_AnimatorController = new AnimatorController(objectReader); - foreach (var m_AnimationClip in m_AnimatorController.m_AnimationClips) - { - if (m_AnimationClip.TryGet(out objectReader)) - { - animationClipHashSet.Add(objectReader); - } - } } } } @@ -205,7 +187,7 @@ namespace AssetStudio private ImportedFrame ConvertFrame(Transform trans) { var frame = new ImportedFrame(); - trans.m_GameObject.TryGetGameObject(out var m_GameObject); + trans.m_GameObject.TryGet(out var m_GameObject); frame.Name = m_GameObject.m_Name; frame.InitChildren(trans.m_Children.Count); var m_EulerRotation = QuatToEuler(new[] { trans.m_LocalRotation[0], -trans.m_LocalRotation[1], -trans.m_LocalRotation[2], trans.m_LocalRotation[3] }); @@ -243,7 +225,7 @@ namespace AssetStudio } foreach (var pptr in trans.m_Children) { - if (pptr.TryGetTransform(out var child)) + if (pptr.TryGet(out var child)) ConvertFrames(child, frame); } } @@ -254,9 +236,8 @@ namespace AssetStudio if (mesh == null) return; var iMesh = new ImportedMesh(); - meshR.m_GameObject.TryGetGameObject(out var m_GameObject2); - m_GameObject2.m_Transform.TryGetTransform(out var meshTransform); - iMesh.Name = GetMeshPath(meshTransform); + meshR.m_GameObject.TryGet(out var m_GameObject2); + iMesh.Name = GetMeshPath(m_GameObject2.m_Transform); iMesh.SubmeshList = new List(); var subHashSet = new HashSet(); var combine = false; @@ -294,9 +275,9 @@ namespace AssetStudio Material mat = null; if (i - firstSubMesh < meshR.m_Materials.Length) { - if (meshR.m_Materials[i - firstSubMesh].TryGet(out var MaterialPD)) + if (meshR.m_Materials[i - firstSubMesh].TryGet(out var m_Material)) { - mat = new Material(MaterialPD); + mat = m_Material; } } ImportedMaterial iMat = ConvertMaterial(mat); @@ -431,9 +412,9 @@ namespace AssetStudio for (int i = 0; i < sMesh.m_Bones.Length; i++) { var bone = new ImportedBone(); - if (sMesh.m_Bones[i].TryGetTransform(out var m_Transform)) + if (sMesh.m_Bones[i].TryGet(out var m_Transform)) { - if (m_Transform.m_GameObject.TryGetGameObject(out var m_GameObject)) + if (m_Transform.m_GameObject.TryGet(out var m_GameObject)) { bone.Name = m_GameObject.m_Name; } @@ -538,7 +519,7 @@ namespace AssetStudio //TODO combine mesh if (combine) { - meshR.m_GameObject.TryGetGameObject(out var m_GameObject); + meshR.m_GameObject.TryGet(out var m_GameObject); var frame = ImportedHelpers.FindChildOrRoot(m_GameObject.m_Name, FrameList[0]); if (frame?.Parent != null) { @@ -567,26 +548,19 @@ namespace AssetStudio { if (meshR is SkinnedMeshRenderer sMesh) { - if (sMesh.m_Mesh.TryGet(out var MeshPD)) + if (sMesh.m_Mesh.TryGet(out var m_Mesh)) { - return new Mesh(MeshPD); + return m_Mesh; } } else { - meshR.m_GameObject.TryGetGameObject(out var m_GameObject); - foreach (var m_Component in m_GameObject.m_Components) + meshR.m_GameObject.TryGet(out var m_GameObject); + if (m_GameObject.m_MeshFilter != null) { - if (m_Component.TryGet(out var objectReader)) + if (m_GameObject.m_MeshFilter.m_Mesh.TryGet(out var m_Mesh)) { - if (objectReader.type == ClassIDType.MeshFilter) - { - var m_MeshFilter = new MeshFilter(objectReader); - if (m_MeshFilter.m_Mesh.TryGet(out var MeshPD)) - { - return new Mesh(MeshPD); - } - } + return m_Mesh; } } } @@ -596,7 +570,7 @@ namespace AssetStudio private string GetMeshPath(Transform meshTransform) { - meshTransform.m_GameObject.TryGetGameObject(out var m_GameObject); + meshTransform.m_GameObject.TryGet(out var m_GameObject); var curFrame = ImportedHelpers.FindChildOrRoot(m_GameObject.m_Name, FrameList[0]); var path = curFrame.Name; while (curFrame.Parent != null) @@ -610,8 +584,8 @@ namespace AssetStudio private string GetTransformPath(Transform transform) { - transform.m_GameObject.TryGetGameObject(out var m_GameObject); - if (transform.m_Father.TryGetTransform(out var father)) + transform.m_GameObject.TryGet(out var m_GameObject); + if (transform.m_Father.TryGet(out var father)) { return GetTransformPath(father) + "/" + m_GameObject.m_Name; } @@ -675,9 +649,9 @@ namespace AssetStudio foreach (var texEnv in mat.m_TexEnvs) { Texture2D m_Texture2D = null; - if (texEnv.m_Texture.TryGet(out var m_Texture) && m_Texture.type == ClassIDType.Texture2D) //TODO other Texture + if (texEnv.m_Texture.TryGet(out var m_Texture)) //TODO other Texture { - m_Texture2D = new Texture2D(m_Texture, true); + m_Texture2D = m_Texture; } if (m_Texture2D == null) @@ -758,9 +732,8 @@ namespace AssetStudio private void ConvertAnimations() { - foreach (var assetPreloadData in animationClipHashSet) + foreach (var animationClip in animationClipHashSet) { - var animationClip = new AnimationClip(assetPreloadData); var iAnim = new ImportedKeyframedAnimation(); AnimationList.Add(iAnim); iAnim.Name = animationClip.m_Name; @@ -1027,7 +1000,7 @@ namespace AssetStudio } foreach (var pptr in m_Transform.m_Children) { - if (pptr.TryGetTransform(out var child)) + if (pptr.TryGet(out var child)) CreateBonePathHash(child); } } diff --git a/AssetStudioTools/ScriptHelper.cs b/AssetStudioTools/ScriptHelper.cs index 022e78d..50674d5 100644 --- a/AssetStudioTools/ScriptHelper.cs +++ b/AssetStudioTools/ScriptHelper.cs @@ -13,9 +13,8 @@ namespace AssetStudio { var m_MonoBehaviour = new MonoBehaviour(reader); var sb = CreateMonoBehaviourHeader(m_MonoBehaviour); - if (m_MonoBehaviour.m_Script.TryGet(out var script)) + if (m_MonoBehaviour.m_Script.TryGet(out var m_Script)) { - var m_Script = new MonoScript(script); if (!moduleDic.TryGetValue(m_Script.m_AssemblyName, out var module)) { return sb.ToString(); @@ -150,7 +149,7 @@ namespace AssetStudio } if (indent != -1 && IsAssignFromUnityObject(typeDef)) { - var pptr = reader.ReadPPtr(); + var pptr = new PPtr(reader); sb.AppendLine($"{new string('\t', indent)}PPtr<{typeDef.Name}> {name} = {{fileID: {pptr.m_FileID}, pathID: {pptr.m_PathID}}}"); return; } @@ -291,19 +290,24 @@ namespace AssetStudio { switch (typeDef.FullName) { - case "UnityEngine.Vector2": - case "UnityEngine.Vector3": - case "UnityEngine.Vector4": - case "UnityEngine.Rect": - case "UnityEngine.Quaternion": - case "UnityEngine.Matrix4x4": + case "UnityEngine.AnimationCurve": + case "UnityEngine.Bounds": + case "UnityEngine.BoundsInt": case "UnityEngine.Color": case "UnityEngine.Color32": - case "UnityEngine.LayerMask": - case "UnityEngine.AnimationCurve": case "UnityEngine.Gradient": - case "UnityEngine.RectOffset": case "UnityEngine.GUIStyle": + case "UnityEngine.LayerMask": + case "UnityEngine.Matrix4x4": + 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/AssetStudioTools/ShaderConverter.cs b/AssetStudioTools/ShaderConverter.cs index e96de53..79d61f5 100644 --- a/AssetStudioTools/ShaderConverter.cs +++ b/AssetStudioTools/ShaderConverter.cs @@ -42,7 +42,7 @@ namespace AssetStudio new ShaderProgram(blobReader); } }*/ - return shader.reader.Dump(); + return shader.Dump(); } return Encoding.UTF8.GetString(shader.m_Script); } diff --git a/AssetStudioTools/SpriteHelper.cs b/AssetStudioTools/SpriteHelper.cs index a936f7c..f8f1221 100644 --- a/AssetStudioTools/SpriteHelper.cs +++ b/AssetStudioTools/SpriteHelper.cs @@ -8,27 +8,26 @@ namespace AssetStudio { public static Bitmap GetImageFromSprite(Sprite m_Sprite) { - if (m_Sprite.m_SpriteAtlas != null && m_Sprite.m_SpriteAtlas.TryGet(out var objectReader)) + if (m_Sprite.m_SpriteAtlas != null && m_Sprite.m_SpriteAtlas.TryGet(out var m_SpriteAtlas)) { - var m_SpriteAtlas = new SpriteAtlas(objectReader); - if (m_SpriteAtlas.m_RenderDataMap.TryGetValue(m_Sprite.m_RenderDataKey, out var spriteAtlasData) && spriteAtlasData.texture.TryGet(out objectReader)) + if (m_SpriteAtlas.m_RenderDataMap.TryGetValue(m_Sprite.m_RenderDataKey, out var spriteAtlasData) && spriteAtlasData.texture.TryGet(out var m_Texture2D)) { - return CutImage(objectReader, spriteAtlasData.textureRect, m_Sprite, spriteAtlasData.settingsRaw); + return CutImage(m_Texture2D, spriteAtlasData.textureRect, m_Sprite, spriteAtlasData.settingsRaw); } } else { - if (m_Sprite.texture.TryGet(out objectReader)) + if (m_Sprite.texture.TryGet(out var m_Texture2D)) { - return CutImage(objectReader, m_Sprite.textureRect, m_Sprite, m_Sprite.settingsRaw); + return CutImage(m_Texture2D, m_Sprite.textureRect, m_Sprite, m_Sprite.settingsRaw); } } return null; } - private static Bitmap CutImage(ObjectReader texture2DAsset, RectangleF textureRect, Sprite m_Sprite, SpriteSettings settingsRaw) + private static Bitmap CutImage(Texture2D m_Texture2D, RectangleF textureRect, Sprite m_Sprite, SpriteSettings settingsRaw) { - var texture2D = new Texture2DConverter(new Texture2D(texture2DAsset, true)); + var texture2D = new Texture2DConverter(m_Texture2D); var originalImage = texture2D.ConvertToBitmap(false); if (originalImage != null) { diff --git a/AssetStudioTools/Texture2DConverter.cs b/AssetStudioTools/Texture2DConverter.cs index f94c90c..4b6ae74 100644 --- a/AssetStudioTools/Texture2DConverter.cs +++ b/AssetStudioTools/Texture2DConverter.cs @@ -87,7 +87,7 @@ namespace AssetStudio public Texture2DConverter(Texture2D m_Texture2D) { image_data_size = m_Texture2D.image_data_size; - image_data = m_Texture2D.image_data; + image_data = m_Texture2D.image_data.Value; m_Width = m_Texture2D.m_Width; m_Height = m_Texture2D.m_Height; m_TextureFormat = m_Texture2D.m_TextureFormat; @@ -913,7 +913,7 @@ namespace AssetStudio buff = new byte[stride * m_Height]; for (int i = 0; i < m_Height; i++) { - Array.Copy(image_data, i * m_Width * 2, buff, i * stride, m_Width * 2); + Buffer.BlockCopy(image_data, i * m_Width * 2, buff, i * stride, m_Width * 2); } } else