diff --git a/r5dev/rtech/rtech_utils.cpp b/r5dev/rtech/rtech_utils.cpp index 6e39d19c..4c3cd933 100644 --- a/r5dev/rtech/rtech_utils.cpp +++ b/r5dev/rtech/rtech_utils.cpp @@ -707,10 +707,93 @@ RPakLoadedInfo_t* RTech::GetPakLoadedInfo(const char* szPakName) return nullptr; } + +//----------------------------------------------------------------------------- +// Purpose: process guid relations for asset +//----------------------------------------------------------------------------- +void RTech::PakProcessGuidRelationsForAsset(PakFile_t* pPak, RPakAssetEntry* pAsset) +{ + RPakDescriptor* pGuidDescriptors = &pPak->m_pGuidDescriptors[pAsset->m_nUsesStartIdx]; + + volatile uint32_t* v5 = reinterpret_cast(*(reinterpret_cast(g_pUnknownPakStruct) + 0x17 * (pPak->qword578 & 0x1FF) + 0x160212)); + + if (rtech_debug->GetBool()) + DevMsg(eDLL_T::RTECH, "Processing GUID relations for asset '0x%-16llX' in pak '%-32s'. Uses: %-4i\n", pAsset->m_Guid, pPak->m_pszFileName, pAsset->m_nUsesCount); + + for (uint64_t i = 0; i < pAsset->m_nUsesCount; i++) + { + void** pCurrentGuid = reinterpret_cast(pPak->m_ppPagePointers[pGuidDescriptors[i].m_Index] + pGuidDescriptors[i].m_Offset); + + // Get current guid. + uint64_t currentGuid = reinterpret_cast(*pCurrentGuid); + + // Get asset index. + int assetIdx = currentGuid & 0x3FFFF; + uint64_t assetIdxEntryGuid = g_pUnknownPakStruct->m_Assets[assetIdx].m_Guid; + + int64_t v9 = 2i64 * InterlockedExchangeAdd(v5, 1u); + *(uint64_t*)&v5[2 * v9 + 2] = currentGuid; + *(uint64_t*)&v5[2 * v9 + 4] = pAsset->m_Guid; + + std::function fnCheckAsset = [&](bool shouldCheckTwo) + { + while (true) + { + if (shouldCheckTwo && assetIdxEntryGuid == 2) + { + if (pPak->m_PakHdr.m_nAssetEntryCount) + return false; + } + + assetIdx++; + assetIdx &= 0x3FFFF; + assetIdxEntryGuid = g_pUnknownPakStruct->m_Assets[assetIdx].m_Guid; + + // Check if we have a deadlock and report it if we have rtech_debug enabled. + if (rtech_debug->GetBool() && assetIdx > 0x40000) + { + DevMsg(eDLL_T::RTECH, "Possible deadlock detected in fnCheckAsset for asset '0x%-16llX' in pak '%-32s'. Uses: %-4i | assetIdxEntryGuid: '0x%-16llX' | currentGuid: '0x%-16llX'\n", pAsset->m_Guid, pPak->m_pszFileName, pAsset->m_nUsesCount, assetIdxEntryGuid, currentGuid); + if (IsDebuggerPresent()) + DebugBreak(); + } + + if (assetIdxEntryGuid == currentGuid) + return true; + } + }; + + if (assetIdxEntryGuid != currentGuid) + { + // Are we some special asset with the guid 2? + if (!fnCheckAsset(true)) + { + RPakAssetEntry* assetEntries = pPak->m_pAssetEntries; + uint64_t a; for (a = 0; assetEntries->m_Guid != currentGuid; a++, assetEntries++) + { + if (a >= pPak->m_PakHdr.m_nAssetEntryCount) + { + fnCheckAsset(false); + break; + } + } + + assetIdx = pPak->qword580[a]; + } + } + + // Finally write the pointer to the guid entry. + *pCurrentGuid = g_pUnknownPakStruct->m_Assets[assetIdx].m_pHead; + } +} + void RTech_Utils_Attach() { DetourAttach((LPVOID*)&RTech_OpenFile, &RTech::OpenFile); +#ifdef GAMEDLL_S3 + DetourAttach((LPVOID*)&RTech_Pak_ProcessGuidRelationsForAsset, &RTech::PakProcessGuidRelationsForAsset); +#endif + #if not defined DEDICATED && defined GAMEDLL_S3 DetourAttach((LPVOID*)&RTech_CreateDXTexture, &RTech::CreateDXTexture); #endif // !DEDICATED @@ -718,9 +801,12 @@ void RTech_Utils_Attach() void RTech_Utils_Detach() { - // [ PIXIE ]: Everything related to RTech::OpenFile should be compatible across seasons. DetourDetach((LPVOID*)&RTech_OpenFile, &RTech::OpenFile); +#ifdef GAMEDLL_S3 + DetourDetach((LPVOID*)&RTech_Pak_ProcessGuidRelationsForAsset, &RTech::PakProcessGuidRelationsForAsset); +#endif + #if not defined DEDICATED && defined GAMEDLL_S3 DetourDetach((LPVOID*)&RTech_CreateDXTexture, &RTech::CreateDXTexture); #endif // !DEDICATED diff --git a/r5dev/rtech/rtech_utils.h b/r5dev/rtech/rtech_utils.h index 95b532a5..84635e6c 100644 --- a/r5dev/rtech/rtech_utils.h +++ b/r5dev/rtech/rtech_utils.h @@ -109,9 +109,37 @@ struct RPakAssetBinding_t // [ PIXIE ]: Should be the full size across Season 0-3. }; +struct RPakAssetEntry +{ + uint64_t m_Guid; + uint64_t m_Padding; + void* m_pHead; + void* m_pCpu; + uint64_t m_nStarpakOffset; + uint64_t m_nStarpakOptOffset; + uint16_t m_nPageEnd; + uint16_t unk1; + uint32_t m_nRelationsStartIdx; + uint32_t m_nUsesStartIdx; + uint32_t m_nRelationsCount; + uint32_t m_nUsesCount; + uint32_t m_nAssetHeaderSize; + uint32_t m_nVersion; + uint32_t m_nMagic; +}; + +struct RPakAssetEntryShort +{ + uint64_t m_Guid; + uint64_t m_Padding; + void* m_pHead; + void* m_pCpu; +}; + struct RPakUnknownStruct_t { RPakAssetBinding_t m_nAssetBindings[64]; // [ PIXIE ]: Max possible registered assets on Season 3, 0-2 I did not check yet. + RPakAssetEntryShort m_Assets[0x40000]; // End size unknown. }; @@ -204,6 +232,58 @@ public: uint64_t m_nUnkEnd; //0x00B0/0x00E8 }; //Size: 0x00B8/0x00E8 +struct RPakDescriptor +{ + uint32_t m_Index; + uint32_t m_Offset; +}; + +struct __declspec(align(2)) PakFile_t +{ + int m_nDescCount; + int m_nProcessedAssetCount; + int m_nPageEnd; + int m_nPageStart; + uint32_t m_nPatchIndex_maybe; + uint32_t dword14; + char gap18[184]; + uint32_t unsigned_intD0; + char gapD4[284]; + uint64_t m_nInputBytePos; + uint8_t byte1F8; + char gap1F9[4]; + uint8_t byte1FD; + uint8_t byte1FE; + uint8_t byte200; + RPakDecompState_t m_PakDecompState; + uint64_t qword288; + uint64_t qword290; + uint64_t qword298; + uint64_t qword2A0; + char* m_PatchData; + char gap2B0[696]; + unsigned __int8(__fastcall* pfunc568)(__int64, LARGE_INTEGER*, unsigned __int64); + uint64_t qword570; + uint64_t qword578; + int* qword580; + uint8_t** m_ppPagePointers; + void* m_pPatchCompressPairs; + uint64_t qword598; + char* m_pszStreamingFilePaths; + char* m_pszOptStreamingFilePaths; + void* m_pVirtualSegments; + void* m_pMemPages; + void* m_pVirtualPointers; + RPakAssetEntry* m_pAssetEntries; + RPakDescriptor* m_pGuidDescriptors; + uint32_t* m_pFileRelations; + char gap5E0[40]; + RPakAssetEntry** m_ppAssetEntries; + char gap610[520]; + const char* m_pszFileName; + RPakHeader_t m_PakHdr; +}; + /* ==== RTECH =========================================================================================================================================================== */ #if not defined DEDICATED inline CMemory p_RTech_CreateDXTexture; @@ -220,6 +300,11 @@ inline auto RTech_FindFreeSlotInFiles = p_RTech_FindFreeSlotInFiles.RCast(); +#ifdef GAMEDLL_S3 +inline CMemory p_Pak_ProcessGuidRelationsForAsset; +inline auto RTech_Pak_ProcessGuidRelationsForAsset = p_RTech_OpenFile.RCast(); +#endif + inline CMemory p_StreamDB_Init; inline auto v_StreamDB_Init = p_StreamDB_Init.RCast(); @@ -247,6 +332,11 @@ public: static int32_t OpenFile(const CHAR* szFilePath, void* unused, LONGLONG* fileSizeOut); +#ifdef GAMEDLL_S3 + static void PakProcessGuidRelationsForAsset(PakFile_t* pak, RPakAssetEntry* asset); +#endif + + #if not defined DEDICATED static void CreateDXTexture(TextureHeader_t* textureHeader, int64_t cpuArg); void** LoadShaderSet(void** VTablePtr); @@ -306,6 +396,11 @@ class VPakFile : public IDetour p_RTech_OpenFile = g_GameDll.FindPatternSIMD(reinterpret_cast("\xE8\x00\x00\x00\x00\x89\x85\x08\x01\x00\x00"), "x????xxxxxx").FollowNearCallSelf(); RTech_OpenFile = p_RTech_OpenFile.RCast(); /*E8 ? ? ? ? 89 85 08 01 00 00*/ + +#ifdef GAMEDLL_S3 + p_Pak_ProcessGuidRelationsForAsset = g_GameDll.FindPatternSIMD(reinterpret_cast("\xE8\x00\x00\x00\x00\x48\x8B\x86\x00\x00\x00\x00\x42\x8B\x0C\xB0"), "x????xxx????xxxx").FollowNearCallSelf(); + RTech_Pak_ProcessGuidRelationsForAsset = p_Pak_ProcessGuidRelationsForAsset.RCast(); /*E8 ? ? ? ? 48 8B 86 ? ? ? ? 42 8B 0C B0*/ +#endif } virtual void GetVar(void) const {