[Threading]: Initialize tls stuff, making va thread safe (#657)
This commit is contained in:
parent
24ccd9af3b
commit
d8166a4166
@ -246,13 +246,20 @@ namespace Components
|
||||
if (ent->client->sess.sessionState != Game::SESS_STATE_PLAYING || !CheatsOk(ent))
|
||||
return;
|
||||
|
||||
Scheduler::Once([ent]
|
||||
{
|
||||
auto** bgs = Game::Sys::GetTls<Game::bgs_t*>(Game::Sys::ThreadOffset::LEVEL_BGS);
|
||||
|
||||
assert(*bgs == nullptr);
|
||||
|
||||
*bgs = Game::level_bgs;
|
||||
|
||||
ent->flags &= ~(Game::FL_GODMODE | Game::FL_DEMI_GODMODE);
|
||||
ent->health = 0;
|
||||
ent->client->ps.stats[0] = 0;
|
||||
Game::player_die(ent, ent, ent, 100000, Game::MOD_SUICIDE, 0, nullptr, Game::HITLOC_NONE, 0);
|
||||
}, Scheduler::Pipeline::SERVER);
|
||||
|
||||
assert(*bgs == Game::level_bgs);
|
||||
|
||||
*bgs = nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -7,39 +7,42 @@ namespace Components
|
||||
std::thread Discovery::Thread;
|
||||
std::string Discovery::Challenge;
|
||||
|
||||
Dvar::Var Discovery::NetDiscoveryPortRangeMin;
|
||||
Dvar::Var Discovery::NetDiscoveryPortRangeMax;
|
||||
|
||||
void Discovery::Perform()
|
||||
{
|
||||
Discovery::IsPerforming = true;
|
||||
IsPerforming = true;
|
||||
}
|
||||
|
||||
Discovery::Discovery()
|
||||
{
|
||||
Dvar::Register<int>("net_discoveryPortRangeMin", 25000, 0, 65535, Game::DVAR_ARCHIVE, "Minimum scan range port for local server discovery");
|
||||
Dvar::Register<int>("net_discoveryPortRangeMax", 35000, 1, 65536, Game::DVAR_ARCHIVE, "Maximum scan range port for local server discovery");
|
||||
NetDiscoveryPortRangeMin = Dvar::Register<int>("net_discoveryPortRangeMin", 25000, 0, 65535, Game::DVAR_NONE, "Minimum scan range port for local server discovery");
|
||||
NetDiscoveryPortRangeMax = Dvar::Register<int>("net_discoveryPortRangeMax", 35000, 1, 65536, Game::DVAR_NONE, "Maximum scan range port for local server discovery");
|
||||
|
||||
// An additional thread prevents lags
|
||||
// Not sure if that's the best way though
|
||||
Discovery::IsPerforming = false;
|
||||
Discovery::IsTerminating = false;
|
||||
Discovery::Thread = std::thread([]()
|
||||
IsPerforming = false;
|
||||
IsTerminating = false;
|
||||
Thread = std::thread([]
|
||||
{
|
||||
while (!Discovery::IsTerminating)
|
||||
while (!IsTerminating)
|
||||
{
|
||||
if (Discovery::IsPerforming)
|
||||
if (IsPerforming)
|
||||
{
|
||||
int start = Game::Sys_Milliseconds();
|
||||
const auto start = Game::Sys_Milliseconds();
|
||||
|
||||
Logger::Print("Starting local server discovery...\n");
|
||||
|
||||
Discovery::Challenge = Utils::Cryptography::Rand::GenerateChallenge();
|
||||
Challenge = Utils::Cryptography::Rand::GenerateChallenge();
|
||||
|
||||
unsigned int minPort = Dvar::Var("net_discoveryPortRangeMin").get<unsigned int>();
|
||||
unsigned int maxPort = Dvar::Var("net_discoveryPortRangeMax").get<unsigned int>();
|
||||
Network::BroadcastRange(minPort, maxPort, Utils::String::VA("discovery %s", Discovery::Challenge.data()));
|
||||
const auto minPort = NetDiscoveryPortRangeMin.get<unsigned int>();
|
||||
const auto maxPort = NetDiscoveryPortRangeMax.get<unsigned int>();
|
||||
Network::BroadcastRange(minPort, maxPort, std::format("discovery {}", Challenge));
|
||||
|
||||
Logger::Print("Discovery sent within {}ms, awaiting responses...\n", Game::Sys_Milliseconds() - start);
|
||||
|
||||
Discovery::IsPerforming = false;
|
||||
IsPerforming = false;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(50ms);
|
||||
@ -70,7 +73,7 @@ namespace Components
|
||||
return;
|
||||
}
|
||||
|
||||
if (Utils::ParseChallenge(data) != Discovery::Challenge)
|
||||
if (Utils::ParseChallenge(data) != Challenge)
|
||||
{
|
||||
Logger::Print("Received discovery with invalid challenge from: {}\n", address.getString());
|
||||
return;
|
||||
@ -87,12 +90,12 @@ namespace Components
|
||||
|
||||
void Discovery::preDestroy()
|
||||
{
|
||||
Discovery::IsPerforming = false;
|
||||
Discovery::IsTerminating = true;
|
||||
IsPerforming = false;
|
||||
IsTerminating = true;
|
||||
|
||||
if (Discovery::Thread.joinable())
|
||||
if (Thread.joinable())
|
||||
{
|
||||
Discovery::Thread.join();
|
||||
Thread.join();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,5 +16,8 @@ namespace Components
|
||||
static bool IsPerforming;
|
||||
static std::thread Thread;
|
||||
static std::string Challenge;
|
||||
|
||||
static Dvar::Var NetDiscoveryPortRangeMin;
|
||||
static Dvar::Var NetDiscoveryPortRangeMax;
|
||||
};
|
||||
}
|
||||
|
@ -232,11 +232,11 @@ namespace Components
|
||||
{
|
||||
if (!download) download = &CLDownload;
|
||||
|
||||
auto host = "http://" + download->target.getString();
|
||||
const auto host = "http://" + download->target.getString();
|
||||
|
||||
auto listUrl = host + (download->isMap ? "/map" : "/list") + (download->isPrivate ? ("?password=" + download->hashedPassword) : "");
|
||||
const auto listUrl = host + (download->isMap ? "/map" : "/list") + (download->isPrivate ? ("?password=" + download->hashedPassword) : "");
|
||||
|
||||
auto list = Utils::WebIO("IW4x", listUrl).setTimeout(5000)->get();
|
||||
const auto list = Utils::WebIO("IW4x", listUrl).setTimeout(5000)->get();
|
||||
if (list.empty())
|
||||
{
|
||||
if (download->terminateThread) return;
|
||||
@ -276,7 +276,7 @@ namespace Components
|
||||
static std::string mod;
|
||||
mod = download->mod;
|
||||
|
||||
for (unsigned int i = 0; i < download->files.size(); ++i)
|
||||
for (std::size_t i = 0; i < download->files.size(); ++i)
|
||||
{
|
||||
if (download->terminateThread) return;
|
||||
|
||||
@ -319,7 +319,6 @@ namespace Components
|
||||
Scheduler::Once([]
|
||||
{
|
||||
Game::Dvar_SetString(*Game::fs_gameDirVar, mod.data());
|
||||
const_cast<Game::dvar_t*>(*Game::fs_gameDirVar)->modified = true;
|
||||
|
||||
mod.clear();
|
||||
|
||||
@ -673,6 +672,10 @@ namespace Components
|
||||
|
||||
Download::Download()
|
||||
{
|
||||
AssertSize(Game::va_info_t, 0x804);
|
||||
AssertSize(jmp_buf, 0x40);
|
||||
AssertSize(Game::TraceThreadInfo, 0x8);
|
||||
|
||||
if (Dedicated::IsEnabled())
|
||||
{
|
||||
mg_mgr_init(&Mgr);
|
||||
@ -690,6 +693,8 @@ namespace Components
|
||||
Terminate = false;
|
||||
ServerThread = Utils::Thread::CreateNamedThread("Mongoose", []
|
||||
{
|
||||
Com_InitThreadData();
|
||||
|
||||
while (!Terminate)
|
||||
{
|
||||
mg_mgr_poll(&Mgr, 100);
|
||||
|
@ -13,12 +13,12 @@ namespace Components
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
if (News::Thread.joinable())
|
||||
if (Thread.joinable())
|
||||
{
|
||||
Logger::Debug("Awaiting thread termination...");
|
||||
News::Thread.join();
|
||||
Thread.join();
|
||||
|
||||
if (!strcmp(Localization::Get("MPUI_MOTD_TEXT"), NEWS_MOTD_DEFAULT))
|
||||
if (!std::strcmp(Localization::Get("MPUI_MOTD_TEXT"), NEWS_MOTD_DEFAULT))
|
||||
{
|
||||
Logger::Print("Failed to fetch motd!\n");
|
||||
result = false;
|
||||
@ -43,14 +43,12 @@ namespace Components
|
||||
|
||||
Dvar::Register<bool>("g_firstLaunch", true, Game::DVAR_ARCHIVE, "");
|
||||
|
||||
Dvar::Register<int>("cl_updateoldversion", REVISION, REVISION, REVISION, Game::DVAR_INIT, "Current version number.");
|
||||
|
||||
UIScript::Add("checkFirstLaunch", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
|
||||
{
|
||||
if (Dvar::Var("g_firstLaunch").get<bool>())
|
||||
{
|
||||
Command::Execute("openmenu menu_first_launch", false);
|
||||
//Dvar::Var("g_firstLaunch").set(false);
|
||||
//Dvar::Var("g_firstLaunch").set(false); // The menus should set it
|
||||
}
|
||||
});
|
||||
|
||||
@ -67,15 +65,15 @@ namespace Components
|
||||
|
||||
// hook for getting the news ticker string
|
||||
Utils::Hook::Nop(0x6388BB, 2); // skip the "if (item->text[0] == '@')" localize check
|
||||
Utils::Hook(0x6388C1, News::GetNewsText, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x6388C1, GetNewsText, HOOK_CALL).install()->quick();
|
||||
|
||||
if (!Utils::IsWineEnvironment() && !Loader::IsPerformingUnitTests())
|
||||
{
|
||||
News::Terminate = false;
|
||||
News::Thread = std::thread([]()
|
||||
Terminate = false;
|
||||
Thread = std::thread([]()
|
||||
{
|
||||
Changelog::LoadChangelog();
|
||||
if (News::Terminate) return;
|
||||
if (Terminate) return;
|
||||
|
||||
std::string data = Utils::Cache::GetFile("/iw4/motd.txt");
|
||||
if (!data.empty())
|
||||
@ -83,12 +81,12 @@ namespace Components
|
||||
Localization::Set("MPUI_MOTD_TEXT", data);
|
||||
}
|
||||
|
||||
if (!Loader::IsPerformingUnitTests() && !News::Terminate)
|
||||
if (!Loader::IsPerformingUnitTests() && !Terminate)
|
||||
{
|
||||
while (!News::Terminate)
|
||||
while (!Terminate)
|
||||
{
|
||||
// Sleep for 3 minutes
|
||||
for (int i = 0; i < 180 && !News::Terminate; ++i)
|
||||
for (int i = 0; i < 180 && !Terminate; ++i)
|
||||
{
|
||||
std::this_thread::sleep_for(1s);
|
||||
}
|
||||
@ -100,13 +98,11 @@ namespace Components
|
||||
|
||||
void News::preDestroy()
|
||||
{
|
||||
News::Terminate = true;
|
||||
Terminate = true;
|
||||
|
||||
if (News::Thread.joinable())
|
||||
if (Thread.joinable())
|
||||
{
|
||||
News::Thread.join();
|
||||
Thread.join();
|
||||
}
|
||||
|
||||
News::Thread = std::thread();
|
||||
}
|
||||
}
|
||||
|
@ -154,9 +154,6 @@ namespace Components
|
||||
// dvar setting function, unknown stuff related to server thread sync
|
||||
Utils::Hook::Set<std::uint8_t>(0x647781, 0xEB);
|
||||
|
||||
// make VA thread safe
|
||||
Utils::Hook(0x4785B0, Utils::String::VA, HOOK_JUMP).install()->quick();
|
||||
|
||||
Utils::Hook(0x627695, 0x627040, HOOK_CALL).install()->quick();
|
||||
Utils::Hook(0x43D1C7, PacketEventStub, HOOK_JUMP).install()->quick();
|
||||
Utils::Hook(0x6272E3, FrameEpilogueStub, HOOK_JUMP).install()->quick();
|
||||
|
@ -11,7 +11,8 @@ namespace Components
|
||||
|
||||
bool ZoneBuilder::MainThreadInterrupted;
|
||||
DWORD ZoneBuilder::InterruptingThreadId;
|
||||
volatile bool ZoneBuilder::Terminate = false;
|
||||
|
||||
volatile bool ZoneBuilder::CommandThreadTerminate = false;
|
||||
std::thread ZoneBuilder::CommandThread;
|
||||
|
||||
Dvar::Var ZoneBuilder::PreferDiskAssetsDvar;
|
||||
@ -120,7 +121,7 @@ namespace Components
|
||||
this->writeZone();
|
||||
}
|
||||
|
||||
void ZoneBuilder::Zone::loadFastFiles()
|
||||
void ZoneBuilder::Zone::loadFastFiles() const
|
||||
{
|
||||
Logger::Print("Loading required FastFiles...\n");
|
||||
|
||||
@ -793,7 +794,8 @@ namespace Components
|
||||
return GetCurrentThreadId() == Utils::Hook::Get<DWORD>(0x1CDE7FC);
|
||||
}
|
||||
|
||||
static Game::XZoneInfo baseZones_old[] = {
|
||||
static Game::XZoneInfo baseZones_old[] =
|
||||
{
|
||||
{ "code_pre_gfx_mp", Game::DB_ZONE_CODE, 0 },
|
||||
{ "localized_code_pre_gfx_mp", Game::DB_ZONE_CODE_LOC, 0 },
|
||||
{ "code_post_gfx_mp", Game::DB_ZONE_CODE, 0 },
|
||||
@ -805,7 +807,8 @@ namespace Components
|
||||
};
|
||||
|
||||
|
||||
static Game::XZoneInfo baseZones[] = {
|
||||
static Game::XZoneInfo baseZones[] =
|
||||
{
|
||||
{ "defaults", Game::DB_ZONE_CODE, 0 },
|
||||
{ "techsets", Game::DB_ZONE_CODE, 0 },
|
||||
{ "common_mp", Game::DB_ZONE_COMMON, 0 },
|
||||
@ -819,7 +822,20 @@ namespace Components
|
||||
ExitProcess(0);
|
||||
}
|
||||
|
||||
int APIENTRY ZoneBuilder::EntryPoint(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nShowCmd*/)
|
||||
void ZoneBuilder::CommandThreadCallback()
|
||||
{
|
||||
Com_InitThreadData();
|
||||
|
||||
while (!ZoneBuilder::CommandThreadTerminate)
|
||||
{
|
||||
ZoneBuilder::AssumeMainThreadRole();
|
||||
Utils::Hook::Call<void(int, int)>(0x4E2C80)(0, 0); // Cbuf_Execute
|
||||
ZoneBuilder::ResetThreadRole();
|
||||
std::this_thread::sleep_for(1ms);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL APIENTRY ZoneBuilder::EntryPoint(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nShowCmd*/)
|
||||
{
|
||||
Utils::Hook::Call<void()>(0x42F0A0)(); // Com_InitCriticalSections
|
||||
Utils::Hook::Call<void()>(0x4301B0)(); // Com_InitMainThread
|
||||
@ -835,11 +851,14 @@ namespace Components
|
||||
Utils::Hook::Call<void()>(0x4A62A0)(); // LargeLocalInit
|
||||
Utils::Hook::Call<void()>(0x4DCC10)(); // Sys_InitCmdEvents
|
||||
Utils::Hook::Call<void()>(0x64A020)(); // PMem_Init
|
||||
|
||||
if (!Flags::HasFlag("stdout"))
|
||||
{
|
||||
Console::ShowAsyncConsole();
|
||||
Utils::Hook::Call<void()>(0x43D140)(); // Com_EventLoop
|
||||
}
|
||||
|
||||
|
||||
Utils::Hook::Call<void(unsigned int)>(0x502580)(static_cast<unsigned int>(__rdtsc())); // Netchan_Init
|
||||
Utils::Hook::Call<void()>(0x429080)(); // FS_InitFileSystem
|
||||
Utils::Hook::Call<void()>(0x4BFBE0)(); // Con_InitChannels
|
||||
@ -848,21 +867,10 @@ namespace Components
|
||||
Game::NET_Init();
|
||||
Utils::Hook::Call<void()>(0x4F5090)(); // SND_InitDriver
|
||||
Utils::Hook::Call<void()>(0x46A630)(); // SND_Init
|
||||
//Utils::Hook::Call<void()>(0x4D3660)(); // SV_Init
|
||||
//Utils::Hook::Call<void()>(0x4121E0)(); // SV_InitServerThread
|
||||
//Utils::Hook::Call<void()>(0x464A90)(); // Com_ParseCommandLine
|
||||
Utils::Hook::Call<void()>(0x43D140)(); // Com_EventLoop
|
||||
|
||||
ZoneBuilder::CommandThread = std::thread([]
|
||||
{
|
||||
while (!ZoneBuilder::Terminate)
|
||||
{
|
||||
ZoneBuilder::AssumeMainThreadRole();
|
||||
Utils::Hook::Call<void(int, int)>(0x4E2C80)(0, 0); // Cbuf_Execute
|
||||
ZoneBuilder::ResetThreadRole();
|
||||
std::this_thread::sleep_for(1ms);
|
||||
}
|
||||
});
|
||||
ZoneBuilder::CommandThread = Utils::Thread::CreateNamedThread("Command Thread", ZoneBuilder::CommandThreadCallback);
|
||||
ZoneBuilder::CommandThread.detach();
|
||||
|
||||
Command::Add("quit", ZoneBuilder::Com_Quitf_t);
|
||||
|
||||
@ -873,8 +881,7 @@ namespace Components
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::Warning(Game::CON_CHANNEL_DONT_FILTER,
|
||||
"Missing new init zones (defaults.ff & techsets.ff). You will need to load fastfiles to manually obtain techsets.\n");
|
||||
Logger::Warning(Game::CON_CHANNEL_DONT_FILTER, "Missing new init zones (defaults.ff & techsets.ff). You will need to load fastfiles to manually obtain techsets.\n");
|
||||
Game::DB_LoadXAssets(baseZones_old, ARRAYSIZE(baseZones_old), 0);
|
||||
}
|
||||
|
||||
@ -908,7 +915,7 @@ namespace Components
|
||||
}
|
||||
|
||||
Logger::Print(" --------------------------------------------------------------------------------\n");
|
||||
Logger::Print(" IW4x ZoneBuilder (" VERSION ")\n");
|
||||
Logger::Print(" IW4x ZoneBuilder ({})\n", VERSION);
|
||||
Logger::Print(" Commands:\n");
|
||||
Logger::Print("\t-buildzone [zone]: builds a zone from a csv located in zone_source\n");
|
||||
Logger::Print("\t-buildall: builds all zones in zone_source\n");
|
||||
@ -1006,8 +1013,8 @@ namespace Components
|
||||
{
|
||||
assert(data);
|
||||
auto* sound = Utils::Hook::Get<Game::MssSound*>(0x112AE04);
|
||||
auto length = sound->info.data_len;
|
||||
auto allocatedSpace = Game::Z_Malloc(length);
|
||||
const auto length = sound->info.data_len;
|
||||
const auto allocatedSpace = Game::Z_Malloc(static_cast<int>(length));
|
||||
memcpy_s(allocatedSpace, length, data, length);
|
||||
|
||||
data = allocatedSpace;
|
||||
@ -1022,8 +1029,6 @@ namespace Components
|
||||
AssertSize(Game::XFile, 40);
|
||||
static_assert(Game::MAX_XFILE_COUNT == 8, "XFile block enum is invalid!");
|
||||
|
||||
ZoneBuilder::EndAssetTrace();
|
||||
|
||||
if (ZoneBuilder::IsEnabled())
|
||||
{
|
||||
// Prevent loading textures (preserves loaddef)
|
||||
@ -1035,10 +1040,10 @@ namespace Components
|
||||
// Release the loaddef
|
||||
Game::DB_ReleaseXAssetHandlers[Game::XAssetType::ASSET_TYPE_IMAGE] = ZoneBuilder::ReleaseTexture;
|
||||
|
||||
//r_loadForrenderer = 0
|
||||
// r_loadForrenderer = 0
|
||||
Utils::Hook::Set<BYTE>(0x519DDF, 0);
|
||||
|
||||
//r_delayloadimage retn
|
||||
// r_delayloadimage ret
|
||||
Utils::Hook::Set<BYTE>(0x51F450, 0xC3);
|
||||
|
||||
// r_registerDvars hack
|
||||
@ -1056,7 +1061,7 @@ namespace Components
|
||||
// Don't mark assets
|
||||
//Utils::Hook::Nop(0x5BB632, 5);
|
||||
|
||||
// Don't load sounds
|
||||
// Load sounds
|
||||
Utils::Hook(0x492EFC, ReallocateLoadedSounds, HOOK_CALL).install()->quick();
|
||||
|
||||
// Don't display errors when assets are missing (we might manually build those)
|
||||
@ -1092,14 +1097,14 @@ namespace Components
|
||||
Utils::Hook::Set<DWORD>(0x64A029, 0x38400000); // 900 MiB
|
||||
Utils::Hook::Set<DWORD>(0x64A057, 0x38400000);
|
||||
|
||||
// change fs_game domain func
|
||||
// change FS_GameDirDomainFunc
|
||||
Utils::Hook::Set<int(*)(Game::dvar_t*, Game::DvarValue)>(0x643203, [](Game::dvar_t* dvar, Game::DvarValue value)
|
||||
{
|
||||
int result = Utils::Hook::Call<int(Game::dvar_t*, Game::DvarValue)>(0x642FC0)(dvar, value);
|
||||
|
||||
if (result)
|
||||
{
|
||||
if (std::string(value.string) != dvar->current.string)
|
||||
if (std::strcmp(value.string, dvar->current.string) != 0)
|
||||
{
|
||||
dvar->current.string = value.string;
|
||||
Game::FS_Restart(0, 0);
|
||||
@ -1118,7 +1123,7 @@ namespace Components
|
||||
// handle Com_error Calls
|
||||
Utils::Hook(Game::Com_Error, ZoneBuilder::HandleError, HOOK_JUMP).install()->quick();
|
||||
|
||||
// thread fuckery hooks
|
||||
// Sys_IsMainThread hook
|
||||
Utils::Hook(0x4C37D0, ZoneBuilder::IsThreadMainThreadHook, HOOK_JUMP).install()->quick();
|
||||
|
||||
// Don't exec startup config in fs_restart
|
||||
@ -1134,31 +1139,16 @@ namespace Components
|
||||
{
|
||||
if (!ZoneBuilder::TraceZone.empty() && ZoneBuilder::TraceZone == FastFiles::Current())
|
||||
{
|
||||
ZoneBuilder::TraceAssets.push_back({ type, name });
|
||||
OutputDebugStringA((name + "\n").data());
|
||||
ZoneBuilder::TraceAssets.emplace_back(std::make_pair(type, name));
|
||||
#ifdef _DEBUG
|
||||
OutputDebugStringA(Utils::String::Format("%s\n", name));
|
||||
#endif
|
||||
}
|
||||
});
|
||||
|
||||
Command::Add("verifyzone", [](Command::Params* params)
|
||||
{
|
||||
if (params->size() < 2) return;
|
||||
/*
|
||||
Utils::Hook(0x4AE9C2, []
|
||||
{
|
||||
Game::WeaponCompleteDef** varPtr = (Game::WeaponCompleteDef**)0x112A9F4;
|
||||
Game::WeaponCompleteDef* var = *varPtr;
|
||||
OutputDebugStringA("");
|
||||
Utils::Hook::Call<void()>(0x4D1D60)(); // DB_PopStreamPos
|
||||
}, HOOK_JUMP).install()->quick();
|
||||
|
||||
Utils::Hook(0x4AE9B4, []
|
||||
{
|
||||
Game::WeaponCompleteDef** varPtr = (Game::WeaponCompleteDef**)0x112A9F4;
|
||||
Game::WeaponCompleteDef* var = *varPtr;
|
||||
OutputDebugStringA("");
|
||||
Utils::Hook::Call<void()>(0x4D1D60)(); // DB_PopStreamPos
|
||||
}, HOOK_JUMP).install()->quick();
|
||||
*/
|
||||
|
||||
std::string zone = params->get(1);
|
||||
|
||||
@ -1601,7 +1591,7 @@ namespace Components
|
||||
|
||||
ZoneBuilder::~ZoneBuilder()
|
||||
{
|
||||
ZoneBuilder::Terminate = true;
|
||||
ZoneBuilder::CommandThreadTerminate = true;
|
||||
if (ZoneBuilder::CommandThread.joinable())
|
||||
{
|
||||
ZoneBuilder::CommandThread.join();
|
||||
|
@ -74,7 +74,7 @@ namespace Components
|
||||
bool isPrimaryAsset() { return this->assetDepth <= 1; }
|
||||
|
||||
private:
|
||||
void loadFastFiles();
|
||||
void loadFastFiles() const;
|
||||
|
||||
bool loadAssets();
|
||||
bool loadAssetByName(const std::string& type, std::string name, bool isSubAsset = true);
|
||||
@ -140,7 +140,7 @@ namespace Components
|
||||
static std::string FindMaterialByTechnique(const std::string& name);
|
||||
static void ReallocateLoadedSounds(void*& data, void* a2);
|
||||
|
||||
static int __stdcall EntryPoint(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nShowCmd*/);
|
||||
static BOOL APIENTRY EntryPoint(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nShowCmd*/);
|
||||
static void HandleError(Game::errorParm_t code, const char* fmt, ...);
|
||||
static void SoftErrorAssetOverflow();
|
||||
|
||||
@ -151,10 +151,12 @@ namespace Components
|
||||
|
||||
static void Com_Quitf_t();
|
||||
|
||||
static void CommandThreadCallback();
|
||||
|
||||
static bool MainThreadInterrupted;
|
||||
static DWORD InterruptingThreadId;
|
||||
|
||||
static volatile bool Terminate;
|
||||
static volatile bool CommandThreadTerminate;
|
||||
static std::thread CommandThread;
|
||||
};
|
||||
}
|
||||
|
@ -76,3 +76,19 @@ namespace Game
|
||||
|
||||
extern const char* Com_LoadInfoString_FastFile(const char* fileName, const char* fileDesc, const char* ident, char* loadBuffer);
|
||||
}
|
||||
|
||||
#define Com_InitThreadData() \
|
||||
{ \
|
||||
static Game::ProfileStack profile_stack{}; \
|
||||
static Game::va_info_t va_info{}; \
|
||||
static jmp_buf g_com_error{}; \
|
||||
static Game::TraceThreadInfo g_trace_thread_info{}; \
|
||||
static void* g_thread_values[Game::THREAD_VALUE_COUNT]{}; \
|
||||
auto** thread_data = \
|
||||
Game::Sys::GetTls<void*>(Game::Sys::ThreadOffset::THREAD_VALUES); \
|
||||
*thread_data = g_thread_values; \
|
||||
Game::Sys_SetValue(Game::THREAD_VALUE_PROF_STACK, &profile_stack); \
|
||||
Game::Sys_SetValue(Game::THREAD_VALUE_VA, &va_info); \
|
||||
Game::Sys_SetValue(Game::THREAD_VALUE_COM_ERROR, &g_com_error); \
|
||||
Game::Sys_SetValue(Game::THREAD_VALUE_TRACE, &g_trace_thread_info); \
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ namespace Game
|
||||
Cbuf_AddServerText_f_t Cbuf_AddServerText_f = Cbuf_AddServerText_f_t(0x4BB9B0);
|
||||
Cbuf_AddText_t Cbuf_AddText = Cbuf_AddText_t(0x404B20);
|
||||
Cbuf_InsertText_t Cbuf_InsertText = Cbuf_InsertText_t(0x4940B0);
|
||||
Cbuf_Execute_t Cbuf_Execute = Cbuf_Execute_t(0x4E2C80);
|
||||
|
||||
CG_DrawDisconnect_t CG_DrawDisconnect = CG_DrawDisconnect_t(0x454A70);
|
||||
CG_NextWeapon_f_t CG_NextWeapon_f = CG_NextWeapon_f_t(0x449DE0);
|
||||
@ -381,7 +382,9 @@ namespace Game
|
||||
|
||||
Material** whiteMaterial = reinterpret_cast<Material**>(0x8EE4B8);
|
||||
|
||||
unsigned long* _tls_index = reinterpret_cast<unsigned long*>(0x66D94A8);
|
||||
unsigned long* g_dwTlsIndex = reinterpret_cast<unsigned long*>(0x66D94A8);
|
||||
|
||||
bgs_t* level_bgs = reinterpret_cast<bgs_t*>(0x19BD680);
|
||||
|
||||
unsigned int* playerCardUIStringIndex = reinterpret_cast<unsigned int*>(0x62CD7A8);
|
||||
char (*playerCardUIStringBuf)[PLAYER_CARD_UI_STRING_COUNT][38] = reinterpret_cast<char(*)[PLAYER_CARD_UI_STRING_COUNT][38]>(0x62CB4F8);
|
||||
|
@ -15,6 +15,9 @@ namespace Game
|
||||
typedef void(*Cbuf_InsertText_t)(int localClientNum, const char* text);
|
||||
extern Cbuf_InsertText_t Cbuf_InsertText;
|
||||
|
||||
typedef void(*Cbuf_Execute_t)(int localClientNum, int controllerIndex);
|
||||
extern Cbuf_Execute_t Cbuf_Execute;
|
||||
|
||||
typedef void(*CG_DrawDisconnect_t)(int localClientNum);
|
||||
extern CG_DrawDisconnect_t CG_DrawDisconnect;
|
||||
|
||||
@ -712,7 +715,9 @@ namespace Game
|
||||
|
||||
extern Material** whiteMaterial;
|
||||
|
||||
extern unsigned long* _tls_index;
|
||||
extern unsigned long* g_dwTlsIndex;
|
||||
|
||||
extern bgs_t* level_bgs;
|
||||
|
||||
constexpr std::size_t PLAYER_CARD_UI_STRING_COUNT = 18;
|
||||
extern unsigned int* playerCardUIStringIndex;
|
||||
|
@ -10333,6 +10333,59 @@ namespace Game
|
||||
TraceCheckCount checkcount;
|
||||
};
|
||||
|
||||
struct ProfileAtom
|
||||
{
|
||||
unsigned int value[1];
|
||||
};
|
||||
|
||||
volatile struct ProfileReadable
|
||||
{
|
||||
unsigned int hits;
|
||||
ProfileAtom total;
|
||||
ProfileAtom self;
|
||||
};
|
||||
|
||||
struct ProfileWritable
|
||||
{
|
||||
int nesting;
|
||||
unsigned int hits;
|
||||
ProfileAtom start[3];
|
||||
ProfileAtom total;
|
||||
ProfileAtom child;
|
||||
};
|
||||
|
||||
struct profile_t
|
||||
{
|
||||
ProfileWritable write;
|
||||
ProfileReadable read;
|
||||
};
|
||||
|
||||
struct profile_guard_t
|
||||
{
|
||||
int id;
|
||||
profile_t** ppStack;
|
||||
};
|
||||
|
||||
struct ProfileStack
|
||||
{
|
||||
profile_t prof_root;
|
||||
profile_t* prof_pStack[16384];
|
||||
profile_t** prof_ppStack;
|
||||
profile_t prof_array[443];
|
||||
ProfileAtom prof_overhead_internal;
|
||||
ProfileAtom prof_overhead_external;
|
||||
profile_guard_t prof_guardstack[32];
|
||||
int prof_guardpos;
|
||||
float prof_timescale;
|
||||
};
|
||||
|
||||
struct bgs_t
|
||||
{
|
||||
unsigned char __pad0[0x82950];
|
||||
};
|
||||
|
||||
static_assert(sizeof(bgs_t) == 0x82950);
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#ifndef IDA
|
||||
|
@ -21,6 +21,7 @@ namespace Game
|
||||
Sys_SendPacket_t Sys_SendPacket = Sys_SendPacket_t(0x60FDC0);
|
||||
Sys_ShowConsole_t Sys_ShowConsole = Sys_ShowConsole_t(0x4305E0);
|
||||
Sys_SuspendOtherThreads_t Sys_SuspendOtherThreads = Sys_SuspendOtherThreads_t(0x45A190);
|
||||
Sys_SetValue_t Sys_SetValue = Sys_SetValue_t(0x4B2F50);
|
||||
|
||||
char(*sys_exitCmdLine)[1024] = reinterpret_cast<char(*)[1024]>(0x649FB68);
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
namespace Game
|
||||
{
|
||||
|
||||
typedef void(*Sys_Error_t)(const char* error, ...);
|
||||
extern Sys_Error_t Sys_Error;
|
||||
|
||||
@ -60,6 +59,9 @@ namespace Game
|
||||
typedef void(*Sys_SuspendOtherThreads_t)();
|
||||
extern Sys_SuspendOtherThreads_t Sys_SuspendOtherThreads;
|
||||
|
||||
typedef void(*Sys_SetValue_t)(int valueIndex, void* data);
|
||||
extern Sys_SetValue_t Sys_SetValue;
|
||||
|
||||
extern char(*sys_exitCmdLine)[1024];
|
||||
|
||||
extern RTL_CRITICAL_SECTION* s_criticalSection;
|
||||
@ -68,4 +70,22 @@ namespace Game
|
||||
extern void Sys_UnlockRead(FastCriticalSection* critSect);
|
||||
|
||||
extern bool Sys_TryEnterCriticalSection(CriticalSection critSect);
|
||||
|
||||
class Sys
|
||||
{
|
||||
public:
|
||||
enum ThreadOffset : unsigned int
|
||||
{
|
||||
LEVEL_BGS = 0xC,
|
||||
THREAD_VALUES = 0x14,
|
||||
DVAR_MODIFIED_FLAGS = 0x18,
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
static T* GetTls(ThreadOffset offset)
|
||||
{
|
||||
const auto* tls = reinterpret_cast<std::uintptr_t*>(__readfsdword(0x2C));
|
||||
return reinterpret_cast<T*>(tls[*g_dwTlsIndex] + offset);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user