Merge pull request #307 from diamante0018/fix-418

[Dedicated] Fix crash on start
This commit is contained in:
Dss0 2022-06-16 16:42:19 +02:00 committed by GitHub
commit b8bca79c67
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 264 additions and 235 deletions

View File

@ -115,6 +115,9 @@ namespace Components
Loader::Register(new Events()); Loader::Register(new Events());
Loader::Pregame = false; Loader::Pregame = false;
// Make sure preDestroy is called when the game shuts down
Scheduler::OnGameShutdown(Loader::PreDestroy);
} }
void Loader::Uninitialize() void Loader::Uninitialize()

View File

@ -7,6 +7,12 @@ namespace Components
Dvar::Var Branding::CGDrawVersionY; Dvar::Var Branding::CGDrawVersionY;
Game::dvar_t** Branding::Version = reinterpret_cast<Game::dvar_t**>(0x1AD7930); Game::dvar_t** Branding::Version = reinterpret_cast<Game::dvar_t**>(0x1AD7930);
#ifdef _DEBUG
constexpr auto* BUILD_TYPE = "IW4x_DEV MP";
#else
constexpr auto* BUILD_TYPE = "IW4x MP";
#endif
void Branding::CG_DrawVersion() void Branding::CG_DrawVersion()
{ {
// Default values // Default values
@ -45,15 +51,9 @@ namespace Components
const char* Branding::GetVersionString() const char* Branding::GetVersionString()
{ {
#ifdef _DEBUG
const auto* buildType = "IW4x_DEV MP";
#else
const auto* buildType = "IW4x MP";
#endif
// IW4x is technically a beta // IW4x is technically a beta
const auto* result = Utils::String::VA("%s %s build %s %s", const auto* result = Utils::String::VA("%s %s build %s %s",
buildType, "(Beta)", Branding::GetBuildNumber(), reinterpret_cast<const char*>(0x7170A0)); BUILD_TYPE, "(Beta)", Branding::GetBuildNumber(), reinterpret_cast<const char*>(0x7170A0));
return result; return result;
} }
@ -103,6 +103,11 @@ namespace Components
// Short version dvar // Short version dvar
Utils::Hook::Set<const char*>(0x60BD91, SHORTVERSION); Utils::Hook::Set<const char*>(0x60BD91, SHORTVERSION);
// Com_Init_Try_Block_Function
Utils::Hook::Set<const char*>(0x60BAF4, BUILD_TYPE);
Utils::Hook::Set<const char*>(0x60BAEf, SHORTVERSION);
Utils::Hook::Set<const char*>(0x60BAE5, __DATE__);
Utils::Hook(0x4B12B0, Branding::GetBuildNumber, HOOK_JUMP).install()->quick(); Utils::Hook(0x4B12B0, Branding::GetBuildNumber, HOOK_JUMP).install()->quick();
// Version string color // Version string color

View File

@ -410,7 +410,7 @@ namespace Components
{ {
cg_chatWidth = Dvar::Register<int>("cg_chatWidth", 52, 1, std::numeric_limits<int>::max(), Game::DVAR_ARCHIVE, "The normalized maximum width of a chat message"); cg_chatWidth = Dvar::Register<int>("cg_chatWidth", 52, 1, std::numeric_limits<int>::max(), Game::DVAR_ARCHIVE, "The normalized maximum width of a chat message");
sv_disableChat = Dvar::Register<bool>("sv_disableChat", false, Game::dvar_flag::DVAR_NONE, "Disable chat messages from clients"); sv_disableChat = Dvar::Register<bool>("sv_disableChat", false, Game::dvar_flag::DVAR_NONE, "Disable chat messages from clients");
Scheduler::Once(Chat::AddChatCommands, Scheduler::Pipeline::MAIN); Scheduler::OnGameInitialized(AddChatCommands, Scheduler::Pipeline::SERVER);
// Intercept chat sending // Intercept chat sending
Utils::Hook(0x4D000B, PreSayStub, HOOK_CALL).install()->quick(); Utils::Hook(0x4D000B, PreSayStub, HOOK_CALL).install()->quick();

View File

@ -103,7 +103,7 @@ namespace Components
Command::AddRaw(name, Game::Cbuf_AddServerText); Command::AddRaw(name, Game::Cbuf_AddServerText);
} }
FunctionMapSV.insert_or_assign(command, std::move(callback)); FunctionMapSV.insert_or_assign(command, callback);
} }
void Command::AddRaw(const char* name, void(*callback)(), bool key) void Command::AddRaw(const char* name, void(*callback)(), bool key)

View File

@ -53,9 +53,8 @@ namespace Components
static void Add(const char* name, const std::function<void()>& callback); static void Add(const char* name, const std::function<void()>& callback);
static void Add(const char* name, const std::function<void(Command::Params*)>& callback); static void Add(const char* name, const std::function<void(Command::Params*)>& callback);
static void AddSV(const char* name, const std::function<void(Command::Params*)>& callback);
static void AddRaw(const char* name, void(*callback)(), bool key = false); static void AddRaw(const char* name, void(*callback)(), bool key = false);
static void AddRawSV(const char* name, void(*callback)()); static void AddSV(const char* name, const std::function<void(Command::Params*)>& callback);
static void Execute(std::string command, bool sync = true); static void Execute(std::string command, bool sync = true);
static Game::cmd_function_t* Find(const std::string& command); static Game::cmd_function_t* Find(const std::string& command);
@ -64,6 +63,8 @@ namespace Components
static std::unordered_map<std::string, std::function<void(Command::Params*)>> FunctionMap; static std::unordered_map<std::string, std::function<void(Command::Params*)>> FunctionMap;
static std::unordered_map<std::string, std::function<void(Command::Params*)>> FunctionMapSV; static std::unordered_map<std::string, std::function<void(Command::Params*)>> FunctionMapSV;
static void AddRawSV(const char* name, void(*callback)());
static void MainCallback(); static void MainCallback();
static void MainCallbackSV(); static void MainCallbackSV();
}; };

