From 4297cd9ce33aaf47c15cc38aa912873122036674 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Sat, 20 May 2023 14:06:36 +0200 Subject: [PATCH] Experimental BSP_LUMP loading hook The 'CMapLoadHelper' constructor has been rebuild to load lump files too (if they exist). Currently, the game only reads the packed BSP file, or lumps if they exist in the filesystem cache. The newly added logic also reads them from a file. This is currently broken, most likely due to alignment problems. Experimental. --- r5dev/engine/modelloader.cpp | 154 ++++++++++++++++++++++++++++++++++- r5dev/engine/modelloader.h | 34 ++++++-- 2 files changed, 178 insertions(+), 10 deletions(-) diff --git a/r5dev/engine/modelloader.cpp b/r5dev/engine/modelloader.cpp index 4bfe7b96..0a0b4a4d 100644 --- a/r5dev/engine/modelloader.cpp +++ b/r5dev/engine/modelloader.cpp @@ -9,9 +9,71 @@ #include "engine/cmodel_bsp.h" #include "engine/modelloader.h" #include "datacache/mdlcache.h" +#ifndef DEDICATED +#include +#endif // !DEDICATED +#include model_t* pErrorMDL = nullptr; +//----------------------------------------------------------------------------- +// Purpose: checks if the lump type is valid and used +// Input : lumpType - +//----------------------------------------------------------------------------- +bool IsLumpIdxValid(int lumpType) +{ + switch (lumpType) + { + case LUMP_PLANES: + case LUMP_VERTICES: + case LUMP_SHADOW_ENVIRONMENTS: + case LUMP_SURFACE_NAMES: + case LUMP_CONTENTS_MASKS: + case LUMP_SURFACE_PROPERTIES: + case LUMP_BVH_NODES: + case LUMP_BVH_LEAF_DATA: + case LUMP_PACKED_VERTICES: + case LUMP_VERTEX_NORMALS: + case LUMP_UNKNOWN_37: + case LUMP_UNKNOWN_38: + case LUMP_UNKNOWN_39: + case LUMP_VERTEX_UNLIT: + case LUMP_VERTEX_LIT_FLAT: + case LUMP_VERTEX_LIT_BUMP: + case LUMP_VERTEX_UNLIT_TS: + case LUMP_MESH_INDICES: + case LUMP_LIGHTMAP_DATA_SKY: + case LUMP_CSM_AABB_NODES: + case LUMP_CSM_OBJ_REFERENCES: + case LUMP_LIGHTPROBES: + case LUMP_LIGHTPROBE_TREE: + case LUMP_LIGHTPROBE_REFERENCES: + case LUMP_LIGHTMAP_DATA_REAL_TIME_LIGHTS: + case LUMP_CELL_BSP_NODES: + case LUMP_CELLS: + case LUMP_PORTALS: + case LUMP_PORTAL_VERTICES: + case LUMP_PORTAL_EDGES: + case LUMP_PORTAL_VERTEX_EDGES: + case LUMP_PORTAL_VERTEX_REFERENCES: + case LUMP_PORTAL_EDGE_REFERENCES: + case LUMP_PORTAL_EDGE_INTERSECT_AT_EDGE: + case LUMP_PORTAL_EDGE_INTERSECT_AT_VERTEX: + case LUMP_PORTAL_EDGE_INTERSECT_HEADER: + case LUMP_OCCLUSION_MESH_VERTICES: + case LUMP_OCCLUSION_MESH_INDICES: + case LUMP_CELL_AABB_NODES: + case LUMP_OBJ_REFERENCES: + case LUMP_OBJ_REFERENCE_BOUNDS: + case LUMP_SHADOW_MESH_OPAQUE_VERTICES: + case LUMP_SHADOW_MESH_INDICES: + case LUMP_SHADOW_MESHES: + return true; + default: + return false; + } +} + //----------------------------------------------------------------------------- // Purpose: // Input : *loader - @@ -55,9 +117,97 @@ uint64_t CModelLoader::Map_LoadModelGuts(CModelLoader* loader, model_t* model) return CModelLoader__Map_LoadModelGuts(loader, model); } -void CMapLoadHelper::Constructor(CMapLoadHelper* helper, int lumpToLoad) +void CMapLoadHelper::Constructor(CMapLoadHelper* loader, int lumpToLoad) { - CMapLoadHelper__CMapLoadHelper(helper, lumpToLoad); +#ifndef DEDICATED + g_pEngineVGui->UpdateProgressBar(PROGRESS_DEFAULT); +#endif // !DEDICATED + + if (lumpToLoad > HEADER_LUMPS-1) + Error(eDLL_T::ENGINE, EXIT_FAILURE, "Can't load lump %i, range is 0 to %i!!!", lumpToLoad, HEADER_LUMPS-1); + + loader->m_nLumpID = lumpToLoad; + loader->m_nLumpSize = 0; + loader->m_pData = nullptr; + loader->m_pRawData = nullptr; + loader->m_pUncompressedData = nullptr; + loader->m_nUncompressedLumpSize = 0; + loader->m_bUncompressedDataExternal = 0; + loader->m_bExternal = false; + loader->m_bUnk = false; + loader->m_nLumpOffset = -1; + + if (lumpToLoad <= s_MapHeader->lastLump) + { + lump_t* lump = &s_MapHeader->lumps[lumpToLoad]; + + int lumpOffset = lump->fileofs; + if (!lumpOffset) + return; // Idk if this is correct. + + int lumpSize = lump->filelen; + if (lumpSize) + { + loader->m_nLumpSize = lumpSize; + loader->m_nLumpOffset = lump->fileofs; + loader->m_nLumpVersion = lump->version; + + FileHandle_t mapFileHandle = *s_MapFileHandle; + + if (mapFileHandle == FILESYSTEM_INVALID_HANDLE) + { + Error(eDLL_T::ENGINE, EXIT_FAILURE, "Can't load map from invalid handle!!!"); + lumpSize = loader->m_nLumpSize; + } + + loader->m_nUncompressedLumpSize = lumpSize; + + char pathBuf[MAX_PATH]; + FileSystemCache fileCache; + + fileCache.pBuffer = nullptr; + + if (IsLumpIdxValid(lumpToLoad) + && (V_snprintf(pathBuf, sizeof(pathBuf), "%s.%.4X.bsp_lump", s_szMapPathName, lumpToLoad), FileSystem()->ReadFromCache(pathBuf, &fileCache))) + { + loader->m_pRawData = nullptr; + loader->m_pData = fileCache.pBuffer->pData; + loader->m_bExternal = true; + loader->m_bUnk = fileCache.pBuffer->nUnk0 == 0; + } + else + { + int bytesToRead = lumpSize ? lumpSize : 1; + loader->m_pRawData = MemAllocSingleton()->Alloc(bytesToRead); + + if (loader->m_nLumpSize) + { + FileHandle_t hLumpFile = FileSystem()->Open(pathBuf, "rb"); + + if (hLumpFile != FILESYSTEM_INVALID_HANDLE) + { + FileSystem()->ReadEx(loader->m_pRawData, bytesToRead, bytesToRead, hLumpFile); + FileSystem()->Close(hLumpFile); + + loader->m_bExternal = true; + } + else // Seek to offset in packed BSP file to load the lump. + { + FileSystem()->Seek(mapFileHandle, loader->m_nLumpOffset, FILESYSTEM_SEEK_HEAD); + FileSystem()->ReadEx(loader->m_pRawData, bytesToRead, bytesToRead, mapFileHandle); + } + + loader->m_pData = loader->m_pRawData; + } + } + } + } + else + { + loader->m_nLumpSize = 0; + loader->m_nLumpOffset = 0; + loader->m_nLumpVersion = 0; + } } /////////////////////////////////////////////////////////////////////////////// diff --git a/r5dev/engine/modelloader.h b/r5dev/engine/modelloader.h index 25384f16..6f48c6c7 100644 --- a/r5dev/engine/modelloader.h +++ b/r5dev/engine/modelloader.h @@ -1,5 +1,6 @@ #pragma once #include "engine/gl_model_private.h" +#include "public/bspfile.h" //----------------------------------------------------------------------------- // Purpose: @@ -55,18 +56,17 @@ class CMapLoadHelper public: static void Constructor(CMapLoadHelper* helper, int lumpToLoad); - public: int m_nLumpSize; int m_nLumpOffset; int m_nLumpVersion; - unsigned __int8* m_pRawData; - char* m_pData; - unsigned __int8* m_pUncompressedData; - char gap_28[5]; + byte* m_pRawData; + byte* m_pData; + byte* m_pUncompressedData; + int m_nUncompressedLumpSize; + bool m_bUncompressedDataExternal; bool m_bExternal; bool m_bUnk; - char gap_2F; int m_nLumpID; char m_szLumpFilename[260]; }; @@ -92,6 +92,9 @@ inline auto CModelLoader__Map_IsValid = p_CModelLoader__Map_IsValid.RCast(); +inline CMemory p_Map_LoadModel; +inline auto v_Map_LoadModel = p_Map_LoadModel.RCast(); + //inline CMemory p_GetSpriteInfo; // DEDICATED PATCH! //inline auto GetSpriteInfo = p_GetSpriteInfo.RCast(); @@ -99,6 +102,9 @@ inline auto CMapLoadHelper__CMapLoadHelper = p_CMapLoadHelper__CMapLoadHelper.RC //inline auto BuildSpriteLoadName = p_BuildSpriteLoadName.RCast(); inline CModelLoader* g_pModelLoader; +inline FileHandle_t* s_MapFileHandle; +inline BSPHeader_t* s_MapHeader; +inline const char* s_szMapPathName; /*size = 260*/ /////////////////////////////////////////////////////////////////////////////// class VModelLoader : public IDetour @@ -111,9 +117,14 @@ class VModelLoader : public IDetour LogFunAdr("CModelLoader::Map_LoadModelGuts", p_CModelLoader__Map_LoadModelGuts.GetPtr()); LogFunAdr("CModelLoader::Map_IsValid", p_CModelLoader__Map_IsValid.GetPtr()); LogFunAdr("CModelLoader::Studio_LoadModel", p_CModelLoader__Studio_LoadModel.GetPtr()); + LogFunAdr("CMapLoadHelper::CMapLoadHelper", p_CMapLoadHelper__CMapLoadHelper.GetPtr()); + LogFunAdr("Map_LoadModel", p_Map_LoadModel.GetPtr()); //LogFunAdr("GetSpriteInfo", p_GetSpriteInfo.GetPtr()); //LogFunAdr("BuildSpriteLoadName", p_BuildSpriteLoadName.GetPtr()); LogVarAdr("g_pModelLoader", reinterpret_cast(g_pModelLoader)); + LogVarAdr("s_MapFileHandle", reinterpret_cast(s_MapFileHandle)); + LogVarAdr("s_MapHeader", reinterpret_cast(s_MapHeader)); + LogVarAdr("s_szMapPathName", reinterpret_cast(s_szMapPathName)); } virtual void GetFun(void) const { @@ -137,8 +148,7 @@ class VModelLoader : public IDetour //p_BuildSpriteLoadName = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 41 56 48 81 EC ?? ?? ?? ?? 4D 8B F1 48 8B F2"); p_CMapLoadHelper__CMapLoadHelper = g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 7C 24 ?? 41 56 48 81 EC 60"); - - CMapLoadHelper__CMapLoadHelper = p_CMapLoadHelper__CMapLoadHelper.RCast(); + p_Map_LoadModel = g_GameDll.FindPatternSIMD("48 83 EC 28 8B 05 ?? ?? ?? ?? FF C8"); CModelLoader__FindModel = p_CModelLoader__FindModel.RCast(); CModelLoader__LoadModel = p_CModelLoader__LoadModel.RCast(); @@ -146,6 +156,10 @@ class VModelLoader : public IDetour CModelLoader__Studio_LoadModel = p_CModelLoader__Studio_LoadModel.RCast(); CModelLoader__Map_LoadModelGuts = p_CModelLoader__Map_LoadModelGuts.RCast(); CModelLoader__Map_IsValid = p_CModelLoader__Map_IsValid.RCast(); + + CMapLoadHelper__CMapLoadHelper = p_CMapLoadHelper__CMapLoadHelper.RCast(); + v_Map_LoadModel = p_Map_LoadModel.RCast(); + //GetSpriteInfo = p_GetSpriteInfo.RCast(); //BuildSpriteLoadName = p_BuildSpriteLoadName.RCast(); } @@ -153,6 +167,10 @@ class VModelLoader : public IDetour { g_pModelLoader = g_GameDll.FindPatternSIMD( "48 89 4C 24 ?? 53 55 56 41 54 41 55 41 56 41 57 48 81 EC ?? ?? ?? ??").FindPatternSelf("48 ?? 0D", CMemory::Direction::DOWN).ResolveRelativeAddressSelf(3, 7).RCast(); + + s_MapFileHandle = p_Map_LoadModel.FindPattern("48 8B").ResolveRelativeAddressSelf(0x3, 0x7).RCast(); + s_MapHeader = p_Map_LoadModel.FindPattern("48 8D").ResolveRelativeAddressSelf(0x3, 0x7).RCast(); + s_szMapPathName = p_CMapLoadHelper__CMapLoadHelper.FindPattern("4C 8D").ResolveRelativeAddressSelf(0x3, 0x7).RCast(); } virtual void GetCon(void) const { } virtual void Attach(void) const;