New game entries.

This commit is contained in:
Razmoth
2023-01-15 17:11:32 +04:00
parent 217965745c
commit d768e85916
5 changed files with 141 additions and 11 deletions

View File

@@ -156,7 +156,7 @@ namespace AssetStudio
return header;
}
private void ReadHeaderAndBlocksInfo(EndianBinaryReader reader)
private void ReadHeaderAndBlocksInfo(FileReader reader)
{
if (m_Header.version >= 4)
{
@@ -208,7 +208,7 @@ namespace AssetStudio
return blocksStream;
}
private void ReadBlocksAndDirectory(EndianBinaryReader reader, Stream blocksStream)
private void ReadBlocksAndDirectory(FileReader reader, Stream blocksStream)
{
var isCompressed = m_Header.signature == "UnityWeb";
foreach (var blockInfo in m_BlocksInfo)
@@ -278,7 +278,7 @@ namespace AssetStudio
XORShift128.Init = false;
}
private void ReadHeader(EndianBinaryReader reader)
private void ReadHeader(FileReader reader)
{
if (Game.Type.IsBH3() && XORShift128.Init)
{
@@ -309,7 +309,7 @@ namespace AssetStudio
}
}
private void ReadBlocksInfoAndDirectory(EndianBinaryReader reader)
private void ReadBlocksInfoAndDirectory(FileReader reader)
{
if (Game.Type.IsCNUnity())
{
@@ -430,7 +430,7 @@ namespace AssetStudio
}
}
private void ReadBlocks(EndianBinaryReader reader, Stream blocksStream)
private void ReadBlocks(FileReader reader, Stream blocksStream)
{
for (int i = 0; i < m_BlocksInfo.Length; i++)
{
@@ -464,6 +464,10 @@ namespace AssetStudio
{
CNUnity.DecryptBlock(compressedBytesSpan, compressedSize, i);
}
if (Game.Type.IsOPFP())
{
OPFPUtils.Decrypt(compressedBytesSpan, reader.FullPath);
}
var uncompressedSize = (int)blockInfo.uncompressedSize;
var uncompressedBytes = BigArrayPool<byte>.Shared.Rent(uncompressedSize);
var uncompressedBytesSpan = uncompressedBytes.AsSpan(0, uncompressedSize);

View File

@@ -0,0 +1,40 @@
using System;
namespace AssetStudio
{
public static class OPFPUtils
{
public static readonly string[] EncrytpedFolders = { "UI/", "Atlas/", "UITexture/", "DynamicAtlas/" };
public static void Decrypt(Span<byte> data, string path)
{
if (IsEncryptionBundle(path, out var key))
{
data[0] ^= key;
for (int i = 1; i < data.Length; i++)
{
data[i] ^= data[i - 1];
}
}
}
private static bool IsEncryptionBundle(string path, out byte key)
{
path = path.Replace("\\", "/");
foreach(var encryptedFolder in EncrytpedFolders)
{
var index = path.IndexOf(encryptedFolder, 0, path.Length, StringComparison.OrdinalIgnoreCase);
if (index != -1)
{
var assetPath = path[index..];
if (assetPath.StartsWith(encryptedFolder, StringComparison.OrdinalIgnoreCase))
{
key = (byte)assetPath.Length;
return true;
}
}
}
key = 0x00;
return false;
}
}
}

View File

@@ -148,6 +148,12 @@ namespace AssetStudio
case GameType.OPFP:
reader = ParseOPFP(reader);
break;
case GameType.AlchemyStars:
reader = ParseAlchemyStars(reader);
break;
case GameType.FantasyOfWind:
reader = DecryptFantasyOfWind(reader);
break;
}
}
if (reader.FileType == FileType.BundleFile && game.Type.IsBlockFile())

View File

@@ -27,6 +27,8 @@ namespace AssetStudio
Games.Add(index++, new Game(GameType.Naraka));
Games.Add(index++, new Game(GameType.EnsembleStars));
Games.Add(index++, new Game(GameType.OPFP));
Games.Add(index++, new Game(GameType.AlchemyStars));
Games.Add(index++, new Game(GameType.FantasyOfWind));
}
public static Game GetGame(int index)
{
@@ -123,7 +125,9 @@ namespace AssetStudio
Naraka,
CNUnity,
EnsembleStars,
OPFP
OPFP,
AlchemyStars,
FantasyOfWind
}
public static class GameTypes

View File

@@ -7,6 +7,7 @@ using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using static AssetStudio.BundleFile;
using static AssetStudio.Crypto;
@@ -273,16 +274,91 @@ namespace AssetStudio
public static FileReader ParseOPFP(FileReader reader)
{
MemoryStream ms = new();
var data = reader.ReadBytes((int)reader.BaseStream.Length);
var stream = reader.BaseStream;
var data = reader.ReadBytes(0x1000);
var idx = data.Search("UnityFS");
if (idx != -1)
{
var count = data.Length - idx;
ms = new(data, idx, count);
stream = new BlockStream(stream, idx);
}
return new FileReader(reader.FullPath, stream);
}
public static FileReader ParseAlchemyStars(FileReader reader)
{
var stream = reader.BaseStream;
var data = reader.ReadBytes(0x1000);
var idx = data.Search("UnityFS");
if (idx != -1)
{
var idx2 = data[(idx + 1)..].Search("UnityFS");
if (idx2 != -1)
{
stream = new BlockStream(stream, idx + idx2 + 1);
}
else
{
stream = new BlockStream(stream, idx);
}
}
return new FileReader(reader.FullPath, stream);
}
public static FileReader DecryptFantasyOfWind(FileReader reader)
{
byte[] encryptKeyName = Encoding.UTF8.GetBytes("28856");
const int MinLength = 0xC8;
const int KeyLength = 8;
const int EnLength = 0x32;
const int StartEnd = 0x14;
const int HeadLength = 5;
var signature = reader.ReadStringToNull(HeadLength);
if (string.Compare(signature, "K9999") > 0 || reader.Length <= MinLength)
{
reader.Position = 0;
return reader;
}
reader.Position = reader.Length + ~StartEnd;
var keyLength = reader.ReadByte();
reader.Position = reader.Length - StartEnd - 2;
var enLength = reader.ReadByte();
var enKeyPos = (byte)((keyLength % KeyLength) + KeyLength);
var encryptedLength = (byte)((enLength % EnLength) + EnLength);
reader.Position = reader.Length - StartEnd - enKeyPos;
var encryptKey = reader.ReadBytes(KeyLength);
var subByte = (byte)(reader.Length - StartEnd - KeyLength - (keyLength % KeyLength));
for (var i = 0; i < KeyLength; i++)
{
if (encryptKey[i] == 0)
{
encryptKey[i] = (byte)(subByte + i);
}
}
var key = new byte[encryptKeyName.Length + KeyLength];
encryptKeyName.CopyTo(key.AsMemory(0));
encryptKey.CopyTo(key.AsMemory(encryptKeyName.Length));
reader.Position = HeadLength;
var data = reader.ReadBytes(encryptedLength);
for (int i = 0; i < encryptedLength; i++)
{
data[i] ^= key[i % key.Length];
}
MemoryStream ms = new();
ms.Write(Encoding.UTF8.GetBytes("Unity"));
ms.Write(data);
reader.BaseStream.CopyTo(ms);
ms.Position = 0;
return new FileReader(reader.FullPath, ms);
}
}