View File

@ -232,7 +232,7 @@ namespace Components
// Only skip intro here, invocation will be done later. // Only skip intro here, invocation will be done later.
Utils::Hook::Set<BYTE>(0x60BECF, 0xEB); Utils::Hook::Set<BYTE>(0x60BECF, 0xEB);
Scheduler::Once([]() Scheduler::Once([]
{ {
Command::Execute("openmenu popup_reconnectingtoparty", false); Command::Execute("openmenu popup_reconnectingtoparty", false);
}, Scheduler::Pipeline::CLIENT, 8s); }, Scheduler::Pipeline::CLIENT, 8s);

View File

@ -140,9 +140,6 @@ namespace Components
void Dedicated::AddDedicatedCommands() void Dedicated::AddDedicatedCommands()
{ {
Dvar::Register<const char*>("sv_sayName", "^7Console", Game::dvar_flag::DVAR_NONE, "The name to pose as for 'say' commands");
Dvar::Register<const char*>("sv_motd", "", Game::dvar_flag::DVAR_NONE, "A custom message of the day for servers");
// Say command // Say command
Command::AddSV("say", [](Command::Params* params) Command::AddSV("say", [](Command::Params* params)
{ {
@ -214,7 +211,7 @@ namespace Components
if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled()) if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled())
{ {
// Make sure all callbacks are handled // Make sure all callbacks are handled
Scheduler::Loop(Steam::SteamAPI_RunCallbacks, Scheduler::Pipeline::MAIN); Scheduler::Loop(Steam::SteamAPI_RunCallbacks, Scheduler::Pipeline::SERVER);
Dedicated::SVLanOnly = Dvar::Register<bool>("sv_lanOnly", false, Dedicated::SVLanOnly = Dvar::Register<bool>("sv_lanOnly", false,
Game::dvar_flag::DVAR_NONE, "Don't act as node"); Game::dvar_flag::DVAR_NONE, "Don't act as node");
@ -282,7 +279,13 @@ namespace Components
if (!ZoneBuilder::IsEnabled()) if (!ZoneBuilder::IsEnabled())
{ {
Scheduler::Once(Dedicated::AddDedicatedCommands, Scheduler::Pipeline::MAIN); Scheduler::Once([]
{
Dvar::Register<const char*>("sv_sayName", "^7Console", Game::dvar_flag::DVAR_NONE, "The name to pose as for 'say' commands");
Dvar::Register<const char*>("sv_motd", "", Game::dvar_flag::DVAR_NONE, "A custom message of the day for servers");
}, Scheduler::Pipeline::MAIN);
Scheduler::OnGameInitialized(Dedicated::AddDedicatedCommands, Scheduler::Pipeline::SERVER);
// Post initialization point // Post initialization point
Utils::Hook(0x60BFBF, Dedicated::PostInitializationStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x60BFBF, Dedicated::PostInitializationStub, HOOK_JUMP).install()->quick();
@ -295,13 +298,8 @@ namespace Components
}, Scheduler::Pipeline::SERVER, 10s); }, Scheduler::Pipeline::SERVER, 10s);
// Heartbeats // Heartbeats
Scheduler::Loop([] Scheduler::Once(Dedicated::Heartbeat, Scheduler::Pipeline::SERVER);
{ Scheduler::Loop(Dedicated::Heartbeat, Scheduler::Pipeline::SERVER, 2min);
if (Dvar::Var("sv_maxclients").get<int>() > 0)
{
Dedicated::Heartbeat();
}
}, Scheduler::Pipeline::SERVER, 2min);
} }
} }
else else

View File

@ -961,7 +961,7 @@ namespace Components
}, Scheduler::Pipeline::MAIN); }, Scheduler::Pipeline::MAIN);
Events::OnVMShutdown([]() Events::OnVMShutdown([]
{ {
Download::ScriptDownloads.clear(); Download::ScriptDownloads.clear();
}); });

View File

