smol thingy's
This commit is contained in:
parent
9fad4ec948
commit
0d8ca4ef7a
@ -42,7 +42,7 @@ namespace auth
|
||||
|
||||
std::string get_protected_data()
|
||||
{
|
||||
std::string input = "X-Labs-S1x-Auth";
|
||||
std::string input = "X-Labs-H1Mod-Auth";
|
||||
|
||||
DATA_BLOB data_in{}, data_out{};
|
||||
data_in.pbData = reinterpret_cast<uint8_t*>(input.data());
|
||||
|
1
src/client/component/binding.cpp
Normal file
1
src/client/component/binding.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include <std_include.hpp>
|
1
src/client/component/exception.cpp
Normal file
1
src/client/component/exception.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include <std_include.hpp>
|
@ -243,10 +243,10 @@ namespace network
|
||||
utils::hook::call(0x140480E62, &net_compare_address); // H1MP64(1.4)
|
||||
|
||||
// increase cl_maxpackets
|
||||
dvars::override::register_int("cl_maxpackets", 1000, 1, 1000, game::DVAR_FLAG_SAVED);
|
||||
dvars::override::register_int("cl_maxpackets", 1000, 1, 1000, game::DVAR_FLAG_SAVED, true);
|
||||
|
||||
// increase snaps
|
||||
dvars::override::register_int("sv_remote_client_snapshot_msec", 33, 33, 100, game::DVAR_FLAG_NONE);
|
||||
dvars::override::register_int("sv_remote_client_snapshot_msec", 33, 33, 100, game::DVAR_FLAG_NONE, true);
|
||||
|
||||
// ignore impure client
|
||||
utils::hook::jump(0x140481B58, reinterpret_cast<void*>(0x140481BEE)); // H1MP64(1.4)
|
||||
@ -256,10 +256,10 @@ namespace network
|
||||
utils::hook::set<uint8_t>(0x14051345A, 0); // H1MP64(1.4)
|
||||
|
||||
// don't read checksum
|
||||
utils::hook::jump(0x140513389, 0x14051339F);
|
||||
utils::hook::jump(0x140513389, 0x14051339F); // H1MP64(1.4)
|
||||
|
||||
// don't try to reconnect client
|
||||
utils::hook::call(0x140480DFF, reconnect_migratated_client);
|
||||
utils::hook::call(0x140480DFF, reconnect_migratated_client); // H1MP64(1.4)
|
||||
utils::hook::nop(0x140480DDB, 4); // H1MP64(1.4) this crashes when reconnecting for some reason
|
||||
|
||||
// allow server owner to modify net_port before the socket bind
|
||||
|
78
src/client/component/patches.cpp
Normal file
78
src/client/component/patches.cpp
Normal file
@ -0,0 +1,78 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include "game/game.hpp"
|
||||
#include "game/dvars.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/string.hpp>
|
||||
#include <component/scheduler.hpp>
|
||||
|
||||
namespace patches
|
||||
{
|
||||
namespace
|
||||
{
|
||||
utils::hook::detour gscr_set_save_dvar_hook;
|
||||
utils::hook::detour dvar_register_float_hook;
|
||||
|
||||
void gscr_set_save_dvar_stub()
|
||||
{
|
||||
const auto string = utils::string::to_lower(utils::hook::invoke<const char*>(SELECT_VALUE(0x140375210, 0x140443150), 0));
|
||||
if (string == "cg_fov" || string == "cg_fovscale")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
gscr_set_save_dvar_hook.invoke<void>();
|
||||
}
|
||||
|
||||
game::dvar_t* cg_fov = nullptr;
|
||||
game::dvar_t* cg_fovScale = nullptr;
|
||||
|
||||
game::dvar_t* dvar_register_float_stub(int hash, const char* dvarName, float value, float min, float max, unsigned int flags)
|
||||
{
|
||||
static const auto cg_fov_hash = game::generateHashValue("cg_fov");
|
||||
static const auto cg_fov_scale_hash = game::generateHashValue("cg_fovscale");
|
||||
|
||||
if (hash == cg_fov_hash)
|
||||
{
|
||||
return cg_fov;
|
||||
}
|
||||
|
||||
if (hash == cg_fov_scale_hash)
|
||||
{
|
||||
return cg_fovScale;
|
||||
}
|
||||
|
||||
return dvar_register_float_hook.invoke<game::dvar_t*>(hash, dvarName, value, min, max, flags);
|
||||
}
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
// Unlock fps in main menu
|
||||
utils::hook::set<BYTE>(SELECT_VALUE(0x14018D47B, 0x14025B86B), 0xEB); // H1(1.4)
|
||||
|
||||
// Fix mouse lag
|
||||
utils::hook::nop(SELECT_VALUE(0x1403E3C05, 0x1404DB1AF), 6);
|
||||
scheduler::loop([]()
|
||||
{
|
||||
SetThreadExecutionState(ES_DISPLAY_REQUIRED);
|
||||
}, scheduler::pipeline::main);
|
||||
|
||||
// Prevent game from overriding cg_fov and cg_fovscale values
|
||||
gscr_set_save_dvar_hook.create(SELECT_VALUE(0x1402AE020, 0x14036B600), &gscr_set_save_dvar_stub);
|
||||
|
||||
// Make cg_fov and cg_fovscale saved dvars
|
||||
cg_fov = dvars::register_float("cg_fov", 65.f, 40.f, 200.f, game::DvarFlags::DVAR_FLAG_SAVED, true);
|
||||
cg_fovScale = dvars::register_float("cg_fovScale", 1.f, 0.1f, 2.f, game::DvarFlags::DVAR_FLAG_SAVED, true);
|
||||
|
||||
dvar_register_float_hook.create(game::Dvar_RegisterFloat.get(), dvar_register_float_stub);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(patches::component)
|
53
src/client/component/slowmotion.cpp
Normal file
53
src/client/component/slowmotion.cpp
Normal file
@ -0,0 +1,53 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
#include "game/game.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/string.hpp>
|
||||
|
||||
namespace slowmotion
|
||||
{
|
||||
namespace
|
||||
{
|
||||
void scr_cmd_set_slow_motion()
|
||||
{
|
||||
if (game::Scr_GetNumParam() < 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int duration = 1000;
|
||||
float end = 1.0f;
|
||||
const float start = game::Scr_GetFloat(0);
|
||||
|
||||
if (game::Scr_GetNumParam() >= 2)
|
||||
{
|
||||
end = game::Scr_GetFloat(1u);
|
||||
}
|
||||
|
||||
if (game::Scr_GetNumParam() >= 3)
|
||||
{
|
||||
duration = static_cast<int>(game::Scr_GetFloat(2u) * 1000.0f);
|
||||
}
|
||||
|
||||
game::SV_SetConfigstring(10, utils::string::va("%i %i %g %g", *game::mp::gameTime, duration, start, end));
|
||||
game::Com_SetSlowMotion(start, end, duration);
|
||||
}
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
if (!game::environment::is_dedi())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
utils::hook::jump(0x140365480, scr_cmd_set_slow_motion); // H1(1.4)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(slowmotion::component)
|
100
src/client/component/system_check.cpp
Normal file
100
src/client/component/system_check.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
#include "system_check.hpp"
|
||||
|
||||
#include "game/game.hpp"
|
||||
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/cryptography.hpp>
|
||||
|
||||
namespace system_check
|
||||
{
|
||||
namespace
|
||||
{
|
||||
std::string read_zone(const std::string& name)
|
||||
{
|
||||
std::string data{};
|
||||
if (utils::io::read_file(name, &data))
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
if (utils::io::read_file("zone/" + name, &data))
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string hash_zone(const std::string& name)
|
||||
{
|
||||
const auto data = read_zone(name);
|
||||
return utils::cryptography::sha256::compute(data, true);
|
||||
}
|
||||
|
||||
bool verify_hashes(const std::unordered_map<std::string, std::string>& zone_hashes)
|
||||
{
|
||||
for (const auto& zone_hash : zone_hashes)
|
||||
{
|
||||
const auto hash = hash_zone(zone_hash.first);
|
||||
if (hash != zone_hash.second)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_system_valid()
|
||||
{
|
||||
static std::unordered_map<std::string, std::string> mp_zone_hashes =
|
||||
{
|
||||
{"patch_common_mp.ff", "3F44B0CFB0B8E0FBD9687C2942204AB7F11E66E6E15C73B8B4A5EB5920115A31"},
|
||||
};
|
||||
|
||||
static std::unordered_map<std::string, std::string> sp_zone_hashes =
|
||||
{
|
||||
// Steam doesn't necessarily deliver this file :(
|
||||
{"patch_common.ff", "BB0617DD94AF2F511571E7184BBEDE76E64D97E5D0DAFDB457F00717F035EBF0"},
|
||||
};
|
||||
|
||||
|
||||
return verify_hashes(mp_zone_hashes) && (game::environment::is_dedi() || verify_hashes(sp_zone_hashes));
|
||||
}
|
||||
|
||||
void verify_binary_version()
|
||||
{
|
||||
const auto value = *reinterpret_cast<DWORD*>(0x140001337);
|
||||
if (value != 0xFFB8006D && value != 0xFFB80080)
|
||||
{
|
||||
throw std::runtime_error("Unsupported Call of Duty: Modern Warfare Remastered version(1.4)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool is_valid()
|
||||
{
|
||||
static auto valid = is_system_valid();
|
||||
return valid;
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
void post_load() override
|
||||
{
|
||||
verify_binary_version();
|
||||
|
||||
if (!is_valid())
|
||||
{
|
||||
MessageBoxA(nullptr, "Your game files are outdated or unsupported.\n"
|
||||
"Please get the latest officially supported Call of Duty: Modern Warfare Remastered 1.4 files, or you will get random crashes and issues.",
|
||||
"Invalid game files!", MB_ICONINFORMATION);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(system_check::component)
|
6
src/client/component/system_check.hpp
Normal file
6
src/client/component/system_check.hpp
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
namespace system_check
|
||||
{
|
||||
bool is_valid();
|
||||
}
|
60
src/client/component/thread_names.cpp
Normal file
60
src/client/component/thread_names.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include "scheduler.hpp"
|
||||
|
||||
#include "game/game.hpp"
|
||||
|
||||
#include <utils/thread.hpp>
|
||||
|
||||
namespace thread_names
|
||||
{
|
||||
namespace
|
||||
{
|
||||
void set_thread_names()
|
||||
{
|
||||
static std::unordered_map<int, std::string> thread_names =
|
||||
{
|
||||
{game::THREAD_CONTEXT_MAIN, "Main"},
|
||||
{game::THREAD_CONTEXT_BACKEND, "Backend"}, // Renderer
|
||||
{game::THREAD_CONTEXT_WORKER0, "Worker0"},
|
||||
{game::THREAD_CONTEXT_WORKER1, "Worker1"},
|
||||
{game::THREAD_CONTEXT_WORKER2, "Worker2"},
|
||||
{game::THREAD_CONTEXT_WORKER3, "Worker3"},
|
||||
{game::THREAD_CONTEXT_WORKER4, "Worker4"},
|
||||
{game::THREAD_CONTEXT_WORKER5, "Worker5"},
|
||||
{game::THREAD_CONTEXT_WORKER6, "Worker6"},
|
||||
{game::THREAD_CONTEXT_WORKER7, "Worker7"},
|
||||
{game::THREAD_CONTEXT_SERVER, "Server"},
|
||||
{game::THREAD_CONTEXT_CINEMATIC, "Cinematic"},
|
||||
{game::THREAD_CONTEXT_DATABASE, "Database"},
|
||||
{game::THREAD_CONTEXT_STREAM, "Stream"},
|
||||
{game::THREAD_CONTEXT_SNDSTREAMPACKETCALLBACK, "Snd stream packet callback"},
|
||||
{game::THREAD_CONTEXT_STATS_WRITE, "Stats write"},
|
||||
};
|
||||
|
||||
for (const auto& thread_name : thread_names)
|
||||
{
|
||||
const auto id = game::threadIds[thread_name.first];
|
||||
if (id)
|
||||
{
|
||||
utils::thread::set_name(id, thread_name.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
set_thread_names();
|
||||
scheduler::once(set_thread_names, scheduler::pipeline::main);
|
||||
scheduler::once(set_thread_names, scheduler::pipeline::renderer);
|
||||
scheduler::once(set_thread_names, scheduler::pipeline::server);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(thread_names::component)
|
55
src/client/component/videos.cpp
Normal file
55
src/client/component/videos.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include "game/game.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
|
||||
namespace videos
|
||||
{
|
||||
namespace
|
||||
{
|
||||
utils::hook::detour playvid_hook;
|
||||
std::unordered_map<std::string, std::string> video_replaces;
|
||||
|
||||
void playvid(const char* name, const int a2, const int a3)
|
||||
{
|
||||
const auto vid = video_replaces.find(name);
|
||||
if (vid != video_replaces.end())
|
||||
{
|
||||
char path[256];
|
||||
game::Sys_BuildAbsPath(path, sizeof(path), game::SF_VIDEO, vid->second.data(), ".bik");
|
||||
|
||||
if (game::Sys_FileExists(path))
|
||||
{
|
||||
name = vid->second.data();
|
||||
}
|
||||
}
|
||||
|
||||
return playvid_hook.invoke<void>(name, a2, a3);
|
||||
}
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
playvid_hook.create(SELECT_VALUE(0x1404A9D00, 0x1405B0AF0), &playvid); // H1(1.4)
|
||||
|
||||
if (game::environment::is_mp())
|
||||
{
|
||||
video_replaces["menus_bg_comp2"] = "menus_bg_h1mod";
|
||||
video_replaces["mp_menus_bg_options"] = "menus_bg_h1mod_blur";
|
||||
}
|
||||
else if (game::environment::is_sp())
|
||||
{
|
||||
video_replaces["sp_menus_bg_main_menu"] = "menus_bg_h1mod_sp";
|
||||
video_replaces["sp_menus_bg_campaign"] = "menus_bg_h1mod_sp";
|
||||
video_replaces["sp_menus_bg_options"] = "menus_bg_h1mod_sp";
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(videos::component)
|
@ -21,6 +21,8 @@ namespace dvars
|
||||
game::dvar_t* r_fullbright;
|
||||
game::dvar_t* r_chams;
|
||||
|
||||
game::dvar_t* cg_legacyCrashHandling;
|
||||
|
||||
std::string dvar_get_vector_domain(const int components, const game::dvar_limits& domain)
|
||||
{
|
||||
if (domain.vector.min == -FLT_MAX)
|
||||
@ -196,6 +198,7 @@ namespace dvars
|
||||
"cg_fovExtraCam",
|
||||
"cg_fovMin",
|
||||
"cg_fovScale",
|
||||
"cg_legacyCrashHandling",
|
||||
"cl_maxpackets",
|
||||
"cl_maxPing",
|
||||
"com_introPlayed",
|
||||
|
@ -21,6 +21,8 @@ namespace dvars
|
||||
extern game::dvar_t* r_fullbright;
|
||||
extern game::dvar_t* r_chams;
|
||||
|
||||
extern game::dvar_t* cg_legacyCrashHandling;
|
||||
|
||||
extern std::vector<std::string> dvar_list;
|
||||
|
||||
std::string dvar_get_vector_domain(const int components, const game::dvar_limits& domain);
|
||||
|
@ -17,10 +17,14 @@ namespace game
|
||||
|
||||
WEAK symbol<CodPlayMode()> Com_GetCurrentCoDPlayMode{ 0, 0x1405039A0 }; // H1(1.4)
|
||||
|
||||
WEAK symbol<void(float, float, int)> Com_SetSlowMotion{ 0, 0x1400DB790 }; // H1(1.4)
|
||||
|
||||
WEAK symbol<void(unsigned int weapon, bool isAlternate, char* output, unsigned int maxStringLen)> BG_GetWeaponNameComplete{ 0, 0x140165580 };
|
||||
|
||||
WEAK symbol<void()> Com_Quit_f{ 0x140352BE0, 0x1400DA830 }; // H1(1.4)
|
||||
|
||||
WEAK symbol<const char* (int, int, int)> Key_KeynumToString{ 0x140187CC0, 0x14024FE10 }; // H1(1.4)
|
||||
|
||||
WEAK symbol<void(const char* text_in)> Cmd_TokenizeString{ 0x140344110, 0x1404046F0 }; // H1(1.4)
|
||||
|
||||
WEAK symbol<void(const char* dvar, const char* buffer)> Dvar_SetCommand{ 0x1403C72B0, 0x1404FD0A0 }; // H1(1.4)
|
||||
@ -46,7 +50,9 @@ namespace game
|
||||
WEAK symbol<dvar_t* (int dvarName, const char* a2, float x, float y, float z, float w, float min, float max, unsigned int flags)> Dvar_RegisterVec4{ 0x1403C5220, 0x1404FAF40 }; // H1(1.4)
|
||||
WEAK symbol<dvar_t* (const char* dvarName, const char** valueList, int defaultIndex, unsigned int flags)> Dvar_RegisterEnum{ 0x1403C4AC0, 0x1404C0EC0 }; // H1(1.4)
|
||||
|
||||
WEAK symbol<float(int index)> Scr_GetFloat{ 0x140374D20, 0x140442D10 }; // H1(1.4)
|
||||
|
||||
WEAK symbol<int()> Scr_GetNumParam{ 0x140374F30, 0x140442E70 }; // H1(1.4)
|
||||
|
||||
WEAK symbol<long long(const char* qpath, char** buffer)> FS_ReadFile{ 0x1403B9020, 0x1404EE720 }; // H1(1.4)
|
||||
|
||||
@ -171,6 +177,8 @@ namespace game
|
||||
WEAK symbol<const char* (scr_string_t stringValue)> SL_ConvertToString{ 0x14036D420, 0x1405BFBB0 };
|
||||
WEAK symbol<scr_string_t(const char* str, unsigned int user)> SL_GetString{ 0x14036D9A0, 0x1405C0170 };
|
||||
|
||||
WEAK symbol<void(int index, const char* string)> SV_SetConfigstring{ 0, 0x140486720 }; // H1(1.4)
|
||||
|
||||
WEAK symbol<bool()> SV_Loaded{ 0x140442F60, 0x1404864A0 }; // H1(1.4)
|
||||
|
||||
WEAK symbol<bool(const char* map)> SV_MapExists{ 0, 0x14047ED60 }; // H1(1.4)
|
||||
@ -192,9 +200,16 @@ namespace game
|
||||
|
||||
WEAK symbol<void(int arg, char* buffer, int bufferLength)> SV_Cmd_ArgvBuffer{ 0x1402EEFD0, 0x1403B05C0 };
|
||||
|
||||
// Variables
|
||||
WEAK symbol<CmdArgs> sv_cmd_args{ 0, 0x14946BA20 }; // mwr maybe
|
||||
WEAK symbol<void(char* path, int pathSize, Sys_Folder folder, const char* filename, const char* ext)>
|
||||
Sys_BuildAbsPath{ 0x1403CFF90, 0x140507010 }; // H1(1.4)
|
||||
|
||||
WEAK symbol<bool(const char* path)> Sys_FileExists{ 0x1403E0CE0, 0x1405115E0 }; // H1(1.4)
|
||||
|
||||
// Variables
|
||||
WEAK symbol<CmdArgs> sv_cmd_args{ 0, 0x14946BA20 }; // H1(1.4)
|
||||
|
||||
|
||||
WEAK symbol<const char*> command_whitelist{ 0x141079A60, 0x14120C6D0 }; // H1(1.4)
|
||||
|
||||
WEAK symbol<const char*> g_assetNames{ 0, 0x140BEF280 };
|
||||
WEAK symbol<int> g_poolSize{ 0, 0x140FEADF0 }; // H1(1.4)
|
||||
@ -214,14 +229,17 @@ namespace game
|
||||
WEAK symbol<function_stack_t> scr_function_stack{ 0,0x14BAA93C0 };
|
||||
WEAK symbol<void*> DB_XAssetPool{ 0x140DE8C80, 0x140FEB5D0 }; // H1(1.4)
|
||||
|
||||
WEAK symbol<DWORD> threadIds{0x14B19B880, 0x149810E00 }; // H1(1.4)
|
||||
|
||||
namespace mp
|
||||
{
|
||||
WEAK symbol<gentity_s> g_entities{ 0, 0x14621E530 }; // H1(1.4)
|
||||
WEAK symbol<client_t> svs_clients{ 0, 0x14B204A10 }; // H1(1.4)
|
||||
WEAK symbol<int> gameTime{ 0, 0x14621BDBC }; // H1(1.4)
|
||||
}
|
||||
|
||||
namespace sp
|
||||
{
|
||||
WEAK symbol<gentity_s> g_entities{ 0x14550DD90 , 0 };
|
||||
WEAK symbol<gentity_s> g_entities{ 0x14550DD90 , 0 }; // H1(1.4)
|
||||
}
|
||||
}
|
||||
|
@ -110,16 +110,6 @@ void remove_crash_file()
|
||||
utils::io::remove_file("__h1Exe");
|
||||
}
|
||||
|
||||
void verify_mwr_version()
|
||||
{
|
||||
const auto value = *reinterpret_cast<DWORD*>(0x140001337);
|
||||
//sp && mp
|
||||
if (value != 0xFFB8006D && value != 0xFFB80080)
|
||||
{
|
||||
throw std::runtime_error("Unsupported Call of Duty: Modern Warfare Remastered version"s);
|
||||
}
|
||||
}
|
||||
|
||||
void enable_dpi_awareness()
|
||||
{
|
||||
const utils::nt::library user32{"user32.dll"};
|
||||
@ -203,8 +193,6 @@ int main()
|
||||
|
||||
if (!component_loader::post_load()) return 0;
|
||||
|
||||
verify_mwr_version();
|
||||
|
||||
premature_shutdown = false;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
|
Loading…
Reference in New Issue
Block a user