diff --git a/FModel/Globals.cs b/FModel/Globals.cs index 8a2394d3..80034602 100644 --- a/FModel/Globals.cs +++ b/FModel/Globals.cs @@ -24,7 +24,7 @@ namespace FModel }); public static bool bSearch = false; // trigger the event to select a file thank to the search window public static string sSearch = string.Empty; // this will be the file name triggered - public static FGame Game = new FGame(EGame.Unknown, EPakVersion.LATEST); + public static FGame Game = new FGame(EGame.Unknown, EPakVersion.LATEST, 0); public const EFModel Build = #if RELEASE EFModel.Release; @@ -39,11 +39,13 @@ namespace FModel { public EGame ActualGame; public EPakVersion Version; + public int SubVersion; - public FGame(EGame game, EPakVersion version) + public FGame(EGame game, EPakVersion version, int subVersion) { ActualGame = game; Version = version; + SubVersion = subVersion; } public string GetName() diff --git a/FModel/Grabber/Paks/PaksGrabber.cs b/FModel/Grabber/Paks/PaksGrabber.cs index e1341ffb..df443714 100644 --- a/FModel/Grabber/Paks/PaksGrabber.cs +++ b/FModel/Grabber/Paks/PaksGrabber.cs @@ -46,8 +46,12 @@ namespace FModel.Grabber.Paks if (!Utils.Paks.IsFileReadLocked(new FileInfo(paks[i]))) { PakFileReader pakFile = new PakFileReader(paks[i]); - if (i == 0) Globals.Game.Version = pakFile.Info.Version; DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[PAK]", "[Registering]", $"{pakFile.FileName} with GUID {pakFile.Info.EncryptionKeyGuid.Hex}"); + if (i == 0) + { + Globals.Game.Version = pakFile.Info.Version; + Globals.Game.SubVersion = pakFile.Info.SubVersion; + } Application.Current.Dispatcher.Invoke(delegate { diff --git a/FModel/PakReader/Parsers/Objects/FPakEntry.cs b/FModel/PakReader/Parsers/Objects/FPakEntry.cs index 14ecb8f6..fafa8f78 100644 --- a/FModel/PakReader/Parsers/Objects/FPakEntry.cs +++ b/FModel/PakReader/Parsers/Objects/FPakEntry.cs @@ -71,7 +71,7 @@ namespace PakReader.Parsers.Objects else CompressionMethodIndex = reader.ReadUInt32(); } - if (Version <= EPakVersion.INITIAL) reader.ReadInt64(); // Timestamp + if (Version < EPakVersion.NO_TIMESTAMPS) reader.ReadInt64(); // Timestamp reader.ReadBytes(20); // Hash if (Version >= EPakVersion.COMPRESSION_ENCRYPTION) { diff --git a/FModel/PakReader/Parsers/Objects/FPakInfo.cs b/FModel/PakReader/Parsers/Objects/FPakInfo.cs index 68725e31..326b2725 100644 --- a/FModel/PakReader/Parsers/Objects/FPakInfo.cs +++ b/FModel/PakReader/Parsers/Objects/FPakInfo.cs @@ -20,29 +20,29 @@ namespace PakReader.Parsers.Objects public readonly string[] CompressionMethods; // 160 bytes // 221 bytes total - internal const long SERIALIZED_SIZE = 4 * 2 + 8 * 2 + 20 + /* new fields */ 1 + 16; + internal const long _SIZE = 4 * 2 + 8 * 2 + 20 + 1 + 16; + internal const long _SIZE8 = _SIZE + 4 * 32; + internal const long _SIZE8A = _SIZE8 + 32; + internal const long _SIZE9 = _SIZE8A + 1; internal FPakInfo ReadPakInfo(BinaryReader reader) { - long offset = reader.BaseStream.Length - SERIALIZED_SIZE; - long terminator = offset - 300; - int maxNumCompressionMethods = 0; - while (offset > terminator) + long fileSize = reader.BaseStream.Length; + long[] OffsetsToTry = new long[4] { _SIZE, _SIZE8, _SIZE8A, _SIZE9 }; + for (int i = 0; i < OffsetsToTry.Length; i++) { - reader.BaseStream.Seek(offset, SeekOrigin.Begin); - FPakInfo info = new FPakInfo(reader, maxNumCompressionMethods); - if (info.Version != EPakVersion.INVALID) - return info; - else + if (fileSize - OffsetsToTry[i] > 0) { - offset -= COMPRESSION_METHOD_NAME_LEN; - maxNumCompressionMethods++; + reader.BaseStream.Seek(fileSize - OffsetsToTry[i], SeekOrigin.Begin); + FPakInfo info = new FPakInfo(reader, OffsetsToTry[i]); + if (info.Version != EPakVersion.INVALID) + return info; } } return default; } - internal FPakInfo(BinaryReader reader, int maxNumCompressionMethods) + internal FPakInfo(BinaryReader reader, long offset) { // Serialize if version is at least EPakVersion.ENCRYPTION_KEY_GUID EncryptionKeyGuid = new FGuid(reader); @@ -62,15 +62,12 @@ namespace PakReader.Parsers.Objects } Version = (EPakVersion)reader.ReadInt32(); - int b; - if (maxNumCompressionMethods == 5 && Version == EPakVersion.FNAME_BASED_COMPRESSION_METHOD) // UE4.23 - b = (((int)Version) << 4) | (1); - else - b = (((int)Version) << 4) | (0); - SubVersion = b & 15; + SubVersion = (offset == _SIZE8A && Version == EPakVersion.FNAME_BASED_COMPRESSION_METHOD) ? 1 : 0; IndexOffset = reader.ReadInt64(); IndexSize = reader.ReadInt64(); IndexHash = new FSHAHash(reader); + if (Version == EPakVersion.FROZEN_INDEX) + reader.ReadByte(); // bIndexIsFrozen if (Version < EPakVersion.FNAME_BASED_COMPRESSION_METHOD) { @@ -78,10 +75,10 @@ namespace PakReader.Parsers.Objects } else { - int BufferSize = COMPRESSION_METHOD_NAME_LEN * maxNumCompressionMethods; + int BufferSize = COMPRESSION_METHOD_NAME_LEN * 4; byte[] Methods = reader.ReadBytes(BufferSize); - var MethodList = new List(maxNumCompressionMethods); - for (int i = 0; i < maxNumCompressionMethods; i++) + var MethodList = new List(4); + for (int i = 0; i < 4; i++) { if (Methods[i*COMPRESSION_METHOD_NAME_LEN] != 0) { @@ -90,6 +87,11 @@ namespace PakReader.Parsers.Objects } CompressionMethods = MethodList.ToArray(); } + + if (Version < EPakVersion.INDEX_ENCRYPTION) + bEncryptedIndex = false; + if (Version < EPakVersion.ENCRYPTION_KEY_GUID) + EncryptionKeyGuid = new FGuid(0u, 0u, 0u, 0u); } } } diff --git a/FModel/PakReader/Parsers/Objects/FTexturePlatformData.cs b/FModel/PakReader/Parsers/Objects/FTexturePlatformData.cs index f2b54dfb..05920f1f 100644 --- a/FModel/PakReader/Parsers/Objects/FTexturePlatformData.cs +++ b/FModel/PakReader/Parsers/Objects/FTexturePlatformData.cs @@ -22,8 +22,8 @@ namespace PakReader.Parsers.Objects FirstMipToSerialize = 0; // what: https://github.com/EpicGames/UnrealEngine/blob/4.24/Engine/Source/Runtime/Engine/Private/TextureDerivedData.cpp#L1316 Mips = reader.ReadTArray(() => new FTexture2DMipMap(reader, ubulk, bulkOffset)); - - if (FModel.Globals.Game.ActualGame == FModel.EGame.Valorant || FModel.Globals.Game.Version > EPakVersion.FNAME_BASED_COMPRESSION_METHOD) + + if (FModel.Globals.Game.Version > EPakVersion.FNAME_BASED_COMPRESSION_METHOD || FModel.Globals.Game.SubVersion == 1) { if (reader.ReadInt32() != 0) throw new FileLoadException("VirtualTextures are not supported"); }