@ -213,6 +213,8 @@ namespace Components
Game::dvar_t* Dvar::Dvar_RegisterName(const char* name, const char* /*default*/, unsigned __int16 flags, const char* description) Game::dvar_t* Dvar::Dvar_RegisterName(const char* name, const char* /*default*/, unsigned __int16 flags, const char* description)
{ {
// Name watcher // Name watcher
if (!Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled())
{
Scheduler::Loop([] Scheduler::Loop([]
{ {
static std::string lastValidName = "Unknown Soldier"; static std::string lastValidName = "Unknown Soldier";
@ -232,7 +234,8 @@ namespace Components
lastValidName = name; lastValidName = name;
Friends::UpdateName(); Friends::UpdateName();
} }
}, Scheduler::MAIN, 3s); // Don't need to do this every frame }, Scheduler::CLIENT, 3s); // Don't need to do this every frame
}
std::string username = "Unknown Soldier"; std::string username = "Unknown Soldier";

View File

@ -569,7 +569,9 @@ namespace Components
FastFiles::AddZonePath("zone\\patch\\"); FastFiles::AddZonePath("zone\\patch\\");
FastFiles::AddZonePath("zone\\dlc\\"); FastFiles::AddZonePath("zone\\dlc\\");
Scheduler::Loop([]() if (!Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled())
{
Scheduler::Loop([]
{ {
if (FastFiles::Current().empty() || !Dvar::Var("ui_zoneDebug").get<bool>()) return; if (FastFiles::Current().empty() || !Dvar::Var("ui_zoneDebug").get<bool>()) return;
@ -589,8 +591,9 @@ namespace Components
fastfileLoadProgress = 0.0f; fastfileLoadProgress = 0.0f;
} }
Game::R_AddCmdDrawText(Utils::String::VA("Loading FastFile: %s [%0.1f%%]", FastFiles::Current().data(), fastfileLoadProgress), 0x7FFFFFFF, font, 5.0f, static_cast<float>(Renderer::Height() - 5), 1.0f, 1.0f, 0.0f, color, Game::ITEM_TEXTSTYLE_NORMAL); Game::R_AddCmdDrawText(Utils::String::VA("Loading FastFile: %s [%0.1f%%]", FastFiles::Current().data(), fastfileLoadProgress), std::numeric_limits<int>::max(), font, 5.0f, static_cast<float>(Renderer::Height() - 5), 1.0f, 1.0f, 0.0f, color, Game::ITEM_TEXTSTYLE_NORMAL);
}, Scheduler::Pipeline::RENDERER); }, Scheduler::Pipeline::RENDERER);
}
Command::Add("loadzone", [](Command::Params* params) Command::Add("loadzone", [](Command::Params* params)
{ {

View File

@ -724,7 +724,7 @@ namespace Components
Friends::UpdateState(); Friends::UpdateState();
Friends::UpdateFriends(); Friends::UpdateFriends();
}, Scheduler::Pipeline::MAIN); }, Scheduler::Pipeline::CLIENT);
} }
Friends::~Friends() Friends::~Friends()

View File

