From c37e2e65b78f9040cc7984597f9d70d517fb4b43 Mon Sep 17 00:00:00 2001 From: VaDiM Date: Fri, 18 Oct 2024 20:55:34 +0300 Subject: [PATCH] Fixes and improvements for asset parsing via typetree --- AssetStudio/AssetsManager.cs | 11 ++-- AssetStudio/Classes/AnimationClip.cs | 7 +-- AssetStudio/Classes/PPtr.cs | 5 ++ AssetStudio/Classes/SpriteAtlas.cs | 2 + AssetStudio/Classes/Texture2D.cs | 8 +-- AssetStudio/Classes/Texture2DArray.cs | 10 ++-- .../ByteArrayConverter.cs | 25 ++++++++ .../FloatConverter.cs} | 18 +----- .../JsonConverterHelpers/PPtrConverter.cs | 53 +++++++++++++++++ .../RenderDataMapConverter.cs | 58 +++++++++++++++++++ AssetStudio/TypeTreeHelper.cs | 23 +++++++- .../CubismMotion3Converter.cs | 4 +- 12 files changed, 184 insertions(+), 40 deletions(-) create mode 100644 AssetStudio/JsonConverterHelpers/ByteArrayConverter.cs rename AssetStudio/{JsonConverterHelper.cs => JsonConverterHelpers/FloatConverter.cs} (63%) create mode 100644 AssetStudio/JsonConverterHelpers/PPtrConverter.cs create mode 100644 AssetStudio/JsonConverterHelpers/RenderDataMapConverter.cs diff --git a/AssetStudio/AssetsManager.cs b/AssetStudio/AssetsManager.cs index 835ed88..8b6f336 100644 --- a/AssetStudio/AssetsManager.cs +++ b/AssetStudio/AssetsManager.cs @@ -515,16 +515,17 @@ namespace AssetStudio var jsonOptions = new JsonSerializerOptions { - Converters = { new JsonConverterHelper.ByteArrayConverter() }, + Converters = { new JsonConverterHelper.ByteArrayConverter(), new JsonConverterHelper.PPtrConverter() }, NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals, IncludeFields = true, }; var progressCount = assetsFileList.Sum(x => x.m_Objects.Count); - int i = 0; + var i = 0; Progress.Reset(); foreach (var assetsFile in assetsFileList) { + JsonConverterHelper.PPtrConverter.AssetsFile = assetsFile; foreach (var objectInfo in assetsFile.m_Objects) { var objectReader = new ObjectReader(assetsFile.reader, assetsFile, objectInfo); @@ -542,7 +543,7 @@ namespace AssetStudio break; case ClassIDType.AnimationClip: obj = objectReader.serializedType?.m_Type != null && LoadingViaTypeTreeEnabled - ? new AnimationClip(objectReader, TypeTreeHelper.ReadType(objectReader.serializedType.m_Type, objectReader), jsonOptions) + ? new AnimationClip(objectReader, TypeTreeHelper.ReadTypeByteArray(objectReader.serializedType.m_Type, objectReader), jsonOptions) : new AnimationClip(objectReader); break; case ClassIDType.Animator: @@ -620,12 +621,12 @@ namespace AssetStudio break; case ClassIDType.Texture2D: obj = objectReader.serializedType?.m_Type != null && LoadingViaTypeTreeEnabled - ? new Texture2D(objectReader, TypeTreeHelper.ReadType(objectReader.serializedType.m_Type, objectReader), jsonOptions) + ? new Texture2D(objectReader, TypeTreeHelper.ReadTypeByteArray(objectReader.serializedType.m_Type, objectReader), jsonOptions) : new Texture2D(objectReader); break; case ClassIDType.Texture2DArray: obj = objectReader.serializedType?.m_Type != null && LoadingViaTypeTreeEnabled - ? new Texture2DArray(objectReader, TypeTreeHelper.ReadType(objectReader.serializedType.m_Type, objectReader), jsonOptions) + ? new Texture2DArray(objectReader, TypeTreeHelper.ReadTypeByteArray(objectReader.serializedType.m_Type, objectReader), jsonOptions) : new Texture2DArray(objectReader); break; case ClassIDType.Transform: diff --git a/AssetStudio/Classes/AnimationClip.cs b/AssetStudio/Classes/AnimationClip.cs index e1e282b..79af15a 100644 --- a/AssetStudio/Classes/AnimationClip.cs +++ b/AssetStudio/Classes/AnimationClip.cs @@ -1,5 +1,4 @@ using System; -using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; @@ -1031,9 +1030,9 @@ namespace AssetStudio public AnimationClip() { } - public AnimationClip(ObjectReader reader, IDictionary typeDict, JsonSerializerOptions jsonOptions) : base(reader) + public AnimationClip(ObjectReader reader, byte[] type, JsonSerializerOptions jsonOptions) : base(reader) { - var parsedAnimClip = JsonSerializer.Deserialize(JsonSerializer.SerializeToUtf8Bytes(typeDict, jsonOptions), jsonOptions); + var parsedAnimClip = JsonSerializer.Deserialize(type, jsonOptions); m_AnimationType = parsedAnimClip.m_AnimationType; m_Legacy = parsedAnimClip.m_Legacy; m_Compressed = parsedAnimClip.m_Compressed; @@ -1052,8 +1051,6 @@ namespace AssetStudio m_MuscleClip = parsedAnimClip.m_MuscleClip; m_ClipBindingConstant = parsedAnimClip.m_ClipBindingConstant; m_Events = parsedAnimClip.m_Events; - - typeDict.Clear(); } public AnimationClip(ObjectReader reader) : base(reader) diff --git a/AssetStudio/Classes/PPtr.cs b/AssetStudio/Classes/PPtr.cs index 9bec685..a4e2bf6 100644 --- a/AssetStudio/Classes/PPtr.cs +++ b/AssetStudio/Classes/PPtr.cs @@ -19,6 +19,11 @@ namespace AssetStudio public PPtr() { } + public void SetAssetsFile(SerializedFile assetsFile) + { + _assetsFile = assetsFile; + } + private bool TryGetAssetsFile(out SerializedFile result) { result = null; diff --git a/AssetStudio/Classes/SpriteAtlas.cs b/AssetStudio/Classes/SpriteAtlas.cs index dfe34a5..d5174f4 100644 --- a/AssetStudio/Classes/SpriteAtlas.cs +++ b/AssetStudio/Classes/SpriteAtlas.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Text.Json.Serialization; namespace AssetStudio { @@ -45,6 +46,7 @@ namespace AssetStudio public sealed class SpriteAtlas : NamedObject { public PPtr[] m_PackedSprites; + [JsonConverter(typeof(JsonConverterHelper.RenderDataMapConverter))] public Dictionary, SpriteAtlasData> m_RenderDataMap; public bool m_IsVariant; diff --git a/AssetStudio/Classes/Texture2D.cs b/AssetStudio/Classes/Texture2D.cs index 915668b..42989c4 100644 --- a/AssetStudio/Classes/Texture2D.cs +++ b/AssetStudio/Classes/Texture2D.cs @@ -1,6 +1,6 @@ using System; -using System.Collections; using System.Text.Json; +using System.Text.Json.Serialization; namespace AssetStudio { @@ -15,6 +15,7 @@ namespace AssetStudio public GLTextureSettings m_TextureSettings; public int m_ImageCount; public byte[] m_PlatformBlob; + [JsonPropertyName("image data")] public ResourceReader image_data; public StreamingInfo m_StreamData; @@ -53,9 +54,9 @@ namespace AssetStudio byteSize = (uint)(m_Width * m_Height) * 4; } - public Texture2D(ObjectReader reader, IDictionary typeDict, JsonSerializerOptions jsonOptions) : base(reader) + public Texture2D(ObjectReader reader, byte[] type, JsonSerializerOptions jsonOptions) : base(reader) { - var parsedTex2d = JsonSerializer.Deserialize(JsonSerializer.SerializeToUtf8Bytes(typeDict, jsonOptions), jsonOptions); + var parsedTex2d = JsonSerializer.Deserialize(type, jsonOptions); m_Width = parsedTex2d.m_Width; m_Height = parsedTex2d.m_Height; m_CompleteImageSize = parsedTex2d.m_CompleteImageSize; @@ -70,7 +71,6 @@ namespace AssetStudio image_data = !string.IsNullOrEmpty(m_StreamData?.path) ? new ResourceReader(m_StreamData.path, assetsFile, m_StreamData.offset, m_StreamData.size) : new ResourceReader(reader, parsedTex2d.image_data.Offset, parsedTex2d.image_data.Size); - typeDict.Clear(); } public Texture2D(ObjectReader reader) : base(reader) diff --git a/AssetStudio/Classes/Texture2DArray.cs b/AssetStudio/Classes/Texture2DArray.cs index 39dee29..8d2a997 100644 --- a/AssetStudio/Classes/Texture2DArray.cs +++ b/AssetStudio/Classes/Texture2DArray.cs @@ -1,6 +1,6 @@ -using System.Collections; -using System.Collections.Generic; +using System.Collections.Generic; using System.Text.Json; +using System.Text.Json.Serialization; namespace AssetStudio { @@ -14,6 +14,7 @@ namespace AssetStudio public uint m_DataSize; public GLTextureSettings m_TextureSettings; public int m_ColorSpace; + [JsonPropertyName("image data")] public ResourceReader image_data; public StreamingInfo m_StreamData; public List TextureList; @@ -50,9 +51,9 @@ namespace AssetStudio TextureList = new List(); } - public Texture2DArray(ObjectReader reader, IDictionary typeDict, JsonSerializerOptions jsonOptions) : base(reader) + public Texture2DArray(ObjectReader reader, byte[] type, JsonSerializerOptions jsonOptions) : base(reader) { - var parsedTex2dArray = JsonSerializer.Deserialize(JsonSerializer.SerializeToUtf8Bytes(typeDict, jsonOptions), jsonOptions); + var parsedTex2dArray = JsonSerializer.Deserialize(type, jsonOptions); m_Width = parsedTex2dArray.m_Width; m_Height = parsedTex2dArray.m_Height; m_Depth = parsedTex2dArray.m_Depth; @@ -65,7 +66,6 @@ namespace AssetStudio image_data = !string.IsNullOrEmpty(m_StreamData?.path) ? new ResourceReader(m_StreamData.path, assetsFile, m_StreamData.offset, m_StreamData.size) : new ResourceReader(reader, parsedTex2dArray.image_data.Offset, parsedTex2dArray.image_data.Size); - typeDict.Clear(); TextureList = new List(); } diff --git a/AssetStudio/JsonConverterHelpers/ByteArrayConverter.cs b/AssetStudio/JsonConverterHelpers/ByteArrayConverter.cs new file mode 100644 index 0000000..03b9b28 --- /dev/null +++ b/AssetStudio/JsonConverterHelpers/ByteArrayConverter.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace AssetStudio +{ + public static partial class JsonConverterHelper + { + public class ByteArrayConverter : JsonConverter + { + public override byte[] Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return reader.TokenType == JsonTokenType.StartArray + ? JsonSerializer.Deserialize>(ref reader).ToArray() //JsonArray to ByteArray + : JsonSerializer.Deserialize(ref reader); + } + + public override void Write(Utf8JsonWriter writer, byte[] value, JsonSerializerOptions options) + { + writer.WriteBase64StringValue(value); + } + } + } +} diff --git a/AssetStudio/JsonConverterHelper.cs b/AssetStudio/JsonConverterHelpers/FloatConverter.cs similarity index 63% rename from AssetStudio/JsonConverterHelper.cs rename to AssetStudio/JsonConverterHelpers/FloatConverter.cs index d2ab040..8c195b2 100644 --- a/AssetStudio/JsonConverterHelper.cs +++ b/AssetStudio/JsonConverterHelpers/FloatConverter.cs @@ -1,28 +1,12 @@ using System; -using System.Collections.Generic; using System.Globalization; using System.Text.Json; using System.Text.Json.Serialization; namespace AssetStudio { - public static class JsonConverterHelper + public static partial class JsonConverterHelper { - public class ByteArrayConverter : JsonConverter - { - public override byte[] Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return reader.TokenType == JsonTokenType.StartArray - ? JsonSerializer.Deserialize>(ref reader).ToArray() //JsonArray to ByteArray - : JsonSerializer.Deserialize(ref reader); - } - - public override void Write(Utf8JsonWriter writer, byte[] value, JsonSerializerOptions options) - { - writer.WriteBase64StringValue(value); - } - } - public class FloatConverter : JsonConverter { public override float Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) diff --git a/AssetStudio/JsonConverterHelpers/PPtrConverter.cs b/AssetStudio/JsonConverterHelpers/PPtrConverter.cs new file mode 100644 index 0000000..3809624 --- /dev/null +++ b/AssetStudio/JsonConverterHelpers/PPtrConverter.cs @@ -0,0 +1,53 @@ +using System; +using System.Text.Json; +using System.Text.Json.Nodes; +using System.Text.Json.Serialization; + +namespace AssetStudio +{ + public static partial class JsonConverterHelper + { + public class PPtrConverter : JsonConverterFactory + { + public static SerializedFile AssetsFile; + + public override bool CanConvert(Type typeToConvert) + { + if (!typeToConvert.IsGenericType) + return false; + + var generic = typeToConvert.GetGenericTypeDefinition(); + return generic == typeof(PPtr<>); + } + + public override JsonConverter CreateConverter(Type type, JsonSerializerOptions options) + { + var elementType = type.GetGenericArguments()[0]; + var converter = (JsonConverter)Activator.CreateInstance(typeof(PPtrConverter<>).MakeGenericType(elementType), AssetsFile); + return converter; + } + } + + private class PPtrConverter : JsonConverter> where T : Object + { + private readonly SerializedFile _assetsFile; + + public PPtrConverter(SerializedFile assetsFile) + { + _assetsFile = assetsFile; + } + + public override PPtr Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + var pptrObj = JsonSerializer.Deserialize>(ref reader); + pptrObj.SetAssetsFile(_assetsFile); + return pptrObj; + } + + public override void Write(Utf8JsonWriter writer, PPtr value, JsonSerializerOptions options) + { + JsonSerializer.Serialize(value); + } + } + } +} diff --git a/AssetStudio/JsonConverterHelpers/RenderDataMapConverter.cs b/AssetStudio/JsonConverterHelpers/RenderDataMapConverter.cs new file mode 100644 index 0000000..8f24531 --- /dev/null +++ b/AssetStudio/JsonConverterHelpers/RenderDataMapConverter.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Text.Json.Nodes; +using System.Text.Json.Serialization; + +namespace AssetStudio +{ + public static partial class JsonConverterHelper + { + public class RenderDataMapConverter : JsonConverter, SpriteAtlasData>> + { + public override Dictionary, SpriteAtlasData> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + var dataArray = JsonSerializer.Deserialize[]>(ref reader, options); + var renderDataMap = new Dictionary, SpriteAtlasData>(dataArray.Length); + foreach (var kvp in dataArray) + { + var jsonFirst = kvp.Key["first"]; + var first = jsonFirst.Deserialize(options).Convert(); + var second = (long) kvp.Key["second"]; + renderDataMap.Add(new KeyValuePair(first, second), kvp.Value); + } + return renderDataMap; + } + + public override void Write(Utf8JsonWriter writer, Dictionary, SpriteAtlasData> value, JsonSerializerOptions options) + { + var jsonDict = new Dictionary(); + foreach (var kv in value) + { + var strKey = $"{kv.Key.Key}, {kv.Key.Value}"; + jsonDict.Add(strKey, kv.Value); + } + var strValue = JsonSerializer.Serialize(jsonDict, options).Replace(" ", " "); + writer.WriteRawValue(strValue); + } + } + + private class GUID + { + [JsonPropertyName("data[0]")] public uint data0; + [JsonPropertyName("data[1]")] public uint data1; + [JsonPropertyName("data[2]")] public uint data2; + [JsonPropertyName("data[3]")] public uint data3; + + public Guid Convert() + { + var guidBytes = new byte[16]; + BitConverter.GetBytes(data0).CopyTo(guidBytes, 0); + BitConverter.GetBytes(data1).CopyTo(guidBytes, 4); + BitConverter.GetBytes(data2).CopyTo(guidBytes, 8); + BitConverter.GetBytes(data3).CopyTo(guidBytes, 12); + return new Guid(guidBytes); + } + } + } +} diff --git a/AssetStudio/TypeTreeHelper.cs b/AssetStudio/TypeTreeHelper.cs index 7bfa0bc..ba40fb1 100644 --- a/AssetStudio/TypeTreeHelper.cs +++ b/AssetStudio/TypeTreeHelper.cs @@ -3,11 +3,24 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.IO; using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; namespace AssetStudio { public static class TypeTreeHelper { + private static readonly JsonSerializerOptions JsonOptions; + static TypeTreeHelper() + { + JsonOptions = new JsonSerializerOptions + { + NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals, + ReferenceHandler = ReferenceHandler.IgnoreCycles, + IncludeFields = true, + }; + } + public static string ReadTypeString(TypeTree m_Type, ObjectReader reader) { reader.Reset(); @@ -163,6 +176,14 @@ namespace AssetStudio reader.AlignStream(); } + public static byte[] ReadTypeByteArray(TypeTree m_Types, ObjectReader reader) + { + var type = ReadType(m_Types, reader); + var bytes = JsonSerializer.SerializeToUtf8Bytes(type, JsonOptions); + type.Clear(); + return bytes; + } + public static OrderedDictionary ReadType(TypeTree m_Types, ObjectReader reader) { reader.Reset(); @@ -171,7 +192,7 @@ namespace AssetStudio for (int i = 1; i < m_Nodes.Count; i++) { var m_Node = m_Nodes[i]; - var varNameStr = m_Node.m_Name.Replace("image data", "image_data"); + var varNameStr = m_Node.m_Name; obj[varNameStr] = ReadValue(m_Nodes, reader, ref i); } var readed = reader.Position - reader.byteStart; diff --git a/AssetStudioUtility/CubismLive2DExtractor/CubismMotion3Converter.cs b/AssetStudioUtility/CubismLive2DExtractor/CubismMotion3Converter.cs index 98f8419..85a08bc 100644 --- a/AssetStudioUtility/CubismLive2DExtractor/CubismMotion3Converter.cs +++ b/AssetStudioUtility/CubismLive2DExtractor/CubismMotion3Converter.cs @@ -7,7 +7,6 @@ namespace CubismLive2DExtractor { class CubismMotion3Converter { - private SerializedFile assetsFile; private Dictionary bonePathHash = new Dictionary(); public List AnimationList { get; protected set; } = new List(); @@ -30,7 +29,6 @@ namespace CubismLive2DExtractor foreach (var animationClip in animationClips) { var iAnim = new ImportedKeyframedAnimation(); - assetsFile = animationClip.assetsFile; AnimationList.Add(iAnim); iAnim.Name = animationClip.m_Name; iAnim.SampleRate = animationClip.m_SampleRate; @@ -136,7 +134,7 @@ namespace CubismLive2DExtractor target = "PartOpacity"; } } - else if (binding.script.TryGet(out MonoScript script, assetsFile)) + else if (binding.script.TryGet(out MonoScript script)) { switch (script.m_ClassName) {