diff --git a/deps/protobuf b/deps/protobuf index c44ca26f..4f379f81 160000 --- a/deps/protobuf +++ b/deps/protobuf @@ -1 +1 @@ -Subproject commit c44ca26fe89ed8a81d3ee475a2ccc1797141dbce +Subproject commit 4f379f81cef4dd8e005fd0bcc9199bf842fc35d4 diff --git a/deps/zlib b/deps/zlib index 70a8763b..9852c209 160000 --- a/deps/zlib +++ b/deps/zlib @@ -1 +1 @@ -Subproject commit 70a8763b7187f2536ce7fe4d399ce9a79c9faf7c +Subproject commit 9852c209ac49c0d8d1192e46115d7c37d4344bbd diff --git a/src/Components/Modules/AntiCheat.cpp b/src/Components/Modules/AntiCheat.cpp index ac994710..993f51f9 100644 --- a/src/Components/Modules/AntiCheat.cpp +++ b/src/Components/Modules/AntiCheat.cpp @@ -89,6 +89,7 @@ namespace Components void AntiCheat::CrashClient() { #ifdef DEBUG_DETECTIONS + Logger::Flush(); MessageBoxA(0, "Check the log for more information!", "AntiCheat triggered", MB_ICONERROR); ExitProcess(0xFFFFFFFF); #else @@ -217,8 +218,8 @@ namespace Components if (lastCheck) count = 0; else ++count; - // If there was no check within the last 120 seconds, crash! - if ((milliseconds > 1000 * 25) && ((lastCheck && (milliseconds - lastCheck) > 1000 * 40) || count > 1)) + // If there was no check within the last 40 seconds, crash! + if ((milliseconds > 1000 * 40) && ((lastCheck && (milliseconds - lastCheck) > 1000 * 40) || count > 1)) { #ifdef DEBUG_DETECTIONS Logger::Print("AntiCheat: Integrity check failed"); @@ -260,7 +261,7 @@ namespace Components void AntiCheat::Frame() { - // Perform check only every 30 seconds + // Perform check only every 10 seconds if (AntiCheat::LastCheck && (Game::Sys_Milliseconds() - AntiCheat::LastCheck) < 1000 * 10) return; AntiCheat::LastCheck = Game::Sys_Milliseconds(); diff --git a/src/Components/Modules/AssetHandler.cpp b/src/Components/Modules/AssetHandler.cpp index 95cf3e8e..51970eb2 100644 --- a/src/Components/Modules/AssetHandler.cpp +++ b/src/Components/Modules/AssetHandler.cpp @@ -50,16 +50,19 @@ namespace Components { Game::XAssetHeader header = { 0 }; - // Allow call DB_FindXAssetHeader within the hook - AssetHandler::BypassState = true; - - if (AssetHandler::TypeCallbacks.find(type) != AssetHandler::TypeCallbacks.end()) + if (filename) { - header = AssetHandler::TypeCallbacks[type](type, filename); - } + // Allow call DB_FindXAssetHeader within the hook + AssetHandler::BypassState = true; - // Disallow calling DB_FindXAssetHeader ;) - AssetHandler::BypassState = false; + if (AssetHandler::TypeCallbacks.find(type) != AssetHandler::TypeCallbacks.end()) + { + header = AssetHandler::TypeCallbacks[type](type, filename); + } + + // Disallow calling DB_FindXAssetHeader ;) + AssetHandler::BypassState = false; + } return header; } @@ -155,6 +158,11 @@ namespace Components AssetHandler::RestrictSignal.connect(callback); } + void AssetHandler::ClearRelocations() + { + AssetHandler::Relocations.clear(); + } + void AssetHandler::Relocate(void* start, void* to, DWORD size) { for (DWORD i = 0; i < size; i += 4) @@ -167,12 +175,14 @@ namespace Components void AssetHandler::OffsetToAlias(Utils::Stream::Offset* offset) { // Same here, reinterpret the value, as we're operating inside the game's environment - offset->pointer = *reinterpret_cast((*Game::g_streamBlocks)[offset->GetUnpackedBlock()].data + offset->GetUnpackedOffset()); + void* pointer = (*Game::g_streamBlocks)[offset->GetUnpackedBlock()].data + offset->GetUnpackedOffset(); - if (AssetHandler::Relocations.find(offset->pointer) != AssetHandler::Relocations.end()) + if (AssetHandler::Relocations.find(pointer) != AssetHandler::Relocations.end()) { - offset->pointer = AssetHandler::Relocations[offset->pointer]; + pointer = AssetHandler::Relocations[pointer]; } + + offset->pointer = *reinterpret_cast(pointer); } void AssetHandler::ZoneSave(Game::XAsset asset, ZoneBuilder::Zone* builder) @@ -285,6 +295,7 @@ namespace Components delete i->second; } + AssetHandler::Relocations.clear(); AssetHandler::AssetInterfaces.clear(); AssetHandler::RestrictSignal.clear(); AssetHandler::TypeCallbacks.clear(); diff --git a/src/Components/Modules/AssetHandler.hpp b/src/Components/Modules/AssetHandler.hpp index 9ff1c981..b04e0b7c 100644 --- a/src/Components/Modules/AssetHandler.hpp +++ b/src/Components/Modules/AssetHandler.hpp @@ -27,8 +27,13 @@ namespace Components static void OnFind(Game::XAssetType type, Callback* callback); static void OnLoad(RestrictCallback* callback); + static void ClearRelocations(); static void Relocate(void* start, void* to, DWORD size = 4); + static void Relocate(DWORD start, DWORD size, DWORD to) { + Relocate((void*)start, (void*)to, size); + } + static void ZoneSave(Game::XAsset asset, ZoneBuilder::Zone* builder); static void ZoneMark(Game::XAsset asset, ZoneBuilder::Zone* builder); diff --git a/src/Components/Modules/Download.cpp b/src/Components/Modules/Download.cpp index e4d14444..66de47ff 100644 --- a/src/Components/Modules/Download.cpp +++ b/src/Components/Modules/Download.cpp @@ -532,7 +532,7 @@ namespace Components "\r\n", mimeType.data(), buffer.size()); mg_send(nc, buffer.data(), static_cast(buffer.size())); - } + } else { mg_printf(nc, diff --git a/src/Components/Modules/FastFiles.cpp b/src/Components/Modules/FastFiles.cpp index 0a69c314..7853b68a 100644 --- a/src/Components/Modules/FastFiles.cpp +++ b/src/Components/Modules/FastFiles.cpp @@ -154,6 +154,12 @@ namespace Components } Zones::InstallPatches(*version); + + // TODO: Ugly hotpatch, beautify that! +// if (*version >= 316) +// { +// *version = XFILE_VERSION; +// } } FastFiles::FastFiles() diff --git a/src/Components/Modules/FileSystem.cpp b/src/Components/Modules/FileSystem.cpp index f11c3c3b..779a8b6a 100644 --- a/src/Components/Modules/FileSystem.cpp +++ b/src/Components/Modules/FileSystem.cpp @@ -2,30 +2,45 @@ namespace Components { - FileSystem::File::File(std::string file) : Name(file), Handle(0) + void FileSystem::File::Read() + { + char* buffer = nullptr; + int size = Game::FS_ReadFile(this->FilePath.data(), &buffer); + + this->Buffer.clear(); + + if (size >= 0) + { + this->Buffer.append(buffer, size); + Game::FS_FreeFile(buffer); + } + } + + + FileSystem::FileReader::FileReader(std::string file) : Name(file), Handle(0) { this->Size = Game::FS_FOpenFileRead(this->Name.data(), &this->Handle, 0); } - FileSystem::File::~File() + FileSystem::FileReader::~FileReader() { - if (this->Exists()) + if (this->Exists() && this->Handle) { Game::FS_FCloseFile(this->Handle); } } - bool FileSystem::File::Exists() + bool FileSystem::FileReader::Exists() { return (this->Size > 0); } - std::string FileSystem::File::GetName() + std::string FileSystem::FileReader::GetName() { return this->Name; } - std::string FileSystem::File::GetBuffer() + std::string FileSystem::FileReader::GetBuffer() { Utils::Memory::Allocator allocator; if (!this->Exists()) return std::string(); @@ -34,7 +49,7 @@ namespace Components this->Seek(0, FS_SEEK_SET); char* buffer = allocator.AllocateArray(this->Size); - if (!FileSystem::File::Read(buffer, this->Size)) + if (!this->Read(buffer, this->Size)) { this->Seek(position, FS_SEEK_SET); return std::string(); @@ -45,7 +60,7 @@ namespace Components return std::string(buffer, this->Size); } - bool FileSystem::File::Read(void* buffer, size_t size) + bool FileSystem::FileReader::Read(void* buffer, size_t size) { if (!this->Exists() || static_cast(this->Size) < size || Game::FS_Read(buffer, size, this->Handle) != static_cast(size)) { @@ -55,7 +70,7 @@ namespace Components return true; } - void FileSystem::File::Seek(int offset, int origin) + void FileSystem::FileReader::Seek(int offset, int origin) { if (this->Exists()) { diff --git a/src/Components/Modules/FileSystem.hpp b/src/Components/Modules/FileSystem.hpp index 554710db..37b43f44 100644 --- a/src/Components/Modules/FileSystem.hpp +++ b/src/Components/Modules/FileSystem.hpp @@ -4,12 +4,29 @@ namespace Components { public: - class File + class File + { + public: + File() {}; + File(std::string file) : FilePath(file) { this->Read(); }; + + bool Exists() { return !this->Buffer.empty(); }; + std::string GetName() { return this->FilePath; }; + std::string& GetBuffer() { return this->Buffer; }; + + private: + std::string FilePath; + std::string Buffer; + + void Read(); + }; + + class FileReader { public: - File() : Size(-1), Name(), Handle(0) {}; - File(std::string file); - ~File(); + FileReader() : Size(-1), Name(), Handle(0) {}; + FileReader(std::string file); + ~FileReader(); bool Exists(); std::string GetName(); diff --git a/src/Components/Modules/Logger.cpp b/src/Components/Modules/Logger.cpp index 98aa5e30..5e0c9730 100644 --- a/src/Components/Modules/Logger.cpp +++ b/src/Components/Modules/Logger.cpp @@ -83,6 +83,21 @@ namespace Components return buffer; } + void Logger::Flush() + { +// if (!Game::Sys_IsMainThread()) +// { +// while (!Logger::MessageQueue.empty()) +// { +// std::this_thread::sleep_for(10ms); +// } +// } +// else + { + Logger::Frame(); + } + } + void Logger::Frame() { std::lock_guard _(Logger::MessageMutex); @@ -300,5 +315,11 @@ namespace Components Logger::MessageMutex.lock(); Logger::MessageQueue.clear(); Logger::MessageMutex.unlock(); + + // Flush the console log + if (int fh = *reinterpret_cast(0x1AD8F28)) + { + Game::FS_FCloseFile(fh); + } } } diff --git a/src/Components/Modules/Logger.hpp b/src/Components/Modules/Logger.hpp index 47e9fca8..1628a619 100644 --- a/src/Components/Modules/Logger.hpp +++ b/src/Components/Modules/Logger.hpp @@ -23,6 +23,8 @@ namespace Components static void PipeOutput(void(*callback)(std::string)); + static void Flush(); + private: static std::mutex MessageMutex; static std::vector MessageQueue; diff --git a/src/Components/Modules/Maps.cpp b/src/Components/Modules/Maps.cpp index c0960b5c..a967aa3e 100644 --- a/src/Components/Modules/Maps.cpp +++ b/src/Components/Modules/Maps.cpp @@ -84,6 +84,24 @@ namespace Components return; } + if (type == Game::XAssetType::ASSET_TYPE_WEAPON) + { + if (!strstr(name.data(), "_mp") && name != "none" && name != "destructible_car") + { + *restrict = true; + return; + } + } + + if (type == Game::XAssetType::ASSET_TYPE_STRINGTABLE) + { + if (FastFiles::Current() == "mp_cross_fire") + { + *restrict = true; + return; + } + } + if (type == Game::XAssetType::ASSET_TYPE_MAP_ENTS) { static std::string mapEntities; @@ -106,7 +124,10 @@ namespace Components if (_strnicmp("mp_", mapname, 3)) { format = "maps/%s.d3dbsp"; + } + if (_strnicmp("mp_", mapname, 3) || mapname == "mp_nuked"s || mapname == "mp_bloc"s || mapname == "mp_cargoship"s || mapname == "mp_cross_fire"s) + { // Adjust pointer to GameMap_Data Utils::Hook::Set(0x4D90B7, &(Game::DB_XAssetPool[Game::XAssetType::ASSET_TYPE_GAME_MAP_SP].gameMapSP[0].data)); } @@ -137,6 +158,11 @@ namespace Components Maps::DependencyList[expression] = zone; } + int 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); @@ -196,6 +222,9 @@ namespace Components // Intercept map zone loading Utils::Hook(0x42C2AF, Maps::LoadMapZones, HOOK_CALL).Install()->Quick(); + // Ignore SP entities + Utils::Hook(0x444810, Maps::IgnoreEntityStub, HOOK_JUMP).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); @@ -218,6 +247,11 @@ namespace Components //Maps::AddDependency("gulag", "mp_subbase"); //Maps::AddDependency("invasion", "mp_rust"); Maps::AddDependency("co_hunted", "mp_storm"); + Maps::AddDependency("mp_nuked", "iw4x_dependencies_mp"); + Maps::AddDependency("mp_bloc", "iw4x_dependencies_mp"); + Maps::AddDependency("mp_bloc", "iw4x_dependencies_mp"); + Maps::AddDependency("mp_cargoship", "iw4x_dependencies_mp"); + Maps::AddDependency("mp_cross_fire", "iw4x_dependencies_mp"); Maps::AddDependency("^(?!mp_).*", "iw4x_dependencies_mp"); // All maps not starting with "mp_" } diff --git a/src/Components/Modules/Maps.hpp b/src/Components/Modules/Maps.hpp index d6b04dcc..730e60b5 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 int IgnoreEntityStub(const char* entity); + void ReallocateEntryPool(); }; } diff --git a/src/Components/Modules/Menus.cpp b/src/Components/Modules/Menus.cpp index 21a6efe5..9625b7d0 100644 --- a/src/Components/Modules/Menus.cpp +++ b/src/Components/Modules/Menus.cpp @@ -45,7 +45,7 @@ namespace Components Game::Script_SetupTokens(script, reinterpret_cast(0x797F80)); script->punctuations = reinterpret_cast(0x797F80); - memcpy(script->buffer, buffer.data(), script->length + 1); + std::memcpy(script->buffer, buffer.data(), script->length + 1); script->length = Game::Script_CleanString(script->buffer); diff --git a/src/Components/Modules/ModelSurfs.cpp b/src/Components/Modules/ModelSurfs.cpp index 7d18fca1..9fac8e6f 100644 --- a/src/Components/Modules/ModelSurfs.cpp +++ b/src/Components/Modules/ModelSurfs.cpp @@ -3,7 +3,7 @@ namespace Components { std::map ModelSurfs::BufferMap; - std::map ModelSurfs::AllocMap; + std::map ModelSurfs::AllocMap; IUnknown* ModelSurfs::GetBuffer(void* buffer) { @@ -38,7 +38,7 @@ namespace Components Game::XModelSurfs* ModelSurfs::LoadXModelSurfaces(std::string name) { Utils::Memory::Allocator allocator; - FileSystem::File model(fmt::sprintf("models/%s", name.data())); + FileSystem::FileReader model(fmt::sprintf("models/%s", name.data())); if (!model.Exists()) { @@ -79,7 +79,7 @@ namespace Components Game::CModelSectionHeader* section = &header.sectionHeader[i]; for (int j = section->fixupStart; j < section->fixupStart + section->fixupCount; ++j) { - unsigned int fixup = fixups[i]; + unsigned int fixup = fixups[j]; *reinterpret_cast(reinterpret_cast(section->buffer) + (fixup >> 3)) += reinterpret_cast(header.sectionHeader[fixup & 3].buffer); } } @@ -90,24 +90,26 @@ namespace Components allocationData->indexBuffer = header.sectionHeader[Game::SECTION_INDEX].buffer; allocationData->vertexBuffer = header.sectionHeader[Game::SECTION_VERTEX].buffer; - ModelSurfs::AllocMap[allocationData->vertexBuffer] = allocationData; - *reinterpret_cast(reinterpret_cast(allocationData->mainArray) + 44) = allocationData; - Assert_Size(Game::XSurface, 64); Game::XModelSurfs* modelSurfs = reinterpret_cast(allocationData->mainArray); Game::XSurface* tempSurfaces = allocator.AllocateArray(modelSurfs->numSurfaces); char* surfaceData = reinterpret_cast(modelSurfs->surfaces); + ModelSurfs::AllocMap[modelSurfs->name] = allocationData; + *reinterpret_cast(reinterpret_cast(allocationData->mainArray) + 44) = allocationData; + for (int i = 0; i < modelSurfs->numSurfaces; ++i) { - memcpy(&tempSurfaces[i], surfaceData + (i * 84), 12); - memcpy(&tempSurfaces[i].indexBuffer, surfaceData + (i * 84) + 16, 20); - memcpy(&tempSurfaces[i].numCT, surfaceData + (i * 84) + 40, 8); - memcpy(&tempSurfaces[i].pad5, surfaceData + (i * 84) + 52, 24); + char* source = &surfaceData[i * 84]; + + std::memcpy(&tempSurfaces[i], source, 12); + std::memcpy(&tempSurfaces[i].indexBuffer, source + 16, 20); + std::memcpy(&tempSurfaces[i].numCT, source + 40, 8); + std::memcpy(&tempSurfaces[i].something, source + 52, 24); tempSurfaces[i].streamHandle = 0xFF; // Fake handle for buffer interception } - memcpy(surfaceData, tempSurfaces, 64 * modelSurfs->numSurfaces); + std::memcpy(surfaceData, tempSurfaces, 64 * modelSurfs->numSurfaces); ModelSurfs::CreateBuffers(modelSurfs); @@ -117,8 +119,8 @@ namespace Components bool ModelSurfs::LoadSurfaces(Game::XModel* model) { if (!model) return false; - bool changed = false; + bool changed = false; short surfCount = 0; for (char i = 0; i < model->numLods; ++i) @@ -129,16 +131,18 @@ namespace Components { Game::XModelSurfs* newSurfs = ModelSurfs::LoadXModelSurfaces(surfs->name); - surfs->surfaces = newSurfs->surfaces; - surfs->numSurfaces = newSurfs->numSurfaces; + surfs->surfaces = newSurfs->surfaces; + surfs->numSurfaces = newSurfs->numSurfaces; - model->lods[i].surfaces = newSurfs; - memcpy(model->lods[i].pad3, newSurfs->pad, 24); + model->lods[i].surfs = newSurfs->surfaces; + std::memcpy(model->lods[i].pad3, newSurfs->pad, 24); short numSurfs = static_cast(newSurfs->numSurfaces); - model->lods[i].someCount = numSurfs; - model->lods[i].someTotalCount = surfCount; + model->lods[i].numSurfs = numSurfs; + model->lods[i].maxSurfs = surfCount; surfCount += numSurfs; + + changed = true; } } @@ -147,11 +151,15 @@ namespace Components void ModelSurfs::ReleaseModelSurf(Game::XAssetHeader header) { + bool hasCustomSurface = false; for (int i = 0; i < header.surfaces->numSurfaces && header.surfaces->surfaces; ++i) { Game::XSurface* surface = &header.surfaces->surfaces[i]; + if (surface->streamHandle == 0xFF) { + hasCustomSurface = true; + auto buffer = ModelSurfs::BufferMap.find(surface->indexBuffer); if (buffer != ModelSurfs::BufferMap.end()) { @@ -165,17 +173,20 @@ namespace Components buffer->second->Release(); ModelSurfs::BufferMap.erase(buffer); } + } + } - auto allocData = ModelSurfs::AllocMap.find(surface->vertexBuffer); - if (allocData != ModelSurfs::AllocMap.end()) - { - Utils::Memory::Free(allocData->second->indexBuffer); - Utils::Memory::Free(allocData->second->vertexBuffer); - Utils::Memory::Free(allocData->second->mainArray); - Utils::Memory::Free(allocData->second); + if (hasCustomSurface) + { + auto allocData = ModelSurfs::AllocMap.find(header.surfaces->name); + if (allocData != ModelSurfs::AllocMap.end()) + { + Utils::Memory::FreeAlign(allocData->second->indexBuffer); + Utils::Memory::FreeAlign(allocData->second->vertexBuffer); + Utils::Memory::Free(allocData->second->mainArray); + Utils::Memory::Free(allocData->second); - ModelSurfs::AllocMap.erase(allocData); - } + ModelSurfs::AllocMap.erase(allocData); } } } @@ -295,7 +306,7 @@ namespace Components // Install hooks Utils::Hook(0x47A6BD, ModelSurfs::XModelSurfsFixup, HOOK_CALL).Install()->Quick(); Utils::Hook(0x558F12, ModelSurfs::GetIndexBaseStub, HOOK_CALL).Install()->Quick(); - Utils::Hook(0x5BC050, ModelSurfs::GetIndexBufferStub, HOOK_JUMP).Install()->Quick(); + Utils::Hook(0x4B4DE0, ModelSurfs::GetIndexBufferStub, HOOK_JUMP).Install()->Quick(); Utils::Hook(0x558E70, ModelSurfs::GetIndexBufferStub2, HOOK_CALL).Install()->Quick(); Utils::Hook(0x5BC050, ModelSurfs::GetVertexBufferStub, HOOK_JUMP).Install()->Quick(); } diff --git a/src/Components/Modules/ModelSurfs.hpp b/src/Components/Modules/ModelSurfs.hpp index 4a68f7b1..2f69f59d 100644 --- a/src/Components/Modules/ModelSurfs.hpp +++ b/src/Components/Modules/ModelSurfs.hpp @@ -10,9 +10,9 @@ namespace Components const char* GetName() { return "ModelSurfs"; }; #endif - private: + //private: static std::map BufferMap; - static std::map AllocMap; + static std::map AllocMap; static void ReleaseModelSurf(Game::XAssetHeader header); diff --git a/src/Components/Modules/QuickPatch.cpp b/src/Components/Modules/QuickPatch.cpp index 8b84f6d1..a11b28a4 100644 --- a/src/Components/Modules/QuickPatch.cpp +++ b/src/Components/Modules/QuickPatch.cpp @@ -88,7 +88,7 @@ namespace Components size = Game::MSG_ReadBitsCompress(from, buffer, size); if (size > 0x800) return 0; - memcpy(to, buffer, size); + std::memcpy(to, buffer, size); return size; } @@ -101,7 +101,7 @@ namespace Components size = Game::MSG_ReadBitsCompress(from, buffer, size); if (size > 0x20000) return 0; - memcpy(to, buffer, size); + std::memcpy(to, buffer, size); return size; } diff --git a/src/Components/Modules/Zones.cpp b/src/Components/Modules/Zones.cpp index fa72f063..5fd8174e 100644 --- a/src/Components/Modules/Zones.cpp +++ b/src/Components/Modules/Zones.cpp @@ -2,16 +2,813 @@ namespace Components { - int Zones::ZoneVersion; + int Zones::ZoneVersion; + + Utils::Hook Zones::LoadFxElemDefHook; + Utils::Hook Zones::LoadFxElemDefArrayHook; + Utils::Hook Zones::LoadXModelLodInfoHook; + Utils::Hook Zones::LoadXModelHook; + Utils::Hook Zones::LoadXSurfaceArrayHook; + Utils::Hook Zones::LoadGameWorldSpHook; + Utils::Hook Zones::LoadPathDataHook; + Utils::Hook Zones::LoadVehicleDefHook; + Utils::Hook Zones::Loadsnd_alias_tArrayHook; + Utils::Hook Zones::LoadLoadedSoundHook; + + Utils::Hook fxEffectLoadHook; + + static char* fxEffectStringValue[64]; + static int fxEffectIndex = 0; + + void FxEffectLoadHookFunc(int a1, char* buffer, int len) + { + len /= 252; + + int count = len; + len *= 260; + + __asm + { + push len + push buffer + push a1 + call fxEffectLoadHook.Original + add esp, 0Ch + } + + fxEffectIndex = 0; + char* tempVar = new char[len]; + + for (int i = 0; i < count; i++) + { + AssetHandler::Relocate((DWORD)buffer + (260 * i), 252, (DWORD)buffer + (252 * i)); + + std::memcpy(tempVar + (252 * i), buffer + (260 * i), 252); + + fxEffectStringValue[i] = *(char**)(buffer + (260 * i) + 256); + } + + std::memcpy(buffer, tempVar, len); + + delete[] tempVar; + } + + bool Zones::LoadFxElemDefStub(bool atStreamStart, Game::FxElemDef* fxElem, int size) + { + if (fxElem->elemType == 3) + { + fxElem->elemType = 2; + } + else if (fxElem->elemType >= 5) + { + fxElem->elemType -= 2; + } + + return Game::Load_Stream(atStreamStart, fxElem, size); + } + + void Zones::LoadFxElemDefArrayStub(bool atStreamStart) + { + Game::Load_FxElemDef(atStreamStart); + *Game::varXString = &fxEffectStringValue[fxEffectIndex++]; + Game::Load_XString(0); + } + + bool Zones::LoadXModel(bool atStreamStart, char* xmodel, int size) + { + bool result = Game::Load_Stream(atStreamStart, xmodel, size); + + int elSize = (Zones::ZoneVersion == VERSION_ALPHA2) ? 364 : 360; + + Game::XModel model[2]; // Allocate 2 models, as we exceed the buffer + + std::memcpy(model, xmodel, 36); + std::memcpy(&model->pad3[0x1C], &xmodel[44], 28); + + for (int i = 0; i < 4; i++) + { + std::memcpy(&model->lods[i], &xmodel[72 + (i * 56)], 12); + std::memcpy(&model->lods[i].pad3, &xmodel[72 + (i * 56) + 16], 32); + + std::memcpy(reinterpret_cast(&model) + (elSize - 4) - (i * 4), &xmodel[72 + (i * 56) + 12], 4); + } + + std::memcpy(&model->lods[3].pad4[0], &xmodel[292], (elSize - 292 - 4)/*68*/); + std::memcpy(&model->physPreset, &xmodel[(elSize - 8)], 8); + + model[1].name = reinterpret_cast(0xDEC0ADDE); + + std::memcpy(xmodel, &model, elSize); + + return result; + } + + void Zones::LoadXModelLodInfo(int i) + { + int elSize = (Zones::ZoneVersion == VERSION_ALPHA2) ? 364 : 360; + *Game::varXString = reinterpret_cast(reinterpret_cast(*Game::varXModel) + (elSize - 4) - (4 * (4 - i))); + Game::Load_XString(false); + } + + void __declspec(naked) Zones::LoadXModelLodInfoStub() + { + __asm + { + push edi + call Zones::LoadXModelLodInfo + pop edi + + jmp Game::Load_XModelSurfsFixup + } + } + + bool Zones::LoadXSurfaceArray(bool atStreamStart, char* buffer, int size) + { + size >>= 6; + + int count = size; + size *= 84; + + bool result = Game::Load_Stream(atStreamStart, buffer, size); + + Utils::Memory::Allocator allocator; + Game::XSurface* tempSurfaces = allocator.AllocateArray(count); + + for (int i = 0; i < count; ++i) + { + char* source = &buffer[i * 84]; + + std::memcpy(&tempSurfaces[i], source, 12); + std::memcpy(&tempSurfaces[i].indexBuffer, source + 16, 20); + std::memcpy(&tempSurfaces[i].numCT, source + 40, 8); + std::memcpy(&tempSurfaces[i].something, source + 52, 24); + } + + std::memcpy(buffer, tempSurfaces, sizeof(Game::XSurface) * count); + + return result; + } + + Utils::Hook loadWeaponDefHook; + + void Load_WeaponDef_CodC(int /*doLoad*/) + { + // setup structures we use + DWORD varWeaponDef = *(DWORD*)0x112A9F4;//*(DWORD*)0x112AE14; + + // and do the stuff + Game::Load_Stream(1, (void*)varWeaponDef, (Zones::ZoneVersion >= 318) ? 3156 : 3112); + + Game::DB_PushStreamPos(3); + + *Game::varXString = (char**)(varWeaponDef + 0); + Game::Load_XString(false); + + *Game::varXString = (char**)(varWeaponDef + 4); + Game::Load_XString(false); + + *Game::varXString = (char**)(varWeaponDef + 8); + Game::Load_XString(false); + + *Game::varXString = (char**)(varWeaponDef + 12); + Game::Load_XString(false); + + *Game::varXModelPtr = (Game::XModel*)(varWeaponDef + 16); + Game::Load_XModelPtr(false); + + for (int i = 0, offset = 20; i < 32; i++, offset += 4) + { + *Game::varXModelPtr = (Game::XModel*)(varWeaponDef + offset); + Game::Load_XModelPtr(false); + } + + // 148 + for (int offset = 148; offset <= 168; offset += 4) + { + *Game::varXModelPtr = (Game::XModel*)(varWeaponDef + offset); + Game::Load_XModelPtr(false); + } + + // 172 + // 32 scriptstrings, should not need to be loaded + + // 236 + *Game::varXString = (char**)(varWeaponDef + 236); + Game::Load_XStringArray(false, 48); + + // 428 + *Game::varXString = (char**)(varWeaponDef + 428); + Game::Load_XStringArray(false, 48); + + // 620 + *Game::varXString = (char**)(varWeaponDef + 620); + Game::Load_XStringArray(false, 48); + + // 812 + // 16 * 4 scriptstrings + + // 972 + *Game::varFxEffectDefHandle = (Game::FxEffectDef*)(varWeaponDef + 972);; + Game::Load_FxEffectDefHandle(false); + + *Game::varFxEffectDefHandle = (Game::FxEffectDef*)(varWeaponDef + 976); + Game::Load_FxEffectDefHandle(false); + + // 980 + // 50 soundalias name references; up to and including 1180 + for (int i = 0, offset = 980; i < 50; i++, offset += 4) + { + *Game::varsnd_alias_list_name = (Game::snd_alias_list_t**)(varWeaponDef + offset); + Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); + } + + if (Zones::ZoneVersion >= 318) + { + for (int i = 0, offset = 1184; i < 2; i++, offset += 4) + { + *Game::varsnd_alias_list_name = (Game::snd_alias_list_t**)(varWeaponDef + offset); + Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); + } + + varWeaponDef += 8; // to compensate for the 2 in between here + } + + if (*(DWORD*)(varWeaponDef + 1184)) + { + if (*(DWORD*)(varWeaponDef + 1184) == -1) + { + *(DWORD*)(varWeaponDef + 1184) = (DWORD)Game::DB_AllocStreamPos(3); + *Game::varsnd_alias_list_name = *(Game::snd_alias_list_t***)(varWeaponDef + 1184); + + Game::Load_snd_alias_list_nameArray(true, 31); + } + else + { + // full usability requires ConvertOffsetToPointer here + } + } + + if (*(DWORD*)(varWeaponDef + 1188)) + { + if (*(DWORD*)(varWeaponDef + 1188) == -1) + { + *(DWORD*)(varWeaponDef + 1188) = (DWORD)Game::DB_AllocStreamPos(3); + *Game::varsnd_alias_list_name = *(Game::snd_alias_list_t***)(varWeaponDef + 1188); + + Game::Load_snd_alias_list_nameArray(true, 31); + } + else + { + // full usability requires ConvertOffsetToPointer here + } + } + + // 1192 + for (int offset = 1192; offset <= 1204; offset += 4) + { + *Game::varFxEffectDefHandle = (Game::FxEffectDef*)(varWeaponDef + offset); + Game::Load_FxEffectDefHandle(false); + } + + // 1208 + static int matOffsets1[] = { 1208, 1212, 1428, 1432, 1436, 1440, 1444, 1448, 1456, 1464 }; + + for (int i = 0; i < sizeof(matOffsets1) / sizeof(int); i++) + { + *Game::varMaterialHandle = (Game::Material*)(varWeaponDef + matOffsets1[i]); + Game::Load_MaterialHandle(false); + } + + *Game::varXString = (char**)(varWeaponDef + 1484); + Game::Load_XString(false); + + *Game::varXString = (char**)(varWeaponDef + 1492); + Game::Load_XString(false); + + *Game::varXString = (char**)(varWeaponDef + 1508); + Game::Load_XString(false); + + for (int offset = 1764; offset <= 1776; offset += 4) + { + *Game::varMaterialHandle = (Game::Material*)(varWeaponDef + offset); + Game::Load_MaterialHandle(false); + } + + *Game::varPhysCollmapPtr = (Game::PhysCollmap*)(varWeaponDef + 1964); + Game::Load_PhysCollmapPtr(0); + + *Game::varXModelPtr = (Game::XModel*)(varWeaponDef + 2052); + Game::Load_XModelPtr(0); + + *Game::varFxEffectDefHandle = (Game::FxEffectDef*)(varWeaponDef + 2060); + Game::Load_FxEffectDefHandle(false); + + *Game::varFxEffectDefHandle = (Game::FxEffectDef*)(varWeaponDef + 2064); + Game::Load_FxEffectDefHandle(false); + + *Game::varsnd_alias_list_name = (Game::snd_alias_list_t**)(varWeaponDef + 2068); + Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); + + *Game::varsnd_alias_list_name = (Game::snd_alias_list_t**)(varWeaponDef + 2072); + Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); + + *Game::varFxEffectDefHandle = (Game::FxEffectDef*)(varWeaponDef + 2336); + Game::Load_FxEffectDefHandle(false); + + *Game::varFxEffectDefHandle = (Game::FxEffectDef*)(varWeaponDef + 2340); + Game::Load_FxEffectDefHandle(false); + + *Game::varFxEffectDefHandle = (Game::FxEffectDef*)(varWeaponDef + 2368); // 2376 + Game::Load_FxEffectDefHandle(false); + + *Game::varsnd_alias_list_name = (Game::snd_alias_list_t**)(varWeaponDef + 2372); // 2380 + Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); + + *Game::varXString = (char**)(varWeaponDef + 2548); // 2556 + Game::Load_XString(false); + + if (*(DWORD*)(varWeaponDef + 2556) == -1) // 2564 + { + DWORD vec2 = (DWORD)Game::DB_AllocStreamPos(3); + *(DWORD*)(varWeaponDef + 2556) = vec2; + + Game::Load_Stream(1, (void*)vec2, 8 * *(short*)(varWeaponDef + ((Zones::ZoneVersion >= 318) ? 3076 : 3040))); + } + + *Game::varXString = (char**)(varWeaponDef + 2552); + Game::Load_XString(false); + + if (*(DWORD*)(varWeaponDef + 2560) == -1) + { + DWORD vec2 = (DWORD)Game::DB_AllocStreamPos(3); + *(DWORD*)(varWeaponDef + 2560) = vec2; + + Game::Load_Stream(1, (void*)vec2, 8 * *(short*)(varWeaponDef + ((Zones::ZoneVersion >= 318) ? 3078 : 3042))); + } + + *Game::varXString = (char**)(varWeaponDef + 2640); + Game::Load_XString(false); + + *Game::varXString = (char**)(varWeaponDef + 2644); + Game::Load_XString(false); + + *Game::varXString = (char**)(varWeaponDef + 2676); + Game::Load_XString(false); + + *Game::varXString = (char**)(varWeaponDef + 2680); + Game::Load_XString(false); + + *Game::varXString = (char**)(varWeaponDef + 2804); + Game::Load_XString(false); + + *Game::varXString = (char**)(varWeaponDef + 2808); + Game::Load_XString(false); + + *Game::varTracerDefPtr = (Game::TracerDef*)(varWeaponDef + 2812); + Game::Load_TracerDefPtr(false); + + *Game::varsnd_alias_list_name = (Game::snd_alias_list_t**)(varWeaponDef + 2840); + Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); // 2848 + + *Game::varFxEffectDefHandle = (Game::FxEffectDef*)(varWeaponDef + 2844); + Game::Load_FxEffectDefHandle(false); + + *Game::varXString = (char**)(varWeaponDef + 2848); + Game::Load_XString(false); + + *Game::varsnd_alias_list_name = (Game::snd_alias_list_t**)(varWeaponDef + 2864); + Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); + + *Game::varsnd_alias_list_name = (Game::snd_alias_list_t**)(varWeaponDef + 2868); + Game::Load_snd_alias_list_nameArray(false, 4); + + *Game::varsnd_alias_list_name = (Game::snd_alias_list_t**)(varWeaponDef + 2884); + Game::Load_snd_alias_list_nameArray(false, 4); + + *Game::varsnd_alias_list_name = (Game::snd_alias_list_t**)(varWeaponDef + 2900); + Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); + + *Game::varsnd_alias_list_name = (Game::snd_alias_list_t**)(varWeaponDef + 2904); // 2912 + Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); + + if (Zones::ZoneVersion >= 318) + { + for (int i = 0, offset = 2972; i < 6; i++, offset += 4) + { + *Game::varsnd_alias_list_name = (Game::snd_alias_list_t**)(varWeaponDef + offset); + Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); + } + + varWeaponDef += (6 * 4); + varWeaponDef += 12; + } + else + { + + } + + *Game::varXString = (char**)(varWeaponDef + 2984); + Game::Load_XString(false); + + *Game::varXString = (char**)(varWeaponDef + 2996); + Game::Load_XString(false); + + *Game::varXString = (char**)(varWeaponDef + 3000); + Game::Load_XString(false); + + *Game::varMaterialHandle = (Game::Material*)(varWeaponDef + 3008); + Game::Load_MaterialHandle(false); + + *Game::varMaterialHandle = (Game::Material*)(varWeaponDef + 3012); + Game::Load_MaterialHandle(false); + + *Game::varMaterialHandle = (Game::Material*)(varWeaponDef + 3016); + Game::Load_MaterialHandle(false); + + if (*(DWORD*)(varWeaponDef + 3044) == -1) + { + DWORD vec2 = (DWORD)Game::DB_AllocStreamPos(3); + *(DWORD*)(varWeaponDef + 3044) = vec2; + + Game::Load_Stream(1, (void*)vec2, 8 * *(short*)(varWeaponDef + 3040)); + } + + if (*(DWORD*)(varWeaponDef + 3048) == -1) + { + DWORD vec2 = (DWORD)Game::DB_AllocStreamPos(3); + *(DWORD*)(varWeaponDef + 3048) = vec2; + + Game::Load_Stream(1, (void*)vec2, 8 * *(short*)(varWeaponDef + 3042)); + } + + Game::DB_PopStreamPos(); + } + + bool Zones::LoadGameWorldSp(bool atStreamStart, char* buffer) + { + bool result = Game::Load_Stream(atStreamStart, buffer, 84); + + Game::GameWorldSp world[2]; + std::memcpy(&world, buffer, 44); + std::memcpy(&world[1], &buffer[44], 28); + std::memcpy(&world->vehicleTrack, &buffer[72], 12); + + std::memcpy(buffer, world, 84); + + return result; + } + + Utils::Hook pathDataTailHook; + + void PathDataTailHookFunc() + { + DWORD varStuff = *(DWORD*)0x112AD7C; + DWORD varThing; + + if (*(DWORD*)(varStuff + 56)) + { + *(DWORD*)(varStuff + 56) = (DWORD)Game::DB_AllocStreamPos(0); + varThing = *(DWORD*)(varStuff + 56); + Game::Load_Stream(1, (void*)varThing, *(DWORD*)(varStuff + 52)); + } + + if (*(DWORD*)(varStuff + 64)) + { + *(DWORD*)(varStuff + 64) = (DWORD)Game::DB_AllocStreamPos(0); + varThing = *(DWORD*)(varStuff + 64); + Game::Load_Stream(1, (void*)varThing, *(DWORD*)(varStuff + 60)); + } + + if (*(DWORD*)(varStuff + 76)) + { + *(DWORD*)(varStuff + 76) = (DWORD)Game::DB_AllocStreamPos(0); + varThing = *(DWORD*)(varStuff + 76); + Game::Load_Stream(1, (void*)varThing, *(DWORD*)(varStuff + 72)); + } + } + + bool Zones::Loadsnd_alias_tArray(bool atStreamStart, char* buffer, int len) + { + len /= 100; + int count = len; + len *= 108; + + bool result = Game::Load_Stream(atStreamStart, buffer, len); + + Utils::Memory::Allocator allocator; + Game::snd_alias_t* tempSounds = allocator.AllocateArray(count); + + for (int i = 0; i < count; i++) + { + char* src = &buffer[i * 108]; + + std::memcpy(&tempSounds[i], src + 0, 60); + std::memcpy(&tempSounds[i].pad2[36], src + 68, 20); + std::memcpy(&tempSounds[i].pad2[56], src + 88, 20); + + AssetHandler::Relocate(src + 0, buffer + (i * 100) + 0, 60); + AssetHandler::Relocate(src + 68, buffer + (i * 100) + 60, 20); + AssetHandler::Relocate(src + 88, buffer + (i * 100) + 80, 20); + } + + std::memcpy(buffer, tempSounds, sizeof(Game::snd_alias_t) * count); + + return result; + } + + bool Zones::LoadLoadedSound(bool atStreamStart, char* buffer) + { + bool result = Game::Load_Stream(atStreamStart, buffer, 48); + + std::memmove(buffer + 28, buffer + 32, 16); + AssetHandler::Relocate(buffer + 32, buffer + 28, 16); + + return result; + } + + bool Zones::LoadVehicleDef(bool atStreamStart, char* buffer) + { + bool result = Game::Load_Stream(atStreamStart, buffer, 788); + + Game::VehicleDef vehicle[2]; + std::memcpy(vehicle, &buffer[0], 400); + std::memcpy(&vehicle->pad[404], &buffer[400], 388); + + AssetHandler::Relocate(buffer + 400, buffer + 408, 388); + + std::memcpy(buffer, vehicle, 788); + + return result; + } + + Utils::Hook loadWeaponAttachHook; + + DWORD varWeaponAttachStuff; + + void Load_WeaponAttachStuff(int count) + { + Game::Load_Stream(1, (void*)varWeaponAttachStuff, 12 * count); + + DWORD* varStuff = (DWORD*)varWeaponAttachStuff; + + for (int i = 0; i < count; i++) + { + //DWORD* varXString = (DWORD*)0x112B340; + + if (varStuff[1] < 16 || varStuff[1] == 39) + { + if (varStuff[2] == -1) + { + varStuff[2] = (DWORD)Game::DB_AllocStreamPos(0); + *Game::varConstChar = (const char*)varStuff[2]; + Game::Load_XStringCustom(Game::varConstChar); + + //if (*useEntryNames) + { + //DBG(("wA: %s\n", *varXStringData)); + } + } + else if (varStuff[2]) + { + // meh, no convertin' here + } + } + + varStuff += 3; + } + } + + Utils::Hook menuDefLoadHook; + + void MenuDefLoadHookFunc(int doLoad, char* buffer, int len) + { + len += 4; + + __asm + { + push len + push buffer + push doLoad + call menuDefLoadHook.Original + add esp, 0Ch + } + + std::memcpy(buffer + 168, buffer + 172, 232); + + AssetHandler::Relocate((DWORD)buffer + 172, 232, (DWORD)buffer + 168); + } + + void Load_WeaponAttach(int /*doLoad*/) + { + // setup structures we use + DWORD varWeaponAttach = *(DWORD*)0x112ADE0;//*(DWORD*)0x112AE14; + DWORD* varXString = (DWORD*)0x112B340; + + // and do the stuff + Game::Load_Stream(1, (void*)varWeaponAttach, 12); + + Game::DB_PushStreamPos(3); + + *varXString = varWeaponAttach + 0; + Game::Load_XString(false); + + *(void**)(varWeaponAttach + 8) = Game::DB_AllocStreamPos(3); + + varWeaponAttachStuff = *(DWORD*)(varWeaponAttach + 8); + Load_WeaponAttachStuff(*(int*)(varWeaponAttach + 4)); + + Game::DB_PopStreamPos(); + } + + Utils::Hook loadTechniquePassHook; + + void Load_TechniquePassHookFunc(bool atStreamStart, Game::ShaderArgumentDef* pass, size_t size) + { + int count = size / 8; + + Game::MaterialPass* curPass = *(Game::MaterialPass**)0x112A960; + count = curPass->argCount1 + curPass->argCount2 + curPass->argCount3; + + Game::Load_Stream(atStreamStart, pass, size); + + for (int i = 0; i < count; i++) + { + Game::ShaderArgumentDef* arg = &pass[i]; + + if (arg->type != 3 && arg->type != 5) + { + continue; + } + + // should be min 68 currently + // >= 58 fixes foliage without bad side effects + // >= 53 still has broken shadow mapping + // >= 23 is still broken somehow + if (arg->paramID >= 58 && arg->paramID <= 135) // >= 34 would be 31 in iw4 terms + { + arg->paramID -= 3; + } + // >= 21 works fine for specular, but breaks trees + // >= 4 is too low, breaks specular + else if (arg->paramID >= 11 && arg->paramID < 58) + { + arg->paramID -= 2; + } + } + } + + Utils::Hook loadStructuredDataChildArrayHook; + + void Load_StructuredDataChildArrayHookFunc(bool atStreamStart, char* data, size_t size) + { + int count = size / 16; + size = count * 24; + + Game::Load_Stream(atStreamStart, data, size); + + for (int i = 0; i < count; i++) + { + std::memcpy(data + (i * 16), data + (i * 24), 16); + AssetHandler::Relocate((DWORD)data + (i * 24), 16, (DWORD)data + (i * 16)); + } + } void Zones::InstallPatches(int version) { + AssetHandler::ClearRelocations(); + + if (Zones::ZoneVersion == version) return; Zones::ZoneVersion = version; + + bool patch = (version >= VERSION_ALPHA2); + if (Zones::ZoneVersion == VERSION_ALPHA2 || Zones::ZoneVersion == VERSION_ALPHA3 || Zones::ZoneVersion == XFILE_VERSION) + { + Utils::Hook::Set(0x4158F4, version); + Utils::Hook::Set(0x4158FB, version); + } + + // physpreset size + Utils::Hook::Set(0x49CE0A, (patch) ? 68 : 44); + + // XModel size + Utils::Hook::Set(0x410D8A, (patch) ? ((Zones::ZoneVersion == VERSION_ALPHA2) ? 0x16C : 0x168) : 0x130); + + // XSurface size + Utils::Hook::Set(0x48E84A, (patch) ? 48 : 36); + + // impactfx internal size/count + Utils::Hook::Set(0x4447B6, (patch) ? 0x8C0 : 0x834); + Utils::Hook::Set(0x4447D1, (patch) ? 16 : 15); + + // GameWorldSp asset type + Utils::Hook::Set(0x41899A, (patch) ? 18 : 17); + + // PathData internal struct size + Utils::Hook::Set(0x4D6A04, (patch) ? 148 : 136); + Utils::Hook::Set(0x4D6A49, (patch) ? 148 : 136); + + // PathData internal struct data size + Utils::Hook::Set(0x463D63, (patch) ? 0x9090 : 0x048D); + Utils::Hook::Set(0x463D65, (patch) ? 0x90 : 0x40); + Utils::Hook::Set(0x463D66, (patch) ? 0x9004E0C1 : 0xC003C003); // shl eax, 4 instead of add eax, eax * 2 + + // addon_map_ents asset type (we reuse it for weaponattach) + Utils::Hook::Set(0x418B30, (patch) ? 43 : Game::ASSET_TYPE_ADDON_MAP_ENTS); + + if (patch) + { + Zones::LoadFxElemDefArrayHook.Install(); + Zones::LoadFxElemDefHook.Install(); + + Zones::LoadXModelLodInfoHook.Install(); + Zones::LoadXModelHook.Install(); + + Zones::LoadXSurfaceArrayHook.Install(); + Zones::LoadGameWorldSpHook.Install(); + pathDataTailHook.Install(); + + loadWeaponDefHook.Install(); + Zones::LoadVehicleDefHook.Install(); + + Zones::Loadsnd_alias_tArrayHook.Install(); + Zones::LoadLoadedSoundHook.Install(); + menuDefLoadHook.Install(); + fxEffectLoadHook.Install(); + + loadWeaponAttachHook.Install(); + + if (Zones::ZoneVersion >= VERSION_ALPHA3) + { + Zones::LoadPathDataHook.Install(); + } + + loadTechniquePassHook.Install(); + loadStructuredDataChildArrayHook.Install(); + } + else + { + Zones::LoadFxElemDefArrayHook.Uninstall(); + Zones::LoadFxElemDefHook.Uninstall(); + + Zones::LoadXModelLodInfoHook.Uninstall(); + Zones::LoadXModelHook.Uninstall(); + + Zones::LoadXSurfaceArrayHook.Uninstall(); + Zones::LoadGameWorldSpHook.Uninstall(); + pathDataTailHook.Uninstall(); + + loadWeaponDefHook.Uninstall(); + Zones::LoadVehicleDefHook.Uninstall(); + + Zones::Loadsnd_alias_tArrayHook.Uninstall(); + Zones::LoadLoadedSoundHook.Uninstall(); + menuDefLoadHook.Uninstall(); + fxEffectLoadHook.Uninstall(); + + loadWeaponAttachHook.Uninstall(); + + Zones::LoadPathDataHook.Uninstall(); + + loadTechniquePassHook.Uninstall(); + loadStructuredDataChildArrayHook.Uninstall(); + } + + AntiCheat::EmptyHash(); } Zones::Zones() { + Zones::ZoneVersion = 0; + // Ignore missing soundaliases for now + // TODO: Include them in the dependency zone! + Utils::Hook::Nop(0x644207, 5); + + // Block Mark_pathnode_constant_t + Utils::Hook::Set(0x4F74B0, 0xC3); + + Zones::LoadFxElemDefArrayHook.Initialize(0x495938, Zones::LoadFxElemDefArrayStub, HOOK_CALL); + Zones::LoadFxElemDefHook.Initialize(0x45ADA0, Zones::LoadFxElemDefStub, HOOK_CALL); + Zones::LoadXModelLodInfoHook.Initialize(0x4EA6FE, Zones::LoadXModelLodInfoStub, HOOK_CALL); + Zones::LoadXModelHook.Initialize(0x410D90, Zones::LoadXModel, HOOK_CALL); + Zones::LoadXSurfaceArrayHook.Initialize(0x4925C8, Zones::LoadXSurfaceArray, HOOK_CALL); + Zones::LoadGameWorldSpHook.Initialize(0x4F4D0D, Zones::LoadGameWorldSp, HOOK_CALL); + loadWeaponDefHook.Initialize(0x47CCD2, Load_WeaponDef_CodC, HOOK_CALL); + Zones::LoadVehicleDefHook.Initialize(0x483DA0, Zones::LoadVehicleDef, HOOK_CALL); + Zones::Loadsnd_alias_tArrayHook.Initialize(0x4F0AC8, Zones::Loadsnd_alias_tArray, HOOK_CALL); + Zones::LoadLoadedSoundHook.Initialize(0x403A5D, Zones::LoadLoadedSound, HOOK_CALL); + loadWeaponAttachHook.Initialize(0x463022, Load_WeaponAttach, HOOK_CALL); + menuDefLoadHook.Initialize(0x41A570, MenuDefLoadHookFunc, HOOK_CALL); + fxEffectLoadHook.Initialize(0x49591B, FxEffectLoadHookFunc, HOOK_CALL); + loadTechniquePassHook.Initialize(0x428F0A, Load_TechniquePassHookFunc, HOOK_CALL); + loadStructuredDataChildArrayHook.Initialize(0x4B1EB8, Load_StructuredDataChildArrayHookFunc, HOOK_CALL); + + pathDataTailHook.Initialize(0x427A1B, PathDataTailHookFunc, HOOK_JUMP); + + Zones::LoadPathDataHook.Initialize(0x4F4D3B, [] () + { + ZeroMemory(*Game::varPathData, sizeof(Game::PathData)); + }, HOOK_CALL); } Zones::~Zones() diff --git a/src/Components/Modules/Zones.hpp b/src/Components/Modules/Zones.hpp index 84ab67bd..96938b9b 100644 --- a/src/Components/Modules/Zones.hpp +++ b/src/Components/Modules/Zones.hpp @@ -1,3 +1,6 @@ +#define VERSION_ALPHA2 316 +#define VERSION_ALPHA3 318//319 + namespace Components { class Zones : public Component @@ -12,7 +15,30 @@ namespace Components static void InstallPatches(int version); - private: + //private: static int ZoneVersion; + + static Utils::Hook LoadFxElemDefHook; + static Utils::Hook LoadFxElemDefArrayHook; + static Utils::Hook LoadXModelLodInfoHook; + static Utils::Hook LoadXModelHook; + static Utils::Hook LoadXSurfaceArrayHook; + static Utils::Hook LoadGameWorldSpHook; + static Utils::Hook LoadPathDataHook; + static Utils::Hook LoadVehicleDefHook; + static Utils::Hook Loadsnd_alias_tArrayHook; + static Utils::Hook LoadLoadedSoundHook; + + static void LoadFxElemDefArrayStub(bool atStreamStart); + static bool LoadFxElemDefStub(bool atStreamStart, Game::FxElemDef* fxElem, int size); + + static void LoadXModelLodInfo(int i); + static void LoadXModelLodInfoStub(); + static bool LoadXModel(bool atStreamStart, char* xmodel, int size); + static bool LoadXSurfaceArray(bool atStreamStart, char* buffer, int size); + static bool LoadGameWorldSp(bool atStreamStart, char* buffer); + static bool LoadVehicleDef(bool atStreamStart, char* buffer); + static bool Loadsnd_alias_tArray(bool atStreamStart, char* buffer, int len); + static bool LoadLoadedSound(bool atStreamStart, char* buffer); }; } diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index eda3e309..eceb4b54 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -32,6 +32,10 @@ namespace Game Con_DrawMiniConsole_t Con_DrawMiniConsole = (Con_DrawMiniConsole_t)0x464F30; Con_DrawSolidConsole_t Con_DrawSolidConsole = (Con_DrawSolidConsole_t)0x5A5040; + DB_AllocStreamPos_t DB_AllocStreamPos = (DB_AllocStreamPos_t)0x418380; + DB_PushStreamPos_t DB_PushStreamPos = (DB_PushStreamPos_t)0x458A20; + DB_PopStreamPos_t DB_PopStreamPos = (DB_PopStreamPos_t)0x4D1D60; + DB_BeginRecoverLostDevice_t DB_BeginRecoverLostDevice = (DB_BeginRecoverLostDevice_t)0x4BFF90; DB_EndRecoverLostDevice_t DB_EndRecoverLostDevice = (DB_EndRecoverLostDevice_t)0x46B660; DB_EnumXAssets_t DB_EnumXAssets = (DB_EnumXAssets_t)0x4B76D0; @@ -94,6 +98,20 @@ namespace Game Image_Release_t Image_Release = (Image_Release_t)0x51F010; LargeLocalInit_t LargeLocalInit = (LargeLocalInit_t)0x4A62A0; + + Load_Stream_t Load_Stream = (Load_Stream_t)0x470E30; + Load_XString_t Load_XString = (Load_XString_t)0x47FDA0; + Load_XModelPtr_t Load_XModelPtr = (Load_XModelPtr_t)0x4FCA70; + Load_XModelSurfsFixup_t Load_XModelSurfsFixup = (Load_XModelSurfsFixup_t)0x40D7A0; + Load_XStringArray_t Load_XStringArray = (Load_XStringArray_t)0x4977F0; + Load_XStringCustom_t Load_XStringCustom = (Load_XStringCustom_t)0x4E0DD0; + Load_FxEffectDefHandle_t Load_FxEffectDefHandle = (Load_FxEffectDefHandle_t)0x4D9B90; + Load_FxElemDef_t Load_FxElemDef = (Load_FxElemDef_t)0x45AD90; + Load_SndAliasCustom_t Load_SndAliasCustom = (Load_SndAliasCustom_t)0x49B6B0; + Load_MaterialHandle_t Load_MaterialHandle = (Load_MaterialHandle_t)0x403960; + Load_PhysCollmapPtr_t Load_PhysCollmapPtr = (Load_PhysCollmapPtr_t)0x47E990; + Load_TracerDefPtr_t Load_TracerDefPtr = (Load_TracerDefPtr_t)0x493090; + Load_snd_alias_list_nameArray_t Load_snd_alias_list_nameArray = (Load_snd_alias_list_nameArray_t)0x4499F0; Menus_CloseAll_t Menus_CloseAll = (Menus_CloseAll_t)0x4BA5B0; Menus_OpenByName_t Menus_OpenByName = (Menus_OpenByName_t)0x4CCE60; @@ -257,6 +275,17 @@ namespace Game mapname_t* mapnames = (mapname_t*)0x7471D0; + char*** varXString = (char***)0x112B340; + TracerDef** varTracerDefPtr = (TracerDef**)0x112B3BC; + XModel** varXModelPtr = (XModel**)0x112A934; + XModel** varXModel = (XModel**)0x112AE14; + PathData** varPathData = (PathData**)0x112AD7C; + const char** varConstChar = (const char**)0x112A774; + Material** varMaterialHandle = (Material**)0x112A878; + FxEffectDef** varFxEffectDefHandle = (FxEffectDef**)0x112ACC0; + PhysCollmap** varPhysCollmapPtr = (PhysCollmap **)0x112B440; + snd_alias_list_t*** varsnd_alias_list_name = (snd_alias_list_t***)0x112AF38; + XAssetHeader ReallocateAssetPool(XAssetType type, unsigned int newSize) { int elSize = DB_GetXAssetSizeHandlers[type](); @@ -476,7 +505,7 @@ namespace Game if (Components::Dvar::Var("r_loadForRenderer").Get()) { void* buffer = R_AllocStaticIndexBuffer(storeHere, 2 * count); - memcpy(buffer, data, 2 * count); + std::memcpy(buffer, data, 2 * count); if (storeHere && *storeHere) { diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 637e202c..39181e76 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -66,6 +66,15 @@ namespace Game typedef void (__cdecl * Con_DrawSolidConsole_t)(); extern Con_DrawSolidConsole_t Con_DrawSolidConsole; + typedef char *(__cdecl *DB_AllocStreamPos_t)(int alignment); + extern DB_AllocStreamPos_t DB_AllocStreamPos; + + typedef void(__cdecl * DB_PushStreamPos_t)(unsigned int index); + extern DB_PushStreamPos_t DB_PushStreamPos; + + typedef void(__cdecl * DB_PopStreamPos_t)(); + extern DB_PopStreamPos_t DB_PopStreamPos; + typedef void(__cdecl * DB_BeginRecoverLostDevice_t)(); extern DB_BeginRecoverLostDevice_t DB_BeginRecoverLostDevice; @@ -224,6 +233,45 @@ namespace Game typedef void(__cdecl * LargeLocalInit_t)(); extern LargeLocalInit_t LargeLocalInit; + typedef bool(__cdecl * Load_Stream_t)(bool atStreamStart, const void *ptr, int size); + extern Load_Stream_t Load_Stream; + + typedef void(__cdecl * Load_XString_t)(bool atStreamStart); + extern Load_XString_t Load_XString; + + typedef void(__cdecl * Load_XModelPtr_t)(bool atStreamStart); + extern Load_XModelPtr_t Load_XModelPtr; + + typedef void(__cdecl * Load_XModelSurfsFixup_t)(XModelSurfs **, XModelLodInfo *); + extern Load_XModelSurfsFixup_t Load_XModelSurfsFixup; + + typedef void(__cdecl * Load_XStringArray_t)(bool atStreamStart, int count); + extern Load_XStringArray_t Load_XStringArray; + + typedef void(__cdecl * Load_XStringCustom_t)(const char **str); + extern Load_XStringCustom_t Load_XStringCustom; + + typedef void(__cdecl *Load_FxEffectDefHandle_t)(bool atStreamStart); + extern Load_FxEffectDefHandle_t Load_FxEffectDefHandle; + + typedef void(__cdecl *Load_FxElemDef_t)(bool atStreamStart); + extern Load_FxElemDef_t Load_FxElemDef; + + typedef void(__cdecl * Load_SndAliasCustom_t)(snd_alias_list_t** var); + extern Load_SndAliasCustom_t Load_SndAliasCustom; + + typedef void(__cdecl *Load_MaterialHandle_t)(bool atStreamStart); + extern Load_MaterialHandle_t Load_MaterialHandle; + + typedef void(__cdecl *Load_PhysCollmapPtr_t)(bool atStreamStart); + extern Load_PhysCollmapPtr_t Load_PhysCollmapPtr; + + typedef void(__cdecl *Load_TracerDefPtr_t)(bool atStreamStart); + extern Load_TracerDefPtr_t Load_TracerDefPtr; + + typedef void(__cdecl *Load_snd_alias_list_nameArray_t)(bool atStreamStart, int count); + extern Load_snd_alias_list_nameArray_t Load_snd_alias_list_nameArray; + typedef void(__cdecl * Menus_CloseAll_t)(UiContext *dc); extern Menus_CloseAll_t Menus_CloseAll; @@ -517,6 +565,17 @@ namespace Game extern mapname_t* mapnames; + extern char*** varXString; + extern TracerDef** varTracerDefPtr; + extern XModel** varXModelPtr; + extern XModel** varXModel; + extern PathData** varPathData; + extern const char** varConstChar; + extern Material** varMaterialHandle; + extern FxEffectDef** varFxEffectDefHandle; + extern PhysCollmap** varPhysCollmapPtr; + extern snd_alias_list_t*** varsnd_alias_list_name; + XAssetHeader ReallocateAssetPool(XAssetType type, unsigned int newSize); void Menu_FreeItemMemory(Game::itemDef_t* item); const char* TableLookup(StringTable* stringtable, int row, int column); diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 719c98d2..7ecb1c14 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -368,6 +368,19 @@ namespace Game void *stateBitTable; }; + struct TracerDef + { + const char * name; + Material * material; + unsigned int drawInterval; + float speed; + float beamLength; + float beamWidth; + float screwRadius; + float screwDist; + float colors[5][4]; + }; + struct keyname_t { const char *name; @@ -1398,16 +1411,13 @@ namespace Game struct XModelLodInfo { - // I'm not sure if this is correct - short someCount; - short someTotalCount; - + char pad[4]; short numSurfs; // +4 - short pad2;// +6 + short maxSurfs;// +6 XModelSurfs* surfaces; // +8 - char pad3[24]; + char pad3[24]; // +12 XSurface* surfs; - char pad4[4]; // +12 + char pad4[4]; }; struct cplane_t @@ -1532,8 +1542,6 @@ namespace Game PhysCollmap* physCollmap; }; // total size 304 - //static_assert(offsetof(XModel, lods) <= 70, ""); - struct CModelAllocData { void* mainArray; @@ -2273,20 +2281,37 @@ namespace Game char pad[112]; }; - struct GameMap_SP + struct PathData + { + char pad[40]; + }; + + struct VehicleTrack + { + char pad[8]; + }; + + struct GameWorldSp { const char* name; - char pad[48]; + PathData pathData; + VehicleTrack vehicleTrack; GameMap_Data* data; }; - struct GameMap_MP + struct GameWorldMp { const char* name; GameMap_Data* data; }; + struct VehicleDef + { + const char* name; + char pad[716]; + }; + union XAssetHeader { void *data; @@ -2312,8 +2337,10 @@ namespace Game XAnimParts* xanim; clipMap_t* clipMap; FxEffectDef* fx; - GameMap_MP* gameMapMP; - GameMap_SP* gameMapSP; + GameWorldMp* gameMapMP; + GameWorldSp* gameMapSP; + TracerDef* tracer; + VehicleDef* vehicle; }; struct XAsset diff --git a/src/Utils/Memory.cpp b/src/Utils/Memory.cpp index 97f97674..7e56bd80 100644 --- a/src/Utils/Memory.cpp +++ b/src/Utils/Memory.cpp @@ -36,6 +36,19 @@ namespace Utils Memory::Free(const_cast(data)); } + void Memory::FreeAlign(void* data) + { + if (data) + { + _aligned_free(data); + } + } + + void Memory::FreeAlign(const void* data) + { + Memory::FreeAlign(const_cast(data)); + } + // Complementary function for memset, which checks if memory is filled with a char bool Memory::IsSet(void* mem, char chr, size_t length) { diff --git a/src/Utils/Memory.hpp b/src/Utils/Memory.hpp index a4c83bfb..d6b98bb6 100644 --- a/src/Utils/Memory.hpp +++ b/src/Utils/Memory.hpp @@ -108,6 +108,9 @@ namespace Utils static void Free(void* data); static void Free(const void* data); + static void FreeAlign(void* data); + static void FreeAlign(const void* data); + static bool IsSet(void* mem, char chr, size_t length); }; }