@ -246,24 +246,7 @@ namespace Components
} }
} }
Logger::Logger() void Logger::AddServerCommands()
{
Dvar::Register<bool>("iw4x_onelog", false, Game::dvar_flag::DVAR_LATCH | Game::dvar_flag::DVAR_ARCHIVE, "Only write the game log to the 'userraw' OS folder");
Utils::Hook(0x642139, Logger::BuildOSPathStub, HOOK_JUMP).install()->quick();
Logger::PipeOutput(nullptr);
Scheduler::Loop(Logger::Frame, Scheduler::Pipeline::MAIN);
Utils::Hook(0x4B0218, Logger::GameLogStub, HOOK_CALL).install()->quick();
Utils::Hook(Game::Com_PrintMessage, Logger::PrintMessageStub, HOOK_JUMP).install()->quick();
if (Loader::IsPerformingUnitTests())
{
Utils::Hook(Game::Com_Printf, Logger::PrintStub, HOOK_JUMP).install()->quick();
}
Scheduler::Once([]
{ {
Command::AddSV("log_add", [](Command::Params* params) Command::AddSV("log_add", [](Command::Params* params)
{ {
@ -285,22 +268,22 @@ namespace Components
if (Utils::String::VA("%i", num) == std::string(params->get(1)) && static_cast<unsigned int>(num) < Logger::LoggingAddresses[0].size()) if (Utils::String::VA("%i", num) == std::string(params->get(1)) && static_cast<unsigned int>(num) < Logger::LoggingAddresses[0].size())
{ {
auto addr = Logger::LoggingAddresses[0].begin() + num; auto addr = Logger::LoggingAddresses[0].begin() + num;
Logger::Print("Address %s removed\n", addr->getCString()); Logger::Print("Address {} removed\n", addr->getCString());
Logger::LoggingAddresses[0].erase(addr); Logger::LoggingAddresses[0].erase(addr);
} }
else else
{ {
Network::Address addr(params->get(1)); Network::Address addr(params->get(1));
auto i = std::find(Logger::LoggingAddresses[0].begin(), Logger::LoggingAddresses[0].end(), addr); const auto i = std::find(Logger::LoggingAddresses[0].begin(), Logger::LoggingAddresses[0].end(), addr);
if (i != Logger::LoggingAddresses[0].end()) if (i != Logger::LoggingAddresses[0].end())
{ {
Logger::LoggingAddresses[0].erase(i); Logger::LoggingAddresses[0].erase(i);
Logger::Print("Address %s removed\n", addr.getCString()); Logger::Print("Address {} removed\n", addr.getCString());
} }
else else
{ {
Logger::Print("Address %s not found!\n", addr.getCString()); Logger::Print("Address {} not found!\n", addr.getCString());
} }
} }
}); });
@ -312,7 +295,7 @@ namespace Components
for (unsigned int i = 0; i < Logger::LoggingAddresses[0].size(); ++i) for (unsigned int i = 0; i < Logger::LoggingAddresses[0].size(); ++i)
{ {
Logger::Print("#%03d: %5s\n", i, Logger::LoggingAddresses[0][i].getCString()); Logger::Print("{}: {}\n", i, Logger::LoggingAddresses[0][i].getCString());
} }
}); });
@ -320,7 +303,7 @@ namespace Components
{ {
if (params->size() < 2) return; if (params->size() < 2) return;
Network::Address addr(params->get(1)); const Network::Address addr(params->get(1));
if (std::find(Logger::LoggingAddresses[1].begin(), Logger::LoggingAddresses[1].end(), addr) == Logger::LoggingAddresses[1].end()) if (std::find(Logger::LoggingAddresses[1].begin(), Logger::LoggingAddresses[1].end(), addr) == Logger::LoggingAddresses[1].end())
{ {
@ -335,23 +318,23 @@ namespace Components
int num = atoi(params->get(1)); int num = atoi(params->get(1));
if (Utils::String::VA("%i", num) == std::string(params->get(1)) && static_cast<unsigned int>(num) < Logger::LoggingAddresses[1].size()) if (Utils::String::VA("%i", num) == std::string(params->get(1)) && static_cast<unsigned int>(num) < Logger::LoggingAddresses[1].size())
{ {
auto addr = Logger::LoggingAddresses[1].begin() + num; const auto addr = Logger::LoggingAddresses[1].begin() + num;
Logger::Print("Address %s removed\n", addr->getCString()); Logger::Print("Address {} removed\n", addr->getCString());
Logger::LoggingAddresses[1].erase(addr); Logger::LoggingAddresses[1].erase(addr);
} }
else else
{ {
Network::Address addr(params->get(1)); const Network::Address addr(params->get(1));
auto i = std::find(Logger::LoggingAddresses[1].begin(), Logger::LoggingAddresses[1].end(), addr); const auto i = std::find(Logger::LoggingAddresses[1].begin(), Logger::LoggingAddresses[1].end(), addr);
if (i != Logger::LoggingAddresses[1].end()) if (i != Logger::LoggingAddresses[1].end())
{ {
Logger::LoggingAddresses[1].erase(i); Logger::LoggingAddresses[1].erase(i);
Logger::Print("Address %s removed\n", addr.getCString()); Logger::Print("Address {} removed\n", addr.getCString());
} }
else else
{ {
Logger::Print("Address %s not found!\n", addr.getCString()); Logger::Print("Address {} not found!\n", addr.getCString());
} }
} }
}); });
@ -361,12 +344,31 @@ namespace Components
Logger::Print("# ID: Address\n"); Logger::Print("# ID: Address\n");
Logger::Print("-------------\n"); Logger::Print("-------------\n");
for (unsigned int i = 0; i < Logger::LoggingAddresses[1].size(); ++i) for (std::size_t i = 0; i < Logger::LoggingAddresses[1].size(); ++i)
{ {
Logger::Print("#%03d: %5s\n", i, Logger::LoggingAddresses[1][i].getCString()); Logger::Print("{}: {}\n", i, Logger::LoggingAddresses[1][i].getCString());
} }
}); });
}, Scheduler::Pipeline::MAIN); }
Logger::Logger()
{
Dvar::Register<bool>("iw4x_onelog", false, Game::dvar_flag::DVAR_LATCH | Game::dvar_flag::DVAR_ARCHIVE, "Only write the game log to the 'userraw' OS folder");
Utils::Hook(0x642139, Logger::BuildOSPathStub, HOOK_JUMP).install()->quick();
Logger::PipeOutput(nullptr);
Scheduler::Loop(Logger::Frame, Scheduler::Pipeline::SERVER);
Utils::Hook(0x4B0218, Logger::GameLogStub, HOOK_CALL).install()->quick();
Utils::Hook(Game::Com_PrintMessage, Logger::PrintMessageStub, HOOK_JUMP).install()->quick();
if (Loader::IsPerformingUnitTests())
{
Utils::Hook(Game::Com_Printf, Logger::PrintStub, HOOK_JUMP).install()->quick();
}
Scheduler::OnGameInitialized(Logger::AddServerCommands, Scheduler::Pipeline::SERVER);
} }
Logger::~Logger() Logger::~Logger()

View File

