From e8f6334cd624ff37ff67b130b3a2b99a1ad088a2 Mon Sep 17 00:00:00 2001 From: Philip <12156105+Scobalula@users.noreply.github.com> Date: Wed, 11 May 2022 15:59:48 +0100 Subject: [PATCH] MWR Parasyte --- src/WraithXCOD/WraithXCOD/CoDAssets.cpp | 122 +++++- src/WraithXCOD/WraithXCOD/CoDAssets.h | 8 + .../WraithXCOD/GameModernWarfare4.cpp | 332 +--------------- .../WraithXCOD/GameModernWarfareRM.cpp | 376 +++++++++++++++++- .../WraithXCOD/GameModernWarfareRM.h | 4 + src/WraithXCOD/WraithXCOD/Parasyte.cpp | 51 +++ src/WraithXCOD/WraithXCOD/Parasyte.h | 84 ++++ src/WraithXCOD/WraithXCOD/WraithXCOD.rc | 8 +- src/WraithXCOD/WraithXCOD/WraithXCOD.vcxproj | 2 + .../WraithXCOD/WraithXCOD.vcxproj.filters | 6 + 10 files changed, 649 insertions(+), 344 deletions(-) create mode 100644 src/WraithXCOD/WraithXCOD/Parasyte.cpp create mode 100644 src/WraithXCOD/WraithXCOD/Parasyte.h diff --git a/src/WraithXCOD/WraithXCOD/CoDAssets.cpp b/src/WraithXCOD/WraithXCOD/CoDAssets.cpp index 38eb463..5337a07 100644 --- a/src/WraithXCOD/WraithXCOD/CoDAssets.cpp +++ b/src/WraithXCOD/WraithXCOD/CoDAssets.cpp @@ -439,7 +439,7 @@ const std::vector CoDAssets::GameProcessInfo = { "s2_sp64_ship.exe", SupportedGames::WorldWar2, SupportedGameFlags::SP }, { "s2_mp64_ship.exe", SupportedGames::WorldWar2, SupportedGameFlags::MP }, // Modern Warfare 4 - { "Parasyte.CLI.exe", SupportedGames::ModernWarfare4, SupportedGameFlags::SP }, + { "Parasyte.CLI.exe", SupportedGames::Parasyte, SupportedGameFlags::SP }, // Modern Warfare 2 Remastered { "mw2cr.exe", SupportedGames::ModernWarfare2Remastered, SupportedGameFlags::SP }, // 007 Quantum Solace @@ -455,6 +455,8 @@ FindGameResult CoDAssets::BeginGameMode() // Aquire a lock std::lock_guard Lock(CodMutex); + // Clear Parasyte + ps::state = nullptr; // Result auto Result = FindGameResult::Success; @@ -468,8 +470,11 @@ FindGameResult CoDAssets::BeginGameMode() // If success, load assets if (Result == FindGameResult::Success) { - // Load assets - LoadGame(); + // Load assets, check for Parasyte + if (ps::state != nullptr) + LoadGamePS(); + else + LoadGame(); } else if (GameInstance != nullptr) { @@ -597,18 +602,6 @@ LoadGameResult CoDAssets::LoadGame() case SupportedGames::ModernWarfare: Success = GameModernWarfare::LoadAssets(); break; case SupportedGames::ModernWarfare2: Success = GameModernWarfare2::LoadAssets(); break; case SupportedGames::ModernWarfare3: Success = GameModernWarfare3::LoadAssets(); break; - case SupportedGames::ModernWarfare4: - // Allocate a new XPAK Mega Cache (Must reload CASC as the game can affect it if rerunning, etc. and result in corrupt exports) - // TODO: Find a better solution to this, a good trigger for it to occur is relaunching the game, moving to different parts or Blizzard editing the CASC while - // we have a handle, then try export an image, it'll probably come out black - CleanupPackageCache(); - // Load from casc and on demand - GamePackageCache = std::make_unique(); - GamePackageCache->LoadPackageCacheAsync(GameDirectory); - OnDemandCache = std::make_unique(); - OnDemandCache->LoadPackageCacheAsync(FileSystems::CombinePath(FileSystems::GetDirectoryName(GameInstance->GetProcessPath()), "xpak_cache")); - // Load as normally - Success = GameModernWarfare4::LoadAssets(); break; case SupportedGames::Vanguard: CleanupPackageCache(); // Load from casc and on demand @@ -656,6 +649,90 @@ LoadGameResult CoDAssets::LoadGame() return LoadGameResult::ProcessNotRunning; } +LoadGameResult CoDAssets::LoadGamePS() +{ + // Make sure the process is running + if (GameInstance->IsRunning()) + { + // Setup the assets + GameAssets.reset(new AssetPool()); + // Whether or not we loaded assets + bool Success = false; + + // Create log, if desired + if (SettingsManager::GetSetting("createxassetlog", "false") == "true") + { + XAssetLogWriter = std::make_unique(); + XAssetLogWriter->Open(FileSystems::CombinePath(FileSystems::GetApplicationPath(), "AssetLog.txt")); + } + + // Cleanup + CleanupPackageCache(); + + // Load assets from the game + switch (ps::state->GameID) + { + // Modern Warfare 2019 + case 0x3931524157444F4D: + GameID = SupportedGames::ModernWarfare4; + GameFlags = SupportedGameFlags::None; + GameXImageHandler = GameModernWarfare4::LoadXImage; + GameStringHandler = GameModernWarfare4::LoadStringEntry; + GamePackageCache = std::make_unique(); + OnDemandCache = std::make_unique(); + GamePackageCache->LoadPackageCacheAsync(ps::state->GameDirectory); + OnDemandCache->LoadPackageCacheAsync(FileSystems::CombinePath(ps::state->GameDirectory, "xpak_cache")); + GameGDTProcessor->SetupProcessor("MWR"); + Success = GameModernWarfare4::LoadAssets(); + break; + // Modern Warfare Remastered + case 0x30305453414D4552: + GameID = SupportedGames::ModernWarfareRemastered; + GameFlags = SupportedGameFlags::None; + GameXImageHandler = GameModernWarfareRM::LoadXImagePS; + GameStringHandler = GameModernWarfareRM::LoadStringEntry; + GamePackageCache = std::make_unique(); + GamePackageCache->LoadPackageCacheAsync(ps::state->GameDirectory); + GameGDTProcessor->SetupProcessor("MWR"); + Success = GameModernWarfareRM::LoadAssetsPS(); + break; + } + + // Done with logger + XAssetLogWriter = nullptr; + + // Result check + if (Success) + { + // Sort the assets + std::stable_sort(GameAssets->LoadedAssets.begin(), GameAssets->LoadedAssets.end(), SortAssets); + + // Success + return LoadGameResult::Success; + } + else + { + // Failed to load + return LoadGameResult::NoAssetsFound; + } + } + + // Reset + if (GameAssets != nullptr) + { + // Clean up + GameAssets.reset(); + } + + // Failed + return LoadGameResult::ProcessNotRunning; +} + +ps::XAsset64 CoDAssets::ParasyteRequest(const uint64_t& AssetPointer) +{ + return CoDAssets::GameInstance->Read(AssetPointer); +} + LoadGameFileResult CoDAssets::LoadFile(const std::string& FilePath) { // Setup the assets @@ -1221,6 +1298,18 @@ bool CoDAssets::LocateGameInfo() // Set game string handler GameStringHandler = GameVanguard::LoadStringEntry; break; + case SupportedGames::Parasyte: + // Locate IW8 Database + auto DBFile = FileSystems::CombinePath(FileSystems::GetDirectoryName(CoDAssets::GameInstance->GetProcessPath()), "Data\\CurrentHandler.parasyte_state_info"); + Success = FileSystems::FileExists(DBFile); + // Validate + if (Success) + { + ps::state = std::make_unique(); + Success = ps::state->Load(DBFile); + } + // Don't Check Offsets or Set up GDT until below + return Success; } // Setup the game's cache @@ -2102,6 +2191,9 @@ void CoDAssets::CleanUpGame() { XAssetLogWriter.reset(); } + + // Clean up Parasyte + ps::state = nullptr; } void CoDAssets::LogXAsset(const std::string& Type, const std::string& Name) diff --git a/src/WraithXCOD/WraithXCOD/CoDAssets.h b/src/WraithXCOD/WraithXCOD/CoDAssets.h index 59d84f3..51555e1 100644 --- a/src/WraithXCOD/WraithXCOD/CoDAssets.h +++ b/src/WraithXCOD/WraithXCOD/CoDAssets.h @@ -17,6 +17,9 @@ #include "CoDXConverter.h" #include "CoDGDTProcessor.h" +// Parasyte +#include "Parasyte.h" + // A list of supported Call of Duty games, or none for nothing loaded enum class SupportedGames { @@ -39,6 +42,7 @@ enum class SupportedGames AdvancedWarfare, WorldWar2, Vanguard, + Parasyte, }; // A list of supported game flags for Call of Duty @@ -166,6 +170,10 @@ class CoDAssets static FindGameResult FindGame(); // Attempts to load assets from the loaded game static LoadGameResult LoadGame(); + // Attempts to load assets from the loaded game + static LoadGameResult LoadGamePS(); + // Requests next XAsset + static ps::XAsset64 ParasyteRequest(const uint64_t& AssetPointer); // Attempts to load assets from a file static LoadGameFileResult LoadFile(const std::string& FilePath); // Cleans up a game if attached diff --git a/src/WraithXCOD/WraithXCOD/GameModernWarfare4.cpp b/src/WraithXCOD/WraithXCOD/GameModernWarfare4.cpp index ea2fc4c..04ef6ce 100644 --- a/src/WraithXCOD/WraithXCOD/GameModernWarfare4.cpp +++ b/src/WraithXCOD/WraithXCOD/GameModernWarfare4.cpp @@ -110,30 +110,6 @@ struct MW4SoundAliasNamingInfo uint64_t SecondaryPtr; }; -struct CeleriumXAssetPool -{ - uint64_t FirstXAsset; - uint64_t LastXAsset; - uint64_t LookupTable; -}; - -struct CeleriumXAsset64 -{ - uint32_t Type; - uint32_t HeaderSize; - uint64_t ID; - uint32_t Temp; - uint64_t Owner; - uint64_t Previous; - uint64_t Next; - uint64_t FirstChild; - uint64_t LastChild; - uint64_t Header; - uint64_t ExtendedDataSize; - uint64_t ExtendedData; - uint64_t ExtendedDataPtrOffset; -}; - // Calculates the hash of a sound string uint32_t MW4HashSoundString(const std::string& Value) { @@ -150,73 +126,10 @@ static_assert(sizeof(MW4XAssetPoolData) == 0x18, "Invalid Pool Data Size (Expect bool GameModernWarfare4::LoadOffsets() { - // ---------------------------------------------------- - // Modern Warfare 4 pools and sizes, XAssetPoolData is an array of pool info for each asset pool in the game - // The index of the assets we use are as follows: xanim (3), xmodel (4), ximage (0x9) - // Index * sizeof(MWXAssetPoolData) = the offset of the asset info in this array of data, we can verify it using the xmodel pool and checking for the model hash (0x04647533e968c910) - // Notice: Modern Warfare 4 doesn't store a freePoolHandle at the beginning, so we just read on. - // On Modern Warfare 4, (0x04647533e968c910) will be the first xmodel - // Modern Warfare 4 stringtable, check entries, results may vary - // Reading is: (StringIndex * 28) + StringTablePtr + 8 - // ---------------------------------------------------- - - // Attempt to load the game offsets - if (CoDAssets::GameInstance != nullptr) - { - // Locate IW8 Database - auto DBFile = FileSystems::CombinePath(FileSystems::GetDirectoryName(CoDAssets::GameInstance->GetProcessPath()), "Data\\CurrentHandler.parasyte_state_info"); - - if (FileSystems::FileExists(DBFile)) - { - BinaryReader DBReader; - - if (!DBReader.Open(DBFile, true)) - { - return false; - } - - auto GameID = DBReader.Read(); - auto XAssetPools = DBReader.Read(); - auto StringPool = DBReader.Read(); - - CoDAssets::GameDirectory = DBReader.ReadNullTerminatedString(); - - // Apply game offset info - CoDAssets::GameOffsetInfos.emplace_back(StringPool); - CoDAssets::GameOffsetInfos.emplace_back(CoDAssets::GameInstance->Read(XAssetPools + sizeof(CeleriumXAssetPool) * 9).FirstXAsset); - CoDAssets::GameOffsetInfos.emplace_back(CoDAssets::GameInstance->Read(XAssetPools + sizeof(CeleriumXAssetPool) * 7).FirstXAsset); - CoDAssets::GameOffsetInfos.emplace_back(CoDAssets::GameInstance->Read(XAssetPools + sizeof(CeleriumXAssetPool) * 19).FirstXAsset); - CoDAssets::GameOffsetInfos.emplace_back(CoDAssets::GameInstance->Read(XAssetPools + sizeof(CeleriumXAssetPool) * 11).FirstXAsset); - CoDAssets::GameOffsetInfos.emplace_back(CoDAssets::GameInstance->Read(XAssetPools + sizeof(CeleriumXAssetPool) * 21).FirstXAsset); - CoDAssets::GameOffsetInfos.emplace_back(CoDAssets::GameInstance->Read(XAssetPools + sizeof(CeleriumXAssetPool) * 22).FirstXAsset); - - // Celerium doesn't use pool sizes - CoDAssets::GamePoolSizes.emplace_back(0); - return true; - } - } - // Failed return false; } -// Parse the pool, givin the current offset and asset type -void CeleriumPoolParser(uint64_t PoolOffset, std::function OnAssetParsed) -{ - // Loop and check if each asset is valid, if so, perform callback - for (auto Current = CoDAssets::GameInstance->Read(PoolOffset); ; Current = CoDAssets::GameInstance->Read(Current.Next)) - { - // We should process this asset - if(Current.Header != 0) - OnAssetParsed(Current); - - if (Current.Next == 0) - { - break; - } - } -} - bool GameModernWarfare4::LoadAssets() { // Prepare to load game assets, into the AssetPool @@ -229,7 +142,8 @@ bool GameModernWarfare4::LoadAssets() if (NeedsModels) { - CeleriumPoolParser(CoDAssets::GameOffsetInfos[1], [](CeleriumXAsset64& Asset) + auto Pool = CoDAssets::GameInstance->Read(ps::state->PoolsAddress + 9 * sizeof(ps::XAssetPool64)); + ps::PoolParser64(Pool.FirstXAsset, CoDAssets::ParasyteRequest, [](ps::XAsset64& Asset) { // Read auto ModelResult = CoDAssets::GameInstance->Read(Asset.Header); @@ -256,7 +170,8 @@ bool GameModernWarfare4::LoadAssets() if (NeedsImages) { - CeleriumPoolParser(CoDAssets::GameOffsetInfos[3], [](CeleriumXAsset64& Asset) + auto Pool = CoDAssets::GameInstance->Read(ps::state->PoolsAddress + 19 * sizeof(ps::XAssetPool64)); + ps::PoolParser64(Pool.FirstXAsset, CoDAssets::ParasyteRequest, [](ps::XAsset64& Asset) { // Read auto ImageResult = CoDAssets::GameInstance->Read(Asset.Header); @@ -285,7 +200,8 @@ bool GameModernWarfare4::LoadAssets() if (NeedsAnims) { - CeleriumPoolParser(CoDAssets::GameOffsetInfos[2], [](CeleriumXAsset64& Asset) + auto Pool = CoDAssets::GameInstance->Read(ps::state->PoolsAddress + 7 * sizeof(ps::XAssetPool64)); + ps::PoolParser64(Pool.FirstXAsset, CoDAssets::ParasyteRequest, [](ps::XAsset64& Asset) { // Read auto AnimResult = CoDAssets::GameInstance->Read(Asset.Header); @@ -311,7 +227,8 @@ bool GameModernWarfare4::LoadAssets() if (NeedsMaterials) { - CeleriumPoolParser(CoDAssets::GameOffsetInfos[4], [](CeleriumXAsset64& Asset) + auto Pool = CoDAssets::GameInstance->Read(ps::state->PoolsAddress + 11 * sizeof(ps::XAssetPool64)); + ps::PoolParser64(Pool.FirstXAsset, CoDAssets::ParasyteRequest, [](ps::XAsset64& Asset) { // Read auto MatResult = CoDAssets::GameInstance->Read(Asset.Header); @@ -337,7 +254,8 @@ bool GameModernWarfare4::LoadAssets() // Since MW now stores the entire SABL in Fast Files, we must essentially parse it in memory, SABS files can be loaded as usual. if (NeedsSounds) { - CeleriumPoolParser(CoDAssets::GameOffsetInfos[5], [](CeleriumXAsset64& Asset) + auto Pool = CoDAssets::GameInstance->Read(ps::state->PoolsAddress + 21 * sizeof(ps::XAssetPool64)); + ps::PoolParser64(Pool.FirstXAsset, CoDAssets::ParasyteRequest, [](ps::XAsset64& Asset) { // Read auto SoundResult = CoDAssets::GameInstance->Read(Asset.Header); @@ -430,7 +348,8 @@ bool GameModernWarfare4::LoadAssets() if (NeedsRawFiles) { - CeleriumPoolParser(CoDAssets::GameOffsetInfos[6], [](CeleriumXAsset64& Asset) + auto Pool = CoDAssets::GameInstance->Read(ps::state->PoolsAddress + 22 * sizeof(ps::XAssetPool64)); + ps::PoolParser64(Pool.FirstXAsset, CoDAssets::ParasyteRequest, [](ps::XAsset64& Asset) { // Read auto SoundResult = CoDAssets::GameInstance->Read(Asset.Header); @@ -455,230 +374,6 @@ bool GameModernWarfare4::LoadAssets() }); } - //if (NeedsImages) - //{ - // // Images are the third offset and third pool, skip 8 byte pointer to free head - // auto ImageOffset = CoDAssets::GameOffsetInfos[2]; - // auto ImageCount = CoDAssets::GamePoolSizes[2]; - - // // Calculate maximum pool size - // auto MaximumPoolOffset = (ImageCount * sizeof(MW4GfxImage)) + ImageOffset; - // // Store original offset - // auto MinimumPoolOffset = CoDAssets::GameOffsetInfos[2]; - - // // Loop and read - // for (uint32_t i = 0; i < ImageCount; i++) - // { - // // Read - // auto ImageResult = CoDAssets::GameInstance->Read(ImageOffset); - - // // Check whether or not to skip, if the handle is 0, or, if the handle is a pointer within the current pool - // if ((ImageResult.NamePtr > MinimumPoolOffset && ImageResult.NamePtr < MaximumPoolOffset) || ImageResult.NamePtr == 0) - // { - // // Advance - // ImageOffset += sizeof(MW4GfxImage); - // // Skip this asset - // continue; - // } - - // // Validate and load if need be - // auto ImageName = FileSystems::GetFileName(CoDAssets::GameInstance->ReadNullTerminatedString(ImageResult.NamePtr)); - - // // Log it - // CoDAssets::LogXAsset("Image", ImageName); - - // // Check if it's streamed - // if(ImageResult.LoadedMipLevels > 0) - // { - - // // Make and add - // auto LoadedImage = new CoDImage_t(); - // // Set - // LoadedImage->AssetName = ImageName; - // LoadedImage->AssetPointer = ImageOffset; - // LoadedImage->Width = (uint16_t)ImageResult.LoadedMipWidth; - // LoadedImage->Height = (uint16_t)ImageResult.LoadedMipHeight; - // LoadedImage->Format = ImageResult.ImageFormat; - // LoadedImage->AssetStatus = WraithAssetStatus::Loaded; - - // // Add - // CoDAssets::GameAssets->LoadedAssets.push_back(LoadedImage); - // } - - // // Advance - // ImageOffset += sizeof(MW4GfxImage); - // } - //} - - //// Since MW now stores the entire SABL in Fast Files, we must essentially parse it in memory, SABS files can be loaded as usual. - //if (NeedsSounds) - //{ - // // Images are the fourth offset and foruth pool - // auto SoundOffset = CoDAssets::GameOffsetInfos[3]; - // auto SoundCount = CoDAssets::GamePoolSizes[3]; - - // // Calculate maximum pool size - // auto MaximumPoolOffset = (SoundCount * sizeof(MW4SoundBank)) + SoundOffset; - // // Store original offset - // auto MinimumPoolOffset = CoDAssets::GameOffsetInfos[3]; - - // // Loop and read - // for (uint32_t i = 0; i < SoundCount; i++) - // { - // // Read - // auto SoundResult = CoDAssets::GameInstance->Read(SoundOffset); - - // // Check whether or not to skip, if the handle is 0, or, if the handle is a pointer within the current pool - // if ((SoundResult.NamePtr > MinimumPoolOffset && SoundResult.NamePtr < MaximumPoolOffset) || SoundResult.NamePtr == 0) - // { - // // Advance - // SoundOffset += sizeof(MW4SoundBank); - // // Skip this asset - // continue; - // } - - // auto SoundBankInfo = CoDAssets::GameInstance->Read(SoundResult.SoundBankPtr); - - // if (SoundBankInfo.BankFilePointer > 0) - // { - // // Names by Hash - // std::map SABFileNames; - - // // Parse the loaded header, and offset from the pointer to it - // auto Header = CoDAssets::GameInstance->Read(SoundBankInfo.BankFilePointer); - - // // Verify magic first, same for all SAB files - // // The magic is ('2UX#') - // if (Header.Magic != 0x23585532) - // { - // // Advance - // SoundOffset += sizeof(MW4SoundBank); - // // Skip this asset - // continue; - // } - - // // Get Settings - // auto SkipBlankAudio = SettingsManager::GetSetting("skipblankaudio", "false") == "true"; - - // // Name offset - // auto NamesOffset = CoDAssets::GameInstance->Read(SoundBankInfo.BankFilePointer + 0x250); - - // // Prepare to loop and read entries - // for (size_t i = 0; i < Header.EntriesCount; i++) - // { - // auto Name = CoDAssets::GameInstance->ReadNullTerminatedString(SoundBankInfo.BankFilePointer + NamesOffset + i * 128); - // SABFileNames[MW4HashSoundString(Name)] = Name; - // } - - // // Prepare to loop and read entries - // for (uint32_t i = 0; i < Header.EntriesCount; i++) - // { - // // Read each entry - // auto Entry = CoDAssets::GameInstance->Read(SoundBankInfo.BankFilePointer + Header.EntryTableOffset + i * sizeof(SABv4Entry)); - - // // Prepare to parse the information to our generic structure - // std::string EntryName = ""; - // // Check our options - // if (SABFileNames.size() > 0) - // { - // // We have it in file - // EntryName = SABFileNames[Entry.Key]; - // } - // else - // { - // // We don't have one - // EntryName = Strings::Format("_%llx", Entry.Key); - // } - - // // Log it - // CoDAssets::LogXAsset("Sound", EntryName); - - // // Setup a new entry - // auto LoadedSound = new CoDSound_t(); - // // Set the name, but remove all extensions first - // LoadedSound->AssetName = FileSystems::GetFileNamePurgeExtensions(EntryName); - // LoadedSound->FullPath = FileSystems::GetDirectoryName(EntryName); - - // // Set various properties - // LoadedSound->FrameRate = Entry.FrameRate; - // LoadedSound->FrameCount = Entry.FrameCount; - // LoadedSound->ChannelsCount = Entry.ChannelCount; - // // The offset should be after the seek table, since it is not required - // LoadedSound->AssetPointer = SoundBankInfo.BankFilePointer + (Entry.Offset + Entry.SeekTableLength); - // LoadedSound->AssetSize = Entry.Size; - // LoadedSound->AssetStatus = WraithAssetStatus::Loaded; - // LoadedSound->IsFileEntry = false; - // LoadedSound->Length = (uint32_t)(1000.0f * (float)(LoadedSound->FrameCount / (float)(LoadedSound->FrameRate))); - // // All Modern Warfare (v10) entries are FLAC's with no header - // LoadedSound->DataType = SoundDataTypes::FLAC_NeedsHeader; - - // // Check do we want to skip this - // if (SkipBlankAudio && LoadedSound->AssetSize <= 0) - // { - // delete LoadedSound; - // continue; - // } - - // // Add - // CoDAssets::GameAssets->LoadedAssets.push_back(LoadedSound); - // } - // } - - // // Advance - // SoundOffset += sizeof(MW4SoundBank); - // } - //} - - //if (NeedsRawFiles) - //{ - // // Parse the Rawfile pool - // CoDXPoolParser(CoDAssets::GameOffsetInfos[4], CoDAssets::GamePoolSizes[4], [](MW4SoundBank& Asset, uint64_t& AssetOffset) - // { - // // Validate and load if need be - // auto RawfileName = CoDAssets::GameInstance->ReadNullTerminatedString(Asset.NamePtr) + ".sabs"; - - // // Note actually streamer info pool - // auto Info = CoDAssets::GameInstance->Read(Asset.SoundBankPtr); - - // // Make and add - // auto LoadedRawfile = new CoDRawFile_t(); - // // Set - // LoadedRawfile->AssetName = FileSystems::GetFileName(RawfileName); - // LoadedRawfile->RawFilePath = FileSystems::GetDirectoryName(RawfileName); - // LoadedRawfile->AssetPointer = AssetOffset; - // LoadedRawfile->AssetSize = Info.BankFileSize; - // LoadedRawfile->RawDataPointer = Info.BankFilePointer; - // LoadedRawfile->AssetStatus = WraithAssetStatus::Loaded; - - // // Add - // CoDAssets::GameAssets->LoadedAssets.push_back(LoadedRawfile); - // }); - //} - - //if (NeedsMaterials) - //{ - // // Parse the Rawfile pool - // CoDXPoolParser(CoDAssets::GameOffsetInfos[5], CoDAssets::GamePoolSizes[5], [](MW4XMaterial& Asset, uint64_t& AssetOffset) - // { - // // Validate and load if need be - // auto MaterialName = CoDAssets::GameInstance->ReadNullTerminatedString(Asset.NamePtr); - - // // Log it - // CoDAssets::LogXAsset("Material", MaterialName); - - // // Make and add - // auto LoadedMaterial = new CoDMaterial_t(); - // // Set - // LoadedMaterial->AssetName = FileSystems::GetFileName(MaterialName); - // LoadedMaterial->AssetPointer = AssetOffset; - // LoadedMaterial->ImageCount = Asset.ImageCount; - // LoadedMaterial->AssetStatus = WraithAssetStatus::Loaded; - - // // Add - // CoDAssets::GameAssets->LoadedAssets.push_back(LoadedMaterial); - // }); - //} - // Success, error only on specific load return true; } @@ -1435,8 +1130,7 @@ void GameModernWarfare4::LoadXModel(const XModelLod_t& ModelLOD, const std::uniq std::string GameModernWarfare4::LoadStringEntry(uint64_t Index) { - // Read and return (Offsets[3] = StringTable) - return CoDAssets::GameInstance->ReadNullTerminatedString(CoDAssets::GameOffsetInfos[0] + Index); + return CoDAssets::GameInstance->ReadNullTerminatedString(ps::state->StringsAddress + Index); } void GameModernWarfare4::PerformInitialSetup() { diff --git a/src/WraithXCOD/WraithXCOD/GameModernWarfareRM.cpp b/src/WraithXCOD/WraithXCOD/GameModernWarfareRM.cpp index b3c279f..d058876 100644 --- a/src/WraithXCOD/WraithXCOD/GameModernWarfareRM.cpp +++ b/src/WraithXCOD/WraithXCOD/GameModernWarfareRM.cpp @@ -13,9 +13,6 @@ #include "FileSystems.h" #include "SettingsManager.h" -#include -using namespace std; - // -- Initialize built-in game offsets databases // Modern Warfare RM SP @@ -554,6 +551,257 @@ bool GameModernWarfareRM::LoadAssets() return true; } +bool GameModernWarfareRM::LoadAssetsPS() +{ + // Prepare to load game assets, into the AssetPool + bool NeedsAnims = (SettingsManager::GetSetting("showxanim", "true") == "true"); + bool NeedsModels = (SettingsManager::GetSetting("showxmodel", "true") == "true"); + bool NeedsImages = (SettingsManager::GetSetting("showximage", "false") == "true"); + bool NeedsSounds = (SettingsManager::GetSetting("showxsounds", "false") == "true"); + bool NeedsMaterials = (SettingsManager::GetSetting("showxmtl", "false") == "true"); + + // Check if we need assets + if (NeedsAnims) + { + auto XAnimPool = CoDAssets::GameInstance->Read(ps::state->PoolsAddress + 5 * sizeof(ps::XAssetPool64)); + ps::PoolParser64(XAnimPool.FirstXAsset, CoDAssets::ParasyteRequest, [](ps::XAsset64& Asset) + { + // Read + auto AnimResult = CoDAssets::GameInstance->Read(Asset.Header); + // Validate and load if need be + auto AnimName = CoDAssets::GameInstance->ReadNullTerminatedString(AnimResult.NamePtr); + + // Log it + CoDAssets::LogXAsset("Anim", AnimName); + + // Make and add + auto LoadedAnim = new CoDAnim_t(); + // Set + LoadedAnim->AssetName = AnimName; + LoadedAnim->AssetPointer = Asset.Header; + LoadedAnim->Framerate = AnimResult.Framerate; + LoadedAnim->FrameCount = AnimResult.NumFrames; + LoadedAnim->BoneCount = AnimResult.TotalBoneCount; + LoadedAnim->AssetStatus = Asset.Temp == 1 ? WraithAssetStatus::Placeholder : WraithAssetStatus::Loaded; + // Add + CoDAssets::GameAssets->LoadedAssets.push_back(LoadedAnim); + }); + } + + // Check if we need assets + if (NeedsImages) + { + auto XAnimPool = CoDAssets::GameInstance->Read(ps::state->PoolsAddress + 16 * sizeof(ps::XAssetPool64)); + ps::PoolParser64(XAnimPool.FirstXAsset, CoDAssets::ParasyteRequest, [](ps::XAsset64& Asset) + { + // Read + auto ImageResult = CoDAssets::GameInstance->Read(Asset.Header); + // Validate and load if need be + auto ImageName = FileSystems::GetFileName(CoDAssets::GameInstance->ReadNullTerminatedString(ImageResult.NamePtr)); + + // Calculate the largest image mip + uint32_t LargestWidth = ImageResult.Width; + uint32_t LargestHeight = ImageResult.Height; + + if (ImageResult.Streamed > 0) + { + // Loop and calculate + for (uint32_t i = 0; i < 3; i++) + { + // Compare widths + if (ImageResult.MipLevels[i].Width > LargestWidth) + { + LargestWidth = ImageResult.MipLevels[i].Width; + LargestHeight = ImageResult.MipLevels[i].Height; + } + } + } + + // Make and add + auto LoadedImage = new CoDImage_t(); + // Set + LoadedImage->AssetName = ImageName; + LoadedImage->AssetPointer = Asset.Header; + LoadedImage->Width = (uint16_t)LargestWidth; + LoadedImage->Height = (uint16_t)LargestHeight; + LoadedImage->Format = ImageResult.ImageFormat; + LoadedImage->AssetStatus = WraithAssetStatus::Loaded; + LoadedImage->Streamed = ImageResult.Streamed > 0; + + // Add + CoDAssets::GameAssets->LoadedAssets.push_back(LoadedImage); + }); + } + + // Check if we need assets + if (NeedsMaterials) + { + auto Pool = CoDAssets::GameInstance->Read(ps::state->PoolsAddress + 8 * sizeof(ps::XAssetPool64)); + ps::PoolParser64(Pool.FirstXAsset, CoDAssets::ParasyteRequest, [](ps::XAsset64& Asset) + { + // Read + auto MaterialResult = CoDAssets::GameInstance->Read(Asset.Header); + // Validate and load if need be + auto MaterialName = FileSystems::GetFileName(CoDAssets::GameInstance->ReadNullTerminatedString(MaterialResult.NamePtr)); + // Make and add + auto Material = new CoDMaterial_t(); + // Set + Material->AssetName = Strings::Replace(MaterialName, "*", ""); + Material->AssetPointer = Asset.Header; + Material->ImageCount = (uint8_t)MaterialResult.ImageCount; + Material->AssetStatus = Asset.Temp == 1 ? WraithAssetStatus::Placeholder : WraithAssetStatus::Loaded; + // Add + CoDAssets::GameAssets->LoadedAssets.push_back(Material); + }); + } + + // Check if we need assets + if (NeedsModels) + { + auto Pool = CoDAssets::GameInstance->Read(ps::state->PoolsAddress + 7 * sizeof(ps::XAssetPool64)); + ps::PoolParser64(Pool.FirstXAsset, CoDAssets::ParasyteRequest, [](ps::XAsset64& Asset) + { + // Read + auto ModelResult = CoDAssets::GameInstance->Read(Asset.Header); + // Validate and load if need be + auto ModelName = FileSystems::GetFileName(CoDAssets::GameInstance->ReadNullTerminatedString(ModelResult.NamePtr)); + // Make and add + auto LoadedModel = new CoDModel_t(); + // Set + LoadedModel->AssetName = ModelName; + LoadedModel->AssetPointer = Asset.Header; + LoadedModel->BoneCount = ModelResult.NumBones; + LoadedModel->LodCount = ModelResult.NumLods; + LoadedModel->AssetStatus = Asset.Temp == 1 ? WraithAssetStatus::Placeholder : WraithAssetStatus::Loaded; + // Add + CoDAssets::GameAssets->LoadedAssets.push_back(LoadedModel); + }); + } + // Check if we need assets + if (NeedsSounds) + { + // A temporary table for duplicates, since we are tracing from alias entries... + std::set UniqueEntries; + auto Pool = CoDAssets::GameInstance->Read(ps::state->PoolsAddress + 17 * sizeof(ps::XAssetPool64)); + ps::PoolParser64(Pool.FirstXAsset, CoDAssets::ParasyteRequest, [&UniqueEntries](ps::XAsset64& Asset) + { + // Read + auto SoundResult = CoDAssets::GameInstance->Read(Asset.Header); + // Validate and load if need be + auto SoundName = CoDAssets::GameInstance->ReadNullTerminatedString(SoundResult.NamePtr); + + for (uint32_t j = 0; j < SoundResult.EntryCount; j++) + { + // Load Alias + auto SoundAliasEntry = CoDAssets::GameInstance->Read(SoundResult.EntriesPtr + (j * sizeof(MWRSoundAliasEntry))); + + // Load File Spec + auto SoundFileSpec = CoDAssets::GameInstance->Read(SoundAliasEntry.FileSpecPtr); + // Check type + if (SoundFileSpec.Type == 1) + { + // Read Pointer to Sound + auto LoadedSoundPtr = CoDAssets::GameInstance->Read(SoundAliasEntry.FileSpecPtr + 8); + // Validate uniqueness + if (UniqueEntries.insert(LoadedSoundPtr).second == false) + continue; + // Read Sound + auto LoadedSoundInfo = CoDAssets::GameInstance->Read(LoadedSoundPtr); + + // Validate and load if need be + auto LoadedSoundName = CoDAssets::GameInstance->ReadNullTerminatedString(LoadedSoundInfo.NamePtr); + + // Make and add + auto LoadedSound = new CoDSound_t(); + // Set + LoadedSound->AssetName = FileSystems::GetFileNameWithoutExtension(LoadedSoundName); + LoadedSound->AssetPointer = LoadedSoundInfo.SoundDataPtr; + LoadedSound->FrameRate = LoadedSoundInfo.FrameRate; + LoadedSound->FrameCount = LoadedSoundInfo.FrameCount; + LoadedSound->AssetSize = LoadedSoundInfo.SoundDataSize; + LoadedSound->ChannelsCount = LoadedSoundInfo.Channels; + LoadedSound->IsFileEntry = false; + LoadedSound->FullPath = FileSystems::GetDirectoryName(LoadedSoundName); + LoadedSound->DataType = (LoadedSoundInfo.Format == 7 || LoadedSoundInfo.Format == 6) ? SoundDataTypes::FLAC_WithHeader : SoundDataTypes::WAV_NeedsHeader; + LoadedSound->AssetStatus = WraithAssetStatus::Loaded; + LoadedSound->Length = (uint32_t)(1000.0f * (float)(LoadedSound->FrameCount / (float)(LoadedSound->FrameRate))); + // Add + CoDAssets::GameAssets->LoadedAssets.push_back(LoadedSound); + } + else if (SoundFileSpec.Type == 2) + { + // Read Data + auto StreamedSoundInfo = CoDAssets::GameInstance->Read(SoundAliasEntry.FileSpecPtr + 8); + // Check does it exist + if (StreamedSoundInfo.Exists) + { + // Make and add + auto LoadedSound = new CoDSound_t(); + // Set (we'll use the alias names since streamed audio is nameless) + LoadedSound->AssetName = Strings::Format("%s_%i", Strings::ToLower(SoundName).c_str(), j); + LoadedSound->IsFileEntry = true; + LoadedSound->DataType = SoundDataTypes::FLAC_WithHeader; + LoadedSound->AssetStatus = WraithAssetStatus::Loaded; + LoadedSound->PackageIndex = StreamedSoundInfo.PackageIndex; + LoadedSound->AssetPointer = StreamedSoundInfo.Offset; + LoadedSound->AssetSize = StreamedSoundInfo.Size; + LoadedSound->Length = StreamedSoundInfo.Length; + LoadedSound->FullPath = "streamed"; + LoadedSound->IsLocalized = StreamedSoundInfo.Localization > 0; + // Add + CoDAssets::GameAssets->LoadedAssets.push_back(LoadedSound); + } + } + else if (SoundFileSpec.Type == 3) + { + // Read Primed Data + auto PrimedAudioInfo = CoDAssets::GameInstance->Read(SoundAliasEntry.FileSpecPtr + 8); + // Validate uniqueness + if (UniqueEntries.insert(PrimedAudioInfo.LoadedSoundPtr).second == false) + continue; + // Check does it exist + if (PrimedAudioInfo.Exists) + { + // Read Sound + auto LoadedSoundInfo = CoDAssets::GameInstance->Read(PrimedAudioInfo.LoadedSoundPtr); + // Validate and load if need be + auto LoadedSoundName = CoDAssets::GameInstance->ReadNullTerminatedString(LoadedSoundInfo.NamePtr); + // Make and add + auto LoadedSound = new CoDSound_t(); + // Set + LoadedSound->AssetName = FileSystems::GetFileNameWithoutExtension(LoadedSoundName); + LoadedSound->FrameRate = LoadedSoundInfo.FrameRate; + LoadedSound->FrameCount = LoadedSoundInfo.FrameCount; + LoadedSound->ChannelsCount = LoadedSoundInfo.Channels; + LoadedSound->FullPath = FileSystems::GetDirectoryName(LoadedSoundName); + LoadedSound->DataType = (LoadedSoundInfo.Format == 7 || LoadedSoundInfo.Format == 6) ? SoundDataTypes::FLAC_WithHeader : SoundDataTypes::WAV_NeedsHeader; + LoadedSound->AssetStatus = WraithAssetStatus::Loaded; + LoadedSound->Length = (uint32_t)(1000.0f * (float)(LoadedSound->FrameCount / (float)(LoadedSound->FrameRate))); + LoadedSound->AssetName = FileSystems::GetFileName(LoadedSoundName); + LoadedSound->IsFileEntry = true; + LoadedSound->PackageIndex = PrimedAudioInfo.PackageIndex; + LoadedSound->AssetPointer = PrimedAudioInfo.Offset; + LoadedSound->AssetSize = PrimedAudioInfo.Size; + LoadedSound->IsLocalized = PrimedAudioInfo.Localization > 0; + // Add + CoDAssets::GameAssets->LoadedAssets.push_back(LoadedSound); + } + } + else + { +#if _DEBUG + // Log on debug + printf("Unknown sound type: %d\n", SoundFileSpec.Type); +#endif + } + } + }); + } + + // Success, error only on specific load + return true; +} + std::unique_ptr GameModernWarfareRM::ReadXAnim(const CoDAnim_t* Animation) { // Verify that the program is running @@ -742,7 +990,10 @@ std::unique_ptr GameModernWarfareRM::ReadXImage(const CoDImage_t* Ima } } // Proxy off - return LoadXImage(XImage_t(Usage, 0, Image->AssetPointer, Image->AssetName)); + if(ps::state != nullptr) + return LoadXImagePS(XImage_t(Usage, 0, Image->AssetPointer, Image->AssetName)); + else + return LoadXImage(XImage_t(Usage, 0, Image->AssetPointer, Image->AssetName)); } XMaterial_t GameModernWarfareRM::ReadXMaterial(uint64_t MaterialPointer) @@ -879,8 +1130,121 @@ std::unique_ptr GameModernWarfareRM::LoadXImage(const XImage_t& Image return nullptr; } +struct XImageData +{ + uint16_t Locale; + uint16_t PackageIndex; + uint32_t Checksum; + uint64_t Offset; + uint64_t Size; +}; + +std::unique_ptr GameModernWarfareRM::LoadXImagePS(const XImage_t& Image) +{ + // Prepare to load an image, we only support PAK images + uint32_t ResultSize = 0; + + // We must read the image data + auto ImageInfo = CoDAssets::GameInstance->Read(Image.ImagePtr); + // Buffer + std::unique_ptr ImageData = nullptr; + // Widths + uint32_t LargestWidth = 0; + uint32_t LargestHeight = 0; + + // Check if the image isn't streamed, if it isn't, just exit + if (ImageInfo.Streamed > 0) + { + // Calculate the largest image mip + uint32_t LargestMip = 0; + + // Loop and calculate + for (uint32_t i = 0; i < 3; i++) + { + // Compare widths + if (ImageInfo.MipLevels[i].Width > LargestWidth) + { + LargestMip = i + 1; + LargestWidth = ImageInfo.MipLevels[i].Width; + LargestHeight = ImageInfo.MipLevels[i].Height; + } + } + + // Read info + auto ImageStreamInfo = CoDAssets::GameInstance->Read(Image.ImagePtr + sizeof(MWRGfxImage) + sizeof(XImageData) * LargestMip); + // Read image package name + auto ImagePackageName = Strings::Format("imagefile%i.pak", ImageStreamInfo.PackageIndex); + // Attempt to extract the package asset + ImageData = PAKSupport::AWExtractImagePackage(FileSystems::CombinePath(CoDAssets::GamePackageCache->GetPackagesPath(), ImagePackageName), ImageStreamInfo.Offset, (ImageStreamInfo.Size - ImageStreamInfo.Offset), ResultSize); + } + else + { + ResultSize = CoDAssets::GameInstance->Read(Image.ImagePtr + 40); + LargestWidth = (uint32_t)CoDAssets::GameInstance->Read(Image.ImagePtr + 44); + LargestHeight = (uint32_t)CoDAssets::GameInstance->Read(Image.ImagePtr + 46); + + ImageData = std::make_unique(ResultSize); + + if (CoDAssets::GameInstance->Read(ImageData.get(), CoDAssets::GameInstance->Read(Image.ImagePtr + 56), ResultSize) != ResultSize) + return nullptr; + } + + // Check + if (ImageData != nullptr) + { + // If we have a certain format, prepare to swizzle the data + if (ImageInfo.ImageFormat == 84) + { + // We must swap the R and G channels (for each 16 bytes, swap the 8-byte parts) (A2XY) + auto ImageDataParts = (uint64_t*)ImageData.get(); + + // Store position and blocks to go + uint32_t Position = 0; + uint32_t TotalBlocks = ResultSize / 8; + + // Iterate and swap + do + { + // Hold the first one + auto ImagePartUpper = ImageDataParts[Position]; + + // Place second in first + ImageDataParts[Position] = ImageDataParts[Position + 1]; + ImageDataParts[Position + 1] = ImagePartUpper; + + // Advance 2 + Position += 2; + + // Loop until end + } while (Position < TotalBlocks); + } + + // Prepare to create a MemoryDDS file + auto Result = CoDRawImageTranslator::TranslateBC(ImageData, ResultSize, LargestWidth, LargestHeight, ImageInfo.ImageFormat, 1, (ImageInfo.MapType == (uint8_t)GfxImageMapType::MAPTYPE_CUBE)); + + // Check for, and apply patch if required, if we got a raw result + if (Result != nullptr && Image.ImageUsage == ImageUsageType::NormalMap && (SettingsManager::GetSetting("patchnormals", "true") == "true")) + { + // Set normal map patch + Result->ImagePatchType = ImagePatch::Normal_Expand; + } + + // Return it + return Result; + } + + // Failed to load the image + return nullptr; +} + std::string GameModernWarfareRM::LoadStringEntry(uint64_t Index) { - // Read and return (Offsets[4] = StringTable) - return CoDAssets::GameInstance->ReadNullTerminatedString((16 * Index) + CoDAssets::GameOffsetInfos[5] + 8); + if (ps::state == nullptr) + { + return CoDAssets::GameInstance->ReadNullTerminatedString((16 * Index) + CoDAssets::GameOffsetInfos[5] + 8); + } + else + { + return CoDAssets::GameInstance->ReadNullTerminatedString(ps::state->StringsAddress + Index); + } } \ No newline at end of file diff --git a/src/WraithXCOD/WraithXCOD/GameModernWarfareRM.h b/src/WraithXCOD/WraithXCOD/GameModernWarfareRM.h index 7ba3229..7343231 100644 --- a/src/WraithXCOD/WraithXCOD/GameModernWarfareRM.h +++ b/src/WraithXCOD/WraithXCOD/GameModernWarfareRM.h @@ -19,6 +19,8 @@ class GameModernWarfareRM static bool LoadOffsets(); // Loads assets for Modern Warfare RM static bool LoadAssets(); + // Loads assets for Modern Warfare RM (Parasyte) + static bool LoadAssetsPS(); // Reads an XAnim from Modern Warfare RM static std::unique_ptr ReadXAnim(const CoDAnim_t* Animation); @@ -29,6 +31,8 @@ class GameModernWarfareRM // Reads an XImageDDS from a image reference from Modern Warfare RM static std::unique_ptr LoadXImage(const XImage_t& Image); + // Reads an XImageDDS from a image reference from Modern Warfare RM (Parasyte) + static std::unique_ptr LoadXImagePS(const XImage_t& Image); // Reads an XMaterial from it's logical offset in memory diff --git a/src/WraithXCOD/WraithXCOD/Parasyte.cpp b/src/WraithXCOD/WraithXCOD/Parasyte.cpp new file mode 100644 index 0000000..3b888a8 --- /dev/null +++ b/src/WraithXCOD/WraithXCOD/Parasyte.cpp @@ -0,0 +1,51 @@ +#include "Parasyte.h" + +// Current Context Information +std::unique_ptr ps::state = nullptr; + +ps::State::State() : + GameID(0), + PoolsAddress(0), + StringsAddress(0) {} + +bool ps::State::Load(const std::string& path) +{ + std::ifstream s(path, std::ios::binary); + uint32_t stringSize = 0; + + if (!s) + return false; + + if (!s.read((char*)&GameID, sizeof(GameID))) + return false; + if (!s.read((char*)&PoolsAddress, sizeof(PoolsAddress))) + return false; + if (!s.read((char*)&StringsAddress, sizeof(StringsAddress))) + return false; + if (!s.read((char*)&stringSize, sizeof(stringSize))) + return false; + if (stringSize == 0) + return false; + + GameDirectory.resize(stringSize); + + if (!s.read((char*)GameDirectory.data(), stringSize)) + return false; + + return true; +} + +void ps::PoolParser64(uint64_t offset, std::function request, std::function callback) +{ + for (auto p = request(offset); ; p = request(p.Next)) + { + if (p.Header != 0) + callback(p); + + if (p.Next == 0) + { + break; + } + } +} + diff --git a/src/WraithXCOD/WraithXCOD/Parasyte.h b/src/WraithXCOD/WraithXCOD/Parasyte.h new file mode 100644 index 0000000..8a4e33c --- /dev/null +++ b/src/WraithXCOD/WraithXCOD/Parasyte.h @@ -0,0 +1,84 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +// Parasyte Helpers. +namespace ps +{ + // A class to hold Parasyte State Information + class State + { + public: + // Current Game Directory + std::string GameDirectory; + // Current Game ID + uint64_t GameID; + // Address of Asset Pools + uint64_t PoolsAddress; + // Address of Strings + uint64_t StringsAddress; + + // Creates a new state. + State(); + + // Loads the context from the provided file. + bool Load(const std::string& path); + }; + + // Parasytes XAsset Structure. + struct XAsset64 + { + // The xasset type depending on the game it is from. + uint32_t Type; + // The xasset size. + uint32_t HeaderSize; + // The xasset ID. + uint64_t ID; + // Whether or not this asset is a tempt slot. + uint32_t Temp; + // Header Memory. + uint64_t HeaderMemory; + // The fast file that owns this asset. + uint64_t Owner; + // The previous xasset in the list. + uint64_t Previous; + // The next xasset in the list. + uint64_t Next; + // First child asset we have overriden. + uint64_t FirstChild; + // Last child asset we have overriden. + uint64_t LastChild; + // The asset header. + uint64_t Header; + // The size of the extended data. + uint64_t ExtendedDataSize; + // The extended data, if any. + uint64_t ExtendedData; + // The pointer that points to the extended data. + uint64_t ExtendedDataPtrOffset; + }; + + // Parasytes XAsset Pool Structure. + struct XAssetPool64 + { + // The start of the asset chain. + uint64_t FirstXAsset; + // The end of the asset chain. + uint64_t LastXAsset; + // The asset hash table for this pool. + uint64_t LookupTable; + // Storage for asset headers for this pool. + uint64_t HeaderMemory; + }; + + // Current State Information + extern std::unique_ptr state; + + // Parse the pool, givin the current offset and asset type + void PoolParser64(uint64_t offset, std::function request, std::function callback); +}; + diff --git a/src/WraithXCOD/WraithXCOD/WraithXCOD.rc b/src/WraithXCOD/WraithXCOD/WraithXCOD.rc index 6bb7ae5..736a996 100644 --- a/src/WraithXCOD/WraithXCOD/WraithXCOD.rc +++ b/src/WraithXCOD/WraithXCOD/WraithXCOD.rc @@ -368,8 +368,8 @@ IDI_CHECKMARK ICON "..\\..\\WraithX\\Resources\\Che // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,10,0,0 - PRODUCTVERSION 1,10,0,0 + FILEVERSION 1,20,0,0 + PRODUCTVERSION 1,20,0,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -386,12 +386,12 @@ BEGIN BEGIN VALUE "CompanyName", "DTZxPorter / Scobalula" VALUE "FileDescription", "Greyhound" - VALUE "FileVersion", "1.10.0.0" + VALUE "FileVersion", "1.20.0.0" VALUE "InternalName", "Greyhound" VALUE "LegalCopyright", "Copyright (C) 2022 DTZxPorter / Scobalula" VALUE "OriginalFilename", "Greyhound.exe" VALUE "ProductName", "Greyhound" - VALUE "ProductVersion", "1.10.0.0" + VALUE "ProductVersion", "1.20.0.0" END END BLOCK "VarFileInfo" diff --git a/src/WraithXCOD/WraithXCOD/WraithXCOD.vcxproj b/src/WraithXCOD/WraithXCOD/WraithXCOD.vcxproj index 4aa61bb..35578fe 100644 --- a/src/WraithXCOD/WraithXCOD/WraithXCOD.vcxproj +++ b/src/WraithXCOD/WraithXCOD/WraithXCOD.vcxproj @@ -138,6 +138,7 @@ + @@ -199,6 +200,7 @@ + diff --git a/src/WraithXCOD/WraithXCOD/WraithXCOD.vcxproj.filters b/src/WraithXCOD/WraithXCOD/WraithXCOD.vcxproj.filters index a538ac1..2276090 100644 --- a/src/WraithXCOD/WraithXCOD/WraithXCOD.vcxproj.filters +++ b/src/WraithXCOD/WraithXCOD/WraithXCOD.vcxproj.filters @@ -204,6 +204,9 @@ Source Files\Packages + + Source Files + @@ -386,6 +389,9 @@ Header Files\Packages + + Header Files +