IW5 DLC Prep (#814)
Co-authored-by: FutureRave <edoardo.sanguineti222@gmail.com>
This commit is contained in:
parent
6bae9958e0
commit
678dc349dd
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
|
||||||
@ -135,6 +137,8 @@ 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);
|
||||||
|
|
||||||
@ -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
|
||||||
@ -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();
|
||||||
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -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, "");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
@ -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();
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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();
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user