@ -23,99 +23,99 @@ namespace Components
static void WarningInternal(int channel, std::string_view fmt, std::format_args&& args); static void WarningInternal(int channel, std::string_view fmt, std::format_args&& args);
static void DebugInternal(bool verbose, const std::source_location& srcLoc, std::string_view fmt, std::format_args&& args); static void DebugInternal(bool verbose, const std::source_location& srcLoc, std::string_view fmt, std::format_args&& args);
static inline void Print(std::string_view fmt) __forceinline static void Print(std::string_view fmt)
{ {
PrintInternal(Game::CON_CHANNEL_DONT_FILTER, fmt, std::make_format_args(0)); PrintInternal(Game::CON_CHANNEL_DONT_FILTER, fmt, std::make_format_args(0));
} }
static inline void Print(int channel, std::string_view fmt) __forceinline static void Print(int channel, std::string_view fmt)
{ {
PrintInternal(channel, fmt, std::make_format_args(0)); PrintInternal(channel, fmt, std::make_format_args(0));
} }
template <typename... Args> template <typename... Args>
static inline void Print(std::string_view fmt, Args&&... args) __forceinline static void Print(std::string_view fmt, Args&&... args)
{ {
PrintInternal(Game::CON_CHANNEL_DONT_FILTER, fmt, std::make_format_args(args...)); PrintInternal(Game::CON_CHANNEL_DONT_FILTER, fmt, std::make_format_args(args...));
} }
template <typename... Args> template <typename... Args>
static inline void Print(int channel, std::string_view fmt, Args&&... args) __forceinline static void Print(int channel, std::string_view fmt, Args&&... args)
{ {
PrintInternal(channel, fmt, std::make_format_args(args...)); PrintInternal(channel, fmt, std::make_format_args(args...));
} }
static inline void Error(Game::errorParm_t error, std::string_view fmt) __forceinline static void Error(Game::errorParm_t error, std::string_view fmt)
{ {
ErrorInternal(error, fmt, std::make_format_args(0)); ErrorInternal(error, fmt, std::make_format_args(0));
} }
template <typename... Args> template <typename... Args>
static inline void Error(Game::errorParm_t error, std::string_view fmt, Args&&... args) __forceinline static void Error(Game::errorParm_t error, std::string_view fmt, Args&&... args)
{ {
ErrorInternal(error, fmt, std::make_format_args(args...)); ErrorInternal(error, fmt, std::make_format_args(args...));
} }
static inline void Warning(int channel, std::string_view fmt) __forceinline static void Warning(int channel, std::string_view fmt)
{ {
WarningInternal(channel, fmt, std::make_format_args(0)); WarningInternal(channel, fmt, std::make_format_args(0));
} }
template <typename... Args> template <typename... Args>
static inline void Warning(int channel, std::string_view fmt, Args&&... args) __forceinline static void Warning(int channel, std::string_view fmt, Args&&... args)
{ {
WarningInternal(channel, fmt, std::make_format_args(args...)); WarningInternal(channel, fmt, std::make_format_args(args...));
} }
static inline void PrintError(int channel, std::string_view fmt) __forceinline static void PrintError(int channel, std::string_view fmt)
{ {
PrintErrorInternal(channel, fmt, std::make_format_args(0)); PrintErrorInternal(channel, fmt, std::make_format_args(0));
} }
template <typename... Args> template <typename... Args>
static inline void PrintError(int channel, std::string_view fmt, Args&&... args) __forceinline static void PrintError(int channel, std::string_view fmt, Args&&... args)
{ {
PrintErrorInternal(channel, fmt, std::make_format_args(args...)); PrintErrorInternal(channel, fmt, std::make_format_args(args...));
} }
#ifdef _DEBUG #ifdef _DEBUG
static inline void DebugInfo([[maybe_unused]] std::string_view fmt) __forceinline static void DebugInfo([[maybe_unused]] std::string_view fmt)
{ {
DebugInternal(true, std::source_location::current(), fmt, std::make_format_args(0)); DebugInternal(true, std::source_location::current(), fmt, std::make_format_args(0));
} }
template <typename... Args> template <typename... Args>
static inline void DebugInfo([[maybe_unused]] std::string_view fmt, [[maybe_unused]] Args&&... args) __forceinline static void DebugInfo([[maybe_unused]] std::string_view fmt, [[maybe_unused]] Args&&... args)
{ {
DebugInternal(true, std::source_location::current(), fmt, std::make_format_args(args...)); DebugInternal(true, std::source_location::current(), fmt, std::make_format_args(args...));
} }
static inline void Debug([[maybe_unused]] std::string_view fmt) __forceinline static void Debug([[maybe_unused]] std::string_view fmt)
{ {
DebugInternal(false, std::source_location::current(), fmt, std::make_format_args(0)); DebugInternal(false, std::source_location::current(), fmt, std::make_format_args(0));
} }
template <typename... Args> template <typename... Args>
static inline void Debug([[maybe_unused]] std::string_view fmt, [[maybe_unused]] Args&&... args) __forceinline static void Debug([[maybe_unused]] std::string_view fmt, [[maybe_unused]] Args&&... args)
{ {
DebugInternal(false, std::source_location::current(), fmt, std::make_format_args(args...)); DebugInternal(false, std::source_location::current(), fmt, std::make_format_args(args...));
} }
#else #else
static inline void DebugInfo([[maybe_unused]] std::string_view fmt) __forceinline static void DebugInfo([[maybe_unused]] std::string_view fmt)
{ {
} }
template <typename... Args> template <typename... Args>
static inline void DebugInfo([[maybe_unused]] std::string_view fmt, [[maybe_unused]] Args&&... args) __forceinline static void DebugInfo([[maybe_unused]] std::string_view fmt, [[maybe_unused]] Args&&... args)
{ {
} }
static inline void Debug([[maybe_unused]] std::string_view fmt) __forceinline static void Debug([[maybe_unused]] std::string_view fmt)
{ {
} }
template <typename... Args> template <typename... Args>
static inline void Debug([[maybe_unused]] std::string_view fmt, [[maybe_unused]] Args&&... args) __forceinline static void Debug([[maybe_unused]] std::string_view fmt, [[maybe_unused]] Args&&... args)
{ {
} }
#endif #endif
@ -136,5 +136,7 @@ namespace Components
static void RedirectOSPath(const char* file, char* folder); static void RedirectOSPath(const char* file, char* folder);
static void NetworkLog(const char* data, bool gLog); static void NetworkLog(const char* data, bool gLog);
static void AddServerCommands();
}; };
} }

View File

