- [Core] Adjust LZ4 namespace.

- [Core] Added support to `AnimationClip` [Ark]
This commit is contained in:
Razmoth
2023-11-13 23:06:08 +04:00
parent 5e5b6d1105
commit b768acbd9c
7 changed files with 136 additions and 51 deletions

View File

@@ -15,7 +15,7 @@ namespace AssetStudio
if (shader.m_SubProgramBlob != null) //5.3 - 5.4 if (shader.m_SubProgramBlob != null) //5.3 - 5.4
{ {
var decompressedBytes = new byte[shader.decompressedSize]; var decompressedBytes = new byte[shader.decompressedSize];
var numWrite = LZ4.LZ4.Decompress(shader.m_SubProgramBlob, decompressedBytes); var numWrite = LZ4.Decompress(shader.m_SubProgramBlob, decompressedBytes);
if (numWrite != shader.decompressedSize) if (numWrite != shader.decompressedSize)
{ {
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {shader.decompressedSize} bytes"); throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {shader.decompressedSize} bytes");
@@ -54,7 +54,7 @@ namespace AssetStudio
} }
else else
{ {
var numWrite = LZ4.LZ4.Decompress(shader.compressedBlob.AsSpan().Slice((int)offset, (int)compressedLength), decompressedBytes.AsSpan().Slice(0, (int)decompressedLength)); var numWrite = LZ4.Decompress(shader.compressedBlob.AsSpan().Slice((int)offset, (int)compressedLength), decompressedBytes.AsSpan().Slice(0, (int)decompressedLength));
if (numWrite != decompressedLength) if (numWrite != decompressedLength)
{ {
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {decompressedLength} bytes"); throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {decompressedLength} bytes");

View File

@@ -130,7 +130,7 @@ namespace AssetStudio
var compressedBytesSpan = compressedBytes.AsSpan(0, compressedSize); var compressedBytesSpan = compressedBytes.AsSpan(0, compressedSize);
var uncompressedBytesSpan = uncompressedBytes.AsSpan(0, uncompressedSize); var uncompressedBytesSpan = uncompressedBytes.AsSpan(0, uncompressedSize);
var numWrite = LZ4.LZ4.Decompress(compressedBytesSpan, uncompressedBytesSpan); var numWrite = LZ4.Decompress(compressedBytesSpan, uncompressedBytesSpan);
if (numWrite != uncompressedSize) if (numWrite != uncompressedSize)
{ {
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes"); throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");

View File

@@ -437,7 +437,7 @@ namespace AssetStudio
case CompressionType.Lz4HC: //LZ4HC case CompressionType.Lz4HC: //LZ4HC
{ {
var uncompressedBytes = new byte[uncompressedSize]; var uncompressedBytes = new byte[uncompressedSize];
var numWrite = LZ4.LZ4.Decompress(blocksInfoBytesSpan, uncompressedBytes); var numWrite = LZ4.Decompress(blocksInfoBytesSpan, uncompressedBytes);
if (numWrite != uncompressedSize) if (numWrite != uncompressedSize)
{ {
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes"); throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
@@ -553,7 +553,7 @@ namespace AssetStudio
var uncompressedSize = (int)blockInfo.uncompressedSize; var uncompressedSize = (int)blockInfo.uncompressedSize;
var uncompressedBytes = BigArrayPool<byte>.Shared.Rent(uncompressedSize); var uncompressedBytes = BigArrayPool<byte>.Shared.Rent(uncompressedSize);
var uncompressedBytesSpan = uncompressedBytes.AsSpan(0, uncompressedSize); var uncompressedBytesSpan = uncompressedBytes.AsSpan(0, uncompressedSize);
var numWrite = LZ4.LZ4.Decompress(compressedBytesSpan, uncompressedBytesSpan); var numWrite = LZ4.Decompress(compressedBytesSpan, uncompressedBytesSpan);
if (numWrite != uncompressedSize) if (numWrite != uncompressedSize)
{ {
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes"); throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");
@@ -577,7 +577,7 @@ namespace AssetStudio
var uncompressedSize = (int)blockInfo.uncompressedSize; var uncompressedSize = (int)blockInfo.uncompressedSize;
var uncompressedBytes = BigArrayPool<byte>.Shared.Rent(uncompressedSize); var uncompressedBytes = BigArrayPool<byte>.Shared.Rent(uncompressedSize);
var uncompressedBytesSpan = uncompressedBytes.AsSpan(0, uncompressedSize); var uncompressedBytesSpan = uncompressedBytes.AsSpan(0, uncompressedSize);
var numWrite = LZ4.LZ4Inv.Decompress(compressedBytesSpan, uncompressedBytesSpan); var numWrite = LZ4Inv.Decompress(compressedBytesSpan, uncompressedBytesSpan);
if (numWrite != uncompressedSize) if (numWrite != uncompressedSize)
{ {
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes"); throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");

View File

@@ -795,42 +795,6 @@ namespace AssetStudio
public override void Read(ObjectReader reader) { } public override void Read(ObjectReader reader) { }
} }
public class ArkACLClip : ACLClip
{
public int m_ACLType;
public byte[] m_ACLArray;
public float m_PositionFactor;
public float m_EulerFactor;
public float m_ScaleFactor;
public float m_FloatFactor;
public float m_nPositionCurves;
public float m_nRotationCurves;
public float m_nEulerCurves;
public float m_nScaleCurves;
public override bool IsSet => !m_ACLArray.IsNullOrEmpty();
public ArkACLClip()
{
m_ACLArray = Array.Empty<byte>();
}
public override void Read(ObjectReader reader)
{
m_ACLType = reader.ReadInt32();
m_ACLArray = reader.ReadUInt8Array();
reader.AlignStream();
m_PositionFactor = reader.ReadSingle();
m_EulerFactor = reader.ReadSingle();
m_ScaleFactor = reader.ReadSingle();
m_FloatFactor = reader.ReadSingle();
m_nPositionCurves = reader.ReadSingle();
m_nRotationCurves = reader.ReadSingle();
m_nEulerCurves = reader.ReadSingle();
m_nScaleCurves = reader.ReadSingle();
}
}
public class MHYACLClip : ACLClip public class MHYACLClip : ACLClip
{ {
public uint m_CurveCount; public uint m_CurveCount;
@@ -1101,6 +1065,108 @@ namespace AssetStudio
return denseClip; return denseClip;
} }
} }
public class ArkDenseClip : DenseClip
{
public int m_ACLType;
public byte[] m_ACLArray;
public float m_PositionFactor;
public float m_EulerFactor;
public float m_ScaleFactor;
public float m_FloatFactor;
public uint m_nPositionCurves;
public uint m_nRotationCurves;
public uint m_nEulerCurves;
public uint m_nScaleCurves;
public ArkDenseClip(ObjectReader reader) : base(reader)
{
m_ACLType = reader.ReadInt32();
m_ACLArray = reader.ReadUInt8Array();
reader.AlignStream();
m_PositionFactor = reader.ReadSingle();
m_EulerFactor = reader.ReadSingle();
m_ScaleFactor = reader.ReadSingle();
m_FloatFactor = reader.ReadSingle();
m_nPositionCurves = reader.ReadUInt32();
m_nRotationCurves = reader.ReadUInt32();
m_nEulerCurves = reader.ReadUInt32();
m_nScaleCurves = reader.ReadUInt32();
Process();
}
private void Process()
{
if (m_ACLType == 0 || !m_SampleArray.IsNullOrEmpty())
{
return;
}
var sampleArray = new List<float>();
var size = m_ACLType >> 2;
var factor = (float)((1 << m_ACLType) - 1);
var aclSpan = m_ACLArray.ToUInt4Array().AsSpan();
var buffer = (stackalloc byte[8]);
for (int i = 0; i < m_FrameCount; i++)
{
var index = i * (int)(m_CurveCount * size);
for (int j = 0; j < m_nPositionCurves; j++)
{
sampleArray.Add(ReadCurve(aclSpan, m_PositionFactor, ref index));
}
for (int j = 0; j < m_nRotationCurves; j++)
{
sampleArray.Add(ReadCurve(aclSpan, 1.0f, ref index));
}
for (int j = 0; j < m_nEulerCurves; j++)
{
sampleArray.Add(ReadCurve(aclSpan, m_EulerFactor, ref index));
}
for (int j = 0; j < m_nScaleCurves; j++)
{
sampleArray.Add(ReadCurve(aclSpan, m_ScaleFactor, ref index));
}
var m_nFloatCurves = m_CurveCount - (m_nPositionCurves + m_nRotationCurves + m_nEulerCurves + m_nScaleCurves);
for (int j = 0; j < m_nFloatCurves; j++)
{
sampleArray.Add(ReadCurve(aclSpan, m_FloatFactor, ref index));
}
}
m_SampleArray = sampleArray.ToArray();
}
private float ReadCurve(Span<byte> aclSpan, float curveFactor, ref int curveIndex)
{
var buffer = (stackalloc byte[8]);
var curveSize = m_ACLType >> 2;
var factor = (float)((1 << m_ACLType) - 1);
aclSpan.Slice(curveIndex, curveSize).CopyTo(buffer);
var temp = buffer.ToArray().ToUInt8Array(0, curveSize);
buffer.Clear();
temp.CopyTo(buffer);
float curve;
var value = BitConverter.ToUInt64(buffer);
if (value != 0)
{
curve = ((value / factor) - 0.5f) * 2;
}
else
{
curve = -1.0f;
}
curve *= curveFactor;
curveIndex += curveSize;
return curve;
}
}
public class ConstantClip public class ConstantClip
{ {
@@ -1180,17 +1246,19 @@ namespace AssetStudio
{ {
var version = reader.version; var version = reader.version;
m_StreamedClip = new StreamedClip(reader); m_StreamedClip = new StreamedClip(reader);
m_DenseClip = new DenseClip(reader); if (reader.Game.Type.IsArknightsEndfield())
{
m_DenseClip = new ArkDenseClip(reader);
}
else
{
m_DenseClip = new DenseClip(reader);
}
if (reader.Game.Type.IsSRGroup()) if (reader.Game.Type.IsSRGroup())
{ {
m_ACLClip = new MHYACLClip(); m_ACLClip = new MHYACLClip();
m_ACLClip.Read(reader); m_ACLClip.Read(reader);
} }
if (reader.Game.Type.IsArknightsEndfield())
{
m_ACLClip = new ArkACLClip();
m_ACLClip.Read(reader);
}
if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up if (version[0] > 4 || (version[0] == 4 && version[1] >= 3)) //4.3 and up
{ {
m_ConstantClip = new ConstantClip(reader); m_ConstantClip = new ConstantClip(reader);

View File

@@ -18,6 +18,23 @@ namespace AssetStudio
} }
return buffer; return buffer;
} }
public static byte[] ToUInt8Array(this byte[] source, int offset, int size)
{
var buffer = new byte[size / 2];
for (var i = 0; i < size; i++)
{
var idx = i / 2;
if (i % 2 == 0)
{
buffer[idx] = (byte)(source[offset + i] << 4);
}
else
{
buffer[idx] |= source[offset + i];
}
}
return buffer;
}
public static int Search(this byte[] src, string value, int offset = 0) => Search(src.AsSpan(), Encoding.UTF8.GetBytes(value), offset); public static int Search(this byte[] src, string value, int offset = 0) => Search(src.AsSpan(), Encoding.UTF8.GetBytes(value), offset);
public static int Search(this Span<byte> src, byte[] pattern, int offset = 0) public static int Search(this Span<byte> src, byte[] pattern, int offset = 0)
{ {

View File

@@ -1,6 +1,6 @@
using System; using System;
namespace AssetStudio.LZ4; namespace AssetStudio;
public static class LZ4 public static class LZ4
{ {
public static int Decompress(ReadOnlySpan<byte> cmp, Span<byte> dec) public static int Decompress(ReadOnlySpan<byte> cmp, Span<byte> dec)

View File

@@ -54,7 +54,7 @@ namespace AssetStudio
Logger.Verbose($"uncompressed blocksInfo size: 0x{m_Header.uncompressedBlocksInfoSize:X8}"); Logger.Verbose($"uncompressed blocksInfo size: 0x{m_Header.uncompressedBlocksInfoSize:X8}");
var compressedBlocksInfo = blocksInfoReader.ReadBytes((int)blocksInfoReader.Remaining); var compressedBlocksInfo = blocksInfoReader.ReadBytes((int)blocksInfoReader.Remaining);
var uncompressedBlocksInfo = new byte[(int)m_Header.uncompressedBlocksInfoSize]; var uncompressedBlocksInfo = new byte[(int)m_Header.uncompressedBlocksInfoSize];
var numWrite = LZ4.LZ4.Decompress(compressedBlocksInfo, uncompressedBlocksInfo); var numWrite = LZ4.Decompress(compressedBlocksInfo, uncompressedBlocksInfo);
if (numWrite != m_Header.uncompressedBlocksInfoSize) if (numWrite != m_Header.uncompressedBlocksInfoSize)
{ {
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {m_Header.uncompressedBlocksInfoSize} bytes"); throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {m_Header.uncompressedBlocksInfoSize} bytes");
@@ -127,7 +127,7 @@ namespace AssetStudio
DescrambleEntry(compressedBytesSpan); DescrambleEntry(compressedBytesSpan);
Logger.Verbose($"Descrambled block signature {Convert.ToHexString(compressedBytes, 0, 4)}"); Logger.Verbose($"Descrambled block signature {Convert.ToHexString(compressedBytes, 0, 4)}");
var numWrite = LZ4.LZ4.Decompress(compressedBytesSpan[0xC..compressedSize], uncompressedBytesSpan); var numWrite = LZ4.Decompress(compressedBytesSpan[0xC..compressedSize], uncompressedBytesSpan);
if (numWrite != uncompressedSize) if (numWrite != uncompressedSize)
{ {
throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes"); throw new IOException($"Lz4 decompression error, write {numWrite} bytes but expected {uncompressedSize} bytes");