From 678dc349dd38b609f321b86a4bfa0d2f0df93f52 Mon Sep 17 00:00:00 2001 From: Louve <33836535+Rackover@users.noreply.github.com> Date: Fri, 17 Mar 2023 13:46:29 +0100 Subject: [PATCH] IW5 DLC Prep (#814) Co-authored-by: FutureRave --- src/Components/Modules/ArenaLength.cpp | 44 +-- src/Components/Modules/ArenaLength.hpp | 3 +- src/Components/Modules/AssetHandler.cpp | 204 -------------- src/Components/Modules/FastFiles.cpp | 28 +- src/Components/Modules/FastFiles.hpp | 2 + src/Components/Modules/Maps.cpp | 92 ++++-- src/Components/Modules/Maps.hpp | 7 + src/Components/Modules/QuickPatch.cpp | 9 +- src/Components/Modules/Renderer.cpp | 87 +++++- src/Components/Modules/Renderer.hpp | 2 + src/Components/Modules/UIFeeder.cpp | 99 ++++--- src/Components/Modules/ZoneBuilder.cpp | 9 +- src/Components/Modules/Zones.cpp | 359 ++++++++++++------------ src/Utils/IO.cpp | 8 +- src/Utils/IO.hpp | 2 +- src/Utils/Thread.cpp | 41 --- src/Utils/Thread.hpp | 4 - 17 files changed, 466 insertions(+), 534 deletions(-) diff --git a/src/Components/Modules/ArenaLength.cpp b/src/Components/Modules/ArenaLength.cpp index d7a94f09..e94ea544 100644 --- a/src/Components/Modules/ArenaLength.cpp +++ b/src/Components/Modules/ArenaLength.cpp @@ -2,7 +2,10 @@ namespace Components { - Game::newMapArena_t ArenaLength::NewArenas[128]; + constexpr auto NEW_ARENA_COUNT = 128; + + Game::newMapArena_t ArenaLength::NewArenas[NEW_ARENA_COUNT]; + char* ArenaLength::NewArenaInfos[NEW_ARENA_COUNT]; __declspec(naked) void ArenaLength::ArenaMapOffsetHook1() { @@ -57,16 +60,28 @@ namespace Components ArenaLength::ArenaLength() { - // Reallocate array - Utils::Hook::Set(0x417807, &ArenaLength::NewArenas[0]); - Utils::Hook::Set(0x420717, &ArenaLength::NewArenas[0]); - Utils::Hook::Set(0x49BD22, &ArenaLength::NewArenas[0]); - Utils::Hook::Set(0x4A9649, &ArenaLength::NewArenas[0]); - Utils::Hook::Set(0x4A97C2, &ArenaLength::NewArenas[0]); - Utils::Hook::Set(0x4D077E, &ArenaLength::NewArenas[0]); - Utils::Hook::Set(0x630B00, &ArenaLength::NewArenas[0]); - Utils::Hook::Set(0x630B2E, &ArenaLength::NewArenas[0]); - Utils::Hook::Set(0x632782, &ArenaLength::NewArenas[0]); + // Reallocate ui_arenaInfos + Utils::Hook::Set(0x4A95F0 + 3, ArenaLength::NewArenaInfos); + Utils::Hook::Set(0x4A9620 + 3, ArenaLength::NewArenaInfos); + Utils::Hook::Set(0x4A9653 + 3, ArenaLength::NewArenaInfos); + Utils::Hook::Set(0x4A9684 + 3, ArenaLength::NewArenaInfos); + Utils::Hook::Set(0x4A96B7 + 3, ArenaLength::NewArenaInfos); + Utils::Hook::Set(0x4A97B3 + 3, ArenaLength::NewArenaInfos); + Utils::Hook::Set(0x630A9A + 3, ArenaLength::NewArenaInfos); + + // Increase size - patch max arena count + Utils::Hook::Set(0x630AA2 + 1, NEW_ARENA_COUNT); + + // Reallocate sharedUiInfo.mapList + Utils::Hook::Set(0x417807, ArenaLength::NewArenas); + Utils::Hook::Set(0x420717, ArenaLength::NewArenas); + Utils::Hook::Set(0x49BD22, ArenaLength::NewArenas); + Utils::Hook::Set(0x4A9649, ArenaLength::NewArenas); + Utils::Hook::Set(0x4A97C2, ArenaLength::NewArenas); + Utils::Hook::Set(0x4D077E, ArenaLength::NewArenas); + Utils::Hook::Set(0x630B00, ArenaLength::NewArenas); + Utils::Hook::Set(0x630B2E, ArenaLength::NewArenas); + Utils::Hook::Set(0x632782, ArenaLength::NewArenas); Utils::Hook::Set(0x4A967A, ArenaLength::NewArenas[0].description); Utils::Hook::Set(0x4A96AD, ArenaLength::NewArenas[0].mapimage); @@ -109,12 +124,7 @@ namespace Components Utils::Hook(0x632799, ArenaLength::ArenaMapOffsetHook3, HOOK_JUMP).install()->quick(); Utils::Hook(0x4064B2, ArenaLength::ArenaMapOffsetHook4, HOOK_JUMP).install()->quick(); - Utils::Hook::Set(0x4A95F8, 32); - + Utils::Hook::Set(0x4A95F8, sizeof(Game::newMapArena_t::mapName)); Utils::Hook::Set(0x42F22B, offsetof(Game::newMapArena_t, mapName) - offsetof(Game::newMapArena_t, other)); - - // patch max arena count - constexpr auto arenaCount = sizeof(ArenaLength::NewArenas) / sizeof(Game::newMapArena_t); - Utils::Hook::Set(0x630AA3, arenaCount); } } diff --git a/src/Components/Modules/ArenaLength.hpp b/src/Components/Modules/ArenaLength.hpp index f495b5c7..7b1c7eee 100644 --- a/src/Components/Modules/ArenaLength.hpp +++ b/src/Components/Modules/ArenaLength.hpp @@ -7,7 +7,8 @@ namespace Components public: ArenaLength(); - static Game::newMapArena_t NewArenas[128]; + static Game::newMapArena_t NewArenas[]; + static char* NewArenaInfos[]; private: static void ArenaMapOffsetHook1(); diff --git a/src/Components/Modules/AssetHandler.cpp b/src/Components/Modules/AssetHandler.cpp index d7606ee5..825fb0f0 100644 --- a/src/Components/Modules/AssetHandler.cpp +++ b/src/Components/Modules/AssetHandler.cpp @@ -571,210 +571,6 @@ namespace Components AssetHandler::OnLoad([](Game::XAssetType type, Game::XAssetHeader asset, std::string name, bool*) { -#ifdef DEBUG -// #define DUMP_TECHSETS -#ifdef DUMP_TECHSETS - if (type == Game::XAssetType::ASSET_TYPE_VERTEXDECL && !name.empty() && name[0] != ',') - { - std::filesystem::create_directories("techsets/vertexdecl"); - - auto vertexdecl = asset.vertexDecl; - - std::vector routingData; - for (int i = 0; i < vertexdecl->streamCount; i++) - { - routingData.push_back(json11::Json::object - { - { "source", (int)vertexdecl->routing.data[i].source }, - { "dest", (int)vertexdecl->routing.data[i].dest }, - }); - } - - std::vector declData; - for (int i = 0; i < 16; i++) - { - if (vertexdecl->routing.decl[i]) - { - routingData.push_back(int(vertexdecl->routing.decl[i])); - } - else - { - routingData.push_back(nullptr); - } - } - - nlohmann::json vertexData = json11::Json::object - { - { "name", vertexdecl->name }, - { "streamCount", vertexdecl->streamCount }, - { "hasOptionalSource", vertexdecl->hasOptionalSource }, - { "routing", routingData }, - { "decl", declData }, - }; - - auto stringData = vertexData.dump(); - - auto fp = fopen(Utils::String::VA("techsets/vertexdecl/%s.%s.json", vertexdecl->name, Zones::Version() > 276 ? "codo" : "iw4"), "wb"); - fwrite(&stringData[0], stringData.size(), 1, fp); - fclose(fp); - } - - if (type == Game::ASSET_TYPE_TECHNIQUE_SET && !name.empty() && name[0] != ',') - { - std::filesystem::create_directory("techsets"); - std::filesystem::create_directories("techsets/techniques"); - - auto techset = asset.techniqueSet; - - std::vector techniques; - for (int technique = 0; technique < 48; technique++) - { - auto curTech = techset->techniques[technique]; - if (curTech) - { - std::vector passDataArray; - for (int pass = 0; pass < curTech->passCount; pass++) - { - auto curPass = &curTech->passArray[pass]; - - std::vector argDataArray; - for (int arg = 0; arg < curPass->perObjArgCount + curPass->perPrimArgCount + curPass->stableArgCount; arg++) - { - auto curArg = &curPass->args[arg]; - - if (curArg->type == 1 || curArg->type == 7) - { - std::vector literalConsts; - if (curArg->u.literalConst != 0) - { - literalConsts.push_back(curArg->u.literalConst[0]); - literalConsts.push_back(curArg->u.literalConst[1]); - literalConsts.push_back(curArg->u.literalConst[2]); - literalConsts.push_back(curArg->u.literalConst[3]); - } - - nlohmann::json argData = json11::Json::object - { - { "type", curArg->type }, - { "value", literalConsts }, - }; - argDataArray.push_back(argData); - } - else if (curArg->type == 3 || curArg->type == 5) - { - nlohmann::json argData = json11::Json::object - { - { "type", curArg->type }, - { "firstRow", curArg->u.codeConst.firstRow }, - { "rowCount", curArg->u.codeConst.rowCount }, - { "index", curArg->u.codeConst.index }, - }; - argDataArray.push_back(argData); - } - else - { - nlohmann::json argData = json11::Json::object - { - { "type", curArg->type }, - { "value", static_cast(curArg->u.codeSampler) }, - }; - argDataArray.push_back(argData); - } - } - - nlohmann::json passData = json11::Json::object - { - { "perObjArgCount", curPass->perObjArgCount }, - { "perPrimArgCount", curPass->perPrimArgCount }, - { "stableArgCount", curPass->stableArgCount }, - { "args", argDataArray }, - { "pixelShader", curPass->pixelShader ? curPass->pixelShader->name : "" }, - { "vertexShader", curPass->vertexShader ? curPass->vertexShader->name : "" }, - { "vertexDecl", curPass->vertexDecl ? curPass->vertexDecl->name : "" }, - }; - passDataArray.push_back(passData); - } - - nlohmann::json techData = json11::Json::object - { - { "name", curTech->name }, - { "index", technique }, - { "flags", curTech->flags }, - { "numPasses", curTech->passCount }, - { "pass", passDataArray }, - }; - - auto stringData = techData.dump(); - - auto fp = fopen(Utils::String::VA("techsets/techniques/%s.%s.json", curTech->name, Zones::Version() > 276 ? "codo" : "iw4"), "wb"); - fwrite(&stringData[0], stringData.size(), 1, fp); - fclose(fp); - - nlohmann::json techsetTechnique = json11::Json::object - { - { "name", curTech->name }, - { "index", technique }, - }; - techniques.push_back(techsetTechnique); - } - else - { - techniques.push_back(nullptr); - } - } - - nlohmann::json techsetData = json11::Json::object - { - { "name", techset->name }, - { "techniques", techniques }, - }; - - auto stringData = techsetData.dump(); - - auto fp = fopen(Utils::String::VA("techsets/%s.%s.json", techset->name, Zones::Version() > 276 ? "codo" : "iw4"), "wb"); - fwrite(&stringData[0], stringData.size(), 1, fp); - fclose(fp); - } -#endif - - if (type == Game::XAssetType::ASSET_TYPE_TECHNIQUE_SET && Zones::Version() >= 460) - { - auto techset = asset.techniqueSet; - if (techset) - { - for (int t = 0; t < 48; t++) - { - if (techset->techniques[t]) - { - for (int p = 0; p < techset->techniques[t]->passCount; p++) - { - for (int a = 0; a < techset->techniques[t]->passArray[p].perObjArgCount + - techset->techniques[t]->passArray[p].perPrimArgCount + - techset->techniques[t]->passArray[p].stableArgCount; a++) - { - auto arg = &techset->techniques[t]->passArray[p].args[a]; - if (arg->type == 3 || arg->type == 5) - { - if (arg->u.codeConst.index > 140) - { - OutputDebugStringA(Utils::String::VA("codeConst %i is out of range for %s::%s[%i]\n", arg->u.codeConst.index, - techset->name, techset->techniques[t]->name, p)); - - if (!ZoneBuilder::IsEnabled()) - { - __debugbreak(); - } - } - } - } - } - } - } - } - } - -#endif - if (Dvar::Var("r_noVoid").get() && type == Game::XAssetType::ASSET_TYPE_XMODEL && name == "void") { asset.model->numLods = 0; diff --git a/src/Components/Modules/FastFiles.cpp b/src/Components/Modules/FastFiles.cpp index b27ab321..e56732f1 100644 --- a/src/Components/Modules/FastFiles.cpp +++ b/src/Components/Modules/FastFiles.cpp @@ -10,6 +10,8 @@ namespace Components symmetric_CTR FastFiles::CurrentCTR; std::vector FastFiles::ZonePaths; + Dvar::Var FastFiles::g_loadingInitialZones; + bool FastFiles::IsIW4xZone = false; bool FastFiles::StreamRead = false; @@ -133,8 +135,10 @@ namespace Components // This has to be called only once, when the game starts - void FastFiles::LoadInitialZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync) + void FastFiles::LoadInitialZones(Game::XZoneInfo* zoneInfo, unsigned int zoneCount, int sync) { + g_loadingInitialZones.set(true); + std::vector data; Utils::Merge(&data, zoneInfo, zoneCount); @@ -152,7 +156,7 @@ namespace Components } // This has to be called every time the cgame is reinitialized - void FastFiles::LoadDLCUIZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync) + void FastFiles::LoadDLCUIZones(Game::XZoneInfo* zoneInfo, unsigned int zoneCount, int sync) { std::vector data; Utils::Merge(&data, zoneInfo, zoneCount); @@ -177,7 +181,7 @@ namespace Components return FastFiles::LoadLocalizeZones(data.data(), data.size(), sync); } - void FastFiles::LoadGfxZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync) + void FastFiles::LoadGfxZones(Game::XZoneInfo* zoneInfo, unsigned int zoneCount, int sync) { std::vector data; Utils::Merge(&data, zoneInfo, zoneCount); @@ -191,7 +195,7 @@ namespace Components } // This has to be called every time fastfiles are loaded :D - void FastFiles::LoadLocalizeZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync) + void FastFiles::LoadLocalizeZones(Game::XZoneInfo* zoneInfo, unsigned int zoneCount, int sync) { std::vector data; Utils::Merge(&data, zoneInfo, zoneCount); @@ -213,6 +217,11 @@ namespace Components data.push_back(info); Game::DB_LoadXAssets(data.data(), data.size(), sync); + + Scheduler::OnGameInitialized([] + { + g_loadingInitialZones.set(false); + }, Scheduler::Pipeline::MAIN); } // Name is a bit weird, due to FasFileS and ExistS :P @@ -394,7 +403,7 @@ namespace Components return Utils::Hook::Call(0x5BA240)(buffer, length, ivValue); } - static int InflateInitDecrypt(z_streamp strm, const char *version, int stream_size) + static int InflateInitDecrypt(z_streamp strm, const char* version, int stream_size) { if (Zones::Version() >= 319) { @@ -436,7 +445,7 @@ namespace Components return std::min(partialProgress + (currentProgress * singleProgress), 1.0f); } - void FastFiles::LoadZonesStub(Game::XZoneInfo *zoneInfo, unsigned int zoneCount) + void FastFiles::LoadZonesStub(Game::XZoneInfo* zoneInfo, unsigned int zoneCount) { FastFiles::CurrentZone = 0; FastFiles::MaxZones = zoneCount; @@ -500,6 +509,7 @@ namespace Components FastFiles::FastFiles() { Dvar::Register("ui_zoneDebug", false, Game::DVAR_ARCHIVE, "Display current loaded zone."); + g_loadingInitialZones = Dvar::Register("g_loadingInitialZones", true, Game::DVAR_NONE, "Is loading initial zones"); // Fix XSurface assets Utils::Hook(0x0048E8A5, FastFiles::Load_XSurfaceArray, HOOK_CALL).install()->quick(); @@ -580,7 +590,7 @@ namespace Components if (FastFiles::Current().empty() || !Dvar::Var("ui_zoneDebug").get()) return; auto* const font = Game::R_RegisterFont("fonts/consoleFont", 0); - float color[4] = {1.0f, 1.0f, 1.0f, (Game::CL_IsCgameInitialized() ? 0.3f : 1.0f)}; + float color[4] = { 1.0f, 1.0f, 1.0f, (Game::CL_IsCgameInitialized() ? 0.3f : 1.0f) }; auto FFTotalSize = *reinterpret_cast(0x10AA5D8); auto FFCurrentOffset = *reinterpret_cast(0x10AA608); @@ -617,11 +627,11 @@ namespace Components while (!Game::Sys_IsDatabaseReady()) std::this_thread::sleep_for(100ms); }); -#ifdef DEBUG +#ifdef _DEBUG // ZoneBuilder debugging Utils::IO::WriteFile("userraw/logs/iw4_reads.log", "", false); Utils::Hook(0x4A8FA0, FastFiles::LogStreamRead, HOOK_JUMP).install()->quick(); - Utils::Hook(0x4BCB62, []() + Utils::Hook(0x4BCB62, [] { FastFiles::StreamRead = true; Utils::Hook::Call(0x4B8DB0)(true); // currently set to Load_GfxWorld diff --git a/src/Components/Modules/FastFiles.hpp b/src/Components/Modules/FastFiles.hpp index 1e8d3bd2..24f0a03a 100644 --- a/src/Components/Modules/FastFiles.hpp +++ b/src/Components/Modules/FastFiles.hpp @@ -40,6 +40,8 @@ namespace Components static char LastByteRead; + static Dvar::Var g_loadingInitialZones; + static Key CurrentKey; static std::vector ZonePaths; static const char* GetZoneLocation(const char* file); diff --git a/src/Components/Modules/Maps.cpp b/src/Components/Modules/Maps.cpp index 00cf934a..27cd6e9c 100644 --- a/src/Components/Modules/Maps.cpp +++ b/src/Components/Modules/Maps.cpp @@ -11,6 +11,7 @@ namespace Components std::string Maps::CurrentMainZone; std::vector> Maps::DependencyList; std::vector Maps::CurrentDependencies; + std::vector Maps::FoundCustomMaps; Dvar::Var Maps::RListSModels; @@ -105,8 +106,8 @@ namespace Components if (Maps::UserMap.isValid()) { - const std::string mapname = Maps::UserMap.getName(); - const auto* arena = Utils::String::VA("usermaps/%s/%s.arena", mapname.data(), mapname.data()); + const auto mapname = Maps::UserMap.getName(); + const auto arena = GetArenaPath(mapname); if (Utils::IO::FileExists(arena)) { @@ -183,17 +184,17 @@ namespace Components void Maps::OverrideMapEnts(Game::MapEnts* ents) { auto callback = [] (Game::XAssetHeader header, void* ents) - { - Game::MapEnts* mapEnts = reinterpret_cast(ents); - Game::clipMap_t* clipMap = header.clipMap; + { + Game::MapEnts* mapEnts = reinterpret_cast(ents); + Game::clipMap_t* clipMap = header.clipMap; - if (clipMap && mapEnts && !_stricmp(mapEnts->name, clipMap->name)) - { - clipMap->mapEnts = mapEnts; - //*Game::marMapEntsPtr = mapEnts; - //Game::G_SpawnEntitiesFromString(); - } - }; + if (clipMap && mapEnts && !_stricmp(mapEnts->name, clipMap->name)) + { + clipMap->mapEnts = mapEnts; + //*Game::marMapEntsPtr = mapEnts; + //Game::G_SpawnEntitiesFromString(); + } + }; // Internal doesn't lock the thread, as locking is impossible, due to executing this in the thread that holds the current lock Game::DB_EnumXAssets_Internal(Game::XAssetType::ASSET_TYPE_CLIPMAP_MP, callback, ents, true); @@ -338,12 +339,33 @@ namespace Components return (Utils::String::StartsWith(entity, "dyn_") || Utils::String::StartsWith(entity, "node_") || Utils::String::StartsWith(entity, "actor_")); } + std::unordered_map Maps::ParseCustomMapArena(const std::string& singleMapArena) + { + static const std::regex regex(" (\\w*) *\"?((?:\\w| )*)\"?"); + std::unordered_map arena; + + std::smatch m; + + std::string::const_iterator search_start(singleMapArena.cbegin()); + + while (std::regex_search(search_start, singleMapArena.cend(), m, regex)) + { + if (m.size() > 2) + { + arena.emplace(m[1].str(), m[2].str()); + search_start = m.suffix().first; + } + } + + return arena; + } + Maps::MapDependencies Maps::GetDependenciesForMap(const std::string& map) { std::string teamAxis = "opforce_composite"; std::string teamAllies = "us_army"; - Maps::MapDependencies dependencies{}; + Maps::MapDependencies dependencies; // True by default - cause some maps won't have an arenafile entry dependencies.requiresTeamZones = true; @@ -578,6 +600,40 @@ namespace Components return Utils::IO::DirectoryExists(std::format("usermaps/{}", mapname)) && Utils::IO::FileExists(std::format("usermaps/{}/{}.ff", mapname, mapname)); } + void Maps::ScanCustomMaps() + { + FoundCustomMaps.clear(); + Logger::Print("Scanning custom maps...\n"); + + auto basePath = std::format("{}\\usermaps", (*Game::fs_basepath)->current.string); + + auto entries = Utils::IO::ListFiles(basePath); + + for (const auto& entry : entries) + { + if (entry.is_directory()) + { + auto zoneName = entry.path().filename().string(); + auto mapPath = std::format("{}\\{}.ff", entry.path().string(), zoneName); + if (Utils::IO::FileExists(mapPath)) + { + FoundCustomMaps.push_back(zoneName); + Logger::Print("Discovered custom map {}\n", zoneName); + } + } + } + } + + std::string Maps::GetArenaPath(const std::string& mapName) + { + return std::format("usermaps/{}/{}.arena", mapName, mapName); + } + + const std::vector& Maps::GetCustomMaps() + { + return FoundCustomMaps; + } + Game::XAssetEntry* Maps::GetAssetEntryPool() { return *reinterpret_cast(0x48E6F4); @@ -696,13 +752,9 @@ namespace Components Maps::AddDlc({ 1, "Stimulus Pack", {"mp_complex", "mp_compact", "mp_storm", "mp_overgrown", "mp_crash"} }); Maps::AddDlc({ 2, "Resurgence Pack", {"mp_abandon", "mp_vacant", "mp_trailerpark", "mp_strike", "mp_fuel2"} }); - Maps::AddDlc({ 3, "Nuketown", {"mp_nuked"} }); - Maps::AddDlc({ 4, "Classics Pack #1", {"mp_cross_fire", "mp_cargoship", "mp_bloc"} }); - Maps::AddDlc({ 5, "Classics Pack #2", {"mp_killhouse", "mp_bog_sh"} }); - Maps::AddDlc({ 6, "Freighter", {"mp_cargoship_sh"} }); - Maps::AddDlc({ 7, "Resurrection Pack", {"mp_shipment_long", "mp_rust_long", "mp_firingrange"} }); - Maps::AddDlc({ 8, "Recycled Pack", {"mp_bloc_sh", "mp_crash_tropical", "mp_estate_tropical", "mp_fav_tropical", "mp_storm_spring"} }); - Maps::AddDlc({ 9, "Classics Pack #3", {"mp_farm", "mp_backlot", "mp_pipeline", "mp_countdown", "mp_crash_snow", "mp_carentan", "mp_broadcast", "mp_showdown", "mp_convoy"} }); + Maps::AddDlc({ 3, "IW4x Classics", {"mp_nuked", "mp_cross_fire", "mp_cargoship", "mp_bloc", "mp_killhouse", "mp_bog_sh", "mp_cargoship_sh", "mp_shipment_long", "mp_rust_long", "mp_firingrange", "mp_bloc_sh", "mp_crash_tropical", "mp_estate_tropical", "mp_fav_tropical", "mp_storm_spring"} }); + Maps::AddDlc({ 4, "Call Of Duty 4 Pack", {"mp_farm", "mp_backlot", "mp_pipeline", "mp_countdown", "mp_crash_snow", "mp_carentan", "mp_broadcast", "mp_showdown", "mp_convoy"} }); + Maps::AddDlc({ 5, "Modern Warfare 3 Pack", {"mp_dome", "mp_hardhat", "mp_paris", "mp_seatown", "mp_bravo", "mp_underground", "mp_plaza2", "mp_village", "mp_alpha"}}); Maps::UpdateDlcStatus(); diff --git a/src/Components/Modules/Maps.hpp b/src/Components/Modules/Maps.hpp index 28e1d89f..356cf6fe 100644 --- a/src/Components/Modules/Maps.hpp +++ b/src/Components/Modules/Maps.hpp @@ -63,6 +63,12 @@ namespace Components static bool IsCustomMap(); static bool IsUserMap(const std::string& mapname); + static void ScanCustomMaps(); + static std::string GetArenaPath(const std::string& mapName); + static const std::vector& GetCustomMaps(); + + static std::unordered_map ParseCustomMapArena(const std::string& singleMapArena); + private: class DLC { @@ -85,6 +91,7 @@ namespace Components static std::vector> DependencyList; static std::vector CurrentDependencies; + static std::vector FoundCustomMaps; static Dvar::Var RListSModels; diff --git a/src/Components/Modules/QuickPatch.cpp b/src/Components/Modules/QuickPatch.cpp index cfd8024b..41fc91b9 100644 --- a/src/Components/Modules/QuickPatch.cpp +++ b/src/Components/Modules/QuickPatch.cpp @@ -527,18 +527,21 @@ namespace Components std::vector fastFiles; if (std::strcmp(param->get(1), "all") == 0) { - for (const auto& f : Utils::IO::ListFiles("zone/english", false)) + for (const auto& entry : Utils::IO::ListFiles("zone/english", false)) { + const auto& f = entry.path().string(); fastFiles.emplace_back(f.substr(7, f.length() - 10)); } - for (const auto& f : Utils::IO::ListFiles("zone/dlc", false)) + for (const auto& entry : Utils::IO::ListFiles("zone/dlc", false)) { + const auto& f = entry.path().string(); fastFiles.emplace_back(f.substr(3, f.length() - 6)); } - for (const auto& f : Utils::IO::ListFiles("zone/patch", false)) + for (const auto& entry : Utils::IO::ListFiles("zone/patch", false)) { + const auto& f = entry.path().string(); fastFiles.emplace_back(f.substr(5, f.length() - 8)); } } diff --git a/src/Components/Modules/Renderer.cpp b/src/Components/Modules/Renderer.cpp index fd4619b2..4eed9557 100644 --- a/src/Components/Modules/Renderer.cpp +++ b/src/Components/Modules/Renderer.cpp @@ -17,6 +17,7 @@ namespace Components Dvar::Var Renderer::r_playerDrawDebugDistance; Dvar::Var Renderer::r_forceTechnique; Dvar::Var Renderer::r_listSamplers; + Dvar::Var Renderer::r_drawLights; float cyan[4] = { 0.0f, 0.5f, 0.5f, 1.0f }; float red[4] = { 1.0f, 0.0f, 0.0f, 1.0f }; @@ -183,11 +184,9 @@ namespace Components { if (!r_drawTriggers.get()) return; - auto entities = Game::g_entities; - for (std::size_t i = 0; i < Game::MAX_GENTITIES; ++i) { - auto* ent = &entities[i]; + auto* ent = &Game::g_entities[i]; if (ent->r.isInUse) { @@ -264,7 +263,7 @@ namespace Components if (!val) return; auto clientNum = Game::CG_GetClientNum(); - Game::gentity_t* clientEntity = &Game::g_entities[clientNum]; + auto* clientEntity = &Game::g_entities[clientNum]; // Ingame only & player only if (!Game::CL_IsCgameInitialized() || clientEntity->client == nullptr) @@ -358,7 +357,7 @@ namespace Components if (!val) return; auto clientNum = Game::CG_GetClientNum(); - Game::gentity_t* clientEntity = &Game::g_entities[clientNum]; + auto* clientEntity = &Game::g_entities[clientNum]; // Ingame only & player only if (!Game::CL_IsCgameInitialized() || clientEntity->client == nullptr) @@ -538,6 +537,82 @@ namespace Components } } + void Renderer::DrawPrimaryLights() + { + if (!r_drawLights.get()) + { + return; + } + + auto clientNum = Game::CG_GetClientNum(); + auto* clientEntity = &Game::g_entities[clientNum]; + + // Ingame only & player only + if (!Game::CL_IsCgameInitialized() || clientEntity->client == nullptr) + { + return; + } + + auto scene = Game::scene; + auto asset = Game::DB_FindXAssetEntry(Game::XAssetType::ASSET_TYPE_COMWORLD, Utils::String::VA("maps/mp/%s.d3dbsp", (*Game::sv_mapname)->current.string)); + + if (asset == nullptr) + { + return; + } + + auto world = asset->asset.header.comWorld; + + for (size_t i = 0; i < world->primaryLightCount; i++) + { + auto light = &world->primaryLights[i]; + + float to[3]; + to[0] = light->origin[0] + light->dir[0] * 10; + to[1] = light->origin[1] + light->dir[1] * 10; + to[2] = light->origin[2] + light->dir[2] * 10; + + auto n = light->defName == nullptr ? "NONE" : light->defName; + + auto str = std::format("LIGHT #{} ({})", i, n); + + float color[4]{}; + color[3] = 1.0f; + color[0] = light->color[0]; + color[1] = light->color[1]; + color[2] = light->color[2]; + + + Game::R_AddDebugLine(color, light->origin, to); + Game::R_AddDebugString(color, light->origin, 1.0f, str.data()); + } + + if (scene) + { + for (size_t i = 0; i < scene->addedLightCount; i++) + { + auto light = &scene->addedLight[i]; + + float color[4]{}; + color[3] = 1.0f; + color[0] = light->color[0]; + color[1] = light->color[1]; + color[2] = light->color[2]; + + float to[3]; + to[0] = light->origin[0] + light->dir[0] * 10; + to[1] = light->origin[1] + light->dir[1] * 10; + to[2] = light->origin[2] + light->dir[2] * 10; + + auto str = std::format("ADDED LIGHT #{}", i); + + Game::R_AddDebugLine(color, light->origin, to); + Game::R_AddDebugString(color, light->origin, 1.0f, str.data()); + + } + } + } + int Renderer::FixSunShadowPartitionSize(Game::GfxCamera* camera, Game::GfxSunShadowMapMetrics* mapMetrics, Game::GfxSunShadow* sunShadow, Game::GfxSunShadowClip* clip, float* partitionFraction) { auto result = Utils::Hook::Call(0x5463B0)(camera, mapMetrics, sunShadow, clip, partitionFraction); @@ -567,6 +642,7 @@ namespace Components DebugDrawTriggers(); ForceTechnique(); ListSamplers(); + DrawPrimaryLights(); } }, Scheduler::Pipeline::RENDERER); @@ -629,6 +705,7 @@ namespace Components Renderer::r_playerDrawDebugDistance = Game::Dvar_RegisterInt("r_drawDebugDistance", 1000, 0, 50000, Game::DVAR_ARCHIVE, "r_draw debug functions draw distance relative to the player"); Renderer::r_forceTechnique = Game::Dvar_RegisterInt("r_forceTechnique", 0, 0, 14, Game::DVAR_NONE, "Force a base technique on the renderer"); Renderer::r_listSamplers = Game::Dvar_RegisterBool("r_listSamplers", false, Game::DVAR_NONE, "List samplers & sampler states"); + Renderer::r_drawLights = Game::Dvar_RegisterBool("r_drawLights", false, Game::DVAR_NONE, "Draw every comworld light in the level"); }); } diff --git a/src/Components/Modules/Renderer.hpp b/src/Components/Modules/Renderer.hpp index f1e00a96..327f11f6 100644 --- a/src/Components/Modules/Renderer.hpp +++ b/src/Components/Modules/Renderer.hpp @@ -42,6 +42,7 @@ namespace Components static void DebugDrawAABBTrees(); static void ForceTechnique(); static void ListSamplers(); + static void DrawPrimaryLights(); static int FixSunShadowPartitionSize(Game::GfxCamera* camera, Game::GfxSunShadowMapMetrics* mapMetrics, Game::GfxSunShadow* sunShadow, Game::GfxSunShadowClip* clip, float* partitionFraction); @@ -60,5 +61,6 @@ namespace Components static Dvar::Var r_playerDrawDebugDistance; static Dvar::Var r_forceTechnique; static Dvar::Var r_listSamplers; + static Dvar::Var r_drawLights; }; } diff --git a/src/Components/Modules/UIFeeder.cpp b/src/Components/Modules/UIFeeder.cpp index 5ed500c8..526f745a 100644 --- a/src/Components/Modules/UIFeeder.cpp +++ b/src/Components/Modules/UIFeeder.cpp @@ -129,7 +129,7 @@ namespace Components fld ds:739FD0h mov eax, 41A0D7h - jmp eax; + jmp eax } } @@ -279,74 +279,81 @@ namespace Components unsigned int UIFeeder::GetMapCount() { - Game::UI_UpdateArenas(); - Game::UI_SortArenas(); - return *Game::arenaCount; + return Maps::GetCustomMaps().size(); } const char* UIFeeder::GetMapText(unsigned int index, int /*column*/) { - Game::UI_UpdateArenas(); - Game::UI_SortArenas(); - - if (index < static_cast(*Game::arenaCount)) + const auto& maps = Maps::GetCustomMaps(); + if (index < maps.size()) { - return Game::SEH_StringEd_GetString(ArenaLength::NewArenas[reinterpret_cast(0x633E934)[index]].uiName); + return maps.at(index).data(); } +#ifdef DEBUG + if (IsDebuggerPresent()) + { + __debugbreak(); + } +#endif + return ""; } void UIFeeder::SelectMap(unsigned int index) { - Game::UI_UpdateArenas(); - Game::UI_SortArenas(); + const auto& maps = Maps::GetCustomMaps(); - if (index < static_cast(*Game::arenaCount)) + if (index < maps.size()) { - index = reinterpret_cast(0x633E934)[index]; - const char* map_name = ArenaLength::NewArenas[index].mapName; - const char* long_name = ArenaLength::NewArenas[index].uiName; - const char* description = ArenaLength::NewArenas[index].description; + std::string mapName = maps[index]; - UIMapName.set(map_name); - UIMapLong.set(Game::SEH_StringEd_GetString(long_name)); - UIMapDesc.set(Game::SEH_StringEd_GetString(description)); + std::string longName = mapName; + std::string description = "(Missing arena file!)"; + + const auto& arenaPath = Maps::GetArenaPath(mapName); + + if (Utils::IO::FileExists(arenaPath)) + { + const auto& arena = Maps::ParseCustomMapArena(Utils::IO::ReadFile(arenaPath)); + + if (arena.contains("longname")) + { + longName = arena.at("longname"); + } + + if (arena.contains("map")) + { + mapName = arena.at("map"); + } + + if (arena.contains("description")) + { + description = arena.at("description"); + } + } + + UIMapName.set(Localization::Get(mapName.data())); + UIMapLong.set(Localization::Get(longName.data())); + UIMapDesc.set(Localization::Get(description.data())); } } void UIFeeder::ApplyMap([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { - const auto mapname = Dvar::Var("ui_map_name").get(); + const auto* mapname = Dvar::Var("ui_map_name").get(); - Dvar::Var("ui_mapname").set(mapname); - Utils::Hook::Call(0x503B50)(mapname.data()); // Party_SetDisplayMapName + if (*mapname) + { + Game::Dvar_SetString(*Game::ui_mapname, mapname); + Utils::Hook::Call(0x503B50)(mapname); // Party_SetDisplayMapName + } } void UIFeeder::ApplyInitialMap([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) { - const auto* mapname = (*Game::ui_mapname)->current.string; - - Game::UI_UpdateArenas(); - Game::UI_SortArenas(); - - for (unsigned int i = 0; i < static_cast(*Game::arenaCount); ++i) - { - if (!std::strcmp(ArenaLength::NewArenas[i].mapName, mapname)) - { - for (unsigned int j = 0; j < static_cast(*Game::arenaCount); ++j) - { - if (reinterpret_cast(0x633E934)[j] == i) - { - SelectMap(j); - Select(60.0f, j); - break; - } - } - - break; - } - } + Maps::ScanCustomMaps(); + Select(60.0f, 0); // Will select nothing if there's no map } int UIFeeder::CheckSelection(int feeder) @@ -387,8 +394,8 @@ namespace Components Events::OnDvarInit([] { - UIMapLong = Dvar::Register("ui_map_long", "Afghan", Game::DVAR_NONE, ""); - UIMapName = Dvar::Register("ui_map_name", "mp_afghan", Game::DVAR_NONE, ""); + UIMapLong = Dvar::Register("ui_map_long", "", Game::DVAR_NONE, ""); + UIMapName = Dvar::Register("ui_map_name", "", Game::DVAR_NONE, ""); UIMapDesc = Dvar::Register("ui_map_desc", "", Game::DVAR_NONE, ""); }); diff --git a/src/Components/Modules/ZoneBuilder.cpp b/src/Components/Modules/ZoneBuilder.cpp index 452622cf..c1b7a133 100644 --- a/src/Components/Modules/ZoneBuilder.cpp +++ b/src/Components/Modules/ZoneBuilder.cpp @@ -1336,8 +1336,9 @@ namespace Components const auto dir = std::format("zone/{}", Game::Win_GetLanguage()); auto fileList = Utils::IO::ListFiles(dir, false); - for (auto zone : fileList) + for (const auto& entry : fileList) { + auto zone = entry.path().string(); Utils::String::Replace(zone, Utils::String::VA("zone/%s/", Game::Win_GetLanguage()), ""); Utils::String::Replace(zone, ".ff", ""); @@ -1431,8 +1432,10 @@ namespace Components auto list = Utils::IO::ListFiles("zone/techsets", false); int i = 0; int subCount = 0; - for (auto it : list) + for (const auto& entry : list) { + auto it = entry.path().string(); + Utils::String::Replace(it, "zone/techsets/", ""); Utils::String::Replace(it, ".ff", ""); @@ -1555,7 +1558,7 @@ namespace Components // create csv with the techsets in it csvStr.clear(); - for (auto tech : curTechsets_list) + for (const auto& tech : curTechsets_list) { auto mat = ZoneBuilder::FindMaterialByTechnique(tech); if (mat.length() == 0) diff --git a/src/Components/Modules/Zones.cpp b/src/Components/Modules/Zones.cpp index 947fbdfb..2206df39 100644 --- a/src/Components/Modules/Zones.cpp +++ b/src/Components/Modules/Zones.cpp @@ -47,7 +47,7 @@ namespace Components Game::XAssetType currentAssetType = Game::XAssetType::ASSET_TYPE_INVALID; Game::XAssetType previousAssetType = Game::XAssetType::ASSET_TYPE_INVALID; - + bool Zones::LoadFxEffectDef(bool atStreamStart, char* buffer, int size) { int count = 0; @@ -124,7 +124,7 @@ namespace Components } bool result = Game::Load_Stream(atStreamStart, xmodel, size); - + if (Zones::Version() >= VERSION_ALPHA2) { Game::XModel model[2]; // Allocate 2 models, as we exceed the buffer @@ -325,7 +325,7 @@ namespace Components { auto stringCount = (Zones::Version() >= 460) ? 62 : 52; auto arraySize = stringCount * 4; - + // 236 *Game::varXString = reinterpret_cast(varWeaponCompleteDef + 124); Game::Load_XStringArray(false, stringCount); @@ -360,31 +360,31 @@ namespace Components { for (int i = 0; i < 16; i++) { - *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 1028 + (i * 4)); + *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 1028 + (i * 4)); Game::Load_FxEffectDefHandle(false); } for (int i = 0; i < 16; i++) { - *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 1124 + (i * 4)); + *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 1124 + (i * 4)); Game::Load_FxEffectDefHandle(false); } for (int i = 0; i < 16; i++) { - *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 1188 + (i * 4)); + *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 1188 + (i * 4)); Game::Load_FxEffectDefHandle(false); } for (int i = 0; i < 16; i++) { - *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 1316 + (i * 4)); + *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 1316 + (i * 4)); Game::Load_FxEffectDefHandle(false); } for (int i = 0; i < 5; i++) { - *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 1444 + (i * 4)); + *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 1444 + (i * 4)); Game::Load_FxEffectDefHandle(false); } } @@ -421,7 +421,7 @@ namespace Components { auto offset = (Zones::Version() >= 460) ? 1476 : 916; auto count = (Zones::Version() >= 461) ? 58 : (Zones::Version() >= 460) ? 57 : 52; - + // 53 soundalias name references; up to and including 1124 for (int i = 0; i < count; ++i, offset += 4) { @@ -457,7 +457,7 @@ namespace Components if (*reinterpret_cast(varWeaponCompleteDef + 1708) == -1) { *reinterpret_cast(varWeaponCompleteDef + 1708) = Game::DB_AllocStreamPos(3); - *Game::varsnd_alias_list_name = *reinterpret_cast(varWeaponCompleteDef + 1708); + *Game::varsnd_alias_list_name = *reinterpret_cast(varWeaponCompleteDef + 1708); Game::Load_snd_alias_list_nameArray(true, 31); } @@ -472,7 +472,7 @@ namespace Components if (*reinterpret_cast(varWeaponCompleteDef + 1712) == -1) { *reinterpret_cast(varWeaponCompleteDef + 1712) = Game::DB_AllocStreamPos(3); - *Game::varsnd_alias_list_name = *reinterpret_cast(varWeaponCompleteDef + 1712); + *Game::varsnd_alias_list_name = *reinterpret_cast(varWeaponCompleteDef + 1712); Game::Load_snd_alias_list_nameArray(true, 31); } @@ -552,7 +552,7 @@ namespace Components // 1192 for (int offset = 1716; offset <= 1728; offset += 4) { - *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + offset); + *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + offset); Game::Load_FxEffectDefHandle(false); } } @@ -581,7 +581,7 @@ namespace Components static int matOffsets1[] = { 1732, 1736, 1952, 1956, 1960, 1964, 1968, 1972, 1980, 1988, 2000, 2004, 2008, 2012 }; for (int i = 0; i < ARRAYSIZE(matOffsets1); ++i) { - *Game::varMaterialHandle = reinterpret_cast(varWeaponCompleteDef + matOffsets1[i]); + *Game::varMaterialHandle = reinterpret_cast(varWeaponCompleteDef + matOffsets1[i]); Game::Load_MaterialHandle(false); } } @@ -643,7 +643,7 @@ namespace Components { for (int offset = 2332; offset <= 2344; offset += 4) { - *Game::varMaterialHandle = reinterpret_cast(varWeaponCompleteDef + offset); + *Game::varMaterialHandle = reinterpret_cast(varWeaponCompleteDef + offset); Game::Load_MaterialHandle(false); } } @@ -666,10 +666,10 @@ namespace Components if (Zones::Version() >= 460) { - *Game::varPhysCollmapPtr = reinterpret_cast(varWeaponCompleteDef + 2544); + *Game::varPhysCollmapPtr = reinterpret_cast(varWeaponCompleteDef + 2544); Game::Load_PhysCollmapPtr(false); - *Game::varPhysPresetPtr = reinterpret_cast(varWeaponCompleteDef + 2548); + *Game::varPhysPresetPtr = reinterpret_cast(varWeaponCompleteDef + 2548); Game::Load_PhysPresetPtr(false); } else if (Zones::ZoneVersion >= 359) @@ -688,7 +688,7 @@ namespace Components if (Zones::Version() >= 460) { - *Game::varXModelPtr = reinterpret_cast(varWeaponCompleteDef + 2656); + *Game::varXModelPtr = reinterpret_cast(varWeaponCompleteDef + 2656); Game::Load_XModelPtr(false); } else if (Zones::ZoneVersion >= 359) @@ -704,10 +704,10 @@ namespace Components if (Zones::Version() >= 460) { - *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 2664); + *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 2664); Game::Load_FxEffectDefHandle(false); - *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 2668); + *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 2668); Game::Load_FxEffectDefHandle(false); } else if (Zones::ZoneVersion >= 359) @@ -729,10 +729,10 @@ namespace Components if (Zones::Version() >= 460) { - *Game::varsnd_alias_list_name = reinterpret_cast(varWeaponCompleteDef + 2672); + *Game::varsnd_alias_list_name = reinterpret_cast(varWeaponCompleteDef + 2672); Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); - *Game::varsnd_alias_list_name = reinterpret_cast(varWeaponCompleteDef + 2676); + *Game::varsnd_alias_list_name = reinterpret_cast(varWeaponCompleteDef + 2676); Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); } else if (Zones::ZoneVersion >= 359) @@ -754,13 +754,13 @@ namespace Components if (Zones::Version() >= 460) { - *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 2952); + *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 2952); Game::Load_FxEffectDefHandle(false); - *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 2956); + *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 2956); Game::Load_FxEffectDefHandle(false); - *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 2984); + *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 2984); Game::Load_FxEffectDefHandle(false); } else if (Zones::ZoneVersion >= 359) @@ -788,24 +788,24 @@ namespace Components if (Zones::Version() >= 460) { - *Game::varsnd_alias_list_name = reinterpret_cast(varWeaponCompleteDef + 2988); + *Game::varsnd_alias_list_name = reinterpret_cast(varWeaponCompleteDef + 2988); Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); - *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 2992); + *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 2992); Game::Load_FxEffectDefHandle(false); - *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 2996); + *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 2996); Game::Load_FxEffectDefHandle(false); - *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 3000); + *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 3000); Game::Load_FxEffectDefHandle(false); - *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 3004); + *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 3004); Game::Load_FxEffectDefHandle(false); - *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 3008); + *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 3008); Game::Load_FxEffectDefHandle(false); - + *Game::varXString = reinterpret_cast(varWeaponCompleteDef + 3196); Game::Load_XString(false); } @@ -953,37 +953,37 @@ namespace Components if (Zones::Version() >= 460) { - *Game::varTracerDefPtr = reinterpret_cast(varWeaponCompleteDef + 3492 + offsetShift); + *Game::varTracerDefPtr = reinterpret_cast(varWeaponCompleteDef + 3492 + offsetShift); Game::Load_TracerDefPtr(false); - *Game::varTracerDefPtr = reinterpret_cast(varWeaponCompleteDef + 3496 + offsetShift); + *Game::varTracerDefPtr = reinterpret_cast(varWeaponCompleteDef + 3496 + offsetShift); Game::Load_TracerDefPtr(false); - *Game::varTracerDefPtr = reinterpret_cast(varWeaponCompleteDef + 3500 + offsetShift); + *Game::varTracerDefPtr = reinterpret_cast(varWeaponCompleteDef + 3500 + offsetShift); Game::Load_TracerDefPtr(false); - - *Game::varsnd_alias_list_name = reinterpret_cast(varWeaponCompleteDef + 3528 + offsetShift); + + *Game::varsnd_alias_list_name = reinterpret_cast(varWeaponCompleteDef + 3528 + offsetShift); Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); // 2848 - *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 3532 + offsetShift); + *Game::varFxEffectDefHandle = reinterpret_cast(varWeaponCompleteDef + 3532 + offsetShift); Game::Load_FxEffectDefHandle(false); *Game::varXString = reinterpret_cast(varWeaponCompleteDef + 3536 + offsetShift); Game::Load_XString(false); - *Game::varsnd_alias_list_name = reinterpret_cast(varWeaponCompleteDef + 3552 + offsetShift); + *Game::varsnd_alias_list_name = reinterpret_cast(varWeaponCompleteDef + 3552 + offsetShift); Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); - *Game::varsnd_alias_list_name = reinterpret_cast(varWeaponCompleteDef + 3556 + offsetShift); + *Game::varsnd_alias_list_name = reinterpret_cast(varWeaponCompleteDef + 3556 + offsetShift); Game::Load_snd_alias_list_nameArray(false, 4); - *Game::varsnd_alias_list_name = reinterpret_cast(varWeaponCompleteDef + 3572 + offsetShift); + *Game::varsnd_alias_list_name = reinterpret_cast(varWeaponCompleteDef + 3572 + offsetShift); Game::Load_snd_alias_list_nameArray(false, 4); - *Game::varsnd_alias_list_name = reinterpret_cast(varWeaponCompleteDef + 3588 + offsetShift); + *Game::varsnd_alias_list_name = reinterpret_cast(varWeaponCompleteDef + 3588 + offsetShift); Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); - *Game::varsnd_alias_list_name = reinterpret_cast(varWeaponCompleteDef + 3592 + offsetShift); + *Game::varsnd_alias_list_name = reinterpret_cast(varWeaponCompleteDef + 3592 + offsetShift); Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); } else if (Zones::ZoneVersion >= 359) @@ -1049,7 +1049,7 @@ namespace Components { for (int i = 0, offset = 3660 + offsetShift; i < 6; ++i, offset += 4) { - *Game::varsnd_alias_list_name = reinterpret_cast(varWeaponCompleteDef + offset); + *Game::varsnd_alias_list_name = reinterpret_cast(varWeaponCompleteDef + offset); Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); } } @@ -1091,16 +1091,16 @@ namespace Components *Game::varXString = reinterpret_cast(varWeaponCompleteDef + 3732 + offsetShift); Game::Load_XString(false); - *Game::varMaterialHandle = reinterpret_cast(varWeaponCompleteDef + 3740 + offsetShift); + *Game::varMaterialHandle = reinterpret_cast(varWeaponCompleteDef + 3740 + offsetShift); Game::Load_MaterialHandle(false); - *Game::varMaterialHandle = reinterpret_cast(varWeaponCompleteDef + 3744 + offsetShift); + *Game::varMaterialHandle = reinterpret_cast(varWeaponCompleteDef + 3744 + offsetShift); Game::Load_MaterialHandle(false); - *Game::varMaterialHandle = reinterpret_cast(varWeaponCompleteDef + 3748 + offsetShift); + *Game::varMaterialHandle = reinterpret_cast(varWeaponCompleteDef + 3748 + offsetShift); Game::Load_MaterialHandle(false); - *Game::varMaterialHandle = reinterpret_cast(varWeaponCompleteDef + 3752 + offsetShift); + *Game::varMaterialHandle = reinterpret_cast(varWeaponCompleteDef + 3752 + offsetShift); Game::Load_MaterialHandle(false); } else if (Zones::ZoneVersion >= 359) @@ -1441,11 +1441,11 @@ namespace Components Game::Load_XString(false); *reinterpret_cast(varWeaponAttach + 8) = Game::DB_AllocStreamPos(3); - Zones::LoadWeaponAttachStuff(*reinterpret_cast(varWeaponAttach + 8), *reinterpret_cast(varWeaponAttach + 4)); + Zones::LoadWeaponAttachStuff(*reinterpret_cast(varWeaponAttach + 8), *reinterpret_cast(varWeaponAttach + 4)); Game::DB_PopStreamPos(); } - + } bool Zones::LoadMaterialShaderArgumentArray(bool atStreamStart, Game::MaterialShaderArgument* argument, int size) @@ -1455,7 +1455,7 @@ namespace Components Game::MaterialPass* curPass = *Game::varMaterialPass; int count = curPass->perPrimArgCount + curPass->perObjArgCount + curPass->stableArgCount; - + for (int i = 0; i < count && (Zones::ZoneVersion >= VERSION_ALPHA2); ++i) { Game::MaterialShaderArgument* arg = &argument[i]; @@ -1544,13 +1544,13 @@ namespace Components } else if (Zones::Version() == 461) { - static std::unordered_map mapped_constants = + static std::unordered_map mapped_constants = { // mp_raid { 33, 31 }, { 34, 32 }, { 36, 34 }, - { 39, 37 }, + { 39, 37 }, { 40, 38 }, { 42, 40 }, { 43, 41 }, @@ -1582,7 +1582,7 @@ namespace Components // dont know if this applies to 460 too, but I dont have 460 files to test if (!strncmp(techsetName, "wc_unlit_add", 12) || - !strncmp(techsetName, "wc_unlit_multiply", 17) ) + !strncmp(techsetName, "wc_unlit_multiply", 17)) { // fixes glass and water arg->u.codeConst.index = 116; @@ -1653,10 +1653,10 @@ namespace Components { if (arg->u.codeConst.index == 257) { - if (FastFiles::Current() != "mp_conflict" && FastFiles::Current() != "mp_derail_sh" && FastFiles::Current() != "mp_overwatch_sh" && + if (FastFiles::Current() != "mp_conflict" && FastFiles::Current() != "mp_derail_sh" && FastFiles::Current() != "mp_overwatch_sh" && FastFiles::Current() != "mp_con_spring" && FastFiles::Current() != "mp_resistance_sh" && FastFiles::Current() != "mp_lookout_sh") { - const auto varMaterialTechniqueSet = *reinterpret_cast(0x112AE8C); + const auto varMaterialTechniqueSet = *reinterpret_cast(0x112AE8C); if (varMaterialTechniqueSet->name && !strncmp(varMaterialTechniqueSet->name, "mc_", 3)) { // fixes trees @@ -1789,25 +1789,26 @@ namespace Components return result; } - void Zones::FixImageCategory(Game::GfxImage* image) { + void Zones::FixImageCategory(Game::GfxImage* image) + { // CODO makes use of additional enumerator values (9, 10, 11) that don't exist in IW4 // We have to translate them. 9 is for Reflection probes, 11 is for Compass, 10 is for Lightmap switch (image->category) { - case 9: - image->category = Game::ImageCategory::IMG_CATEGORY_AUTO_GENERATED; - break; - case 10: - image->category = Game::ImageCategory::IMG_CATEGORY_LIGHTMAP; - break; - case 11: - image->category = Game::ImageCategory::IMG_CATEGORY_LOAD_FROM_FILE; - break; + case 9: + image->category = Game::ImageCategory::IMG_CATEGORY_AUTO_GENERATED; + break; + case 10: + image->category = Game::ImageCategory::IMG_CATEGORY_LIGHTMAP; + break; + case 11: + image->category = Game::ImageCategory::IMG_CATEGORY_LOAD_FROM_FILE; + break; } - if (image->category > 7 || image->category < 0) { - + if (image->category > 7 || image->category < 0) + { #ifdef DEBUG if (IsDebuggerPresent()) __debugbreak(); #endif @@ -1837,15 +1838,15 @@ namespace Components if (Zones::Version() >= 423) { // don't read assets that are unused by codol, for some retarded reason their header is written in the FF anyway - if (*reinterpret_cast(buffer + (i * 8)) == Game::XAssetType::ASSET_TYPE_CLIPMAP_SP || - *reinterpret_cast(buffer + (i * 8)) == Game::XAssetType::ASSET_TYPE_GAMEWORLD_SP || + if (*reinterpret_cast(buffer + (i * 8)) == Game::XAssetType::ASSET_TYPE_CLIPMAP_SP || + *reinterpret_cast(buffer + (i * 8)) == Game::XAssetType::ASSET_TYPE_GAMEWORLD_SP || *reinterpret_cast(buffer + (i * 8)) == Game::XAssetType::ASSET_TYPE_GAMEWORLD_MP) { *reinterpret_cast(buffer + (i * 8)) = Game::XAssetType::ASSET_TYPE_UI_MAP; *reinterpret_cast(buffer + (i * 8) + 4) = nullptr; } } - + AssetHandler::Relocate(buffer + (i * 16), buffer + (i * 8) + 0, 4); AssetHandler::Relocate(buffer + (i * 16) + 8, buffer + (i * 8) + 4, 4); } @@ -1860,7 +1861,7 @@ namespace Components if (Zones::ZoneVersion >= 359) size += 4; // 446 amd above adds an additional technique if (Zones::ZoneVersion >= 446) size += 4; - + bool result = Game::Load_Stream(atStreamStart, buffer, size); if (Zones::ZoneVersion >= 359) @@ -1888,8 +1889,8 @@ namespace Components if (Zones::Version() >= 446) { - auto lastTechnique = **reinterpret_cast(0x112AEDC); - auto varMaterialTechniqueSet = **reinterpret_cast(0x112B070); + auto lastTechnique = **reinterpret_cast(0x112AEDC); + auto varMaterialTechniqueSet = **reinterpret_cast(0x112B070); // patch last technique to match iw4 varMaterialTechniqueSet->techniques[47] = lastTechnique; @@ -1920,7 +1921,7 @@ namespace Components std::memmove(buffer + 0x50, codol_material + 0x58, 0x10); std::memset(buffer + 0x48 + 5, 0, 3); - + // relocate pointers AssetHandler::Relocate(buffer + 10, buffer, 4); AssetHandler::Relocate(buffer + 0x1B, buffer + 4, 4); @@ -1933,12 +1934,12 @@ namespace Components reinterpret_cast(buffer)->stateBitsEntry[47] = codol_material[0x50]; } else if (Zones::ZoneVersion >= 359) - { + { struct material339_s { char drawSurfBegin[8]; // 4 //int surfaceTypeBits; - const char *name; + const char* name; char drawSurf[6]; union @@ -1987,7 +1988,7 @@ namespace Components int gfxLightMapExtraCount = 0; int* gfxLightMapExtraPtr1 = nullptr; int* gfxLightMapExtraPtr2 = nullptr; - + bool Zones::LoadGfxWorld(bool atStreamStart, char* buffer, int size) { gfxLightMapExtraPtr1 = nullptr; @@ -1996,7 +1997,7 @@ namespace Components if (Zones::Version() >= 460) size += 984; else if (Zones::Version() >= 423) size += 980; else if (Zones::Version() >= 359) size += 968; - + bool result = Game::Load_Stream(atStreamStart, buffer, size); // fix 4 byte difference in FF ver 460+ this turns 460+ into 423 @@ -2005,7 +2006,7 @@ namespace Components std::memmove(buffer + 0x34, buffer + 0x38, size - 0x38); AssetHandler::Relocate(buffer + 0x38, buffer + 0x34, size - 0x38); } - + // fix 12 byte difference in FF ver 423+, this turns 423+ into 359 if (Zones::Version() >= 423) { @@ -2018,7 +2019,7 @@ namespace Components std::memmove(buffer + 0x50 + 0x10, buffer + 0x50 + 0x1C, size - 0x6C); AssetHandler::Relocate(buffer + 0x50 + 0x1C, buffer + 0x50 + 0x10, size - 0x6C); } - + if (Zones::Version() >= 359) { int sunDiff = 8; // Stuff that is part of the sunflare we would overwrite @@ -2123,7 +2124,7 @@ namespace Components { return 19; } - + if (Zones::Version() >= VERSION_ALPHA2) { return 16; @@ -2257,7 +2258,7 @@ namespace Components retn } } - + __declspec(naked) void Zones::GetCurrentAssetTypeStub() { __asm pushad; @@ -2269,7 +2270,7 @@ namespace Components // get asset type mov eax, ds:0x112aa54 mov eax, [eax]; - + // log asset type // mov previousAssetType, currentAssetType; mov currentAssetType, eax; @@ -2294,10 +2295,10 @@ namespace Components if (Zones::Version() >= 446) { for (auto i = 0; i < count; i++) - { + { std::memcpy(buffer + (48 * i) + 0, buffer + (64 * i) + 0, 24); std::memcpy(buffer + (48 * i) + 24, buffer + (64 * i) + 32, 24); - + AssetHandler::Relocate(buffer + (64 * i) + 0, buffer + (48 * i) + 0, 24); AssetHandler::Relocate(buffer + (64 * i) + 32, buffer + (48 * i) + 24, 24); } @@ -2308,14 +2309,14 @@ namespace Components int currentGfxSurfaceIndex = 0; std::vector> gfxSurfaceExtraData; - + int Zones::LoadGfxXSurfaceArray(bool atStreamStart, char* buffer, int size) { currentGfxSurfaceIndex = 0; gfxSurfaceExtraData.clear(); int count = 0; - + if (Zones::Version() >= 423) { size /= 40; @@ -2369,7 +2370,7 @@ namespace Components int Zones::LoadGfxReflectionProbes(bool atStreamStart, char* buffer, int size) { int count = 0; - + if (Zones::Version() >= 446) { size /= 12; @@ -2385,7 +2386,7 @@ namespace Components { auto garbage = *reinterpret_cast(buffer + (20 * i) + 12); auto garbage_count = *reinterpret_cast(buffer + (20 * i) + 16); - + if (garbage != nullptr) { garbage = Game::DB_AllocStreamPos(3); @@ -2435,7 +2436,7 @@ namespace Components __declspec(naked) void Zones::LoadXModelColSurfPtr() { static auto DB_ConvertOffsetToPointer_Address = 0x4A82B0; - + __asm { cmp dword ptr[eax], 0; @@ -2535,7 +2536,7 @@ namespace Components static Game::MapEnts codolMapEnts; static Game::MapEnts* codolMapEntsPtr; - + int Zones::LoadMapEnts(bool atStreamStart, Game::MapEnts* buffer, int size) { if (Zones::Version() >= 446) @@ -2556,16 +2557,16 @@ namespace Components return Game::Load_Stream(atStreamStart, buffer, size); } - + ClipInfo* varClipInfoPtr; void Zones::Load_ClipInfo(bool atStreamStart) { AssertSize(ClipInfo, 64); AssertSize(Game::cplane_s, 20); AssertSize(Game::Bounds, 24); - + Game::Load_Stream(atStreamStart, varClipInfoPtr, sizeof ClipInfo); - + if (varClipInfoPtr->cPlanes) { if (varClipInfoPtr->cPlanes == reinterpret_cast(0xFFFFFFFF)) @@ -2623,7 +2624,7 @@ namespace Components if (varClipInfoPtr->cLeafBrushNodes) { if (varClipInfoPtr->cLeafBrushNodes == reinterpret_cast(0xFFFFFFFF)) - { + { varClipInfoPtr->cLeafBrushNodes = reinterpret_cast(Game::DB_AllocStreamPos(3)); *reinterpret_cast(0x112B130) = varClipInfoPtr->cLeafBrushNodes; Utils::Hook::Call(0x4C29D0)(true, varClipInfoPtr->numCLeafBrushNodes); @@ -2692,13 +2693,13 @@ namespace Components } } } - + int Zones::LoadClipMap(bool atStreamStart) { if (Zones::Version() >= 446) - { + { AssertOffset(codolClipMap_t, pInfo, 72); - + AssertSize(Game::cStaticModel_s, 76); AssertOffset(codolClipMap_t, numStaticModels, 76); AssertOffset(codolClipMap_t, staticModelList, 80); @@ -2707,7 +2708,7 @@ namespace Components Game::Load_Stream(atStreamStart, varClipMap, 256); Game::DB_PushStreamPos(3); - + *Game::varXString = &varClipMap->name; Game::Load_XString(false); @@ -2715,12 +2716,12 @@ namespace Components Load_ClipInfo(false); Game::DB_PushStreamPos(0); - + varClipInfoPtr = varClipMap->pInfo; ClipInfo** assetPointer = nullptr; if (varClipMap->pInfo) { - if (varClipMap->pInfo == reinterpret_cast(0xFFFFFFFF) || + if (varClipMap->pInfo == reinterpret_cast(0xFFFFFFFF) || varClipMap->pInfo == reinterpret_cast(0xFFFFFFFE)) { const auto needsToAllocPointer = varClipMap->pInfo == reinterpret_cast(0xFFFFFFFE); @@ -2842,7 +2843,7 @@ namespace Components } } } - + Game::DB_PopStreamPos(); } @@ -2887,7 +2888,7 @@ namespace Components AssertOffset(codolClipMap_t, dynEntCount[0], 196); AssertOffset(codolClipMap_t, dynEntCount[1], 198); - + // dynamic entity shit for (int i = 0; i < 2; i++) { @@ -2900,7 +2901,7 @@ namespace Components } Game::DB_PushStreamPos(2); - + for (int i = 0; i < 2; i++) { if (varClipMap->dynEntPoseList[i]) @@ -2927,7 +2928,7 @@ namespace Components } Game::DB_PopStreamPos(); - + Game::DB_PopStreamPos(); auto codolMap = new codolClipMap_t; @@ -2935,7 +2936,7 @@ namespace Components auto cancerMap = reinterpret_cast(varClipMap); auto iw4Map = reinterpret_cast(varClipMap); - + memcpy(&iw4Map->planeCount, &codolMap->info.numCPlanes, 8); memcpy(&iw4Map->numStaticModels, &codolMap->numStaticModels, 8); memcpy(&iw4Map->numMaterials, &codolMap->info.numMaterials, 24); @@ -2954,9 +2955,9 @@ namespace Components AssetHandler::Relocate(&cancerMap->numVerts, &iw4Map->vertCount, 52); AssetHandler::Relocate(&cancerMap->info.numBrushes, &iw4Map->numBrushes, 16); AssetHandler::Relocate(&cancerMap->smodelNodeCount, &iw4Map->smodelNodeCount, 48); - + delete codolMap; - + return 1; } else @@ -3027,13 +3028,13 @@ namespace Components std::unordered_map Zones::fileDataMap; std::mutex Zones::fileDataMutex; - + __declspec(naked) int Zones::FS_FOpenFileReadForThreadOriginal(const char*, int*, int) { __asm { sub esp, 0x33C - + push 0x643276 ret } @@ -3060,7 +3061,7 @@ namespace Components { skipFile = true; } - + // if the header seems encrypted... if (fileBuffer.size() > 4 && readSize == retval && !skipFile) { @@ -3084,7 +3085,7 @@ namespace Components register_cipher(&aes_desc); auto aes = find_cipher("aes"); - + // attempt to decrypt the IWI symmetric_CTR ctr_state; ZeroMemory(&ctr_state, sizeof(symmetric_CTR)); @@ -3095,12 +3096,12 @@ namespace Components auto strippedFileName = std::filesystem::path(file).filename().string(); auto nonce = HashCRC32StringInt(strippedFileName, strippedFileName.size()); - + std::uint8_t iv[16]; std::memset(iv, 0, sizeof iv); std::memcpy(iv, &nonce, 4); std::memcpy(iv + 4, &unpackedSize, 4); - + ctr_start(aes, reinterpret_cast(&aesIV[0]), &aesKey[0], sizeof aesKey, 0, CTR_COUNTER_BIG_ENDIAN, &ctr_state); // decrypt image @@ -3118,7 +3119,7 @@ namespace Components readDataSize += blockSize; } - + ctr_done(&ctr_state); if (static_cast(decryptedData[0]) == 0x78) @@ -3145,7 +3146,7 @@ namespace Components // un-read data, file is apparently not encrypted Game::FS_Seek(*filePointer, 0, Game::FS_SEEK_SET); } - + return retval; } @@ -3194,7 +3195,7 @@ namespace Components void Zones::FS_FCloseFileHook(int filePointer) { std::lock_guard _(fileDataMutex); - + FS_FCloseFileOriginal(filePointer); if (const auto itr = fileDataMap.find(filePointer); itr != fileDataMap.end()) @@ -3337,7 +3338,7 @@ namespace Components void Zones::LoadFxWorldAsset(Game::FxWorld** asset) { - Utils::Hook::Call(0x4857F0)(asset); + Utils::Hook::Call(0x4857F0)(asset); if (Zones::Version() >= 423 && asset && *asset) { @@ -3351,7 +3352,7 @@ namespace Components memset(&glassMap, 0, sizeof Game::GameWorldMp); memset(&glassData, 0, sizeof Game::G_GlassData); glassPieces.clear(); - + // generate glassPieces array const auto pieceCount = (*asset)->glassSys.initPieceCount; if (pieceCount > 0) @@ -3399,7 +3400,7 @@ namespace Components } } - return Utils::Hook::Call(0x47A690)(asset); + return Utils::Hook::Call(0x47A690)(asset); } // patch max file amount returned by Sys_ListFiles @@ -3436,7 +3437,7 @@ namespace Components } void Zones::LoadTracerDef(bool atStreamStart, Game::TracerDef* tracer, int size) - { + { if (Zones::Version() >= 460) { size = 116; @@ -3444,7 +3445,7 @@ namespace Components Game::Load_Stream(atStreamStart, tracer, size); *Game::varFxEffectDefHandle = nullptr; - + if (Zones::Version() >= 460) { *Game::varFxEffectDefHandle = reinterpret_cast(tracer + 8); @@ -3460,10 +3461,10 @@ namespace Components { Game::Load_FxEffectDefHandle(false); } - + Game::DB_PopStreamPos(); } - + char* Zones::ParseShellShock_Stub(const char** data_p) { auto token = Game::Com_Parse(data_p); @@ -3479,71 +3480,74 @@ namespace Components { Zones::ZoneVersion = 0; - Command::Add("decryptImages", [](Command::Params*) + if (ZoneBuilder::IsEnabled()) { - auto images = FileSystem::GetSysFileList("iw4x/images", "iwi"); - Logger::Print("decrypting {} images...\n", images.size()); - - for (auto& image : images) + Command::Add("decryptImages", [](Command::Params*) { - char* buffer = nullptr; - auto fileLength = Game::FS_ReadFile(Utils::String::VA("images/%s", image.data()), &buffer); + auto images = FileSystem::GetSysFileList("iw4x/images", "iwi"); + Logger::Print("decrypting {} images...\n", images.size()); - if (fileLength && buffer) + for (auto& image : images) { - if (!std::filesystem::exists("raw/images")) - { - std::filesystem::create_directories("raw/images"); - } + char* buffer = nullptr; + auto fileLength = Game::FS_ReadFile(Utils::String::Format("images/{}", image), &buffer); - if (!std::filesystem::exists(Utils::String::VA("raw/images/%s", image.data()))) + if (fileLength && buffer) { - const auto fp = fopen(Utils::String::VA("raw/images/%s", image.data()), "wb"); - if (fp) + if (!std::filesystem::exists("raw/images")) { - fwrite(buffer, fileLength, 1, fp); - fclose(fp); + std::filesystem::create_directories("raw/images"); } + + if (!std::filesystem::exists(Utils::String::Format("raw/images/{}", image))) + { + const auto fp = fopen(Utils::String::Format("raw/images/{}", image), "wb"); + if (fp) + { + fwrite(buffer, fileLength, 1, fp); + fclose(fp); + } + } + + Game::FS_FreeFile(buffer); } - - Game::FS_FreeFile(buffer); } - } - Logger::Print("decrypted {} images!\n", images.size()); - }); + Logger::Print("decrypted {} images!\n", images.size()); + }); - Command::Add("decryptSounds", []([[maybe_unused]] Command::Params* params) - { - auto sounds = FileSystem::GetSysFileList("iw4x/sound", "iwi"); - Logger::Print("decrypting {} sounds...\n", sounds.size()); - - for (auto& sound : sounds) + Command::Add("decryptSounds", []([[maybe_unused]] Command::Params* params) { - char* buffer = nullptr; - auto len = Game::FS_ReadFile(Utils::String::Format("sound/{}", sound), &buffer); + auto sounds = FileSystem::GetSysFileList("iw4x/sound", "iwi"); + Logger::Print("decrypting {} sounds...\n", sounds.size()); - if (len && buffer) + for (auto& sound : sounds) { - auto path = std::filesystem::path(sound.data()); - std::filesystem::create_directories("raw/sound" / path.parent_path()); + char* buffer = nullptr; + auto len = Game::FS_ReadFile(Utils::String::Format("sound/{}", sound), &buffer); - if (!std::filesystem::exists(std::format("raw/sound/{}", sound))) + if (len && buffer) { - FILE* fp; - if (!fopen_s(&fp, Utils::String::Format("raw/sound/{}", sound), "wb") && fp) + auto path = std::filesystem::path(sound.data()); + std::filesystem::create_directories("raw/sound" / path.parent_path()); + + if (!std::filesystem::exists(std::format("raw/sound/{}", sound))) { - fwrite(buffer, len, 1, fp); - fclose(fp); + FILE* fp; + if (!fopen_s(&fp, Utils::String::Format("raw/sound/{}", sound), "wb") && fp) + { + fwrite(buffer, len, 1, fp); + fclose(fp); + } } + + Game::FS_FreeFile(buffer); } - - Game::FS_FreeFile(buffer); } - } - Logger::Print("decrypted {} sounds!\n", sounds.size()); - }); + Logger::Print("decrypted {} sounds!\n", sounds.size()); + }); + } // patch max filecount Sys_ListFiles can return Utils::Hook::Set(0x45A66B, (maxFileCount + fileCountMultiplier) * 4); @@ -3552,7 +3556,7 @@ namespace Components Utils::Hook::Set(0x45A8CE, maxFileCount); Utils::Hook(0x45A806, RelocateFileCount, HOOK_CALL).install()->quick(); Utils::Hook(0x45A6A0, RelocateFileCount, HOOK_CALL).install()->quick(); - + #ifndef DEBUG // Ignore missing soundaliases for now // TODO: Include them in the dependency zone! @@ -3566,11 +3570,14 @@ namespace Components Utils::Hook::Set(0x418B31, 0x72); // encrypted images hooks - Utils::Hook(0x462000, Zones::FS_FCloseFileHook, HOOK_JUMP).install()->quick(); - Utils::Hook(0x4A04C0, Zones::FS_ReadHook, HOOK_JUMP).install()->quick(); - Utils::Hook(0x643270, Zones::FS_FOpenFileReadForThreadHook, HOOK_JUMP).install()->quick(); - Utils::Hook(0x4A63D0, Zones::FS_SeekHook, HOOK_JUMP).install()->quick(); - + if (ZoneBuilder::IsEnabled()) + { + Utils::Hook(0x462000, Zones::FS_FCloseFileHook, HOOK_JUMP).install()->quick(); + Utils::Hook(0x4A04C0, Zones::FS_ReadHook, HOOK_JUMP).install()->quick(); + Utils::Hook(0x643270, Zones::FS_FOpenFileReadForThreadHook, HOOK_JUMP).install()->quick(); + Utils::Hook(0x4A63D0, Zones::FS_SeekHook, HOOK_JUMP).install()->quick(); + } + // asset hooks Utils::Hook(0x47146D, Zones::LoadTracerDef, HOOK_CALL).install()->quick(); Utils::Hook(0x4714A3, Zones::LoadTracerDefFxEffect, HOOK_JUMP).install()->quick(); @@ -3624,7 +3631,7 @@ namespace Components Utils::Hook(0x4B4EA1, Zones::ParseShellShock_Stub, HOOK_CALL).install()->quick(); Utils::Hook(0x4B4F0C, Zones::ParseShellShock_Stub, HOOK_CALL).install()->quick(); - + Utils::Hook(0x4F4D3B, [] { if (Zones::ZoneVersion >= VERSION_ALPHA3) @@ -3639,7 +3646,7 @@ namespace Components }, HOOK_CALL).install()->quick(); // Change stream for images - Utils::Hook(0x4D3225, [] () + Utils::Hook(0x4D3225, []() { Game::DB_PushStreamPos((Zones::ZoneVersion >= 332) ? 3 : 0); }, HOOK_CALL).install()->quick(); @@ -3651,7 +3658,7 @@ namespace Components // Easy dirty disk debugging Utils::Hook::Set(0x4CF7F0, 0xC3CC); // disable _invoke_watson to allow debugging - Utils::Hook::Set(0x6B9602,0xCCCC); + Utils::Hook::Set(0x6B9602, 0xCCCC); #endif } } diff --git a/src/Utils/IO.cpp b/src/Utils/IO.cpp index c8687e8b..e3606955 100644 --- a/src/Utils/IO.cpp +++ b/src/Utils/IO.cpp @@ -97,22 +97,22 @@ namespace Utils::IO return std::filesystem::is_empty(directory); } - std::vector ListFiles(const std::filesystem::path& directory, const bool recursive) + std::vector ListFiles(const std::filesystem::path& directory, const bool recursive) { - std::vector files; + std::vector files; if (recursive) { for (auto& file : std::filesystem::recursive_directory_iterator(directory)) { - files.push_back(file.path().generic_string()); + files.push_back(file); } } else { for (auto& file : std::filesystem::directory_iterator(directory)) { - files.push_back(file.path().generic_string()); + files.push_back(file); } } diff --git a/src/Utils/IO.hpp b/src/Utils/IO.hpp index a0d4e39c..4d31ec31 100644 --- a/src/Utils/IO.hpp +++ b/src/Utils/IO.hpp @@ -11,5 +11,5 @@ namespace Utils::IO bool CreateDir(const std::string& dir); [[nodiscard]] bool DirectoryExists(const std::filesystem::path& directory); [[nodiscard]] bool DirectoryIsEmpty(const std::filesystem::path& directory); - [[nodiscard]] std::vector ListFiles(const std::filesystem::path& directory, bool recursive = false); + [[nodiscard]] std::vector ListFiles(const std::filesystem::path& directory, bool recursive = false); } diff --git a/src/Utils/Thread.cpp b/src/Utils/Thread.cpp index c6e5423c..70f81997 100644 --- a/src/Utils/Thread.cpp +++ b/src/Utils/Thread.cpp @@ -78,45 +78,4 @@ namespace Utils::Thread return ids; } - - void ForEachThread(const std::function& callback) - { - const auto ids = GetThreadIds(); - - for (const auto& id : ids) - { - auto* const thread = OpenThread(THREAD_ALL_ACCESS, FALSE, id); - if (thread != nullptr) - { - const auto _ = gsl::finally([thread]() - { - CloseHandle(thread); - }); - - callback(thread); - } - } - } - - void SuspendOtherThreads() - { - ForEachThread([](const HANDLE thread) - { - if (GetThreadId(thread) != GetCurrentThreadId()) - { - SuspendThread(thread); - } - }); - } - - void ResumeOtherThreads() - { - ForEachThread([](const HANDLE thread) - { - if (GetThreadId(thread) != GetCurrentThreadId()) - { - ResumeThread(thread); - } - }); - } } diff --git a/src/Utils/Thread.hpp b/src/Utils/Thread.hpp index 084eb2ce..02e76277 100644 --- a/src/Utils/Thread.hpp +++ b/src/Utils/Thread.hpp @@ -16,8 +16,4 @@ namespace Utils::Thread } std::vector GetThreadIds(); - void ForEachThread(const std::function& callback); - - void SuspendOtherThreads(); - void ResumeOtherThreads(); }