IW5 DLC Prep (#814)

Co-authored-by: FutureRave <edoardo.sanguineti222@gmail.com>
This commit is contained in:
Louve 2023-03-17 13:46:29 +01:00 committed by GitHub
parent 6bae9958e0
commit 678dc349dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 466 additions and 534 deletions

View File

@ -2,7 +2,10 @@
namespace Components 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() __declspec(naked) void ArenaLength::ArenaMapOffsetHook1()
{ {
@ -57,16 +60,28 @@ namespace Components
ArenaLength::ArenaLength() ArenaLength::ArenaLength()
{ {
// Reallocate array // Reallocate ui_arenaInfos
Utils::Hook::Set<Game::newMapArena_t*>(0x417807, &ArenaLength::NewArenas[0]); Utils::Hook::Set<char**>(0x4A95F0 + 3, ArenaLength::NewArenaInfos);
Utils::Hook::Set<Game::newMapArena_t*>(0x420717, &ArenaLength::NewArenas[0]); Utils::Hook::Set<char**>(0x4A9620 + 3, ArenaLength::NewArenaInfos);
Utils::Hook::Set<Game::newMapArena_t*>(0x49BD22, &ArenaLength::NewArenas[0]); Utils::Hook::Set<char**>(0x4A9653 + 3, ArenaLength::NewArenaInfos);
Utils::Hook::Set<Game::newMapArena_t*>(0x4A9649, &ArenaLength::NewArenas[0]); Utils::Hook::Set<char**>(0x4A9684 + 3, ArenaLength::NewArenaInfos);
Utils::Hook::Set<Game::newMapArena_t*>(0x4A97C2, &ArenaLength::NewArenas[0]); Utils::Hook::Set<char**>(0x4A96B7 + 3, ArenaLength::NewArenaInfos);
Utils::Hook::Set<Game::newMapArena_t*>(0x4D077E, &ArenaLength::NewArenas[0]); Utils::Hook::Set<char**>(0x4A97B3 + 3, ArenaLength::NewArenaInfos);
Utils::Hook::Set<Game::newMapArena_t*>(0x630B00, &ArenaLength::NewArenas[0]); Utils::Hook::Set<char**>(0x630A9A + 3, ArenaLength::NewArenaInfos);
Utils::Hook::Set<Game::newMapArena_t*>(0x630B2E, &ArenaLength::NewArenas[0]);
Utils::Hook::Set<Game::newMapArena_t*>(0x632782, &ArenaLength::NewArenas[0]); // Increase size - patch max arena count
Utils::Hook::Set<unsigned int>(0x630AA2 + 1, NEW_ARENA_COUNT);
// Reallocate sharedUiInfo.mapList
Utils::Hook::Set<Game::newMapArena_t*>(0x417807, ArenaLength::NewArenas);
Utils::Hook::Set<Game::newMapArena_t*>(0x420717, ArenaLength::NewArenas);
Utils::Hook::Set<Game::newMapArena_t*>(0x49BD22, ArenaLength::NewArenas);
Utils::Hook::Set<Game::newMapArena_t*>(0x4A9649, ArenaLength::NewArenas);
Utils::Hook::Set<Game::newMapArena_t*>(0x4A97C2, ArenaLength::NewArenas);
Utils::Hook::Set<Game::newMapArena_t*>(0x4D077E, ArenaLength::NewArenas);
Utils::Hook::Set<Game::newMapArena_t*>(0x630B00, ArenaLength::NewArenas);
Utils::Hook::Set<Game::newMapArena_t*>(0x630B2E, ArenaLength::NewArenas);
Utils::Hook::Set<Game::newMapArena_t*>(0x632782, ArenaLength::NewArenas);
Utils::Hook::Set<char*>(0x4A967A, ArenaLength::NewArenas[0].description); Utils::Hook::Set<char*>(0x4A967A, ArenaLength::NewArenas[0].description);
Utils::Hook::Set<char*>(0x4A96AD, ArenaLength::NewArenas[0].mapimage); Utils::Hook::Set<char*>(0x4A96AD, ArenaLength::NewArenas[0].mapimage);
@ -109,12 +124,7 @@ namespace Components
Utils::Hook(0x632799, ArenaLength::ArenaMapOffsetHook3, HOOK_JUMP).install()->quick(); Utils::Hook(0x632799, ArenaLength::ArenaMapOffsetHook3, HOOK_JUMP).install()->quick();
Utils::Hook(0x4064B2, ArenaLength::ArenaMapOffsetHook4, HOOK_JUMP).install()->quick(); Utils::Hook(0x4064B2, ArenaLength::ArenaMapOffsetHook4, HOOK_JUMP).install()->quick();
Utils::Hook::Set<BYTE>(0x4A95F8, 32); Utils::Hook::Set<BYTE>(0x4A95F8, sizeof(Game::newMapArena_t::mapName));
Utils::Hook::Set<int>(0x42F22B, offsetof(Game::newMapArena_t, mapName) - offsetof(Game::newMapArena_t, other)); Utils::Hook::Set<int>(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<std::uint32_t>(0x630AA3, arenaCount);
} }
} }

View File

@ -7,7 +7,8 @@ namespace Components
public: public:
ArenaLength(); ArenaLength();
static Game::newMapArena_t NewArenas[128]; static Game::newMapArena_t NewArenas[];
static char* NewArenaInfos[];
private: private:
static void ArenaMapOffsetHook1(); static void ArenaMapOffsetHook1();

View File

@ -571,210 +571,6 @@ namespace Components
AssetHandler::OnLoad([](Game::XAssetType type, Game::XAssetHeader asset, std::string name, bool*) 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<json11::Json> 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<json11::Json> 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<json11::Json> techniques;
for (int technique = 0; technique < 48; technique++)
{
auto curTech = techset->techniques[technique];
if (curTech)
{
std::vector<json11::Json> passDataArray;
for (int pass = 0; pass < curTech->passCount; pass++)
{
auto curPass = &curTech->passArray[pass];
std::vector<json11::Json> 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<float> 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<int>(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<bool>() && type == Game::XAssetType::ASSET_TYPE_XMODEL && name == "void") if (Dvar::Var("r_noVoid").get<bool>() && type == Game::XAssetType::ASSET_TYPE_XMODEL && name == "void")
{ {
asset.model->numLods = 0; asset.model->numLods = 0;

View File

@ -10,6 +10,8 @@ namespace Components
symmetric_CTR FastFiles::CurrentCTR; symmetric_CTR FastFiles::CurrentCTR;
std::vector<std::string> FastFiles::ZonePaths; std::vector<std::string> FastFiles::ZonePaths;
Dvar::Var FastFiles::g_loadingInitialZones;
bool FastFiles::IsIW4xZone = false; bool FastFiles::IsIW4xZone = false;
bool FastFiles::StreamRead = false; bool FastFiles::StreamRead = false;
@ -133,8 +135,10 @@ namespace Components
// This has to be called only once, when the game starts // 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<Game::XZoneInfo> data; std::vector<Game::XZoneInfo> data;
Utils::Merge(&data, zoneInfo, zoneCount); Utils::Merge(&data, zoneInfo, zoneCount);
@ -152,7 +156,7 @@ namespace Components
} }
// This has to be called every time the cgame is reinitialized // 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<Game::XZoneInfo> data; std::vector<Game::XZoneInfo> data;
Utils::Merge(&data, zoneInfo, zoneCount); Utils::Merge(&data, zoneInfo, zoneCount);
@ -177,7 +181,7 @@ namespace Components
return FastFiles::LoadLocalizeZones(data.data(), data.size(), sync); 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<Game::XZoneInfo> data; std::vector<Game::XZoneInfo> data;
Utils::Merge(&data, zoneInfo, zoneCount); Utils::Merge(&data, zoneInfo, zoneCount);
@ -191,7 +195,7 @@ namespace Components
} }
// This has to be called every time fastfiles are loaded :D // 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<Game::XZoneInfo> data; std::vector<Game::XZoneInfo> data;
Utils::Merge(&data, zoneInfo, zoneCount); Utils::Merge(&data, zoneInfo, zoneCount);
@ -213,6 +217,11 @@ namespace Components
data.push_back(info); data.push_back(info);
Game::DB_LoadXAssets(data.data(), data.size(), sync); 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 // Name is a bit weird, due to FasFileS and ExistS :P
@ -394,7 +403,7 @@ namespace Components
return Utils::Hook::Call<int(unsigned char*, int, unsigned char*)>(0x5BA240)(buffer, length, ivValue); return Utils::Hook::Call<int(unsigned char*, int, unsigned char*)>(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) if (Zones::Version() >= 319)
{ {
@ -436,7 +445,7 @@ namespace Components
return std::min(partialProgress + (currentProgress * singleProgress), 1.0f); 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::CurrentZone = 0;
FastFiles::MaxZones = zoneCount; FastFiles::MaxZones = zoneCount;
@ -500,6 +509,7 @@ namespace Components
FastFiles::FastFiles() FastFiles::FastFiles()
{ {
Dvar::Register<bool>("ui_zoneDebug", false, Game::DVAR_ARCHIVE, "Display current loaded zone."); Dvar::Register<bool>("ui_zoneDebug", false, Game::DVAR_ARCHIVE, "Display current loaded zone.");
g_loadingInitialZones = Dvar::Register<bool>("g_loadingInitialZones", true, Game::DVAR_NONE, "Is loading initial zones");
// Fix XSurface assets // Fix XSurface assets
Utils::Hook(0x0048E8A5, FastFiles::Load_XSurfaceArray, HOOK_CALL).install()->quick(); 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<bool>()) return; if (FastFiles::Current().empty() || !Dvar::Var("ui_zoneDebug").get<bool>()) return;
auto* const font = Game::R_RegisterFont("fonts/consoleFont", 0); 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<std::uint32_t*>(0x10AA5D8); auto FFTotalSize = *reinterpret_cast<std::uint32_t*>(0x10AA5D8);
auto FFCurrentOffset = *reinterpret_cast<std::uint32_t*>(0x10AA608); auto FFCurrentOffset = *reinterpret_cast<std::uint32_t*>(0x10AA608);
@ -617,11 +627,11 @@ namespace Components
while (!Game::Sys_IsDatabaseReady()) std::this_thread::sleep_for(100ms); while (!Game::Sys_IsDatabaseReady()) std::this_thread::sleep_for(100ms);
}); });
#ifdef DEBUG #ifdef _DEBUG
// ZoneBuilder debugging // ZoneBuilder debugging
Utils::IO::WriteFile("userraw/logs/iw4_reads.log", "", false); Utils::IO::WriteFile("userraw/logs/iw4_reads.log", "", false);
Utils::Hook(0x4A8FA0, FastFiles::LogStreamRead, HOOK_JUMP).install()->quick(); Utils::Hook(0x4A8FA0, FastFiles::LogStreamRead, HOOK_JUMP).install()->quick();
Utils::Hook(0x4BCB62, []() Utils::Hook(0x4BCB62, []
{ {
FastFiles::StreamRead = true; FastFiles::StreamRead = true;
Utils::Hook::Call<void(bool)>(0x4B8DB0)(true); // currently set to Load_GfxWorld Utils::Hook::Call<void(bool)>(0x4B8DB0)(true); // currently set to Load_GfxWorld

View File

@ -40,6 +40,8 @@ namespace Components
static char LastByteRead; static char LastByteRead;
static Dvar::Var g_loadingInitialZones;
static Key CurrentKey; static Key CurrentKey;
static std::vector<std::string> ZonePaths; static std::vector<std::string> ZonePaths;
static const char* GetZoneLocation(const char* file); static const char* GetZoneLocation(const char* file);

View File

@ -11,6 +11,7 @@ namespace Components
std::string Maps::CurrentMainZone; std::string Maps::CurrentMainZone;
std::vector<std::pair<std::string, std::string>> Maps::DependencyList; std::vector<std::pair<std::string, std::string>> Maps::DependencyList;
std::vector<std::string> Maps::CurrentDependencies; std::vector<std::string> Maps::CurrentDependencies;
std::vector<std::string> Maps::FoundCustomMaps;
Dvar::Var Maps::RListSModels; Dvar::Var Maps::RListSModels;
@ -105,8 +106,8 @@ namespace Components
if (Maps::UserMap.isValid()) if (Maps::UserMap.isValid())
{ {
const std::string mapname = Maps::UserMap.getName(); const auto mapname = Maps::UserMap.getName();
const auto* arena = Utils::String::VA("usermaps/%s/%s.arena", mapname.data(), mapname.data()); const auto arena = GetArenaPath(mapname);
if (Utils::IO::FileExists(arena)) if (Utils::IO::FileExists(arena))
{ {
@ -338,12 +339,33 @@ namespace Components
return (Utils::String::StartsWith(entity, "dyn_") || Utils::String::StartsWith(entity, "node_") || Utils::String::StartsWith(entity, "actor_")); return (Utils::String::StartsWith(entity, "dyn_") || Utils::String::StartsWith(entity, "node_") || Utils::String::StartsWith(entity, "actor_"));
} }
std::unordered_map<std::string, std::string> Maps::ParseCustomMapArena(const std::string& singleMapArena)
{
static const std::regex regex(" (\\w*) *\"?((?:\\w| )*)\"?");
std::unordered_map<std::string, std::string> 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) Maps::MapDependencies Maps::GetDependenciesForMap(const std::string& map)
{ {
std::string teamAxis = "opforce_composite"; std::string teamAxis = "opforce_composite";
std::string teamAllies = "us_army"; std::string teamAllies = "us_army";
Maps::MapDependencies dependencies{}; Maps::MapDependencies dependencies;
// True by default - cause some maps won't have an arenafile entry // True by default - cause some maps won't have an arenafile entry
dependencies.requiresTeamZones = true; 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)); 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<std::string>& Maps::GetCustomMaps()
{
return FoundCustomMaps;
}
Game::XAssetEntry* Maps::GetAssetEntryPool() Game::XAssetEntry* Maps::GetAssetEntryPool()
{ {
return *reinterpret_cast<Game::XAssetEntry**>(0x48E6F4); return *reinterpret_cast<Game::XAssetEntry**>(0x48E6F4);
@ -696,13 +752,9 @@ namespace Components
Maps::AddDlc({ 1, "Stimulus Pack", {"mp_complex", "mp_compact", "mp_storm", "mp_overgrown", "mp_crash"} }); 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({ 2, "Resurgence Pack", {"mp_abandon", "mp_vacant", "mp_trailerpark", "mp_strike", "mp_fuel2"} });
Maps::AddDlc({ 3, "Nuketown", {"mp_nuked"} }); 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, "Classics Pack #1", {"mp_cross_fire", "mp_cargoship", "mp_bloc"} }); 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, "Classics Pack #2", {"mp_killhouse", "mp_bog_sh"} }); 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::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::UpdateDlcStatus(); Maps::UpdateDlcStatus();

View File

@ -63,6 +63,12 @@ namespace Components
static bool IsCustomMap(); static bool IsCustomMap();
static bool IsUserMap(const std::string& mapname); static bool IsUserMap(const std::string& mapname);
static void ScanCustomMaps();
static std::string GetArenaPath(const std::string& mapName);
static const std::vector<std::string>& GetCustomMaps();
static std::unordered_map<std::string, std::string> ParseCustomMapArena(const std::string& singleMapArena);
private: private:
class DLC class DLC
{ {
@ -85,6 +91,7 @@ namespace Components
static std::vector<std::pair<std::string, std::string>> DependencyList; static std::vector<std::pair<std::string, std::string>> DependencyList;
static std::vector<std::string> CurrentDependencies; static std::vector<std::string> CurrentDependencies;
static std::vector<std::string> FoundCustomMaps;
static Dvar::Var RListSModels; static Dvar::Var RListSModels;

View File

@ -527,18 +527,21 @@ namespace Components
std::vector<std::string> fastFiles; std::vector<std::string> fastFiles;
if (std::strcmp(param->get(1), "all") == 0) 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)); 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)); 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)); fastFiles.emplace_back(f.substr(5, f.length() - 8));
} }
} }