@ -7,6 +7,8 @@ namespace Components
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;
Dvar::Var Maps::RListSModels;
bool Maps::SPMap; bool Maps::SPMap;
std::vector<Maps::DLC> Maps::DlcPacks; std::vector<Maps::DLC> Maps::DlcPacks;
@ -775,7 +777,7 @@ namespace Components
Scheduler::Once([] Scheduler::Once([]
{ {
Dvar::Register<bool>("isDlcInstalled_All", false, Game::DVAR_EXTERNAL | Game::DVAR_WRITEPROTECTED, ""); Dvar::Register<bool>("isDlcInstalled_All", false, Game::DVAR_EXTERNAL | Game::DVAR_WRITEPROTECTED, "");
Dvar::Register<bool>("r_listSModels", false, Game::DVAR_NONE, "Display a list of visible SModels"); Maps::RListSModels = Dvar::Register<bool>("r_listSModels", false, Game::DVAR_NONE, "Display a list of visible SModels");
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"} });
@ -882,7 +884,7 @@ namespace Components
Utils::Hook(0x5A9D51, Maps::LoadMapLoadscreenStub, HOOK_CALL).install()->quick(); Utils::Hook(0x5A9D51, Maps::LoadMapLoadscreenStub, HOOK_CALL).install()->quick();
Utils::Hook(0x5B34DD, Maps::LoadMapLoadscreenStub, HOOK_CALL).install()->quick(); Utils::Hook(0x5B34DD, Maps::LoadMapLoadscreenStub, HOOK_CALL).install()->quick();
Command::Add("delayReconnect", [](Command::Params*) Command::Add("delayReconnect", []([[maybe_unused]] Command::Params* params)
{ {
Scheduler::Once([] Scheduler::Once([]
{ {
@ -913,10 +915,16 @@ namespace Components
// Allow hiding specific smodels // Allow hiding specific smodels
Utils::Hook(0x50E67C, Maps::HideModelStub, HOOK_CALL).install()->quick(); Utils::Hook(0x50E67C, Maps::HideModelStub, HOOK_CALL).install()->quick();
if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled())
{
return;
}
// Client only
Scheduler::Loop([] Scheduler::Loop([]
{ {
auto*& gameWorld = *reinterpret_cast<Game::GfxWorld**>(0x66DEE94); auto*& gameWorld = *reinterpret_cast<Game::GfxWorld**>(0x66DEE94);
if (!Game::CL_IsCgameInitialized() || !gameWorld || !Dvar::Var("r_listSModels").get<bool>()) return; if (!Game::CL_IsCgameInitialized() || !gameWorld || !Maps::RListSModels.get<bool>()) return;
std::map<std::string, int> models; std::map<std::string, int> models;
for (unsigned int i = 0; i < gameWorld->dpvs.smodelCount; ++i) for (unsigned int i = 0; i < gameWorld->dpvs.smodelCount; ++i)

View File

@ -83,6 +83,8 @@ 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 Dvar::Var RListSModels;
static void GetBSPName(char* buffer, size_t size, const char* format, const char* mapname); static void GetBSPName(char* buffer, size_t size, const char* format, const char* mapname);
static void LoadAssetRestrict(Game::XAssetType type, Game::XAssetHeader asset, const std::string& name, bool* restrict); static void LoadAssetRestrict(Game::XAssetType type, Game::XAssetHeader asset, const std::string& name, bool* restrict);
static void LoadMapZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync); static void LoadMapZones(Game::XZoneInfo *zoneInfo, unsigned int zoneCount, int sync);

View File

@ -146,7 +146,7 @@ namespace Components
if (!address.isValid()) return; if (!address.isValid()) return;
std::lock_guard<std::recursive_mutex> _(Node::Mutex); std::lock_guard _(Node::Mutex);
for (auto& session : Node::Nodes) for (auto& session : Node::Nodes)
{ {
if (session.address == address) return; if (session.address == address) return;
@ -160,7 +160,7 @@ namespace Components
std::vector<Node::Entry> Node::GetNodes() std::vector<Node::Entry> Node::GetNodes()
{ {
std::lock_guard<std::recursive_mutex> _(Node::Mutex); std::lock_guard _(Node::Mutex);
return Node::Nodes; return Node::Nodes;
} }
@ -197,7 +197,7 @@ namespace Components
if (!frameLimit.elapsed(std::chrono::milliseconds(interval))) return; if (!frameLimit.elapsed(std::chrono::milliseconds(interval))) return;
frameLimit.update(); frameLimit.update();
std::lock_guard<std::recursive_mutex> _(Node::Mutex); std::lock_guard _(Node::Mutex);
Dvar::Var queryLimit("net_serverQueryLimit"); Dvar::Var queryLimit("net_serverQueryLimit");
int sentRequests = 0; int sentRequests = 0;
@ -220,7 +220,7 @@ namespace Components
void Node::Synchronize() void Node::Synchronize()
{ {
std::lock_guard<std::recursive_mutex> _(Node::Mutex); std::lock_guard _(Node::Mutex);
for (auto& node : Node::Nodes) for (auto& node : Node::Nodes)
{ {
//if (node.isValid()) // Comment out to simulate 'syncnodes' behaviour //if (node.isValid()) // Comment out to simulate 'syncnodes' behaviour
@ -237,7 +237,7 @@ namespace Components
Logger::DebugInfo("Received response from {}\n", address.getCString()); Logger::DebugInfo("Received response from {}\n", address.getCString());
std::lock_guard<std::recursive_mutex> _(Node::Mutex); std::lock_guard _(Node::Mutex);
for (int i = 0; i < list.nodes_size(); ++i) for (int i = 0; i < list.nodes_size(); ++i)
{ {
@ -282,9 +282,9 @@ namespace Components
} }
} }
void Node::SendList(Network::Address address) void Node::SendList(const Network::Address& address)
{ {
std::lock_guard<std::recursive_mutex> _(Node::Mutex); std::lock_guard _(Node::Mutex);
// need to keep the message size below 1404 bytes else recipient will just drop it // need to keep the message size below 1404 bytes else recipient will just drop it
std::vector<std::string> nodeListReponseMessages; std::vector<std::string> nodeListReponseMessages;
@ -320,11 +320,13 @@ namespace Components
auto i = 0; auto i = 0;
for (const auto& nodeListData : nodeListReponseMessages) for (const auto& nodeListData : nodeListReponseMessages)
{ {
Scheduler::Once([&] Scheduler::Once([=]
{ {
Logger::DebugInfo("Sending {} nodeListResponse length to {}\n", nodeListData.length(), address.getCString()); #ifdef DEBUG_NODE
Logger::Debug("Sending {} nodeListResponse length to {}\n", nodeListData.length(), address.getCString());
#endif
Session::Send(address, "nodeListResponse", nodeListData); Session::Send(address, "nodeListResponse", nodeListData);
}, Scheduler::Pipeline::MAIN, NODE_SEND_RATE * i++); }, Scheduler::Pipeline::SERVER, NODE_SEND_RATE * i++);
} }
} }
@ -344,16 +346,16 @@ namespace Components
Node::StoreNodes(false); Node::StoreNodes(false);
}, Scheduler::Pipeline::ASYNC); }, Scheduler::Pipeline::ASYNC);
Scheduler::Loop(Node::RunFrame, Scheduler::Pipeline::MAIN); Scheduler::Loop(Node::RunFrame, Scheduler::Pipeline::SERVER);
Session::Handle("nodeListResponse", Node::HandleResponse); Session::Handle("nodeListResponse", Node::HandleResponse);
Session::Handle("nodeListRequest", [](Network::Address address, const std::string&) Session::Handle("nodeListRequest", [](const Network::Address& address, const std::string&)
{ {
Node::SendList(address); Node::SendList(address);
}); });
// Load stored nodes // Load stored nodes
auto loadNodes = []() auto loadNodes = []
{ {
Node::LoadNodePreset(); Node::LoadNodePreset();
Node::LoadNodes(); Node::LoadNodes();
@ -374,7 +376,7 @@ namespace Components
{ {
Logger::Print("Nodes: {}\n", Node::Nodes.size()); Logger::Print("Nodes: {}\n", Node::Nodes.size());
std::lock_guard<std::recursive_mutex> _(Node::Mutex); std::lock_guard _(Node::Mutex);
for (auto& node : Node::Nodes) for (auto& node : Node::Nodes)
{ {
Logger::Print("{}\t({})\n", node.address.getCString(), node.isValid() ? "Valid" : "Invalid"); Logger::Print("{}\t({})\n", node.address.getCString(), node.isValid() ? "Valid" : "Invalid");
@ -390,7 +392,7 @@ namespace Components
Node::~Node() Node::~Node()
{ {
std::lock_guard<std::recursive_mutex> _(Node::Mutex); std::lock_guard _(Node::Mutex);
Node::StoreNodes(true); Node::StoreNodes(true);
Node::Nodes.clear(); Node::Nodes.clear();
} }

View File

@ -51,7 +51,7 @@ namespace Components
static void HandleResponse(Network::Address address, const std::string& data); static void HandleResponse(Network::Address address, const std::string& data);
static void SendList(Network::Address address); static void SendList(const Network::Address& address);
static void LoadNodePreset(); static void LoadNodePreset();
static void LoadNodes(); static void LoadNodes();

View File

@ -286,6 +286,8 @@ namespace Components
Party::Connect(Party::Container.target); Party::Connect(Party::Container.target);
}); });
if (!Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled())
{
Scheduler::Loop([] Scheduler::Loop([]
{ {
if (Party::Container.valid) if (Party::Container.valid)
@ -307,6 +309,7 @@ namespace Components
} }
}, Scheduler::Pipeline::CLIENT); }, Scheduler::Pipeline::CLIENT);
}
// Basic info handler // Basic info handler
Network::OnPacket("getInfo", [](const Network::Address& address, [[maybe_unused]] const std::string& data) Network::OnPacket("getInfo", [](const Network::Address& address, [[maybe_unused]] const std::string& data)

View File

@ -263,9 +263,6 @@ namespace Components
Utils::Hook(0x4FA448, QuickPatch::Dvar_RegisterConMinicon, HOOK_CALL).install()->quick(); Utils::Hook(0x4FA448, QuickPatch::Dvar_RegisterConMinicon, HOOK_CALL).install()->quick();
// Make sure preDestroy is called when the game shuts down
Scheduler::OnGameShutdown(Loader::PreDestroy);
// protocol version (workaround for hacks) // protocol version (workaround for hacks)
Utils::Hook::Set<int>(0x4FB501, PROTOCOL); Utils::Hook::Set<int>(0x4FB501, PROTOCOL);

View File

@ -15,7 +15,7 @@ namespace Components
std::queue<std::pair<Network::Address, std::string>> Session::SignatureQueue; std::queue<std::pair<Network::Address, std::string>> Session::SignatureQueue;
void Session::Send(Network::Address target, const std::string& command, const std::string& data) void Session::Send(const Network::Address& target, const std::string& command, const std::string& data)
{ {
#ifdef DISABLE_SESSION #ifdef DISABLE_SESSION
class DelayedResend class DelayedResend
@ -26,27 +26,27 @@ namespace Components
std::string data; std::string data;
}; };
DelayedResend* delayData = new DelayedResend; auto* delayData = new DelayedResend;
delayData->target = target; delayData->target = target;
delayData->command = command; delayData->command = command;
delayData->data = data; delayData->data = data;
Network::SendCommand(target, command, data); Network::SendCommand(target, command, data);
Scheduler::Once([delayData]() Scheduler::Once([delayData]
{ {
Network::SendCommand(delayData->target, delayData->command, delayData->data); Network::SendCommand(delayData->target, delayData->command, delayData->data);
delete delayData; delete delayData;
}, Scheduler::Pipeline::MAIN, 500ms + std::chrono::milliseconds(rand() % 200)); }, Scheduler::Pipeline::SERVER, 500ms + std::chrono::milliseconds(std::rand() % 200));
#else #else
std::lock_guard<std::recursive_mutex> _(Session::Mutex); std::lock_guard _(Session::Mutex);
auto queue = Session::PacketQueue.find(target); auto queue = Session::PacketQueue.find(target);
if (queue == Session::PacketQueue.end()) if (queue == Session::PacketQueue.end())
{ {
Session::PacketQueue[target] = std::queue<std::shared_ptr<Session::Packet>>(); Session::PacketQueue[target] = std::queue<std::shared_ptr<Session::Packet>>();
queue = Session::PacketQueue.find(target); queue = Session::PacketQueue.find(target);
if (queue == Session::PacketQueue.end()) Logger::Error("Failed to enqueue session packet!\n"); if (queue == Session::PacketQueue.end()) Logger::Error(Game::ERR_FATAL, "Failed to enqueue session packet!\n");
} }
std::shared_ptr<Session::Packet> packet = std::make_shared<Session::Packet>(); std::shared_ptr<Session::Packet> packet = std::make_shared<Session::Packet>();
@ -63,14 +63,14 @@ namespace Components
#ifdef DISABLE_SESSION #ifdef DISABLE_SESSION
Network::OnPacket(packet, callback); Network::OnPacket(packet, callback);
#else #else
std::lock_guard<std::recursive_mutex> _(Session::Mutex); std::lock_guard _(Session::Mutex);
Session::PacketHandlers[packet] = callback; Session::PacketHandlers[packet] = callback;
#endif #endif
} }
void Session::RunFrame() void Session::RunFrame()
{ {
std::lock_guard<std::recursive_mutex> _(Session::Mutex); std::lock_guard _(Session::Mutex);
for (auto queue = Session::PacketQueue.begin(); queue != Session::PacketQueue.end();) for (auto queue = Session::PacketQueue.begin(); queue != Session::PacketQueue.end();)
{ {
@ -155,7 +155,7 @@ namespace Components
Session::Frame frame; Session::Frame frame;
frame.challenge = Utils::Cryptography::Rand::GenerateChallenge(); frame.challenge = Utils::Cryptography::Rand::GenerateChallenge();
std::lock_guard<std::recursive_mutex> _(Session::Mutex); std::lock_guard _(Session::Mutex);
Session::Sessions[address] = frame; Session::Sessions[address] = frame;
Network::SendCommand(address, "sessionAck", frame.challenge); Network::SendCommand(address, "sessionAck", frame.challenge);
@ -163,13 +163,13 @@ namespace Components
Network::OnPacket("sessionAck", [](const Network::Address& address, [[maybe_unused]] const std::string& data) Network::OnPacket("sessionAck", [](const Network::Address& address, [[maybe_unused]] const std::string& data)
{ {
std::lock_guard<std::recursive_mutex> _(Session::Mutex); std::lock_guard _(Session::Mutex);
Session::SignatureQueue.push({ address, data }); Session::SignatureQueue.push({ address, data });
}); });
Network::OnPacket("sessionFin", [](Network::Address& address, [[maybe_unused]] const std::string& data) Network::OnPacket("sessionFin", [](Network::Address& address, [[maybe_unused]] const std::string& data)
{ {
std::lock_guard<std::recursive_mutex> _(Session::Mutex); std::lock_guard _(Session::Mutex);
auto frame = Session::Sessions.find(address); auto frame = Session::Sessions.find(address);
if (frame == Session::Sessions.end()) return; if (frame == Session::Sessions.end()) return;
@ -195,7 +195,7 @@ namespace Components
Session::~Session() Session::~Session()
{ {
std::lock_guard<std::recursive_mutex> _(Session::Mutex); std::lock_guard _(Session::Mutex);
Session::PacketHandlers.clear(); Session::PacketHandlers.clear();
Session::PacketQueue.clear(); Session::PacketQueue.clear();
Session::SignatureQueue = std::queue<std::pair<Network::Address, std::string>>(); Session::SignatureQueue = std::queue<std::pair<Network::Address, std::string>>();

View File

@ -34,7 +34,7 @@ namespace Components
bool unitTest() override; bool unitTest() override;
void preDestroy() override; void preDestroy() override;
static void Send(Network::Address target, const std::string& command, const std::string& data = ""); static void Send(const Network::Address& target, const std::string& command, const std::string& data = "");
static void Handle(const std::string& packet, const Network::NetworkCallback& callback); static void Handle(const std::string& packet, const Network::NetworkCallback& callback);
private: private: