diff --git a/src/Components/Modules/Maps.cpp b/src/Components/Modules/Maps.cpp index 0296dc67..8ceb7174 100644 --- a/src/Components/Modules/Maps.cpp +++ b/src/Components/Modules/Maps.cpp @@ -149,6 +149,11 @@ namespace Components Maps::DependencyList[expression] = zone; } + bool Maps::IgnoreEntityStub(const char* entity) + { + return (Utils::String::StartsWith(entity, "dyn_") || Utils::String::StartsWith(entity, "node_") || Utils::String::StartsWith(entity, "actor_")); + } + void Maps::ReallocateEntryPool() { Assert_Size(Game::XAssetEntry, 16); @@ -208,6 +213,9 @@ namespace Components // Intercept map zone loading Utils::Hook(0x42C2AF, Maps::LoadMapZones, HOOK_CALL).Install()->Quick(); + // Ignore SP entities + Utils::Hook(0x5FBD6E, Maps::IgnoreEntityStub, HOOK_CALL).Install()->Quick(); + Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_GAME_MAP_SP, 1); Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_IMAGE, 7168); Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_LOADED_SOUND, 2700); diff --git a/src/Components/Modules/Maps.hpp b/src/Components/Modules/Maps.hpp index d6b04dcc..a033ba3d 100644 --- a/src/Components/Modules/Maps.hpp +++ b/src/Components/Modules/Maps.hpp @@ -24,6 +24,8 @@ namespace Components static void OverrideMapEnts(Game::MapEnts* ents); + static bool IgnoreEntityStub(const char* entity); + void ReallocateEntryPool(); }; } diff --git a/src/Components/Modules/ModelSurfs.cpp b/src/Components/Modules/ModelSurfs.cpp index 2b7aa5e1..208aec30 100644 --- a/src/Components/Modules/ModelSurfs.cpp +++ b/src/Components/Modules/ModelSurfs.cpp @@ -114,6 +114,239 @@ namespace Components return modelSurfs; } + Game::FS_FOpenFileRead_t FS_FOpenFileReadDatabase = (Game::FS_FOpenFileRead_t)0x42ECA0; + + void FS_FOpenFileReadCurrentThread(char* filename, int* handle) + { + if (GetCurrentThreadId() == *(DWORD*)0x1CDE7FC) + { + Game::FS_FOpenFileRead(filename, handle, 0); + } + else if (GetCurrentThreadId() == *(DWORD*)0x1CDE814) + { + FS_FOpenFileReadDatabase(filename, handle, 0); + } + else + { + *handle = NULL; + } + } + + struct CModelSectionHeader + { + int size; + int offset; + int fixupStart; + int fixupCount; + char* buffer; + }; + + struct CModelHeader + { + int version; + unsigned int signature; + CModelSectionHeader main; + CModelSectionHeader index; + CModelSectionHeader vertex; + CModelSectionHeader fixup; + }; + + void ReadCModelSection(int handle, CModelSectionHeader& header) + { + Game::FS_Seek(handle, header.offset, FS_SEEK_SET); + Game::FS_Read(header.buffer, header.size, handle); + } + + void FixupCModelSection(CModelHeader& header, CModelSectionHeader& section, DWORD* fixups) + { + for (int i = section.fixupStart; i < section.fixupStart + section.fixupCount; i++) + { + DWORD fixup = fixups[i]; + int targetSectionNum = fixup & 3; + CModelSectionHeader* targetSection; + + if (targetSectionNum == 0) + { + targetSection = &header.main; + } + else if (targetSectionNum == 1) + { + targetSection = &header.index; + } + else if (targetSectionNum == 2) + { + targetSection = &header.vertex; + } + + *(DWORD*)(section.buffer + (fixup >> 3)) += (DWORD)targetSection->buffer; + } + } + + void Load_VertexBuffer(void* data, void** where, int len) + { + DWORD func = 0x5112C0; + + __asm + { + push edi + + mov eax, len + mov edi, where + push data + + call func + + add esp, 4 + pop edi + } + } + + typedef void* (__cdecl * R_AllocStaticIndexBuffer_t)(void** store, int length); + R_AllocStaticIndexBuffer_t R_AllocStaticIndexBuffer = (R_AllocStaticIndexBuffer_t)0x51E7A0; + + void Load_IndexBuffer(void* data, void** storeHere, int count) + { + static Game::dvar_t* r_loadForRenderer = *(Game::dvar_t**)0x69F0ED4; + + if (r_loadForRenderer->current.boolean) + { + void* buffer = R_AllocStaticIndexBuffer(storeHere, 2 * count); + memcpy(buffer, data, 2 * count); + + if (IsBadReadPtr(storeHere, 4) || IsBadReadPtr(*storeHere, 4)) + { + Game::Com_Error(0, "Static index buffer allocation failed."); + } + + __asm + { + push ecx + mov ecx, storeHere + mov ecx, [ecx] + + mov eax, [ecx] + add eax, 30h + mov eax, [eax] + + push ecx + call eax + + pop ecx + } + } + } + + void CreateCModelBuffers(void* surfs) + { + Game::XModelSurfs* model = (Game::XModelSurfs*)surfs; + + for (int i = 0; i < model->numSurfaces; i++) + { + Game::XSurface* surface = &model->surfaces[i]; + + void* vertexBuffer; + void* indexBuffer; + + Load_VertexBuffer(surface->vertexBuffer, &vertexBuffer, surface->numVertices * 32); + Load_IndexBuffer(surface->indexBuffer, &indexBuffer, surface->numPrimitives * 3); + + ModelSurfs::BufferMap[surface->vertexBuffer] = (IUnknown*)vertexBuffer; + ModelSurfs::BufferMap[surface->indexBuffer] = (IUnknown*)indexBuffer; + } + } + + char* LoadCModel(const char* name) + { + char filename[512]; + sprintf_s(filename, sizeof(filename), "models/%s", name); + + int handle; + FS_FOpenFileReadCurrentThread(filename, &handle); + + if (handle <= 0) + { + Game::Com_Error(1, "Error opening %s", filename); + } + + CModelHeader header; + + if (Game::FS_Read(&header, sizeof(header), handle) != sizeof(header)) + { + Game::FS_FCloseFile(handle); + Game::Com_Error(1, "%s: header could not be read", filename); + } + + if (header.version != 1) + { + Game::FS_FCloseFile(handle); + Game::Com_Error(1, "%s: header version is not '1'", filename); + } + + static DWORD fixups[4096]; + + if (header.fixup.size >= sizeof(fixups)) + { + Game::FS_FCloseFile(handle); + Game::Com_Error(1, "%s: fixup size too big", filename); + } + + header.main.buffer = (char*)malloc(header.main.size); + header.index.buffer = (char*)_aligned_malloc(header.index.size, 16); + header.vertex.buffer = (char*)_aligned_malloc(header.vertex.size, 16); + header.fixup.buffer = (char*)fixups; + + ReadCModelSection(handle, header.main); + ReadCModelSection(handle, header.index); + ReadCModelSection(handle, header.vertex); + ReadCModelSection(handle, header.fixup); + + Game::FS_FCloseFile(handle); + + FixupCModelSection(header, header.main, fixups); + FixupCModelSection(header, header.index, fixups); + FixupCModelSection(header, header.vertex, fixups); + + Game::CModelAllocData* allocationData = (Game::CModelAllocData*)malloc(sizeof(Game::CModelAllocData)); + allocationData->mainArray = header.main.buffer; + allocationData->indexBuffer = header.index.buffer; + allocationData->vertexBuffer = header.vertex.buffer; + + *(void**)(header.main.buffer + 44) = allocationData; + + // maybe the +36/48 = 0 stuff here? + + // move buffers to work with iw4 + int numSurfaces = *(short*)(header.main.buffer + 8); + + char* tempSurface = new char[84 * numSurfaces]; + char* surface = *(char**)(header.main.buffer + 4); + + for (int i = 0; i < numSurfaces; i++) + { + char* source = &surface[84 * i]; + char* dest = &tempSurface[64 * i]; + + memcpy(dest, source, 12); + memcpy(dest + 12, source + 16, 20); + memcpy(dest + 32, source + 40, 8); + memcpy(dest + 40, source + 52, 24); + + dest[6] = 0xFF; // fake stream handle for the vertex/index buffer get code to use + } + + memcpy(surface, tempSurface, 84 * numSurfaces); + + delete[] tempSurface; + + // create vertex/index buffers + CreateCModelBuffers(header.main.buffer); + + // store the buffer bit + ModelSurfs::AllocMap[header.vertex.buffer] = allocationData; + + return header.main.buffer; + } + bool ModelSurfs::LoadSurfaces(Game::XModel* model) { if (!model) return false; @@ -121,6 +354,9 @@ namespace Components short surfCount = 0; + static_assert(offsetof(Game::XModel, lods) == 64, ""); + static_assert(offsetof(Game::XModelLodInfo, surfs) == 36, ""); + for (char i = 0; i < model->numLods; ++i) { Game::XModelSurfs* surfs = model->lods[i].surfaces; @@ -139,12 +375,46 @@ namespace Components model->lods[i].someCount = numSurfs; model->lods[i].someTotalCount = surfCount; surfCount += numSurfs; + + changed = true; } } return changed; } + bool Load_XModelAssetHookFunc(char* xmodel) + { + bool didStuff = false; + short totalv = 0; + + for (int i = 0; i < xmodel[241]; i++) + { + Game::XModelSurfs* surfs = *(Game::XModelSurfs**)(xmodel + 72 + (44 * i)); + + if (!surfs->surfaces) + { + char* newSurfs = LoadCModel(surfs->name); + + memcpy(xmodel + 76 + (44 * i), &newSurfs[12], 24); + memcpy(xmodel + 100 + (44 * i), &newSurfs[4], 4); + + short v = *(short*)(newSurfs + 8); + *(short*)(xmodel + 68 + (44 * i)) = v; + *(short*)(xmodel + 70 + (44 * i)) = totalv; + + totalv += v; + + surfs->numSurfaces = ((Game::XModelSurfs*)newSurfs)->numSurfaces; + surfs->surfaces = ((Game::XModelSurfs*)newSurfs)->surfaces; + + didStuff = true; + } + } + + return didStuff; + } + void ModelSurfs::ReleaseModelSurf(Game::XAssetHeader header) { for (int i = 0; i < header.surfaces->numSurfaces && header.surfaces->surfaces; ++i) @@ -200,7 +470,8 @@ namespace Components void ModelSurfs::XModelSurfsFixup(Game::XModel* model) { - if (!ModelSurfs::LoadSurfaces(model)) + //if (!ModelSurfs::LoadSurfaces(model)) + if(!Load_XModelAssetHookFunc((char*)model)) { Game::DB_XModelSurfsFixup(model); } diff --git a/src/Components/Modules/ModelSurfs.hpp b/src/Components/Modules/ModelSurfs.hpp index 4a68f7b1..bbf8b864 100644 --- a/src/Components/Modules/ModelSurfs.hpp +++ b/src/Components/Modules/ModelSurfs.hpp @@ -10,7 +10,7 @@ namespace Components const char* GetName() { return "ModelSurfs"; }; #endif - private: + //private: static std::map BufferMap; static std::map AllocMap; diff --git a/src/Components/Modules/Zones.cpp b/src/Components/Modules/Zones.cpp index f28ff362..0863558f 100644 --- a/src/Components/Modules/Zones.cpp +++ b/src/Components/Modules/Zones.cpp @@ -1036,7 +1036,7 @@ namespace Components *(BYTE*)0x463D65 = (iw5) ? 0x90 : 0x40; *(DWORD*)0x463D66 = (iw5) ? 0x9004E0C1 : 0xC003C003; // shl eax, 4 instead of add eax, eax * 2 - // addon_map_ents asset type (we reuse it for weaponattach) + // addon_map_ents asset type (we reuse it for weaponattach) *(BYTE*)0x418B30 = (iw5) ? 43 : Game::ASSET_TYPE_ADDON_MAP_ENTS; // hooks @@ -1103,7 +1103,7 @@ namespace Components loadTechniquePassHook.Uninstall(); loadStructuredDataChildArrayHook.Uninstall(); - //xmodelDefaultHook.Uninstall(); + xmodelDefaultHook.Uninstall(); fxDefaultHook.Uninstall(); } } @@ -1114,19 +1114,12 @@ namespace Components PatchMW2_FifthInfinityApply(version, version >= 316); } - bool IgnoreEntityHookFunc(const char* entity) - { - return (!strncmp(entity, "dyn_", 4) || !strncmp(entity, "node_", 5) || !strncmp(entity, "actor_", 6)/* || !strncmp(entity, "weapon_", 7)*/); - } - Zones::Zones() { // Ignore missing soundaliases for now // TODO: Include them in the dependency zone! Utils::Hook::Nop(0x644207, 5); - Utils::Hook(0x5FBD6E, IgnoreEntityHookFunc).Install()->Quick(); - fxEffectTailHook.Initialize(fxEffectTailHookLoc, FxEffectTailHookStub, HOOK_CALL); fxEffectModifyHook.Initialize(fxEffectModifyHookLoc, FxEffectModifyHookFunc, HOOK_CALL); xLodTailHook.Initialize(xLodTailHookLoc, XModelLODTailHookStub, HOOK_CALL);