diff --git a/src/Components/Modules/FastFiles.cpp b/src/Components/Modules/FastFiles.cpp index 26acdd92..f9d78619 100644 --- a/src/Components/Modules/FastFiles.cpp +++ b/src/Components/Modules/FastFiles.cpp @@ -6,6 +6,7 @@ namespace Components symmetric_CTR FastFiles::CurrentCTR; std::vector FastFiles::ZonePaths; + bool FastFiles::IsIW4xZone = false; bool FastFiles::StreamRead = false; unsigned int FastFiles::CurrentZone; @@ -272,17 +273,22 @@ namespace Components return file; } + void FastFiles::ReadXFileHeader(void* buffer, int size) + { + if (FastFiles::IsIW4xZone) + { + char pad; + Game::DB_ReadXFile(&pad, 1); + } + + Game::DB_ReadXFile(buffer, size); + } + void FastFiles::ReadVersionStub(unsigned int* version, int size) { FastFiles::CurrentZone++; Game::DB_ReadXFileUncompressed(version, size); - // Allow loading of custom version - if (*version == XFILE_VERSION_IW4X) - { - *version = XFILE_VERSION; - } - Zones::SetVersion(*version); // Allow loading of codo versions @@ -297,6 +303,30 @@ namespace Components } } + void FastFiles::ReadHeaderStub(unsigned int* header, int size) + { + FastFiles::IsIW4xZone = false; + Game::DB_ReadXFileUncompressed(header, size); + + if (header[0] == XFILE_HEADER_IW4X) + { + FastFiles::IsIW4xZone = true; + + if (header[1] < XFILE_VERSION_IW4X) + { + Logger::Error("The fastfile you are trying to load is outdated (%d, expected %d)", header[1], XFILE_VERSION_IW4X); + } +#ifdef DEBUG + else if (header[1] > XFILE_VERSION_IW4X) + { + Logger::Error("You are loading a fastfile that is too new (%d, expected %d), how's that possible?", header[1], XFILE_VERSION_IW4X); + } +#endif + + *reinterpret_cast(header) = XFILE_MAGIC_UNSIGNED; + } + } + void FastFiles::AuthLoadInitCrypto() { if (Zones::Version() >= 319) @@ -407,6 +437,9 @@ namespace Components // Allow loading 'newer' zones Utils::Hook(0x4158E7, FastFiles::ReadVersionStub, HOOK_CALL).install()->quick(); + // Allow loading IW4x zones + Utils::Hook(0x4157B8, FastFiles::ReadHeaderStub, HOOK_CALL).install()->quick(); + // Allow custom zone loading if (!ZoneBuilder::IsEnabled()) { @@ -457,6 +490,9 @@ namespace Components Utils::Hook(0x589090, FastFiles::GetFullLoadedFraction, HOOK_CALL).install()->quick(); Utils::Hook(0x629FC0, FastFiles::GetFullLoadedFraction, HOOK_JUMP).install()->quick(); + // XFile header loading + Utils::Hook(0x4159E2, FastFiles::ReadXFileHeader, HOOK_CALL).install()->quick(); + // Add custom zone paths FastFiles::AddZonePath("zone\\patch\\"); FastFiles::AddZonePath("zone\\dlc\\"); diff --git a/src/Components/Modules/FastFiles.hpp b/src/Components/Modules/FastFiles.hpp index efef469a..ee10ea79 100644 --- a/src/Components/Modules/FastFiles.hpp +++ b/src/Components/Modules/FastFiles.hpp @@ -36,6 +36,7 @@ namespace Components static unsigned int CurrentZone; static unsigned int MaxZones; + static bool IsIW4xZone; static bool StreamRead; static Key CurrentKey; @@ -46,8 +47,11 @@ namespace Components static void LoadDLCUIZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync); static void LoadGfxZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync); + static void ReadHeaderStub(unsigned int* header, int size); static void ReadVersionStub(unsigned int* version, int size); + static void ReadXFileHeader(void* buffer, int size); + static void AuthLoadInitCrypto(); static int AuthLoadInflateCompare(unsigned char* buffer, int length, unsigned char* ivValue); static void AuthLoadInflateDecryptBase(); diff --git a/src/Components/Modules/ZoneBuilder.cpp b/src/Components/Modules/ZoneBuilder.cpp index d84753d1..1b6e3e6d 100644 --- a/src/Components/Modules/ZoneBuilder.cpp +++ b/src/Components/Modules/ZoneBuilder.cpp @@ -337,12 +337,12 @@ namespace Components Game::XFileHeader header = { - XFILE_MAGIC_UNSIGNED, #ifdef DEBUG - XFILE_VERSION, + XFILE_MAGIC_UNSIGNED, #else - XFILE_VERSION_IW4X, + XFILE_HEADER_IW4X | (static_cast(XFILE_VERSION_IW4X) << 32), #endif + XFILE_VERSION, Game::XFileLanguage::XLANG_NONE, fileTime.dwHighDateTime, fileTime.dwLowDateTime @@ -352,6 +352,12 @@ namespace Components outBuffer.append(reinterpret_cast(&header), sizeof(header)); std::string zoneBuffer = this->buffer.toBuffer(); + +#ifndef DEBUG + // Insert a random byte, this will destroy the whole alignment and result in a crash, if not handled + zoneBuffer.insert(zoneBuffer.begin(), static_cast(Utils::Cryptography::Rand::GenerateInt())); +#endif + zoneBuffer = Utils::Compression::ZLib::Compress(zoneBuffer); outBuffer.append(zoneBuffer); diff --git a/src/Components/Modules/ZoneBuilder.hpp b/src/Components/Modules/ZoneBuilder.hpp index 021bcfc0..adddca6a 100644 --- a/src/Components/Modules/ZoneBuilder.hpp +++ b/src/Components/Modules/ZoneBuilder.hpp @@ -1,6 +1,8 @@ #define XFILE_MAGIC_UNSIGNED 0x3030317566665749 #define XFILE_VERSION 276 -#define XFILE_VERSION_IW4X 0x78345749 // 'IW4x' + +#define XFILE_HEADER_IW4X 0x78345749 // 'IW4x' +#define XFILE_VERSION_IW4X 1 namespace Components { diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index 5ee3cfbd..84c8cbd5 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -54,6 +54,7 @@ namespace Game DB_IsXAssetDefault_t DB_IsXAssetDefault = (DB_IsXAssetDefault_t)0x48E6A0; DB_LoadXAssets_t DB_LoadXAssets = (DB_LoadXAssets_t)0x4E5930; DB_LoadXFileData_t DB_LoadXFileData = (DB_LoadXFileData_t)0x445460; + DB_ReadXFile_t DB_ReadXFile = (DB_ReadXFile_t)0x445460; DB_ReadXFileUncompressed_t DB_ReadXFileUncompressed = (DB_ReadXFileUncompressed_t)0x4705E0; DB_ReleaseXAssetHandler_t* DB_ReleaseXAssetHandlers = (DB_ReleaseXAssetHandler_t*)0x799AB8; DB_XModelSurfsFixup_t DB_XModelSurfsFixup = (DB_XModelSurfsFixup_t)0x5BAC50; diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index c72bb8cc..4a08c5e5 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -132,6 +132,9 @@ namespace Game typedef void(__cdecl * DB_ReadXFileUncompressed_t)(void* buffer, int size); extern DB_ReadXFileUncompressed_t DB_ReadXFileUncompressed; + typedef void(__cdecl * DB_ReadXFile_t)(void* buffer, int size); + extern DB_ReadXFile_t DB_ReadXFile; + typedef void(__cdecl * DB_ReleaseXAssetHandler_t)(XAssetHeader header); extern DB_ReleaseXAssetHandler_t* DB_ReleaseXAssetHandlers;