View File

@ -17,6 +17,7 @@ namespace Components
Dvar::Var Renderer::r_playerDrawDebugDistance; Dvar::Var Renderer::r_playerDrawDebugDistance;
Dvar::Var Renderer::r_forceTechnique; Dvar::Var Renderer::r_forceTechnique;
Dvar::Var Renderer::r_listSamplers; Dvar::Var Renderer::r_listSamplers;
Dvar::Var Renderer::r_drawLights;
float cyan[4] = { 0.0f, 0.5f, 0.5f, 1.0f }; float cyan[4] = { 0.0f, 0.5f, 0.5f, 1.0f };
float red[4] = { 1.0f, 0.0f, 0.0f, 1.0f }; float red[4] = { 1.0f, 0.0f, 0.0f, 1.0f };
@ -183,11 +184,9 @@ namespace Components
{ {
if (!r_drawTriggers.get<bool>()) return; if (!r_drawTriggers.get<bool>()) return;
auto entities = Game::g_entities;
for (std::size_t i = 0; i < Game::MAX_GENTITIES; ++i) 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) if (ent->r.isInUse)
{ {
@ -264,7 +263,7 @@ namespace Components
if (!val) return; if (!val) return;
auto clientNum = Game::CG_GetClientNum(); auto clientNum = Game::CG_GetClientNum();
Game::gentity_t* clientEntity = &Game::g_entities[clientNum]; auto* clientEntity = &Game::g_entities[clientNum];
// Ingame only & player only // Ingame only & player only
if (!Game::CL_IsCgameInitialized() || clientEntity->client == nullptr) if (!Game::CL_IsCgameInitialized() || clientEntity->client == nullptr)
@ -358,7 +357,7 @@ namespace Components
if (!val) return; if (!val) return;
auto clientNum = Game::CG_GetClientNum(); auto clientNum = Game::CG_GetClientNum();
Game::gentity_t* clientEntity = &Game::g_entities[clientNum]; auto* clientEntity = &Game::g_entities[clientNum];
// Ingame only & player only // Ingame only & player only
if (!Game::CL_IsCgameInitialized() || clientEntity->client == nullptr) if (!Game::CL_IsCgameInitialized() || clientEntity->client == nullptr)
@ -538,6 +537,82 @@ namespace Components
} }
} }
void Renderer::DrawPrimaryLights()
{
if (!r_drawLights.get<bool>())
{
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) int Renderer::FixSunShadowPartitionSize(Game::GfxCamera* camera, Game::GfxSunShadowMapMetrics* mapMetrics, Game::GfxSunShadow* sunShadow, Game::GfxSunShadowClip* clip, float* partitionFraction)
{ {
auto result = Utils::Hook::Call<int(Game::GfxCamera*, Game::GfxSunShadowMapMetrics*, Game::GfxSunShadow*, Game::GfxSunShadowClip*, float*)>(0x5463B0)(camera, mapMetrics, sunShadow, clip, partitionFraction); auto result = Utils::Hook::Call<int(Game::GfxCamera*, Game::GfxSunShadowMapMetrics*, Game::GfxSunShadow*, Game::GfxSunShadowClip*, float*)>(0x5463B0)(camera, mapMetrics, sunShadow, clip, partitionFraction);
@ -567,6 +642,7 @@ namespace Components
DebugDrawTriggers(); DebugDrawTriggers();
ForceTechnique(); ForceTechnique();
ListSamplers(); ListSamplers();
DrawPrimaryLights();
} }
}, Scheduler::Pipeline::RENDERER); }, 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_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_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_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");
}); });
} }

