From e999a859a7cafdd2beda827f0e6c8c1105196a15 Mon Sep 17 00:00:00 2001 From: Zach Toogood Date: Wed, 12 Mar 2025 12:56:27 +0000 Subject: [PATCH] Core: Improve logging from watchdog --- settings/default/logging.lua | 1 - src/common/console_service.cpp | 6 ++ src/common/kernel.cpp | 32 ++++++-- src/common/logging.h | 74 +++++++++--------- src/common/macros.h | 5 ++ src/map/map.cpp | 137 +++++++++++++++++---------------- src/map/navmesh.cpp | 16 ++++ 7 files changed, 161 insertions(+), 110 deletions(-) diff --git a/settings/default/logging.lua b/settings/default/logging.lua index ea08ccb1af2..0093fbdc240 100644 --- a/settings/default/logging.lua +++ b/settings/default/logging.lua @@ -44,7 +44,6 @@ xi.settings.logging = LOG_LUA = true, -- Prints from Lua using `print()` -- Specific Debug loggers - -- NOTE: None of these will print unless you also have the above LOG_DEBUG setting set to true! DEBUG_SOCKETS = false, -- Calls in C++: DebugSockets(...) DEBUG_IPC = false, -- Calls in C++: DebugIPC(...) DEBUG_NAVMESH = false, -- Calls in C++: DebugNavmesh(...) diff --git a/src/common/console_service.cpp b/src/common/console_service.cpp index 860f4478b69..0e613f7ae1a 100644 --- a/src/common/console_service.cpp +++ b/src/common/console_service.cpp @@ -150,6 +150,12 @@ ConsoleService::ConsoleService() crash(); }); + RegisterCommand("throw", "Throw an exception from the console worker thread", + [](std::vector& inputs) + { + throw std::runtime_error("Exception thrown from console command (from worker thread)"); + }); + RegisterCommand("db", "Run both a query and a prepared statement to test the database connection", [](std::vector& inputs) { diff --git a/src/common/kernel.cpp b/src/common/kernel.cpp index aa82bef37af..d0c357e13ee 100644 --- a/src/common/kernel.cpp +++ b/src/common/kernel.cpp @@ -122,7 +122,9 @@ sigfunc* compat_signal(int signo, sigfunc* func) #endif if (sigaction(signo, &sact, &oact) < 0) + { return (SIG_ERR); + } return (oact.sa_handler); } @@ -166,7 +168,6 @@ static void sig_proc(int sn) raise(sn); #endif // _DEBUG #endif // _WIN32 - break; #ifndef _WIN32 case SIGXFSZ: @@ -255,20 +256,35 @@ int main(int argc, char** argv) // clang-format off auto period = settings::get("main.INACTIVITY_WATCHDOG_PERIOD"); auto periodMs = (period > 0) ? std::chrono::milliseconds(period) : 2000ms; - auto watchdog = Watchdog(periodMs, [&]() + auto watchdog = Watchdog(periodMs, [period]() { - ShowCritical(fmt::format("Process main tick has taken {}ms or more.", period).c_str()); if (debug::isRunningUnderDebugger()) { + ShowCritical("!!! INACTIVITY WATCHDOG HAS TRIGGERED !!!"); + ShowCriticalFmt("Process main tick has taken {}ms or more.", period); ShowCritical("Detaching watchdog thread, it will not fire again until restart."); } else if (!settings::get("main.DISABLE_INACTIVITY_WATCHDOG")) { -#ifndef SIGKILL -#define SIGKILL 9 -#endif // SIGKILL - ShowCritical("Watchdog thread time exceeded. Killing process."); - std::raise(SIGKILL); + std::string outputStr = "!!! INACTIVITY WATCHDOG HAS TRIGGERED !!!\n\n"; + + outputStr += fmt::format("Process main tick has taken {}ms or more.\n", period); + outputStr += fmt::format("Backtrace Messages:\n\n"); + + const auto backtrace = logging::GetBacktrace(); + for (const auto& line : backtrace) + { + outputStr += fmt::format(" {}\n", line); + } + + outputStr += "\nKilling Process!!!\n"; + + ShowCritical(outputStr); + + // Allow some time for logging to flush + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + + throw std::runtime_error("Watchdog thread time exceeded. Killing process."); } }); // clang-format on diff --git a/src/common/logging.h b/src/common/logging.h index 8d89442c24d..041bd9f8160 100644 --- a/src/common/logging.h +++ b/src/common/logging.h @@ -23,6 +23,7 @@ #define _LOGGING_H #include "cbasetypes.h" +#include "macros.h" #include "tracy.h" #include @@ -126,59 +127,62 @@ inline auto format_as(type v) \ } STATEMENT_CLOSE #define LOGGER_BODY(LOG_TYPE_MACRO, LogStringName, ...) \ - BEGIN_CATCH_HANDLER auto _msgStr = fmt::sprintf(__VA_ARGS__); TracyZoneScoped; TracyMessageStr(_msgStr); LOG_TYPE_MACRO(spdlog::get(LogStringName), _msgStr); END_CATCH_HANDLER + BEGIN_CATCH_HANDLER const auto _msgStr = fmt::sprintf(__VA_ARGS__); TracyZoneScoped; TracyMessageStr(_msgStr); logging::AddBacktrace(_msgStr); LOG_TYPE_MACRO(spdlog::get(LogStringName), _msgStr); END_CATCH_HANDLER + +#define LOGGER_BODY_CONDITIONAL(LOG_TYPE_MACRO, LogStringName, LogConditionStr, ...) \ + BEGIN_CATCH_HANDLER const auto _msgStr = fmt::sprintf(__VA_ARGS__); TracyZoneScoped; TracyMessageStr(_msgStr); logging::AddBacktrace(_msgStr); if (settings::get(LogConditionStr)) { LOG_TYPE_MACRO(spdlog::get(LogStringName), _msgStr); } END_CATCH_HANDLER #define LOGGER_BODY_FMT(LOG_TYPE_MACRO, LogStringName, ...) \ - BEGIN_CATCH_HANDLER auto _msgStr = fmt::format(__VA_ARGS__); TracyZoneScoped; TracyMessageStr(_msgStr); LOG_TYPE_MACRO(spdlog::get(LogStringName), _msgStr); END_CATCH_HANDLER + BEGIN_CATCH_HANDLER const auto _msgStr = fmt::format(__VA_ARGS__); TracyZoneScoped; TracyMessageStr(_msgStr); logging::AddBacktrace(_msgStr); LOG_TYPE_MACRO(spdlog::get(LogStringName), _msgStr); END_CATCH_HANDLER -#define LOGGER_ENABLE(SettingsString, ...) \ - if (settings::get(SettingsString)) { __VA_ARGS__ ; } STATEMENT_CLOSE +#define LOGGER_BODY_CONDITIONAL_FMT(LOG_TYPE_MACRO, LogStringName, LogConditionStr, ...) \ + BEGIN_CATCH_HANDLER const auto _msgStr = fmt::format(__VA_ARGS__); TracyZoneScoped; TracyMessageStr(_msgStr); logging::AddBacktrace(_msgStr); if (settings::get(LogConditionStr)) { LOG_TYPE_MACRO(spdlog::get(LogStringName), _msgStr); } END_CATCH_HANDLER // Regular Loggers -// NOTE 1: Trace is not for logging to screen or file; it's for filling the crash backtrace buffer and reporting to Tracy. +// NOTE 1: Trace is not for logging to screen or file; it's for filling the backtrace buffer and reporting to Tracy. // NOTE 2: It isn't possible (or a good idea) to allow the user to disable TRACE, ERROR, or CRITICAL logging. #define ShowTrace(...) logging::AddBacktrace(fmt::sprintf(__VA_ARGS__)) -#define ShowDebug(...) LOGGER_ENABLE("logging.LOG_DEBUG", LOGGER_BODY(SPDLOG_LOGGER_DEBUG, "debug", __VA_ARGS__)) -#define ShowInfo(...) LOGGER_ENABLE("logging.LOG_INFO", LOGGER_BODY(SPDLOG_LOGGER_INFO, "info", __VA_ARGS__)) -#define ShowWarning(...) LOGGER_ENABLE("logging.LOG_WARNING", LOGGER_BODY(SPDLOG_LOGGER_WARN, "warn", __VA_ARGS__)) -#define ShowLua(...) LOGGER_ENABLE("logging.LOG_LUA", LOGGER_BODY(SPDLOG_LOGGER_INFO, "lua", __VA_ARGS__)) +#define ShowDebug(...) LOGGER_BODY_CONDITIONAL(SPDLOG_LOGGER_DEBUG, "debug", "logging.LOG_DEBUG", __VA_ARGS__) +#define ShowInfo(...) LOGGER_BODY_CONDITIONAL(SPDLOG_LOGGER_INFO, "info", "logging.LOG_INFO", __VA_ARGS__) +#define ShowWarning(...) LOGGER_BODY_CONDITIONAL(SPDLOG_LOGGER_WARN, "warn", "logging.LOG_WARNING", __VA_ARGS__) +#define ShowLua(...) LOGGER_BODY_CONDITIONAL(SPDLOG_LOGGER_INFO, "lua", "logging.LOG_LUA", __VA_ARGS__) #define ShowError(...) LOGGER_BODY(SPDLOG_LOGGER_ERROR, "error", __VA_ARGS__) #define ShowCritical(...) LOGGER_BODY(SPDLOG_LOGGER_CRITICAL, "critical", __VA_ARGS__) // Regular Loggers fmt variants #define ShowTraceFmt(...) logging::AddBacktrace(fmt::format(__VA_ARGS__)) -#define ShowDebugFmt(...) LOGGER_ENABLE("logging.LOG_DEBUG", LOGGER_BODY_FMT(SPDLOG_LOGGER_DEBUG, "debug", __VA_ARGS__)) -#define ShowInfoFmt(...) LOGGER_ENABLE("logging.LOG_INFO", LOGGER_BODY_FMT(SPDLOG_LOGGER_INFO, "info", __VA_ARGS__)) -#define ShowWarningFmt(...) LOGGER_ENABLE("logging.LOG_WARNING", LOGGER_BODY_FMT(SPDLOG_LOGGER_WARN, "warn", __VA_ARGS__)) -#define ShowLuaFmt(...) LOGGER_ENABLE("logging.LOG_LUA", LOGGER_BODY_FMT(SPDLOG_LOGGER_INFO, "lua", __VA_ARGS__)) +#define ShowDebugFmt(...) LOGGER_BODY_CONDITIONAL_FMT(SPDLOG_LOGGER_DEBUG, "debug", "logging.LOG_DEBUG", __VA_ARGS__) +#define ShowInfoFmt(...) LOGGER_BODY_CONDITIONAL_FMT(SPDLOG_LOGGER_INFO, "info", "logging.LOG_INFO", __VA_ARGS__) +#define ShowWarningFmt(...) LOGGER_BODY_CONDITIONAL_FMT(SPDLOG_LOGGER_WARN, "warn", "logging.LOG_WARNING", __VA_ARGS__) +#define ShowLuaFmt(...) LOGGER_BODY_CONDITIONAL_FMT(SPDLOG_LOGGER_INFO, "lua", "logging.LOG_LUA", __VA_ARGS__) #define ShowErrorFmt(...) LOGGER_BODY_FMT(SPDLOG_LOGGER_ERROR, "error", __VA_ARGS__) #define ShowCriticalFmt(...) LOGGER_BODY_FMT(SPDLOG_LOGGER_CRITICAL, "critical", __VA_ARGS__) // Debug Loggers -#define DebugSockets(...) LOGGER_ENABLE("logging.DEBUG_SOCKETS", ShowDebug(__VA_ARGS__)) -#define DebugIPC(...) LOGGER_ENABLE("logging.DEBUG_IPC", ShowDebug(__VA_ARGS__)) -#define DebugNavmesh(...) LOGGER_ENABLE("logging.DEBUG_NAVMESH", ShowDebug(__VA_ARGS__)) -#define DebugPackets(...) LOGGER_ENABLE("logging.DEBUG_PACKETS", ShowDebug(__VA_ARGS__)) -#define DebugActions(...) LOGGER_ENABLE("logging.DEBUG_ACTIONS", ShowDebug(__VA_ARGS__)) -#define DebugSQL(...) LOGGER_ENABLE("logging.DEBUG_SQL", ShowDebug(__VA_ARGS__)) -#define DebugIDLookup(...) LOGGER_ENABLE("logging.DEBUG_ID_LOOKUP", ShowDebug(__VA_ARGS__)) -#define DebugModules(...) LOGGER_ENABLE("logging.DEBUG_MODULES", ShowDebug(__VA_ARGS__)) -#define DebugAuctions(...) LOGGER_ENABLE("logging.DEBUG_AUCTIONS", ShowDebug(__VA_ARGS__)) -#define DebugDeliveryBox(...) LOGGER_ENABLE("logging.DEBUG_DELIVERY_BOX", ShowDebug(__VA_ARGS__)) -#define DebugBazaars(...) LOGGER_ENABLE("logging.DEBUG_BAZAARS", ShowDebug(__VA_ARGS__)) +#define DebugSockets(...) LOGGER_BODY_CONDITIONAL(SPDLOG_LOGGER_DEBUG, "debug", "logging.DEBUG_SOCKETS", __VA_ARGS__) +#define DebugIPC(...) LOGGER_BODY_CONDITIONAL(SPDLOG_LOGGER_DEBUG, "debug", "logging.DEBUG_IPC", __VA_ARGS__) +#define DebugNavmesh(...) LOGGER_BODY_CONDITIONAL(SPDLOG_LOGGER_DEBUG, "debug", "logging.DEBUG_NAVMESH",__VA_ARGS__) +#define DebugPackets(...) LOGGER_BODY_CONDITIONAL(SPDLOG_LOGGER_DEBUG, "debug", "logging.DEBUG_PACKETS",__VA_ARGS__) +#define DebugActions(...) LOGGER_BODY_CONDITIONAL(SPDLOG_LOGGER_DEBUG, "debug", "logging.DEBUG_ACTIONS", __VA_ARGS__) +#define DebugSQL(...) LOGGER_BODY_CONDITIONAL(SPDLOG_LOGGER_DEBUG, "debug", "logging.DEBUG_SQL", __VA_ARGS__) +#define DebugIDLookup(...) LOGGER_BODY_CONDITIONAL(SPDLOG_LOGGER_DEBUG, "debug", "logging.DEBUG_ID_LOOKUP", __VA_ARGS__) +#define DebugModules(...) LOGGER_BODY_CONDITIONAL(SPDLOG_LOGGER_DEBUG, "debug", "logging.DEBUG_MODULES", __VA_ARGS__) +#define DebugAuctions(...) LOGGER_BODY_CONDITIONAL(SPDLOG_LOGGER_DEBUG, "debug", "logging.DEBUG_AUCTIONS", __VA_ARGS__) +#define DebugDeliveryBox(...) LOGGER_BODY_CONDITIONAL(SPDLOG_LOGGER_DEBUG, "debug", "logging.DEBUG_DELIVERY_BOX", __VA_ARGS__) +#define DebugBazaars(...) LOGGER_BODY_CONDITIONAL(SPDLOG_LOGGER_DEBUG, "debug", "logging.DEBUG_BAZAARS", __VA_ARGS__) // Debug Loggers fmt variants -#define DebugSocketsFmt(...) LOGGER_ENABLE("logging.DEBUG_SOCKETS", ShowDebugFmt(__VA_ARGS__)) -#define DebugIPCFmt(...) LOGGER_ENABLE("logging.DEBUG_IPC", ShowDebugFmt(__VA_ARGS__)) -#define DebugNavmeshFmt(...) LOGGER_ENABLE("logging.DEBUG_NAVMESH", ShowDebugFmt(__VA_ARGS__)) -#define DebugPacketsFmt(...) LOGGER_ENABLE("logging.DEBUG_PACKETS", ShowDebugFmt(__VA_ARGS__)) -#define DebugActionsFmt(...) LOGGER_ENABLE("logging.DEBUG_ACTIONS", ShowDebugFmt(__VA_ARGS__)) -#define DebugSQLFmt(...) LOGGER_ENABLE("logging.DEBUG_SQL", ShowDebugFmt(__VA_ARGS__)) -#define DebugIDLookupFmt(...) LOGGER_ENABLE("logging.DEBUG_ID_LOOKUP", ShowDebugFmt(__VA_ARGS__)) -#define DebugModulesFmt(...) LOGGER_ENABLE("logging.DEBUG_MODULES", ShowDebugFmt(__VA_ARGS__)) -#define DebugAuctionsFmt(...) LOGGER_ENABLE("logging.DEBUG_AUCTIONS", ShowDebugFmt(__VA_ARGS__)) -#define DebugDeliveryBoxFmt(...) LOGGER_ENABLE("logging.DEBUG_DELIVERY_BOX", ShowDebugFmt(__VA_ARGS__)) -#define DebugBazaarsFmt(...) LOGGER_ENABLE("logging.DEBUG_BAZAARS", ShowDebugFmt(__VA_ARGS__)) +#define DebugSocketsFmt(...) LOGGER_BODY_CONDITIONAL_FMT(SPDLOG_LOGGER_DEBUG, "debug", "logging.DEBUG_SOCKETS", __VA_ARGS__) +#define DebugIPCFmt(...) LOGGER_BODY_CONDITIONAL_FMT(SPDLOG_LOGGER_DEBUG, "debug", "logging.DEBUG_IPC", __VA_ARGS__) +#define DebugNavmeshFmt(...) LOGGER_BODY_CONDITIONAL_FMT(SPDLOG_LOGGER_DEBUG, "debug", "logging.DEBUG_NAVMESH", __VA_ARGS__) +#define DebugPacketsFmt(...) LOGGER_BODY_CONDITIONAL_FMT(SPDLOG_LOGGER_DEBUG, "debug", "logging.DEBUG_PACKETS", __VA_ARGS__) +#define DebugActionsFmt(...) LOGGER_BODY_CONDITIONAL_FMT(SPDLOG_LOGGER_DEBUG, "debug", "logging.DEBUG_ACTIONS", __VA_ARGS__) +#define DebugSQLFmt(...) LOGGER_BODY_CONDITIONAL_FMT(SPDLOG_LOGGER_DEBUG, "debug", "logging.DEBUG_SQL", __VA_ARGS__) +#define DebugIDLookupFmt(...) LOGGER_BODY_CONDITIONAL_FMT(SPDLOG_LOGGER_DEBUG, "debug", "logging.DEBUG_ID_LOOKUP", __VA_ARGS__) +#define DebugModulesFmt(...) LOGGER_BODY_CONDITIONAL_FMT(SPDLOG_LOGGER_DEBUG, "debug", "logging.DEBUG_MODULES", __VA_ARGS__) +#define DebugAuctionsFmt(...) LOGGER_BODY_CONDITIONAL_FMT(SPDLOG_LOGGER_DEBUG, "debug", "logging.DEBUG_AUCTIONS", __VA_ARGS__) +#define DebugDeliveryBoxFmt(...) LOGGER_BODY_CONDITIONAL_FMT(SPDLOG_LOGGER_DEBUG, "debug", "logging.DEBUG_DELIVERY_BOX", __VA_ARGS__) +#define DebugBazaarsFmt(...) LOGGER_BODY_CONDITIONAL_FMT(SPDLOG_LOGGER_DEBUG, "debug", "logging.DEBUG_BAZAARS", __VA_ARGS__) // clang-format on diff --git a/src/common/macros.h b/src/common/macros.h index dfb4f8903b4..0b327c0ec24 100644 --- a/src/common/macros.h +++ b/src/common/macros.h @@ -102,3 +102,8 @@ #define _gmtime_s(a, b) gmtime_s(a, b) #define _localtime_s(a, b) localtime_s(a, b) #endif + +// MSVC doesn't have __PRETTY_FUNCTION__ so we use an equivalent +#if defined(_MSC_VER) +#define __PRETTY_FUNCTION__ __FUNCSIG__ +#endif diff --git a/src/map/map.cpp b/src/map/map.cpp index 755f546e7cf..c0bcf527819 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -191,6 +191,75 @@ map_session_data_t* mapsession_createsession(uint32 ip, uint16 port) return map_session_data; } +void initConsoleService() +{ + // clang-format off + gConsoleService = std::make_unique(); + + gConsoleService->RegisterCommand("crash", "Force-crash the process.", + [](std::vector& inputs) + { + crash(); + }); + + gConsoleService->RegisterCommand("gm", "Change a character's GM level.", + [](std::vector& inputs) + { + if (inputs.size() != 3) + { + fmt::print("Usage: gm . example: gm Testo 1\n"); + return; + } + + auto name = inputs[1]; + auto* PChar = zoneutils::GetCharByName(name); + if (!PChar) + { + fmt::print("Couldnt find character: {}\n", name); + return; + } + + auto level = std::clamp(static_cast(stoi(inputs[2])), 0, 5); + + PChar->m_GMlevel = level; + + // NOTE: This is the same logic as charutils::SaveCharGMLevel(PChar); + // But we're not executing on the main thread, so we're doing it with + // our own SQL connection. + { + auto otherSql = std::make_unique(); + auto query = "UPDATE %s SET %s %u WHERE charid = %u"; + otherSql->Query(query, "chars", "gmlevel =", PChar->m_GMlevel, PChar->id); + } + + fmt::print("Promoting {} to GM level {}\n", PChar->name, level); + PChar->pushPacket(PChar, MESSAGE_SYSTEM_3, fmt::format("You have been set to GM level {}.", level)); + }); + + gConsoleService->RegisterCommand("reload_settings", "Reload settings files.", + [&](std::vector& inputs) + { + fmt::print("Reloading settings files\n"); + settings::init(); + }); + + gConsoleService->RegisterCommand("reload_recipes", "Reload crafting recipes.", + [&](std::vector& inputs) + { + fmt::print("Reloading crafting recipes\n"); + synthutils::LoadSynthRecipes(); + }); + + gConsoleService->RegisterCommand("exit", "Terminate the program.", + [&](std::vector& inputs) + { + fmt::print("> Goodbye!\n"); + gConsoleService->stop(); + gRunFlag = false; + }); + // clang-format on +} + /************************************************************************ * * * do_init * @@ -352,6 +421,8 @@ int32 do_init(int32 argc, char** argv) PacketGuard::Init(); + initConsoleService(); + moduleutils::OnInit(); luautils::OnServerStart(); @@ -363,72 +434,6 @@ int32 do_init(int32 argc, char** argv) ShowInfo("The map-server is ready to work!"); ShowInfo("======================================================================="); - // clang-format off - gConsoleService = std::make_unique(); - - gConsoleService->RegisterCommand("crash", "Force-crash the process.", - [](std::vector& inputs) - { - crash(); - }); - - gConsoleService->RegisterCommand("gm", "Change a character's GM level.", - [](std::vector& inputs) - { - if (inputs.size() != 3) - { - fmt::print("Usage: gm . example: gm Testo 1\n"); - return; - } - - auto name = inputs[1]; - auto* PChar = zoneutils::GetCharByName(name); - if (!PChar) - { - fmt::print("Couldnt find character: {}\n", name); - return; - } - - auto level = std::clamp(static_cast(stoi(inputs[2])), 0, 5); - - PChar->m_GMlevel = level; - - // NOTE: This is the same logic as charutils::SaveCharGMLevel(PChar); - // But we're not executing on the main thread, so we're doing it with - // our own SQL connection. - { - auto otherSql = std::make_unique(); - auto query = "UPDATE %s SET %s %u WHERE charid = %u"; - otherSql->Query(query, "chars", "gmlevel =", PChar->m_GMlevel, PChar->id); - } - - fmt::print("Promoting {} to GM level {}\n", PChar->name, level); - PChar->pushPacket(PChar, MESSAGE_SYSTEM_3, fmt::format("You have been set to GM level {}.", level)); - }); - - gConsoleService->RegisterCommand("reload_settings", "Reload settings files.", - [&](std::vector& inputs) - { - fmt::print("Reloading settings files\n"); - settings::init(); - }); - - gConsoleService->RegisterCommand("reload_recipes", "Reload crafting recipes.", - [&](std::vector& inputs) - { - fmt::print("Reloading crafting recipes\n"); - synthutils::LoadSynthRecipes(); - }); - - gConsoleService->RegisterCommand("exit", "Terminate the program.", - [&](std::vector& inputs) - { - fmt::print("> Goodbye!\n"); - gConsoleService->stop(); - gRunFlag = false; - }); - // clang-format on - #ifdef TRACY_ENABLE ShowInfo("*** TRACY IS ENABLED ***"); #endif // TRACY_ENABLE diff --git a/src/map/navmesh.cpp b/src/map/navmesh.cpp index 919df177b02..9363756943d 100644 --- a/src/map/navmesh.cpp +++ b/src/map/navmesh.cpp @@ -262,6 +262,8 @@ std::vector CNavMesh::findPath(const position_t& start, const posit return {}; } + DebugNavmesh("CNavMesh::findPath (%f, %f, %f) -> (%f, %f, %f) (%u)", start.x, start.y, start.z, end.x, end.y, end.z, m_zoneID); + std::vector ret{}; dtStatus status = 0; @@ -363,6 +365,8 @@ std::pair CNavMesh::findRandomPosition(const position_t& star return {}; } + DebugNavmesh("CNavMesh::findRandomPosition (%f, %f, %f) (%u)", start.x, start.y, start.z, m_zoneID); + dtStatus status = 0; float spos[3]; @@ -435,6 +439,8 @@ bool CNavMesh::validPosition(const position_t& position) return true; } + DebugNavmesh("CNavMesh::validPosition (%f, %f, %f) (%u)", position.x, position.y, position.z, m_zoneID); + float spos[3]; CNavMesh::ToDetourPos(&position, spos); @@ -465,6 +471,8 @@ bool CNavMesh::findClosestValidPoint(const position_t& position, float* validPoi return true; } + DebugNavmesh("CNavMesh::findClosestValidPoint (%f, %f, %f) (%u)", position.x, position.y, position.z, m_zoneID); + float spos[3]; CNavMesh::ToDetourPos(&position, spos); @@ -494,6 +502,8 @@ bool CNavMesh::findFurthestValidPoint(const position_t& startPosition, const pos return true; } + DebugNavmesh("CNavMesh::findFurthestValidPoint (%f, %f, %f) -> (%f, %f, %f) (%u)", startPosition.x, startPosition.y, startPosition.z, endPosition.x, endPosition.y, endPosition.z, m_zoneID); + float spos[3]; CNavMesh::ToDetourPos(&startPosition, spos); @@ -536,6 +546,8 @@ void CNavMesh::snapToValidPosition(position_t& position) return; } + DebugNavmesh("CNavMesh::snapToValidPosition (%f, %f, %f) (%u)", position.x, position.y, position.z, m_zoneID); + float spos[3]; CNavMesh::ToDetourPos(&position, spos); @@ -574,6 +586,8 @@ bool CNavMesh::onSameFloor(const position_t& start, float* spos, const position_ return true; } + DebugNavmesh("CNavMesh::onSameFloor (%f, %f, %f) -> (%f, %f, %f) (%u)", start.x, start.y, start.z, end.x, end.y, end.z, m_zoneID); + float verticalDistance = abs(start.y - end.y); if (verticalDistance > 2 * verticalLimit) { @@ -642,6 +656,8 @@ bool CNavMesh::raycast(const position_t& start, const position_t& end) return true; } + DebugNavmesh("CNavMesh::raycast (%f, %f, %f) -> (%f, %f, %f) (%u)", start.x, start.y, start.z, end.x, end.y, end.z, m_zoneID); + dtStatus status = 0; float spos[3];