Fix Endfield

This commit is contained in:
Maverick Chang
2025-02-17 14:30:24 +09:00
parent dbf3a8f16a
commit 8446538322
17 changed files with 481 additions and 157 deletions

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net7.0;net8.0</TargetFrameworks>
<TargetFrameworks>net8.0</TargetFrameworks>
<Version>1.36.00</Version>
<AssemblyVersion>1.36.00</AssemblyVersion>
<FileVersion>1.36.00</FileVersion>

View File

@@ -624,7 +624,7 @@ namespace AssetStudio
{
NetEaseUtils.DecryptWithHeader(compressedBytesSpan);
}
if (Game.Type.IsArknightsEndfield() && i == 0)
if (Game.Type.IsArknightsEndfield() && i == 0 && compressedBytesSpan[..32].Count((byte)0xa6) > 5)
{
FairGuardUtils.Decrypt(compressedBytesSpan);
}
@@ -660,7 +660,7 @@ namespace AssetStudio
try
{
reader.Read(compressedBytesSpan);
if (i == 0)
if (i == 0 && compressedBytesSpan[..32].Count((byte)0xa6) > 5)
{
FairGuardUtils.Decrypt(compressedBytesSpan);
}

View File

@@ -17,6 +17,7 @@ namespace AssetStudio
m_Min = reader.ReadVector3();
m_Max = reader.ReadVector3();
}
}
public class CompressedMesh
@@ -146,6 +147,11 @@ namespace AssetStudio
for (int i = 0; i < m_ChannelsSize; i++)
{
m_Channels.Add(new ChannelInfo(reader));
////Kh0n5u Debug2
//if (i == 1){
// m_Channels[i].dimension = 3;
//}
}
}
@@ -801,6 +807,7 @@ namespace AssetStudio
GetTriangles();
}
private void ReadVertexData()
{
m_VertexCount = (int)m_VertexData.m_VertexCount;
@@ -818,6 +825,11 @@ namespace AssetStudio
{
m_Channel.dimension = 4;
}
////Kh0n5u Debug4
//if (reader.Game.Type.IsArknightsEndfield() && chn == 1)
//{
// m_Channel.dimension = 3;
//}
var vertexFormat = MeshHelper.ToVertexFormat(m_Channel.format, version);
var componentByteSize = (int)MeshHelper.GetFormatSize(vertexFormat);
@@ -845,10 +857,18 @@ namespace AssetStudio
int[] componentsIntArray = null;
float[] componentsFloatArray = null;
if (MeshHelper.IsIntFormat(vertexFormat))
componentsIntArray = MeshHelper.BytesToIntArray(componentBytes, vertexFormat);
if (reader.Game.Type.IsArknightsEndfield() && chn == 1)
{
//componentsFloatArray = MeshHelper.BytesToFloatArray(componentBytes, vertexFormat);
componentsFloatArray = MeshHelper.DecompressEndfieldNormal(componentBytes,vertexFormat);
}
else
componentsFloatArray = MeshHelper.BytesToFloatArray(componentBytes, vertexFormat);
{
if (MeshHelper.IsIntFormat(vertexFormat))
componentsIntArray = MeshHelper.BytesToIntArray(componentBytes, vertexFormat);
else
componentsFloatArray = MeshHelper.BytesToFloatArray(componentBytes, vertexFormat);
}
if (version[0] >= 2018)
{
@@ -858,7 +878,22 @@ namespace AssetStudio
m_Vertices = componentsFloatArray;
break;
case 1: //kShaderChannelNormal
m_Normals = componentsFloatArray;
//Kh0n5u Debug3
//if (reader.Game.Type.IsArknightsEndfield())
//{
// float[] m_Vertices_zero = new float[m_VertexCount * 3];
// for (int i = 0; i < m_VertexCount; i++)
// {
// m_Vertices_zero[i * 3] = 0.0f;
// m_Vertices_zero[i * 3 + 1] = 0.0f;
// m_Vertices_zero[i * 3 + 2] = 1.0f;
// }
// m_Normals = m_Vertices_zero;
//}
//else
//{
m_Normals = componentsFloatArray;
//}
break;
case 2: //kShaderChannelTangent
m_Tangents = componentsFloatArray;
@@ -1457,6 +1492,187 @@ namespace AssetStudio
return result;
}
public static UInt32[] BytesToUInt32Array(byte[] inputBytes, VertexFormat format)
{
var size = GetFormatSize(format);
var len = inputBytes.Length / size;
var result = new UInt32[len];
for (int i = 0; i < len; i++)
{
switch (format)
{
case VertexFormat.UInt32:
result[i] = BinaryPrimitives.ReadUInt32LittleEndian(inputBytes.AsSpan(i * 4));
break;
case VertexFormat.SInt32:
result[i] = (UInt32)BinaryPrimitives.ReadInt32LittleEndian(inputBytes.AsSpan(i * 4));
break;
}
}
return result;
}
public static int[] BytesToSInt32Array(byte[] inputBytes, VertexFormat format)
{
var size = GetFormatSize(format);
var len = inputBytes.Length / size;
var result = new int[len];
for (int i = 0; i < len; i++)
{
switch (format)
{
case VertexFormat.UInt32:
result[i] = (int)BinaryPrimitives.ReadUInt32LittleEndian(inputBytes.AsSpan(i * 4));
break;
case VertexFormat.SInt32:
result[i] = BinaryPrimitives.ReadInt32LittleEndian(inputBytes.AsSpan(i * 4));
break;
}
}
return result;
}
public static float[] DecompressEndfieldNormal(this byte[] inputBytes, VertexFormat format) // 8bits per component
{
var size = MeshHelper.GetFormatSize(format);
var len = inputBytes.Length / size;
var result = new float[len * 3];
var readFloat = new float[len];
readFloat = MeshHelper.BytesToFloatArray(inputBytes, format);
for (int i = 0; i < len; i++)
{
float value = readFloat[i];
float r0x = BitConverter.ToInt32(BitConverter.GetBytes(value)) & 0x40000000;
r0x = (BitConverter.ToUInt32(BitConverter.GetBytes(r0x)) > 0) ? 1.0f : 0.0f;
// (((int3)v2.xxx << (32 - int3(10,10,10) - int3(0,10,20))) >> (32 - int3(10,10,10)))
float r0y = (BitConverter.ToInt32(BitConverter.GetBytes(value)) << 22) >> 22;
float r0z = (BitConverter.ToInt32(BitConverter.GetBytes(value)) << 12) >> 22;
float r0w = (BitConverter.ToInt32(BitConverter.GetBytes(value)) << 2) >> 22;
float r1x = (BitConverter.ToUInt32(BitConverter.GetBytes(value))) >> 31;
float r1y = 0.00195694715f * r0y;
float r1z = 0.00195694715f * r0z;
float r1w = 0.00195694715f * r0w;
float leng = r1x * r1x + r1y * r1y + r1z * r1z + r1w * r1w;
float r2x = 1.0f - Math.Abs(r1y);
float r2y = 1.0f - Math.Abs(r1z);
float r2z = 1.0f - Math.Abs(r1y);
float r3z = r2x - Math.Abs(r1z);
r2x = r3z < 0.0f ? 1.0f : 0.0f;
r0y = r0y >= 0.0f ? 1.0f : 0.0f;
r0z = r0z >= 0.0f ? 1.0f : 0.0f;
r0y = r0y * 2.0f - 1.0f;
r0z = r0z * 2.0f - 1.0f;
r0y = r2y * r0y;
r0z = r2z * r0z;
float r3x = (r2x == 1.0f) ? r0y : r1y;
float r3y = (r2x == 1.0f) ? r0z : r1z;
r0y = r3x* r3x + r3y * r3y + r3z * r3z;
r0y = 1.0f / (float)Math.Sqrt(r0y);
r2x = r3x * r0y;
r2y = r3y * r0y;
r2z = r3z * r0y;
//float old_r3x = r3x;
//r3x = r3y * r0y - r2z;
//r3y = r3z * r0y - r2x;
//r3z = old_r3x * r0y - r2y;
//r0y = r3x * r2x + r3y * r2y + r3z * r2z;
//r3x = r3x - r0y;
//r3y = r3y - r0y;
//r3z = r3z - r0y;
//r0y = r3x * r3x + r3y * r3y + r3z * r3z;
//r0y = 1.0f / (float)Math.Sqrt(r0y);
//r3x = r3x * r0y;
//r3y = r3y * r0y;
//r3z = r3z * r0y;
//float length = r2x * r2x + r2y * r2y + r2z * r2z;
// 计算result[i * 3]的值
result[i * 3] = r2x;
result[i * 3 + 1] = r2y;
result[i * 3 + 2] = r2z;
//result[i * 3] = 0;
//result[i * 3 + 1] = 0;
//result[i * 3 + 2] = 1;
}
return result;
}
public static float[] DecompressOctahedron(this byte[] inputBytes, VertexFormat format) // 8bits per component
{
var size = GetFormatSize(format);
var len = inputBytes.Length / size;
var result = new float[len*3];
var readFloat = new UInt32[len];
readFloat = BytesToUInt32Array(inputBytes, VertexFormat.UInt32);
// read per 8 bits per component
for (int i = 0; i < len; i++)
{
var x = readFloat[i] & 0xFFFF;
var y = (readFloat[i] >> 16) & 0xFFFF;
var z = (readFloat[i] >> 16) & 0xFF;
var w = (readFloat[i] >> 24) & 0xFF;
/* HLSL Decode Example
* float3 Decode(float2 f)
* {
* f = f * 2.0 - 1.0;
* float3 n = float3(f.x, f.y, 1.0 - abs(f.x) - abs(f.y));
* float t = saturate(-n.z);
* n.xy += n.xy >= 0.0 ? -t : t;
* return normalize(n);
* }
*/
float f_x = x / 65535.0f * 2.0f - 1.0f;
float f_y = y / 65535.0f * 2.0f - 1.0f;
float f_z = 1.0f - Math.Abs(f_x) - Math.Abs(f_y);
if (f_z < 0.0f)
{
float f_t = Math.Max(Math.Min(-f_z, 1.0f), 0.0f);
f_x += f_x >= 0.0f ? -f_t : f_t;
f_y += f_y >= 0.0f ? -f_t : f_t;
}
float length = (float)Math.Sqrt(f_x * f_x + f_y * f_y + f_z * f_z);
if (length > 1e-6f)
{
f_x /= length;
f_y /= length;
f_z /= length;
}
result[i * 3] = f_x;
result[i * 3 + 1] = f_y;
result[i * 3 + 2] = f_z;
}
return result;
}
public static int[] BytesToIntArray(byte[] inputBytes, VertexFormat format)
{
var size = GetFormatSize(format);

View File

@@ -11,11 +11,11 @@ namespace AssetStudio
Logger.Verbose($"Attempting to decrypt block with FairGuard encryption...");
var encryptedOffset = 0;
var encryptedSize = bytes.Length > 0x500 ? 0x500 : bytes.Length;
var encryptedSize = Math.Min(0x500, bytes.Length);
if (encryptedSize < 0x20)
{
Logger.Verbose($"block size is less that minimum, skipping...");
Logger.Verbose("block size is less that minimum, skipping...");
return;
}
@@ -27,11 +27,20 @@ namespace AssetStudio
encrypted[i] ^= 0xA6;
}
// old
/*
var seedPart0 = (uint)(encryptedInts[2] ^ 0x1274CBEC ^ encryptedInts[6] ^ 0x3F72EAF3);
var seedPart1 = (uint)(encryptedInts[3] ^ 0xBE482704 ^ encryptedInts[0] ^ encryptedSize);
var seedPart2 = (uint)(encryptedInts[1] ^ encryptedSize ^ encryptedInts[5] ^ 0x753BDCAA);
var seedPart3 = (uint)(encryptedInts[0] ^ 0x82C57E3C ^ encryptedInts[7] ^ 0xE3D947D3);
var seedPart4 = (uint)(encryptedInts[4] ^ 0x6F2A7347 ^ encryptedInts[7] ^ 0x4736C714);
*/
var seedPart0 = (uint)(encryptedInts[2] ^ encryptedInts[6] ^ 0x226a61b9);
var seedPart1 = (uint)(encryptedInts[3] ^ encryptedInts[0] ^ 0x7a39d018 ^ encryptedSize);
var seedPart2 = (uint)(encryptedInts[1] ^ encryptedInts[5] ^ 0x18f6d8aa ^ encryptedSize);
var seedPart3 = (uint)(encryptedInts[0] ^ encryptedInts[7] ^ 0xaa255fb1);
var seedPart4 = (uint)(encryptedInts[4] ^ encryptedInts[7] ^ 0xf78dd8eb);
var seedInts = new uint[] { seedPart0, seedPart1, seedPart2, seedPart3, seedPart4 };
var seedBytes = MemoryMarshal.AsBytes<uint>(seedInts);

View File

@@ -4,6 +4,16 @@ namespace AssetStudio;
public class LZ4Inv : LZ4
{
public new static LZ4Inv Instance => new();
protected override (int encCount, int litCount) GetLiteralToken(ReadOnlySpan<byte> cmp, ref int cmpPos) => ((cmp[cmpPos] >> 4) & 0xf, (cmp[cmpPos++] >> 0) & 0xf);
protected override (int encCount, int litCount) GetLiteralToken(ReadOnlySpan<byte> cmp, ref int cmpPos)
{
var val = cmp[cmpPos++];
var lit = val & 0b00110011;
var enc = val & 0b11001100;
enc >>= 2;
return ((enc & 0b11) | enc >> 2, (lit & 0b11) | lit >> 2);
}
protected override int GetChunkEnd(ReadOnlySpan<byte> cmp, ref int cmpPos) => cmp[cmpPos++] << 8 | cmp[cmpPos++] << 0;
}