Fixes and improvements for asset parsing via typetree

This commit is contained in:
VaDiM 2024-10-18 20:55:34 +03:00
parent 58ee2b8f1e
commit c37e2e65b7
12 changed files with 184 additions and 40 deletions

View File

@ -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:

View File

@ -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<AnimationClip>(JsonSerializer.SerializeToUtf8Bytes(typeDict, jsonOptions), jsonOptions);
var parsedAnimClip = JsonSerializer.Deserialize<AnimationClip>(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)

View File

@ -19,6 +19,11 @@ namespace AssetStudio
public PPtr() { }
public void SetAssetsFile(SerializedFile assetsFile)
{
_assetsFile = assetsFile;
}
private bool TryGetAssetsFile(out SerializedFile result)
{
result = null;

View File

@ -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<Sprite>[] m_PackedSprites;
[JsonConverter(typeof(JsonConverterHelper.RenderDataMapConverter))]
public Dictionary<KeyValuePair<Guid, long>, SpriteAtlasData> m_RenderDataMap;
public bool m_IsVariant;

View File

@ -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<Texture2D>(JsonSerializer.SerializeToUtf8Bytes(typeDict, jsonOptions), jsonOptions);
var parsedTex2d = JsonSerializer.Deserialize<Texture2D>(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)

View File

@ -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<Texture2D> TextureList;
@ -50,9 +51,9 @@ namespace AssetStudio
TextureList = new List<Texture2D>();
}
public Texture2DArray(ObjectReader reader, IDictionary typeDict, JsonSerializerOptions jsonOptions) : base(reader)
public Texture2DArray(ObjectReader reader, byte[] type, JsonSerializerOptions jsonOptions) : base(reader)
{
var parsedTex2dArray = JsonSerializer.Deserialize<Texture2DArray>(JsonSerializer.SerializeToUtf8Bytes(typeDict, jsonOptions), jsonOptions);
var parsedTex2dArray = JsonSerializer.Deserialize<Texture2DArray>(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<Texture2D>();
}

View File

@ -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<byte[]>
{
public override byte[] Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return reader.TokenType == JsonTokenType.StartArray
? JsonSerializer.Deserialize<List<byte>>(ref reader).ToArray() //JsonArray to ByteArray
: JsonSerializer.Deserialize<byte[]>(ref reader);
}
public override void Write(Utf8JsonWriter writer, byte[] value, JsonSerializerOptions options)
{
writer.WriteBase64StringValue(value);
}
}
}
}

View File

@ -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<byte[]>
{
public override byte[] Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return reader.TokenType == JsonTokenType.StartArray
? JsonSerializer.Deserialize<List<byte>>(ref reader).ToArray() //JsonArray to ByteArray
: JsonSerializer.Deserialize<byte[]>(ref reader);
}
public override void Write(Utf8JsonWriter writer, byte[] value, JsonSerializerOptions options)
{
writer.WriteBase64StringValue(value);
}
}
public class FloatConverter : JsonConverter<float>
{
public override float Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)

View File

@ -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<T> : JsonConverter<PPtr<T>> where T : Object
{
private readonly SerializedFile _assetsFile;
public PPtrConverter(SerializedFile assetsFile)
{
_assetsFile = assetsFile;
}
public override PPtr<T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var pptrObj = JsonSerializer.Deserialize<PPtr<T>>(ref reader);
pptrObj.SetAssetsFile(_assetsFile);
return pptrObj;
}
public override void Write(Utf8JsonWriter writer, PPtr<T> value, JsonSerializerOptions options)
{
JsonSerializer.Serialize(value);
}
}
}
}

View File

@ -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<Dictionary<KeyValuePair<Guid, long>, SpriteAtlasData>>
{
public override Dictionary<KeyValuePair<Guid, long>, SpriteAtlasData> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var dataArray = JsonSerializer.Deserialize<KeyValuePair<JsonObject, SpriteAtlasData>[]>(ref reader, options);
var renderDataMap = new Dictionary<KeyValuePair<Guid, long>, SpriteAtlasData>(dataArray.Length);
foreach (var kvp in dataArray)
{
var jsonFirst = kvp.Key["first"];
var first = jsonFirst.Deserialize<GUID>(options).Convert();
var second = (long) kvp.Key["second"];
renderDataMap.Add(new KeyValuePair<Guid, long>(first, second), kvp.Value);
}
return renderDataMap;
}
public override void Write(Utf8JsonWriter writer, Dictionary<KeyValuePair<Guid, long>, SpriteAtlasData> value, JsonSerializerOptions options)
{
var jsonDict = new Dictionary<string, SpriteAtlasData>();
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);
}
}
}
}

View File

@ -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;

View File

@ -7,7 +7,6 @@ namespace CubismLive2DExtractor
{
class CubismMotion3Converter
{
private SerializedFile assetsFile;
private Dictionary<uint, string> bonePathHash = new Dictionary<uint, string>();
public List<ImportedKeyframedAnimation> AnimationList { get; protected set; } = new List<ImportedKeyframedAnimation>();
@ -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)
{