View File

@ -42,6 +42,7 @@ namespace Components
static void DebugDrawAABBTrees(); static void DebugDrawAABBTrees();
static void ForceTechnique(); static void ForceTechnique();
static void ListSamplers(); static void ListSamplers();
static void DrawPrimaryLights();
static int FixSunShadowPartitionSize(Game::GfxCamera* camera, Game::GfxSunShadowMapMetrics* mapMetrics, Game::GfxSunShadow* sunShadow, Game::GfxSunShadowClip* clip, float* partitionFraction); 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_playerDrawDebugDistance;
static Dvar::Var r_forceTechnique; static Dvar::Var r_forceTechnique;
static Dvar::Var r_listSamplers; static Dvar::Var r_listSamplers;
static Dvar::Var r_drawLights;
}; };
} }

View File

@ -129,7 +129,7 @@ namespace Components
fld ds:739FD0h fld ds:739FD0h
mov eax, 41A0D7h mov eax, 41A0D7h
jmp eax; jmp eax
} }
} }
@ -279,74 +279,81 @@ namespace Components
unsigned int UIFeeder::GetMapCount() unsigned int UIFeeder::GetMapCount()
{ {
Game::UI_UpdateArenas(); return Maps::GetCustomMaps().size();
Game::UI_SortArenas();
return *Game::arenaCount;
} }
const char* UIFeeder::GetMapText(unsigned int index, int /*column*/) const char* UIFeeder::GetMapText(unsigned int index, int /*column*/)
{ {
Game::UI_UpdateArenas(); const auto& maps = Maps::GetCustomMaps();
Game::UI_SortArenas(); if (index < maps.size())
if (index < static_cast<unsigned int>(*Game::arenaCount))
{ {
return Game::SEH_StringEd_GetString(ArenaLength::NewArenas[reinterpret_cast<int*>(0x633E934)[index]].uiName); return maps.at(index).data();
} }
#ifdef DEBUG
if (IsDebuggerPresent())
{
__debugbreak();
}
#endif
return ""; return "";
} }
void UIFeeder::SelectMap(unsigned int index) void UIFeeder::SelectMap(unsigned int index)
{ {
Game::UI_UpdateArenas(); const auto& maps = Maps::GetCustomMaps();
Game::UI_SortArenas();
if (index < static_cast<unsigned int>(*Game::arenaCount)) if (index < maps.size())
{ {
index = reinterpret_cast<int*>(0x633E934)[index]; std::string mapName = maps[index];
const char* map_name = ArenaLength::NewArenas[index].mapName;
const char* long_name = ArenaLength::NewArenas[index].uiName;
const char* description = ArenaLength::NewArenas[index].description;
UIMapName.set(map_name); std::string longName = mapName;
UIMapLong.set(Game::SEH_StringEd_GetString(long_name)); std::string description = "(Missing arena file!)";
UIMapDesc.set(Game::SEH_StringEd_GetString(description));
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) 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<std::string>(); const auto* mapname = Dvar::Var("ui_map_name").get<const char*>();
Dvar::Var("ui_mapname").set(mapname); if (*mapname)
Utils::Hook::Call<void(const char*)>(0x503B50)(mapname.data()); // Party_SetDisplayMapName {
Game::Dvar_SetString(*Game::ui_mapname, mapname);
Utils::Hook::Call<void(const char*)>(0x503B50)(mapname); // Party_SetDisplayMapName
}
} }
void UIFeeder::ApplyInitialMap([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info) void UIFeeder::ApplyInitialMap([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{ {
const auto* mapname = (*Game::ui_mapname)->current.string; Maps::ScanCustomMaps();
Select(60.0f, 0); // Will select nothing if there's no map
Game::UI_UpdateArenas();
Game::UI_SortArenas();
for (unsigned int i = 0; i < static_cast<unsigned int>(*Game::arenaCount); ++i)
{
if (!std::strcmp(ArenaLength::NewArenas[i].mapName, mapname))
{
for (unsigned int j = 0; j < static_cast<unsigned int>(*Game::arenaCount); ++j)
{
if (reinterpret_cast<unsigned int*>(0x633E934)[j] == i)
{
SelectMap(j);
Select(60.0f, j);
break;
}
}
break;
}
}
} }
int UIFeeder::CheckSelection(int feeder) int UIFeeder::CheckSelection(int feeder)
@ -387,8 +394,8 @@ namespace Components
Events::OnDvarInit([] Events::OnDvarInit([]
{ {
UIMapLong = Dvar::Register<const char*>("ui_map_long", "Afghan", Game::DVAR_NONE, ""); UIMapLong = Dvar::Register<const char*>("ui_map_long", "", Game::DVAR_NONE, "");
UIMapName = Dvar::Register<const char*>("ui_map_name", "mp_afghan", Game::DVAR_NONE, ""); UIMapName = Dvar::Register<const char*>("ui_map_name", "", Game::DVAR_NONE, "");
UIMapDesc = Dvar::Register<const char*>("ui_map_desc", "", Game::DVAR_NONE, ""); UIMapDesc = Dvar::Register<const char*>("ui_map_desc", "", Game::DVAR_NONE, "");
}); });

View File

@ -1336,8 +1336,9 @@ namespace Components
const auto dir = std::format("zone/{}", Game::Win_GetLanguage()); const auto dir = std::format("zone/{}", Game::Win_GetLanguage());
auto fileList = Utils::IO::ListFiles(dir, false); 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, Utils::String::VA("zone/%s/", Game::Win_GetLanguage()), "");
Utils::String::Replace(zone, ".ff", ""); Utils::String::Replace(zone, ".ff", "");
@ -1431,8 +1432,10 @@ namespace Components
auto list = Utils::IO::ListFiles("zone/techsets", false); auto list = Utils::IO::ListFiles("zone/techsets", false);
int i = 0; int i = 0;
int subCount = 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, "zone/techsets/", "");
Utils::String::Replace(it, ".ff", ""); Utils::String::Replace(it, ".ff", "");
@ -1555,7 +1558,7 @@ namespace Components
// create csv with the techsets in it // create csv with the techsets in it
csvStr.clear(); csvStr.clear();
for (auto tech : curTechsets_list) for (const auto& tech : curTechsets_list)
{ {
auto mat = ZoneBuilder::FindMaterialByTechnique(tech); auto mat = ZoneBuilder::FindMaterialByTechnique(tech);
if (mat.length() == 0) if (mat.length() == 0)

View File

@ -360,31 +360,31 @@ namespace Components
{ {
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
{ {
*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 1028 + (i * 4)); *Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 1028 + (i * 4));
Game::Load_FxEffectDefHandle(false); Game::Load_FxEffectDefHandle(false);
} }
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
{ {
*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 1124 + (i * 4)); *Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 1124 + (i * 4));
Game::Load_FxEffectDefHandle(false); Game::Load_FxEffectDefHandle(false);
} }
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
{ {
*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 1188 + (i * 4)); *Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 1188 + (i * 4));
Game::Load_FxEffectDefHandle(false); Game::Load_FxEffectDefHandle(false);
} }
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
{ {
*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 1316 + (i * 4)); *Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 1316 + (i * 4));
Game::Load_FxEffectDefHandle(false); Game::Load_FxEffectDefHandle(false);
} }
for (int i = 0; i < 5; i++) for (int i = 0; i < 5; i++)
{ {
*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 1444 + (i * 4)); *Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 1444 + (i * 4));
Game::Load_FxEffectDefHandle(false); Game::Load_FxEffectDefHandle(false);
} }
} }
@ -457,7 +457,7 @@ namespace Components
if (*reinterpret_cast<DWORD*>(varWeaponCompleteDef + 1708) == -1) if (*reinterpret_cast<DWORD*>(varWeaponCompleteDef + 1708) == -1)
{ {
*reinterpret_cast<void**>(varWeaponCompleteDef + 1708) = Game::DB_AllocStreamPos(3); *reinterpret_cast<void**>(varWeaponCompleteDef + 1708) = Game::DB_AllocStreamPos(3);
*Game::varsnd_alias_list_name = *reinterpret_cast<Game::snd_alias_list_t * **>(varWeaponCompleteDef + 1708); *Game::varsnd_alias_list_name = *reinterpret_cast<Game::snd_alias_list_t***>(varWeaponCompleteDef + 1708);
Game::Load_snd_alias_list_nameArray(true, 31); Game::Load_snd_alias_list_nameArray(true, 31);
} }
@ -472,7 +472,7 @@ namespace Components
if (*reinterpret_cast<DWORD*>(varWeaponCompleteDef + 1712) == -1) if (*reinterpret_cast<DWORD*>(varWeaponCompleteDef + 1712) == -1)
{ {
*reinterpret_cast<void**>(varWeaponCompleteDef + 1712) = Game::DB_AllocStreamPos(3); *reinterpret_cast<void**>(varWeaponCompleteDef + 1712) = Game::DB_AllocStreamPos(3);
*Game::varsnd_alias_list_name = *reinterpret_cast<Game::snd_alias_list_t * **>(varWeaponCompleteDef + 1712); *Game::varsnd_alias_list_name = *reinterpret_cast<Game::snd_alias_list_t***>(varWeaponCompleteDef + 1712);
Game::Load_snd_alias_list_nameArray(true, 31); Game::Load_snd_alias_list_nameArray(true, 31);
} }
@ -552,7 +552,7 @@ namespace Components
// 1192 // 1192
for (int offset = 1716; offset <= 1728; offset += 4) for (int offset = 1716; offset <= 1728; offset += 4)
{ {
*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + offset); *Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + offset);
Game::Load_FxEffectDefHandle(false); 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 }; 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) for (int i = 0; i < ARRAYSIZE(matOffsets1); ++i)
{ {
*Game::varMaterialHandle = reinterpret_cast<Game::Material * *>(varWeaponCompleteDef + matOffsets1[i]); *Game::varMaterialHandle = reinterpret_cast<Game::Material**>(varWeaponCompleteDef + matOffsets1[i]);
Game::Load_MaterialHandle(false); Game::Load_MaterialHandle(false);
} }
} }
@ -643,7 +643,7 @@ namespace Components
{ {
for (int offset = 2332; offset <= 2344; offset += 4) for (int offset = 2332; offset <= 2344; offset += 4)
{ {
*Game::varMaterialHandle = reinterpret_cast<Game::Material * *>(varWeaponCompleteDef + offset); *Game::varMaterialHandle = reinterpret_cast<Game::Material**>(varWeaponCompleteDef + offset);
Game::Load_MaterialHandle(false); Game::Load_MaterialHandle(false);
} }
} }
@ -666,10 +666,10 @@ namespace Components
if (Zones::Version() >= 460) if (Zones::Version() >= 460)
{ {
*Game::varPhysCollmapPtr = reinterpret_cast<Game::PhysCollmap * *>(varWeaponCompleteDef + 2544); *Game::varPhysCollmapPtr = reinterpret_cast<Game::PhysCollmap**>(varWeaponCompleteDef + 2544);
Game::Load_PhysCollmapPtr(false); Game::Load_PhysCollmapPtr(false);
*Game::varPhysPresetPtr = reinterpret_cast<Game::PhysPreset * *>(varWeaponCompleteDef + 2548); *Game::varPhysPresetPtr = reinterpret_cast<Game::PhysPreset**>(varWeaponCompleteDef + 2548);
Game::Load_PhysPresetPtr(false); Game::Load_PhysPresetPtr(false);
} }
else if (Zones::ZoneVersion >= 359) else if (Zones::ZoneVersion >= 359)
@ -688,7 +688,7 @@ namespace Components
if (Zones::Version() >= 460) if (Zones::Version() >= 460)
{ {
*Game::varXModelPtr = reinterpret_cast<Game::XModel * *>(varWeaponCompleteDef + 2656); *Game::varXModelPtr = reinterpret_cast<Game::XModel**>(varWeaponCompleteDef + 2656);
Game::Load_XModelPtr(false); Game::Load_XModelPtr(false);
} }
else if (Zones::ZoneVersion >= 359) else if (Zones::ZoneVersion >= 359)
@ -704,10 +704,10 @@ namespace Components
if (Zones::Version() >= 460) if (Zones::Version() >= 460)
{ {
*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 2664); *Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 2664);
Game::Load_FxEffectDefHandle(false); Game::Load_FxEffectDefHandle(false);
*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 2668); *Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 2668);
Game::Load_FxEffectDefHandle(false); Game::Load_FxEffectDefHandle(false);
} }
else if (Zones::ZoneVersion >= 359) else if (Zones::ZoneVersion >= 359)
@ -729,10 +729,10 @@ namespace Components
if (Zones::Version() >= 460) if (Zones::Version() >= 460)
{ {
*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 2672); *Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t**>(varWeaponCompleteDef + 2672);
Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name);
*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 2676); *Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t**>(varWeaponCompleteDef + 2676);
Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name);
} }
else if (Zones::ZoneVersion >= 359) else if (Zones::ZoneVersion >= 359)
@ -754,13 +754,13 @@ namespace Components
if (Zones::Version() >= 460) if (Zones::Version() >= 460)
{ {
*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 2952); *Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 2952);
Game::Load_FxEffectDefHandle(false); Game::Load_FxEffectDefHandle(false);
*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 2956); *Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 2956);
Game::Load_FxEffectDefHandle(false); Game::Load_FxEffectDefHandle(false);
*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 2984); *Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 2984);
Game::Load_FxEffectDefHandle(false); Game::Load_FxEffectDefHandle(false);
} }
else if (Zones::ZoneVersion >= 359) else if (Zones::ZoneVersion >= 359)
@ -788,22 +788,22 @@ namespace Components
if (Zones::Version() >= 460) if (Zones::Version() >= 460)
{ {
*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 2988); *Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t**>(varWeaponCompleteDef + 2988);
Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name);
*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 2992); *Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 2992);
Game::Load_FxEffectDefHandle(false); Game::Load_FxEffectDefHandle(false);
*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 2996); *Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 2996);
Game::Load_FxEffectDefHandle(false); Game::Load_FxEffectDefHandle(false);
*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 3000); *Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 3000);
Game::Load_FxEffectDefHandle(false); Game::Load_FxEffectDefHandle(false);
*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 3004); *Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 3004);
Game::Load_FxEffectDefHandle(false); Game::Load_FxEffectDefHandle(false);
*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 3008); *Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 3008);
Game::Load_FxEffectDefHandle(false); Game::Load_FxEffectDefHandle(false);
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3196); *Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3196);
@ -953,37 +953,37 @@ namespace Components
if (Zones::Version() >= 460) if (Zones::Version() >= 460)
{ {
*Game::varTracerDefPtr = reinterpret_cast<Game::TracerDef * *>(varWeaponCompleteDef + 3492 + offsetShift); *Game::varTracerDefPtr = reinterpret_cast<Game::TracerDef**>(varWeaponCompleteDef + 3492 + offsetShift);
Game::Load_TracerDefPtr(false); Game::Load_TracerDefPtr(false);
*Game::varTracerDefPtr = reinterpret_cast<Game::TracerDef * *>(varWeaponCompleteDef + 3496 + offsetShift); *Game::varTracerDefPtr = reinterpret_cast<Game::TracerDef**>(varWeaponCompleteDef + 3496 + offsetShift);
Game::Load_TracerDefPtr(false); Game::Load_TracerDefPtr(false);
*Game::varTracerDefPtr = reinterpret_cast<Game::TracerDef * *>(varWeaponCompleteDef + 3500 + offsetShift); *Game::varTracerDefPtr = reinterpret_cast<Game::TracerDef**>(varWeaponCompleteDef + 3500 + offsetShift);
Game::Load_TracerDefPtr(false); Game::Load_TracerDefPtr(false);
*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 3528 + offsetShift); *Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t**>(varWeaponCompleteDef + 3528 + offsetShift);
Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); // 2848 Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); // 2848
*Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef * *>(varWeaponCompleteDef + 3532 + offsetShift); *Game::varFxEffectDefHandle = reinterpret_cast<Game::FxEffectDef**>(varWeaponCompleteDef + 3532 + offsetShift);
Game::Load_FxEffectDefHandle(false); Game::Load_FxEffectDefHandle(false);
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3536 + offsetShift); *Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3536 + offsetShift);
Game::Load_XString(false); Game::Load_XString(false);
*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 3552 + offsetShift); *Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t**>(varWeaponCompleteDef + 3552 + offsetShift);
Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name);
*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 3556 + offsetShift); *Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t**>(varWeaponCompleteDef + 3556 + offsetShift);
Game::Load_snd_alias_list_nameArray(false, 4); Game::Load_snd_alias_list_nameArray(false, 4);
*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 3572 + offsetShift); *Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t**>(varWeaponCompleteDef + 3572 + offsetShift);
Game::Load_snd_alias_list_nameArray(false, 4); Game::Load_snd_alias_list_nameArray(false, 4);
*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 3588 + offsetShift); *Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t**>(varWeaponCompleteDef + 3588 + offsetShift);
Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name);
*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + 3592 + offsetShift); *Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t**>(varWeaponCompleteDef + 3592 + offsetShift);
Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name);
} }
else if (Zones::ZoneVersion >= 359) else if (Zones::ZoneVersion >= 359)
@ -1049,7 +1049,7 @@ namespace Components
{ {
for (int i = 0, offset = 3660 + offsetShift; i < 6; ++i, offset += 4) for (int i = 0, offset = 3660 + offsetShift; i < 6; ++i, offset += 4)
{ {
*Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t * *>(varWeaponCompleteDef + offset); *Game::varsnd_alias_list_name = reinterpret_cast<Game::snd_alias_list_t**>(varWeaponCompleteDef + offset);
Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name); Game::Load_SndAliasCustom(*Game::varsnd_alias_list_name);
} }
} }
@ -1091,16 +1091,16 @@ namespace Components
*Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3732 + offsetShift); *Game::varXString = reinterpret_cast<char**>(varWeaponCompleteDef + 3732 + offsetShift);
Game::Load_XString(false); Game::Load_XString(false);
*Game::varMaterialHandle = reinterpret_cast<Game::Material * *>(varWeaponCompleteDef + 3740 + offsetShift); *Game::varMaterialHandle = reinterpret_cast<Game::Material**>(varWeaponCompleteDef + 3740 + offsetShift);
Game::Load_MaterialHandle(false); Game::Load_MaterialHandle(false);
*Game::varMaterialHandle = reinterpret_cast<Game::Material * *>(varWeaponCompleteDef + 3744 + offsetShift); *Game::varMaterialHandle = reinterpret_cast<Game::Material**>(varWeaponCompleteDef + 3744 + offsetShift);
Game::Load_MaterialHandle(false); Game::Load_MaterialHandle(false);
*Game::varMaterialHandle = reinterpret_cast<Game::Material * *>(varWeaponCompleteDef + 3748 + offsetShift); *Game::varMaterialHandle = reinterpret_cast<Game::Material**>(varWeaponCompleteDef + 3748 + offsetShift);
Game::Load_MaterialHandle(false); Game::Load_MaterialHandle(false);
*Game::varMaterialHandle = reinterpret_cast<Game::Material * *>(varWeaponCompleteDef + 3752 + offsetShift); *Game::varMaterialHandle = reinterpret_cast<Game::Material**>(varWeaponCompleteDef + 3752 + offsetShift);
Game::Load_MaterialHandle(false); Game::Load_MaterialHandle(false);
} }
else if (Zones::ZoneVersion >= 359) else if (Zones::ZoneVersion >= 359)
@ -1441,7 +1441,7 @@ namespace Components
Game::Load_XString(false); Game::Load_XString(false);
*reinterpret_cast<void**>(varWeaponAttach + 8) = Game::DB_AllocStreamPos(3); *reinterpret_cast<void**>(varWeaponAttach + 8) = Game::DB_AllocStreamPos(3);
Zones::LoadWeaponAttachStuff(*reinterpret_cast<DWORD * *>(varWeaponAttach + 8), *reinterpret_cast<int*>(varWeaponAttach + 4)); Zones::LoadWeaponAttachStuff(*reinterpret_cast<DWORD**>(varWeaponAttach + 8), *reinterpret_cast<int*>(varWeaponAttach + 4));
Game::DB_PopStreamPos(); Game::DB_PopStreamPos();
} }
@ -1582,7 +1582,7 @@ namespace Components
// dont know if this applies to 460 too, but I dont have 460 files to test // dont know if this applies to 460 too, but I dont have 460 files to test
if (!strncmp(techsetName, "wc_unlit_add", 12) || if (!strncmp(techsetName, "wc_unlit_add", 12) ||
!strncmp(techsetName, "wc_unlit_multiply", 17) ) !strncmp(techsetName, "wc_unlit_multiply", 17))
{ {
// fixes glass and water // fixes glass and water
arg->u.codeConst.index = 116; arg->u.codeConst.index = 116;
@ -1656,7 +1656,7 @@ namespace Components
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") FastFiles::Current() != "mp_con_spring" && FastFiles::Current() != "mp_resistance_sh" && FastFiles::Current() != "mp_lookout_sh")
{ {
const auto varMaterialTechniqueSet = *reinterpret_cast<Game::MaterialTechniqueSet * *>(0x112AE8C); const auto varMaterialTechniqueSet = *reinterpret_cast<Game::MaterialTechniqueSet**>(0x112AE8C);
if (varMaterialTechniqueSet->name && !strncmp(varMaterialTechniqueSet->name, "mc_", 3)) if (varMaterialTechniqueSet->name && !strncmp(varMaterialTechniqueSet->name, "mc_", 3))
{ {
// fixes trees // fixes trees
@ -1789,7 +1789,8 @@ namespace Components
return result; 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 // 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 // We have to translate them. 9 is for Reflection probes, 11 is for Compass, 10 is for Lightmap
switch (image->category) switch (image->category)
@ -1806,8 +1807,8 @@ namespace Components
} }
if (image->category > 7 || image->category < 0) { if (image->category > 7 || image->category < 0)
{
#ifdef DEBUG #ifdef DEBUG
if (IsDebuggerPresent()) __debugbreak(); if (IsDebuggerPresent()) __debugbreak();
#endif #endif
@ -1888,8 +1889,8 @@ namespace Components
if (Zones::Version() >= 446) if (Zones::Version() >= 446)
{ {
auto lastTechnique = **reinterpret_cast<Game::MaterialTechnique * **>(0x112AEDC); auto lastTechnique = **reinterpret_cast<Game::MaterialTechnique***>(0x112AEDC);
auto varMaterialTechniqueSet = **reinterpret_cast<Game::MaterialTechniqueSet * **>(0x112B070); auto varMaterialTechniqueSet = **reinterpret_cast<Game::MaterialTechniqueSet***>(0x112B070);
// patch last technique to match iw4 // patch last technique to match iw4
varMaterialTechniqueSet->techniques[47] = lastTechnique; varMaterialTechniqueSet->techniques[47] = lastTechnique;
@ -1938,7 +1939,7 @@ namespace Components
{ {
char drawSurfBegin[8]; // 4 char drawSurfBegin[8]; // 4
//int surfaceTypeBits; //int surfaceTypeBits;
const char *name; const char* name;
char drawSurf[6]; char drawSurf[6];
union union
@ -3337,7 +3338,7 @@ namespace Components
void Zones::LoadFxWorldAsset(Game::FxWorld** asset) void Zones::LoadFxWorldAsset(Game::FxWorld** asset)
{ {
Utils::Hook::Call<void(Game::FxWorld * *)>(0x4857F0)(asset); Utils::Hook::Call<void(Game::FxWorld**)>(0x4857F0)(asset);
if (Zones::Version() >= 423 && asset && *asset) if (Zones::Version() >= 423 && asset && *asset)
{ {
@ -3399,7 +3400,7 @@ namespace Components
} }
} }
return Utils::Hook::Call<void(Game::XModel * *)>(0x47A690)(asset); return Utils::Hook::Call<void(Game::XModel**)>(0x47A690)(asset);
} }
// patch max file amount returned by Sys_ListFiles // patch max file amount returned by Sys_ListFiles
@ -3479,6 +3480,8 @@ namespace Components
{ {
Zones::ZoneVersion = 0; Zones::ZoneVersion = 0;
if (ZoneBuilder::IsEnabled())
{
Command::Add("decryptImages", [](Command::Params*) Command::Add("decryptImages", [](Command::Params*)
{ {
auto images = FileSystem::GetSysFileList("iw4x/images", "iwi"); auto images = FileSystem::GetSysFileList("iw4x/images", "iwi");
@ -3487,7 +3490,7 @@ namespace Components
for (auto& image : images) for (auto& image : images)
{ {
char* buffer = nullptr; char* buffer = nullptr;
auto fileLength = Game::FS_ReadFile(Utils::String::VA("images/%s", image.data()), &buffer); auto fileLength = Game::FS_ReadFile(Utils::String::Format("images/{}", image), &buffer);
if (fileLength && buffer) if (fileLength && buffer)
{ {
@ -3496,9 +3499,9 @@ namespace Components
std::filesystem::create_directories("raw/images"); std::filesystem::create_directories("raw/images");
} }
if (!std::filesystem::exists(Utils::String::VA("raw/images/%s", image.data()))) if (!std::filesystem::exists(Utils::String::Format("raw/images/{}", image)))
{ {
const auto fp = fopen(Utils::String::VA("raw/images/%s", image.data()), "wb"); const auto fp = fopen(Utils::String::Format("raw/images/{}", image), "wb");
if (fp) if (fp)
{ {
fwrite(buffer, fileLength, 1, fp); fwrite(buffer, fileLength, 1, fp);
@ -3544,6 +3547,7 @@ namespace Components
Logger::Print("decrypted {} sounds!\n", sounds.size()); Logger::Print("decrypted {} sounds!\n", sounds.size());
}); });
}
// patch max filecount Sys_ListFiles can return // patch max filecount Sys_ListFiles can return
Utils::Hook::Set<std::uint32_t>(0x45A66B, (maxFileCount + fileCountMultiplier) * 4); Utils::Hook::Set<std::uint32_t>(0x45A66B, (maxFileCount + fileCountMultiplier) * 4);
@ -3566,10 +3570,13 @@ namespace Components
Utils::Hook::Set<BYTE>(0x418B31, 0x72); Utils::Hook::Set<BYTE>(0x418B31, 0x72);
// encrypted images hooks // encrypted images hooks
if (ZoneBuilder::IsEnabled())
{
Utils::Hook(0x462000, Zones::FS_FCloseFileHook, HOOK_JUMP).install()->quick(); Utils::Hook(0x462000, Zones::FS_FCloseFileHook, HOOK_JUMP).install()->quick();
Utils::Hook(0x4A04C0, Zones::FS_ReadHook, 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(0x643270, Zones::FS_FOpenFileReadForThreadHook, HOOK_JUMP).install()->quick();
Utils::Hook(0x4A63D0, Zones::FS_SeekHook, HOOK_JUMP).install()->quick(); Utils::Hook(0x4A63D0, Zones::FS_SeekHook, HOOK_JUMP).install()->quick();
}
// asset hooks // asset hooks
Utils::Hook(0x47146D, Zones::LoadTracerDef, HOOK_CALL).install()->quick(); Utils::Hook(0x47146D, Zones::LoadTracerDef, HOOK_CALL).install()->quick();
@ -3639,7 +3646,7 @@ namespace Components
}, HOOK_CALL).install()->quick(); }, HOOK_CALL).install()->quick();
// Change stream for images // Change stream for images
Utils::Hook(0x4D3225, [] () Utils::Hook(0x4D3225, []()
{ {
Game::DB_PushStreamPos((Zones::ZoneVersion >= 332) ? 3 : 0); Game::DB_PushStreamPos((Zones::ZoneVersion >= 332) ? 3 : 0);
}, HOOK_CALL).install()->quick(); }, HOOK_CALL).install()->quick();
@ -3651,7 +3658,7 @@ namespace Components
// Easy dirty disk debugging // Easy dirty disk debugging
Utils::Hook::Set<WORD>(0x4CF7F0, 0xC3CC); Utils::Hook::Set<WORD>(0x4CF7F0, 0xC3CC);
// disable _invoke_watson to allow debugging // disable _invoke_watson to allow debugging
Utils::Hook::Set<WORD>(0x6B9602,0xCCCC); Utils::Hook::Set<WORD>(0x6B9602, 0xCCCC);
#endif #endif
} }
} }

View File

@ -97,22 +97,22 @@ namespace Utils::IO
return std::filesystem::is_empty(directory); return std::filesystem::is_empty(directory);
} }
std::vector<std::string> ListFiles(const std::filesystem::path& directory, const bool recursive) std::vector<std::filesystem::directory_entry> ListFiles(const std::filesystem::path& directory, const bool recursive)
{ {
std::vector<std::string> files; std::vector<std::filesystem::directory_entry> files;
if (recursive) if (recursive)
{ {
for (auto& file : std::filesystem::recursive_directory_iterator(directory)) for (auto& file : std::filesystem::recursive_directory_iterator(directory))
{ {
files.push_back(file.path().generic_string()); files.push_back(file);
} }
} }
else else
{ {
for (auto& file : std::filesystem::directory_iterator(directory)) for (auto& file : std::filesystem::directory_iterator(directory))
{ {
files.push_back(file.path().generic_string()); files.push_back(file);
} }
} }

View File

@ -11,5 +11,5 @@ namespace Utils::IO
bool CreateDir(const std::string& dir); bool CreateDir(const std::string& dir);
[[nodiscard]] bool DirectoryExists(const std::filesystem::path& directory); [[nodiscard]] bool DirectoryExists(const std::filesystem::path& directory);
[[nodiscard]] bool DirectoryIsEmpty(const std::filesystem::path& directory); [[nodiscard]] bool DirectoryIsEmpty(const std::filesystem::path& directory);
[[nodiscard]] std::vector<std::string> ListFiles(const std::filesystem::path& directory, bool recursive = false); [[nodiscard]] std::vector<std::filesystem::directory_entry> ListFiles(const std::filesystem::path& directory, bool recursive = false);
} }

View File

@ -78,45 +78,4 @@ namespace Utils::Thread
return ids; return ids;
} }
void ForEachThread(const std::function<void(HANDLE)>& 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);
}
});
}
} }

View File

@ -16,8 +16,4 @@ namespace Utils::Thread
} }
std::vector<DWORD> GetThreadIds(); std::vector<DWORD> GetThreadIds();
void ForEachThread(const std::function<void(HANDLE)>& callback);
void SuspendOtherThreads();
void ResumeOtherThreads();
} }