From 2c860f004b5b9849f5b39291c4ce82c47c63f4e9 Mon Sep 17 00:00:00 2001 From: VaDiM Date: Sat, 13 Apr 2024 01:01:23 +0300 Subject: [PATCH] Use system.text.json to parse typetree well, it's still slower than some more suitable libs for such task, but stable and with minimal code changes (and has net472 support, yeah) --- AssetStudio/AssetStudio.csproj | 7 +-- AssetStudio/AssetsManager.cs | 15 ++++-- AssetStudio/Classes/AnimationClip.cs | 8 ++-- AssetStudio/Classes/Object.cs | 68 ++++++++++++--------------- AssetStudio/Classes/Texture2D.cs | 6 +-- AssetStudio/Classes/Texture2DArray.cs | 8 ++-- AssetStudio/JsonConverterHelper.cs | 56 ++++++++++++++++++++++ AssetStudio/TypeTreeHelper.cs | 6 +-- 8 files changed, 115 insertions(+), 59 deletions(-) create mode 100644 AssetStudio/JsonConverterHelper.cs diff --git a/AssetStudio/AssetStudio.csproj b/AssetStudio/AssetStudio.csproj index 6a25eb8..ac0e1d5 100644 --- a/AssetStudio/AssetStudio.csproj +++ b/AssetStudio/AssetStudio.csproj @@ -13,14 +13,11 @@ - + + - - - - diff --git a/AssetStudio/AssetsManager.cs b/AssetStudio/AssetsManager.cs index 04be97c..03a96d3 100644 --- a/AssetStudio/AssetsManager.cs +++ b/AssetStudio/AssetsManager.cs @@ -5,6 +5,8 @@ using System.IO; using System.IO.Compression; using System.Linq; using System.Text; +using System.Text.Json.Serialization; +using System.Text.Json; using static AssetStudio.ImportHelper; namespace AssetStudio @@ -511,6 +513,13 @@ namespace AssetStudio { Logger.Info("Read assets..."); + var jsonOptions = new JsonSerializerOptions + { + Converters = { new JsonConverterHelper.ByteArrayConverter() }, + NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals, + IncludeFields = true, + }; + var progressCount = assetsFileList.Sum(x => x.m_Objects.Count); int i = 0; Progress.Reset(); @@ -533,7 +542,7 @@ namespace AssetStudio break; case ClassIDType.AnimationClip: obj = objectReader.serializedType?.m_Type != null && LoadingViaTypeTreeEnabled - ? new AnimationClip(objectReader, TypeTreeHelper.ReadType(objectReader.serializedType.m_Type, objectReader)) + ? new AnimationClip(objectReader, TypeTreeHelper.ReadType(objectReader.serializedType.m_Type, objectReader), jsonOptions) : new AnimationClip(objectReader); break; case ClassIDType.Animator: @@ -608,12 +617,12 @@ namespace AssetStudio break; case ClassIDType.Texture2D: obj = objectReader.serializedType?.m_Type != null && LoadingViaTypeTreeEnabled - ? new Texture2D(objectReader, TypeTreeHelper.ReadType(objectReader.serializedType.m_Type, objectReader)) + ? new Texture2D(objectReader, TypeTreeHelper.ReadType(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)) + ? new Texture2DArray(objectReader, TypeTreeHelper.ReadType(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 b6fdd85..f3ecdcf 100644 --- a/AssetStudio/Classes/AnimationClip.cs +++ b/AssetStudio/Classes/AnimationClip.cs @@ -1,9 +1,9 @@ -using Newtonsoft.Json; -using System; +using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text.Json; namespace AssetStudio { @@ -1018,9 +1018,9 @@ namespace AssetStudio public AnimationClip() { } - public AnimationClip(ObjectReader reader, IDictionary typeDict) : base(reader) + public AnimationClip(ObjectReader reader, IDictionary typeDict, JsonSerializerOptions jsonOptions) : base(reader) { - var parsedAnimClip = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(typeDict)); + var parsedAnimClip = JsonSerializer.Deserialize(JsonSerializer.SerializeToUtf8Bytes(typeDict, jsonOptions), jsonOptions); m_AnimationType = parsedAnimClip.m_AnimationType; m_Legacy = parsedAnimClip.m_Legacy; m_Compressed = parsedAnimClip.m_Compressed; diff --git a/AssetStudio/Classes/Object.cs b/AssetStudio/Classes/Object.cs index 8a58bbe..82065be 100644 --- a/AssetStudio/Classes/Object.cs +++ b/AssetStudio/Classes/Object.cs @@ -1,5 +1,7 @@ -using Newtonsoft.Json; -using System.Collections.Specialized; +using System.Collections.Specialized; +using System.Text.Encodings.Web; +using System.Text.Json; +using System.Text.Json.Serialization; namespace AssetStudio { @@ -19,6 +21,20 @@ namespace AssetStudio [JsonIgnore] public SerializedType serializedType; public uint byteSize; + private static JsonSerializerOptions jsonOptions; + + static Object() + { + jsonOptions = new JsonSerializerOptions + { + Converters = { new JsonConverterHelper.FloatConverter() }, + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, + NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals, + ReferenceHandler = ReferenceHandler.IgnoreCycles, + IncludeFields = true, + WriteIndented = true, + }; + } public Object() { } @@ -41,34 +57,12 @@ namespace AssetStudio } } - public string Dump() - { - if (serializedType?.m_Type != null) - { - return TypeTreeHelper.ReadTypeString(serializedType.m_Type, reader); - } - return null; - } - - public string Dump(TypeTree m_Type) - { - if (m_Type != null) - { - return TypeTreeHelper.ReadTypeString(m_Type, reader); - } - return null; - } - public string DumpObject() { string str = null; try { - str = JsonConvert.SerializeObject(this, new JsonSerializerSettings - { - Formatting = Formatting.Indented, - ReferenceLoopHandling = ReferenceLoopHandling.Ignore, - }).Replace(" ", " "); + str = JsonSerializer.Serialize(this, GetType(), jsonOptions).Replace(" ", " "); } catch { @@ -77,22 +71,22 @@ namespace AssetStudio return str; } - public OrderedDictionary ToType() + public string Dump(TypeTree m_Type = null) { - if (serializedType?.m_Type != null) - { - return TypeTreeHelper.ReadType(serializedType.m_Type, reader); - } - return null; + m_Type = m_Type ?? serializedType?.m_Type; + if (m_Type == null) + return null; + + return TypeTreeHelper.ReadTypeString(m_Type, reader); } - public OrderedDictionary ToType(TypeTree m_Type) + public OrderedDictionary ToType(TypeTree m_Type = null) { - if (m_Type != null) - { - return TypeTreeHelper.ReadType(m_Type, reader); - } - return null; + m_Type = m_Type ?? serializedType?.m_Type; + if (m_Type == null) + return null; + + return TypeTreeHelper.ReadType(m_Type, reader); } public byte[] GetRawData() diff --git a/AssetStudio/Classes/Texture2D.cs b/AssetStudio/Classes/Texture2D.cs index 74a4a55..915668b 100644 --- a/AssetStudio/Classes/Texture2D.cs +++ b/AssetStudio/Classes/Texture2D.cs @@ -1,6 +1,6 @@ using System; using System.Collections; -using Newtonsoft.Json; +using System.Text.Json; namespace AssetStudio { @@ -53,9 +53,9 @@ namespace AssetStudio byteSize = (uint)(m_Width * m_Height) * 4; } - public Texture2D(ObjectReader reader, IDictionary typeDict) : base(reader) + public Texture2D(ObjectReader reader, IDictionary typeDict, JsonSerializerOptions jsonOptions) : base(reader) { - var parsedTex2d = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(typeDict)); + var parsedTex2d = JsonSerializer.Deserialize(JsonSerializer.SerializeToUtf8Bytes(typeDict, jsonOptions), jsonOptions); m_Width = parsedTex2d.m_Width; m_Height = parsedTex2d.m_Height; m_CompleteImageSize = parsedTex2d.m_CompleteImageSize; diff --git a/AssetStudio/Classes/Texture2DArray.cs b/AssetStudio/Classes/Texture2DArray.cs index 4d3070f..39dee29 100644 --- a/AssetStudio/Classes/Texture2DArray.cs +++ b/AssetStudio/Classes/Texture2DArray.cs @@ -1,6 +1,6 @@ -using Newtonsoft.Json; -using System.Collections; +using System.Collections; using System.Collections.Generic; +using System.Text.Json; namespace AssetStudio { @@ -50,9 +50,9 @@ namespace AssetStudio TextureList = new List(); } - public Texture2DArray(ObjectReader reader, IDictionary typeDict) : base(reader) + public Texture2DArray(ObjectReader reader, IDictionary typeDict, JsonSerializerOptions jsonOptions) : base(reader) { - var parsedTex2dArray = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(typeDict)); + var parsedTex2dArray = JsonSerializer.Deserialize(JsonSerializer.SerializeToUtf8Bytes(typeDict, jsonOptions), jsonOptions); m_Width = parsedTex2dArray.m_Width; m_Height = parsedTex2dArray.m_Height; m_Depth = parsedTex2dArray.m_Depth; diff --git a/AssetStudio/JsonConverterHelper.cs b/AssetStudio/JsonConverterHelper.cs new file mode 100644 index 0000000..d2ab040 --- /dev/null +++ b/AssetStudio/JsonConverterHelper.cs @@ -0,0 +1,56 @@ +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 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) + { + return JsonSerializer.Deserialize(ref reader, new JsonSerializerOptions + { + NumberHandling = options.NumberHandling + }); + } + + public override void Write(Utf8JsonWriter writer, float value, JsonSerializerOptions options) + { + if (float.IsNaN(value) || float.IsInfinity(value)) + { + if (options.NumberHandling == JsonNumberHandling.AllowNamedFloatingPointLiterals) + { + writer.WriteStringValue($"{value.ToString(CultureInfo.InvariantCulture)}"); + } + else + { + writer.WriteStringValue(JsonSerializer.Serialize(value)); + } + } + else + { + writer.WriteNumberValue((decimal)value); + } + } + } + } +} diff --git a/AssetStudio/TypeTreeHelper.cs b/AssetStudio/TypeTreeHelper.cs index 77a309b..7bfa0bc 100644 --- a/AssetStudio/TypeTreeHelper.cs +++ b/AssetStudio/TypeTreeHelper.cs @@ -281,13 +281,13 @@ namespace AssetStudio var vector = GetNodes(m_Nodes, i); i += vector.Count - 1; var size = reader.ReadInt32(); - var list = new List(size); + var array = new object[size]; for (int j = 0; j < size; j++) { int tmp = 3; - list.Add(ReadValue(vector, reader, ref tmp)); + array[j] = ReadValue(vector, reader, ref tmp); } - value = list; + value = array; break; } else //Class