iw4x-client/src/Components/Modules/Logger.cpp

406 lines
9.3 KiB
C++
Raw Normal View History

2022-02-27 07:53:44 -05:00
#include <STDInclude.hpp>
2017-01-19 16:23:59 -05:00
namespace Components
{
std::mutex Logger::MessageMutex;
std::vector<std::string> Logger::MessageQueue;
std::vector<Network::Address> Logger::LoggingAddresses[2];
2018-12-17 08:29:18 -05:00
void(*Logger::PipeCallback)(const std::string&) = nullptr;
2017-01-19 16:23:59 -05:00
bool Logger::IsConsoleReady()
{
return (IsWindow(Console::GetWindow()) != FALSE || (Dedicated::IsEnabled() && !Flags::HasFlag("console")));
2017-01-19 16:23:59 -05:00
}
2022-07-22 05:27:38 -04:00
void Logger::Print_Stub(const int channel, const char* message, ...)
2017-01-19 16:23:59 -05:00
{
2022-06-12 17:07:53 -04:00
char buf[4096] = {0};
2017-01-19 16:23:59 -05:00
2022-06-12 17:07:53 -04:00
va_list va;
va_start(va, message);
_vsnprintf_s(buf, _TRUNCATE, message, va);
va_end(va);
2017-01-19 16:23:59 -05:00
2022-06-12 17:07:53 -04:00
Logger::MessagePrint(channel, {buf});
2017-01-19 16:23:59 -05:00
}
2022-06-12 17:07:53 -04:00
void Logger::MessagePrint(const int channel, const std::string& msg)
2017-01-19 16:23:59 -05:00
{
std::string out = msg;
// Filter out coloured strings for stdout
if (out[0] == '^' && out[1] != '\0')
{
out = out.substr(2);
}
2017-07-03 09:40:32 -04:00
if (Flags::HasFlag("stdout") || Loader::IsPerformingUnitTests())
2017-01-19 16:23:59 -05:00
{
printf("%s", out.data());
2017-01-19 16:23:59 -05:00
fflush(stdout);
return;
}
if (!Logger::IsConsoleReady())
{
OutputDebugStringA(out.data());
2017-01-19 16:23:59 -05:00
}
if (!Game::Sys_IsMainThread())
{
Logger::EnqueueMessage(msg);
2017-01-19 16:23:59 -05:00
}
else
{
Game::Com_PrintMessage(channel, msg.data(), 0);
2017-01-19 16:23:59 -05:00
}
}
void Logger::DebugInternal(std::string_view fmt, std::format_args&& args, [[maybe_unused]] const std::source_location& loc)
2017-01-19 16:23:59 -05:00
{
#ifdef LOGGER_TRACE
2022-07-02 05:41:59 -04:00
const auto msg = std::vformat(fmt, args);
const auto out = std::format("Debug:\n {}\nFile: {}\nLine: {}\n", msg, loc.file_name(), loc.line());
#else
const auto msg = std::vformat(fmt, args);
const auto out = std::format("^2{}\n", msg);
#endif
2017-01-19 16:23:59 -05:00
2022-06-12 17:07:53 -04:00
Logger::MessagePrint(Game::CON_CHANNEL_DONT_FILTER, out);
2017-01-19 16:23:59 -05:00
}
2022-06-12 17:07:53 -04:00
void Logger::PrintInternal(int channel, std::string_view fmt, std::format_args&& args)
2017-01-19 16:23:59 -05:00
{
2022-06-12 17:07:53 -04:00
const auto msg = std::vformat(fmt, args);
Logger::MessagePrint(channel, msg);
2017-01-19 16:23:59 -05:00
}
2022-06-12 17:07:53 -04:00
void Logger::ErrorInternal(const Game::errorParm_t error, const std::string_view fmt, std::format_args&& args)
2017-01-19 16:23:59 -05:00
{
2022-06-12 17:07:53 -04:00
#ifdef _DEBUG
if (IsDebuggerPresent()) __debugbreak();
#endif
const auto msg = std::vformat(fmt, args);
Game::Com_Error(error, "%s", msg.data());
2017-01-19 16:23:59 -05:00
}
2022-06-12 17:07:53 -04:00
void Logger::PrintErrorInternal(int channel, std::string_view fmt, std::format_args&& args)
2017-01-19 16:23:59 -05:00
{
2022-06-12 17:07:53 -04:00
const auto msg = "^1Error: " + std::vformat(fmt, args);
++(*Game::com_errorPrintsCount);
Logger::MessagePrint(channel, msg);
2017-01-19 16:23:59 -05:00
2022-06-12 17:07:53 -04:00
if (*Game::cls_uiStarted != 0 && (*Game::com_fixedConsolePosition == 0))
{
Game::CL_ConsoleFixPosition();
}
}
2022-04-16 04:01:25 -04:00
2022-06-12 17:07:53 -04:00
void Logger::WarningInternal(int channel, std::string_view fmt, std::format_args&& args)
{
const auto msg = "^3" + std::vformat(fmt, args);
2017-01-19 16:23:59 -05:00
2022-06-12 17:07:53 -04:00
Logger::MessagePrint(channel, msg);
2017-01-19 16:23:59 -05:00
}
void Logger::Flush()
{
// if (!Game::Sys_IsMainThread())
// {
// while (!Logger::MessageQueue.empty())
// {
// std::this_thread::sleep_for(10ms);
// }
// }
// else
{
Logger::Frame();
}
}
void Logger::Frame()
{
std::unique_lock _(Logger::MessageMutex);
2017-01-19 16:23:59 -05:00
for (auto i = Logger::MessageQueue.begin(); i != Logger::MessageQueue.end();)
2017-01-19 16:23:59 -05:00
{
Game::Com_PrintMessage(Game::CON_CHANNEL_DONT_FILTER, i->data(), 0);
2017-01-19 16:23:59 -05:00
if (!Logger::IsConsoleReady())
{
OutputDebugStringA(i->data());
2017-01-19 16:23:59 -05:00
}
i = Logger::MessageQueue.erase(i);
}
2017-01-19 16:23:59 -05:00
}
2018-12-17 08:29:18 -05:00
void Logger::PipeOutput(void(*callback)(const std::string&))
2017-01-19 16:23:59 -05:00
{
Logger::PipeCallback = callback;
}
void Logger::PrintMessagePipe(const char* data)
{
if (Logger::PipeCallback)
{
Logger::PipeCallback(data);
}
}
void Logger::NetworkLog(const char* data, bool gLog)
{
if (data == nullptr)
{
return;
}
2017-01-19 16:23:59 -05:00
2022-04-16 04:01:25 -04:00
for (const auto& addr : Logger::LoggingAddresses[gLog & 1])
2017-01-19 16:23:59 -05:00
{
Network::SendCommand(addr, "print", data);
2017-01-19 16:23:59 -05:00
}
}
2022-07-22 05:27:38 -04:00
void Logger::G_LogPrintf_Hk(const char* fmt, ...)
2017-01-19 16:23:59 -05:00
{
2022-07-22 05:27:38 -04:00
char string[1024]{};
char string2[1024]{};
2017-02-01 07:44:25 -05:00
va_list ap;
va_start(ap, fmt);
vsnprintf_s(string2, _TRUNCATE, fmt, ap);
va_end(ap);
2017-01-19 16:23:59 -05:00
2022-07-22 05:27:38 -04:00
const auto time = Game::level->time / 1000;
const auto len = _snprintf_s(string, _TRUNCATE, "%3i:%i%i %s", time / 60, time % 60 / 10, time % 60 % 10, string2);
if (Game::level->logFile != nullptr)
{
Game::FS_Write(string, len, reinterpret_cast<int>(Game::level->logFile));
2017-01-19 16:23:59 -05:00
}
// Allow the network log to run even if logFile was not opened
Logger::NetworkLog(string, true);
2017-01-19 16:23:59 -05:00
}
2022-07-22 05:27:38 -04:00
__declspec(naked) void Logger::PrintMessage_Stub()
2017-01-19 16:23:59 -05:00
{
__asm
{
mov eax, Logger::PipeCallback
test eax, eax
jz returnPrint
2017-02-01 07:44:25 -05:00
pushad
push [esp + 28h]
2017-01-19 16:23:59 -05:00
call Logger::PrintMessagePipe
add esp, 4h
2017-02-01 07:44:25 -05:00
popad
2017-01-19 16:23:59 -05:00
retn
returnPrint:
2017-02-01 07:44:25 -05:00
pushad
2017-01-19 16:23:59 -05:00
push 0
2017-02-01 07:44:25 -05:00
push [esp + 2Ch]
2017-01-19 16:23:59 -05:00
call Logger::NetworkLog
add esp, 8h
2017-02-01 07:44:25 -05:00
popad
2017-01-19 16:23:59 -05:00
push esi
mov esi, [esp + 0Ch]
2017-02-01 07:44:25 -05:00
push 4AA835h
retn
2017-01-19 16:23:59 -05:00
}
}
2018-12-17 08:29:18 -05:00
void Logger::EnqueueMessage(const std::string& message)
2017-01-19 16:23:59 -05:00
{
std::unique_lock _(Logger::MessageMutex);
2017-01-19 16:23:59 -05:00
Logger::MessageQueue.push_back(message);
}
2017-02-24 19:17:11 -05:00
void Logger::RedirectOSPath(const char* file, char* folder)
{
if (Dvar::Var("g_log").get<std::string>() == file)
{
if (folder != "userraw"s)
{
2017-03-18 12:26:35 -04:00
if (Dvar::Var("iw4x_onelog").get<bool>())
2017-02-24 19:17:11 -05:00
{
strcpy_s(folder, 256, "userraw");
}
}
}
}
2022-07-22 05:27:38 -04:00
__declspec(naked) void Logger::BuildOSPath_Stub()
2017-02-24 19:17:11 -05:00
{
__asm
{
pushad
push [esp + 28h]
push [esp + 30h]
call Logger::RedirectOSPath
add esp, 8h
popad
mov eax, [esp + 8h]
push ebp
push esi
mov esi, [esp + 0Ch]
push 64213Fh
retn
}
}
2022-06-16 10:15:26 -04:00
void Logger::AddServerCommands()
2017-01-19 16:23:59 -05:00
{
2022-06-16 10:15:26 -04:00
Command::AddSV("log_add", [](Command::Params* params)
{
if (params->size() < 2) return;
2017-01-19 16:23:59 -05:00
2022-06-16 10:15:26 -04:00
Network::Address addr(params->get(1));
2017-01-19 16:23:59 -05:00
2022-06-16 10:15:26 -04:00
if (std::find(Logger::LoggingAddresses[0].begin(), Logger::LoggingAddresses[0].end(), addr) == Logger::LoggingAddresses[0].end())
{
Logger::LoggingAddresses[0].push_back(addr);
}
});
2017-01-19 16:23:59 -05:00
2022-06-16 10:15:26 -04:00
Command::AddSV("log_del", [](Command::Params* params)
2017-01-19 16:23:59 -05:00
{
2022-06-16 10:15:26 -04:00
if (params->size() < 2) return;
2017-01-19 16:23:59 -05:00
const auto num = atoi(params->get(1));
2022-06-16 10:15:26 -04:00
if (Utils::String::VA("%i", num) == std::string(params->get(1)) && static_cast<unsigned int>(num) < Logger::LoggingAddresses[0].size())
2017-01-19 16:23:59 -05:00
{
2022-06-16 10:15:26 -04:00
auto addr = Logger::LoggingAddresses[0].begin() + num;
2022-08-19 19:10:35 -04:00
Logger::Print("Address {} removed\n", addr->getString());
2022-06-16 10:15:26 -04:00
Logger::LoggingAddresses[0].erase(addr);
}
else
2017-01-19 16:23:59 -05:00
{
2022-06-16 10:15:26 -04:00
Network::Address addr(params->get(1));
2017-01-19 16:23:59 -05:00
2022-06-16 10:15:26 -04:00
const auto i = std::find(Logger::LoggingAddresses[0].begin(), Logger::LoggingAddresses[0].end(), addr);
if (i != Logger::LoggingAddresses[0].end())
2017-01-19 16:23:59 -05:00
{
2022-06-16 10:15:26 -04:00
Logger::LoggingAddresses[0].erase(i);
2022-08-19 19:10:35 -04:00
Logger::Print("Address {} removed\n", addr.getString());
2017-01-19 16:23:59 -05:00
}
else
{
2022-08-19 19:10:35 -04:00
Logger::Print("Address {} not found!\n", addr.getString());
2017-01-19 16:23:59 -05:00
}
2022-06-16 10:15:26 -04:00
}
});
2017-01-19 16:23:59 -05:00
2022-06-16 10:15:26 -04:00
Command::AddSV("log_list", [](Command::Params*)
{
Logger::Print("# ID: Address\n");
Logger::Print("-------------\n");
for (unsigned int i = 0; i < Logger::LoggingAddresses[0].size(); ++i)
2017-01-19 16:23:59 -05:00
{
2022-08-19 19:10:35 -04:00
Logger::Print("#{:03d}: {}\n", i, Logger::LoggingAddresses[0][i].getString());
2022-06-16 10:15:26 -04:00
}
});
2017-01-19 16:23:59 -05:00
2022-06-16 10:15:26 -04:00
Command::AddSV("g_log_add", [](Command::Params* params)
{
if (params->size() < 2) return;
2017-01-19 16:23:59 -05:00
2022-06-16 10:15:26 -04:00
const Network::Address addr(params->get(1));
2017-01-19 16:23:59 -05:00
2022-06-16 10:15:26 -04:00
if (std::find(Logger::LoggingAddresses[1].begin(), Logger::LoggingAddresses[1].end(), addr) == Logger::LoggingAddresses[1].end())
{
Logger::LoggingAddresses[1].push_back(addr);
}
});
2017-01-19 16:23:59 -05:00
2022-06-16 10:15:26 -04:00
Command::AddSV("g_log_del", [](Command::Params* params)
{
if (params->size() < 2) return;
2017-01-19 16:23:59 -05:00
const auto num = std::atoi(params->get(1));
2022-06-16 10:15:26 -04:00
if (Utils::String::VA("%i", num) == std::string(params->get(1)) && static_cast<unsigned int>(num) < Logger::LoggingAddresses[1].size())
{
const auto addr = Logger::LoggingAddresses[1].begin() + num;
2022-08-19 19:10:35 -04:00
Logger::Print("Address {} removed\n", addr->getString());
2022-06-16 10:15:26 -04:00
Logger::LoggingAddresses[1].erase(addr);
}
else
2017-01-19 16:23:59 -05:00
{
2022-06-16 10:15:26 -04:00
const Network::Address addr(params->get(1));
2017-01-19 16:23:59 -05:00
2022-06-16 10:15:26 -04:00
const auto i = std::find(Logger::LoggingAddresses[1].begin(), Logger::LoggingAddresses[1].end(), addr);
if (i != Logger::LoggingAddresses[1].end())
2017-01-19 16:23:59 -05:00
{
2022-06-16 10:15:26 -04:00
Logger::LoggingAddresses[1].erase(i);
2022-08-19 19:10:35 -04:00
Logger::Print("Address {} removed\n", addr.getString());
2017-01-19 16:23:59 -05:00
}
else
{
2022-08-19 19:10:35 -04:00
Logger::Print("Address {} not found!\n", addr.getString());
2017-01-19 16:23:59 -05:00
}
2022-06-16 10:15:26 -04:00
}
});
2017-01-19 16:23:59 -05:00
2022-06-16 10:15:26 -04:00
Command::AddSV("g_log_list", [](Command::Params*)
{
Logger::Print("# ID: Address\n");
Logger::Print("-------------\n");
for (std::size_t i = 0; i < Logger::LoggingAddresses[1].size(); ++i)
2017-01-19 16:23:59 -05:00
{
2022-08-19 19:10:35 -04:00
Logger::Print("#{:03d}: {}\n", i, Logger::LoggingAddresses[1][i].getString());
2022-06-16 10:15:26 -04:00
}
});
}
2017-01-19 16:23:59 -05:00
2022-06-16 10:15:26 -04:00
Logger::Logger()
{
Dvar::Register<bool>("iw4x_onelog", false, Game::DVAR_LATCH | Game::DVAR_ARCHIVE, "Only write the game log to the 'userraw' OS folder");
2022-07-22 05:27:38 -04:00
Utils::Hook(0x642139, Logger::BuildOSPath_Stub, HOOK_JUMP).install()->quick();
2022-06-16 10:15:26 -04:00
Logger::PipeOutput(nullptr);
Scheduler::Loop(Logger::Frame, Scheduler::Pipeline::SERVER);
2022-07-22 05:27:38 -04:00
Utils::Hook(Game::G_LogPrintf, Logger::G_LogPrintf_Hk, HOOK_JUMP).install()->quick();
Utils::Hook(Game::Com_PrintMessage, Logger::PrintMessage_Stub, HOOK_JUMP).install()->quick();
2022-06-16 10:15:26 -04:00
if (Loader::IsPerformingUnitTests())
{
2022-07-22 05:27:38 -04:00
Utils::Hook(Game::Com_Printf, Logger::Print_Stub, HOOK_JUMP).install()->quick();
2022-06-16 10:15:26 -04:00
}
Events::OnSVInit(Logger::AddServerCommands);
2017-01-19 16:23:59 -05:00
}
Logger::~Logger()
{
Logger::LoggingAddresses[0].clear();
Logger::LoggingAddresses[1].clear();
std::unique_lock lock(Logger::MessageMutex);
2017-01-19 16:23:59 -05:00
Logger::MessageQueue.clear();
lock.unlock();
2017-01-19 16:23:59 -05:00
// Flush the console log
if (*Game::logfile)
2017-01-19 16:23:59 -05:00
{
Game::FS_FCloseFile(*Game::logfile);
2017-01-19 16:23:59 -05:00
}
}
}