diff --git a/.gitignore b/.gitignore index 5698779e8..a5e41a779 100644 --- a/.gitignore +++ b/.gitignore @@ -39,4 +39,5 @@ log/ logs/ vcpkg/ -.idea/* \ No newline at end of file +.idea/* +*cbp \ No newline at end of file diff --git a/common/database.cpp b/common/database.cpp index 2ec4675b3..8ff79a44c 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -2063,51 +2063,90 @@ uint32 Database::GetGuildIDByCharID(uint32 character_id) return atoi(row[0]); } -void Database::LoadLogSettings(EQEmuLogSys::LogSettings* log_settings) -{ +void Database::LoadLogSettings(EQEmuLogSys::LogSettings* log_settings) { // log_settings previously initialized to '0' by EQEmuLogSys::LoadLogSettingsDefaults() - - std::string query = - "SELECT " - "log_category_id, " - "log_category_description, " - "log_to_console, " - "log_to_file, " - "log_to_gmsay " - "FROM " - "logsys_categories " - "ORDER BY log_category_id"; + + std::string query = + "SELECT " + "log_category_id, " + "log_category_description, " + "log_to_console, " + "log_to_file, " + "log_to_gmsay " + "FROM " + "logsys_categories " + "ORDER BY log_category_id"; + auto results = QueryDatabase(query); - int log_category = 0; - LogSys.file_logs_enabled = false; + int log_category_id = 0; + + int categories_in_database[1000] = {}; for (auto row = results.begin(); row != results.end(); ++row) { - log_category = atoi(row[0]); - if (log_category <= Logs::None || log_category >= Logs::MaxCategoryID) + log_category_id = atoi(row[0]); + if (log_category_id <= Logs::None || log_category_id >= Logs::MaxCategoryID) { continue; + } - log_settings[log_category].log_to_console = atoi(row[2]); - log_settings[log_category].log_to_file = atoi(row[3]); - log_settings[log_category].log_to_gmsay = atoi(row[4]); + log_settings[log_category_id].log_to_console = static_cast(atoi(row[2])); + log_settings[log_category_id].log_to_file = static_cast(atoi(row[3])); + log_settings[log_category_id].log_to_gmsay = static_cast(atoi(row[4])); - /* Determine if any output method is enabled for the category - and set it to 1 so it can used to check if category is enabled */ - const bool log_to_console = log_settings[log_category].log_to_console > 0; - const bool log_to_file = log_settings[log_category].log_to_file > 0; - const bool log_to_gmsay = log_settings[log_category].log_to_gmsay > 0; + /** + * Determine if any output method is enabled for the category + * and set it to 1 so it can used to check if category is enabled + */ + const bool log_to_console = log_settings[log_category_id].log_to_console > 0; + const bool log_to_file = log_settings[log_category_id].log_to_file > 0; + const bool log_to_gmsay = log_settings[log_category_id].log_to_gmsay > 0; const bool is_category_enabled = log_to_console || log_to_file || log_to_gmsay; - if (is_category_enabled) - log_settings[log_category].is_category_enabled = 1; + if (is_category_enabled) { + log_settings[log_category_id].is_category_enabled = 1; + } - /* - This determines whether or not the process needs to actually file log anything. - If we go through this whole loop and nothing is set to any debug level, there is no point to create a file or keep anything open - */ - if (log_settings[log_category].log_to_file > 0){ + /** + * This determines whether or not the process needs to actually file log anything. + * If we go through this whole loop and nothing is set to any debug level, there is no point to create a file or keep anything open + */ + if (log_settings[log_category_id].log_to_file > 0) { LogSys.file_logs_enabled = true; } + + categories_in_database[log_category_id] = 1; + } + + /** + * Auto inject categories that don't exist in the database... + */ + for (int log_index = Logs::AA; log_index != Logs::MaxCategoryID; log_index++) { + if (!categories_in_database[log_index]) { + + Log(Logs::General, + Logs::Status, + "New Log Category '%s' doesn't exist... Automatically adding to `logsys_categories` table...", + Logs::LogCategoryName[log_index] + ); + + std::string inject_query = StringFormat( + "INSERT INTO logsys_categories " + "(log_category_id, " + "log_category_description, " + "log_to_console, " + "log_to_file, " + "log_to_gmsay) " + "VALUES " + "(%i, '%s', %i, %i, %i)", + log_index, + EscapeString(Logs::LogCategoryName[log_index]).c_str(), + log_settings[log_category_id].log_to_console, + log_settings[log_category_id].log_to_file, + log_settings[log_category_id].log_to_gmsay + ); + + QueryDatabase(inject_query); + } } } diff --git a/common/eqemu_logsys.cpp b/common/eqemu_logsys.cpp index a14a27a1b..9e99e6cbe 100644 --- a/common/eqemu_logsys.cpp +++ b/common/eqemu_logsys.cpp @@ -1,22 +1,23 @@ -/* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2015 EQEMu Development Team (http://eqemulator.net) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY except by those people which sell it, which - are required to give you total support for your newly bought product; - without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/** + * EQEmulator: Everquest Server Emulator + * Copyright (C) 2001-2018 EQEmulator Development Team (https://github.com/EQEmu/Server) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY except by those people which sell it, which + * are required to give you total support for your newly bought product; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * */ - #include "eqemu_logsys.h" #include "platform.h" #include "string_util.h" @@ -33,106 +34,153 @@ std::ofstream process_log; #ifdef _WINDOWS - #include - #include - #include - #include - #include - #include +#include +#include +#include +#include +#include +#include #else - #include - #include + +#include +#include + #endif -/* Linux ANSI console color defines */ +/** + * Linux ANSI console color defines + */ #define LC_RESET "\033[0m" -#define LC_BLACK "\033[30m" /* Black */ -#define LC_RED "\033[31m" /* Red */ -#define LC_GREEN "\033[32m" /* Green */ -#define LC_YELLOW "\033[33m" /* Yellow */ -#define LC_BLUE "\033[34m" /* Blue */ -#define LC_MAGENTA "\033[35m" /* Magenta */ -#define LC_CYAN "\033[36m" /* Cyan */ -#define LC_WHITE "\033[37m" /* White */ +#define LC_BLACK "\033[30m" /* Black */ +#define LC_RED "\033[31m" /* Red */ +#define LC_GREEN "\033[32m" /* Green */ +#define LC_YELLOW "\033[33m" /* Yellow */ +#define LC_BLUE "\033[34m" /* Blue */ +#define LC_MAGENTA "\033[35m" /* Magenta */ +#define LC_CYAN "\033[36m" /* Cyan */ +#define LC_WHITE "\033[37m" /* White */ namespace Console { enum Color { - Black = 0, - Blue = 1, - Green = 2, - Cyan = 3, - Red = 4, - Magenta = 5, - Brown = 6, - LightGray = 7, - DarkGray = 8, - LightBlue = 9, - LightGreen = 10, - LightCyan = 11, - LightRed = 12, + Black = 0, + Blue = 1, + Green = 2, + Cyan = 3, + Red = 4, + Magenta = 5, + Brown = 6, + LightGray = 7, + DarkGray = 8, + LightBlue = 9, + LightGreen = 10, + LightCyan = 11, + LightRed = 12, LightMagenta = 13, - Yellow = 14, - White = 15 + Yellow = 14, + White = 15 }; } +enum GameChatColor { + yellow = 15, + red = 13, + light_green = 14, + light_cyan = 258, + light_purple = 5 +}; + +/** + * EQEmuLogSys Constructor + */ EQEmuLogSys::EQEmuLogSys() { - on_log_gmsay_hook = [](uint16 log_type, const std::string&) {}; + on_log_gmsay_hook = [](uint16 log_type, const std::string &) {}; bool file_logs_enabled = false; - int log_platform = 0; + int log_platform = 0; } +/** + * EQEmuLogSys Deconstructor + */ EQEmuLogSys::~EQEmuLogSys() { } void EQEmuLogSys::LoadLogSettingsDefaults() { - /* Get Executable platform currently running this code (Zone/World/etc) */ + /** + * Get Executable platform currently running this code (Zone/World/etc) + */ log_platform = GetExecutablePlatformInt(); - /* Zero out Array */ + for (int log_category_id = Logs::AA; log_category_id != Logs::MaxCategoryID; log_category_id++) { + log_settings[log_category_id].log_to_console = 0; + log_settings[log_category_id].log_to_file = 0; + log_settings[log_category_id].log_to_gmsay = 0; + log_settings[log_category_id].is_category_enabled = 0; + } + + file_logs_enabled = false; + + /** + * Zero out Array + */ memset(log_settings, 0, sizeof(LogSettings) * Logs::LogCategory::MaxCategoryID); - /* Set Defaults */ - log_settings[Logs::World_Server].log_to_console = Logs::General; - log_settings[Logs::Zone_Server].log_to_console = Logs::General; - log_settings[Logs::QS_Server].log_to_console = Logs::General; - log_settings[Logs::UCS_Server].log_to_console = Logs::General; - log_settings[Logs::Crash].log_to_console = Logs::General; - log_settings[Logs::MySQLError].log_to_console = Logs::General; - log_settings[Logs::Login_Server].log_to_console = Logs::General; + /** + * Set Defaults + */ + log_settings[Logs::World_Server].log_to_console = Logs::General; + log_settings[Logs::Zone_Server].log_to_console = Logs::General; + log_settings[Logs::QS_Server].log_to_console = Logs::General; + log_settings[Logs::UCS_Server].log_to_console = Logs::General; + log_settings[Logs::Crash].log_to_console = Logs::General; + log_settings[Logs::MySQLError].log_to_console = Logs::General; + log_settings[Logs::Login_Server].log_to_console = Logs::General; log_settings[Logs::Headless_Client].log_to_console = Logs::General; - /* Set Category enabled status on defaults */ + /** + * Set Category enabled status on defaults + */ log_settings[Logs::World_Server].is_category_enabled = 1; - log_settings[Logs::Zone_Server].is_category_enabled = 1; - log_settings[Logs::QS_Server].is_category_enabled = 1; - log_settings[Logs::UCS_Server].is_category_enabled = 1; - log_settings[Logs::Crash].is_category_enabled = 1; - log_settings[Logs::MySQLError].is_category_enabled = 1; + log_settings[Logs::Zone_Server].is_category_enabled = 1; + log_settings[Logs::QS_Server].is_category_enabled = 1; + log_settings[Logs::UCS_Server].is_category_enabled = 1; + log_settings[Logs::Crash].is_category_enabled = 1; + log_settings[Logs::MySQLError].is_category_enabled = 1; log_settings[Logs::Login_Server].is_category_enabled = 1; - /* Declare process file names for log writing - If there is no process_file_name declared, no log file will be written, simply - */ - if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformWorld) + /** + * Declare process file names for log writing= + */ + if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformWorld) { platform_file_name = "world"; - else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformQueryServ) + } + else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformQueryServ) { platform_file_name = "query_server"; - else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformZone) + } + else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformZone) { platform_file_name = "zone"; - else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformUCS) + } + else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformUCS) { platform_file_name = "ucs"; - else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformLogin) + } + else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformLogin) { platform_file_name = "login"; - else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformLaunch) + } + else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformLaunch) { platform_file_name = "launcher"; - else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformHC) + } + else if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformHC) { platform_file_name = "hc"; + } } +/** + * @param log_category + * @param in_message + * @return + */ std::string EQEmuLogSys::FormatOutMessageString(uint16 log_category, const std::string &in_message) { std::string ret; @@ -144,17 +192,33 @@ std::string EQEmuLogSys::FormatOutMessageString(uint16 log_category, const std:: return ret; } +/** + * @param debug_level + * @param log_category + * @param message + */ void EQEmuLogSys::ProcessGMSay(uint16 debug_level, uint16 log_category, const std::string &message) { - /* Enabling Netcode based GMSay output creates a feedback loop that ultimately ends in a crash */ - if (log_category == Logs::LogCategory::Netcode) + /** + * Enabling Netcode based GMSay output creates a feedback loop that ultimately ends in a crash + */ + if (log_category == Logs::LogCategory::Netcode) { return; + } - /* Check to see if the process that actually ran this is zone */ - if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformZone) + /** + * Check to see if the process that actually ran this is zone + */ + if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformZone) { on_log_gmsay_hook(log_category, message); + } } +/** + * @param debug_level + * @param log_category + * @param message + */ void EQEmuLogSys::ProcessLogWrite(uint16 debug_level, uint16 log_category, const std::string &message) { if (log_category == Logs::Crash) { @@ -162,7 +226,10 @@ void EQEmuLogSys::ProcessLogWrite(uint16 debug_level, uint16 log_category, const EQEmuLogSys::SetCurrentTimeStamp(time_stamp); std::ofstream crash_log; EQEmuLogSys::MakeDirectory("logs/crashes"); - crash_log.open(StringFormat("logs/crashes/crash_%s_%i.log", platform_file_name.c_str(), getpid()), std::ios_base::app | std::ios_base::out); + crash_log.open( + StringFormat("logs/crashes/crash_%s_%i.log", platform_file_name.c_str(), getpid()), + std::ios_base::app | std::ios_base::out + ); crash_log << time_stamp << " " << message << "\n"; crash_log.close(); } @@ -170,11 +237,17 @@ void EQEmuLogSys::ProcessLogWrite(uint16 debug_level, uint16 log_category, const char time_stamp[80]; EQEmuLogSys::SetCurrentTimeStamp(time_stamp); - if (process_log) + if (process_log) { process_log << time_stamp << " " << message << std::endl; + } } -uint16 EQEmuLogSys::GetWindowsConsoleColorFromCategory(uint16 log_category) { +/** + * @param log_category + * @return + */ +uint16 EQEmuLogSys::GetWindowsConsoleColorFromCategory(uint16 log_category) +{ switch (log_category) { case Logs::Status: case Logs::Normal: @@ -197,7 +270,12 @@ uint16 EQEmuLogSys::GetWindowsConsoleColorFromCategory(uint16 log_category) { } } -std::string EQEmuLogSys::GetLinuxConsoleColorFromCategory(uint16 log_category) { +/** + * @param log_category + * @return + */ +std::string EQEmuLogSys::GetLinuxConsoleColorFromCategory(uint16 log_category) +{ switch (log_category) { case Logs::Status: case Logs::Normal: @@ -220,52 +298,68 @@ std::string EQEmuLogSys::GetLinuxConsoleColorFromCategory(uint16 log_category) { } } -uint16 EQEmuLogSys::GetGMSayColorFromCategory(uint16 log_category) { +/** + * @param log_category + * @return + */ +uint16 EQEmuLogSys::GetGMSayColorFromCategory(uint16 log_category) +{ switch (log_category) { case Logs::Status: case Logs::Normal: - return 15; /* Yellow */ + return GameChatColor::yellow; case Logs::MySQLError: case Logs::Error: - return 13; /* Red */ + return GameChatColor::red; case Logs::MySQLQuery: case Logs::Debug: - return 14; /* Light Green */ + return GameChatColor::light_green; case Logs::Quests: - return 258; /* Light Cyan */ + return GameChatColor::light_cyan; case Logs::Commands: case Logs::Mercenaries: - return 5; /* Light Purple */ + return GameChatColor::light_purple; case Logs::Crash: - return 13; /* Red */ + return GameChatColor::red; default: - return 15; /* Yellow */ + return GameChatColor::yellow; } } +/** + * @param debug_level + * @param log_category + * @param message + */ void EQEmuLogSys::ProcessConsoleMessage(uint16 debug_level, uint16 log_category, const std::string &message) { - - #ifdef _WINDOWS - HANDLE console_handle; - console_handle = GetStdHandle(STD_OUTPUT_HANDLE); - CONSOLE_FONT_INFOEX info = { 0 }; - info.cbSize = sizeof(info); - info.dwFontSize.Y = 12; // leave X as zero - info.FontWeight = FW_NORMAL; - wcscpy(info.FaceName, L"Lucida Console"); - SetCurrentConsoleFontEx(console_handle, NULL, &info); - SetConsoleTextAttribute(console_handle, EQEmuLogSys::GetWindowsConsoleColorFromCategory(log_category)); - std::cout << message << "\n"; - SetConsoleTextAttribute(console_handle, Console::Color::White); - #else - std::cout << EQEmuLogSys::GetLinuxConsoleColorFromCategory(log_category) << message << LC_RESET << std::endl; - #endif +#ifdef _WINDOWS + HANDLE console_handle; + console_handle = GetStdHandle(STD_OUTPUT_HANDLE); + CONSOLE_FONT_INFOEX info = { 0 }; + info.cbSize = sizeof(info); + info.dwFontSize.Y = 12; // leave X as zero + info.FontWeight = FW_NORMAL; + wcscpy(info.FaceName, L"Lucida Console"); + SetCurrentConsoleFontEx(console_handle, NULL, &info); + SetConsoleTextAttribute(console_handle, EQEmuLogSys::GetWindowsConsoleColorFromCategory(log_category)); + std::cout << message << "\n"; + SetConsoleTextAttribute(console_handle, Console::Color::White); +#else + std::cout << EQEmuLogSys::GetLinuxConsoleColorFromCategory(log_category) << message << LC_RESET << std::endl; +#endif } +/** + * Core logging function + * + * @param debug_level + * @param log_category + * @param message + * @param ... + */ void EQEmuLogSys::Out(Logs::DebugLevel debug_level, uint16 log_category, std::string message, ...) { - bool log_to_console = true; if (log_settings[log_category].log_to_console < debug_level) { log_to_console = false; @@ -282,8 +376,9 @@ void EQEmuLogSys::Out(Logs::DebugLevel debug_level, uint16 log_category, std::st } const bool nothing_to_log = !log_to_console && !log_to_file && !log_to_gmsay; - if (nothing_to_log) + if (nothing_to_log) { return; + } va_list args; va_start(args, message); @@ -292,20 +387,32 @@ void EQEmuLogSys::Out(Logs::DebugLevel debug_level, uint16 log_category, std::st std::string output_debug_message = EQEmuLogSys::FormatOutMessageString(log_category, output_message); - if (log_to_console) EQEmuLogSys::ProcessConsoleMessage(debug_level, log_category, output_debug_message); - if (log_to_gmsay) EQEmuLogSys::ProcessGMSay(debug_level, log_category, output_debug_message); - if (log_to_file) EQEmuLogSys::ProcessLogWrite(debug_level, log_category, output_debug_message); + if (log_to_console) { + EQEmuLogSys::ProcessConsoleMessage(debug_level, log_category, output_debug_message); + } + if (log_to_gmsay) { + EQEmuLogSys::ProcessGMSay(debug_level, log_category, output_debug_message); + } + if (log_to_file) { + EQEmuLogSys::ProcessLogWrite(debug_level, log_category, output_debug_message); + } } -void EQEmuLogSys::SetCurrentTimeStamp(char* time_stamp) +/** + * @param time_stamp + */ +void EQEmuLogSys::SetCurrentTimeStamp(char *time_stamp) { - time_t raw_time; - struct tm * time_info; + time_t raw_time; + struct tm *time_info; time(&raw_time); time_info = localtime(&raw_time); strftime(time_stamp, 80, "[%m-%d-%Y :: %H:%M:%S]", time_info); } +/** + * @param directory_name + */ void EQEmuLogSys::MakeDirectory(const std::string &directory_name) { #ifdef _WINDOWS @@ -315,8 +422,9 @@ void EQEmuLogSys::MakeDirectory(const std::string &directory_name) _mkdir(directory_name.c_str()); #else struct stat st; - if (stat(directory_name.c_str(), &st) == 0) // exists + if (stat(directory_name.c_str(), &st) == 0) { // exists return; + } mkdir(directory_name.c_str(), 0755); #endif } @@ -328,29 +436,75 @@ void EQEmuLogSys::CloseFileLogs() } } +/** + * @param log_name + */ void EQEmuLogSys::StartFileLogs(const std::string &log_name) { EQEmuLogSys::CloseFileLogs(); - /* When loading settings, we must have been given a reason in category based logging to output to a file in order to even create or open one... */ - if (file_logs_enabled == false) + /** + * When loading settings, we must have been given a reason in category based logging to output to a file in order to even create or open one... + */ + if (!file_logs_enabled) { return; - - if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformZone) { - if (!log_name.empty()) - platform_file_name = log_name; - - if (platform_file_name.empty()) - return; - - EQEmuLogSys::Out(Logs::General, Logs::Status, "Starting File Log 'logs/%s_%i.log'", platform_file_name.c_str(), getpid()); - EQEmuLogSys::MakeDirectory("logs/zone"); - process_log.open(StringFormat("logs/zone/%s_%i.log", platform_file_name.c_str(), getpid()), std::ios_base::app | std::ios_base::out); - } else { - if (platform_file_name.empty()) - return; - - EQEmuLogSys::Out(Logs::General, Logs::Status, "Starting File Log 'logs/%s_%i.log'", platform_file_name.c_str(), getpid()); - process_log.open(StringFormat("logs/%s_%i.log", platform_file_name.c_str(), getpid()), std::ios_base::app | std::ios_base::out); } -} + + /** + * Zone + */ + if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformZone) { + if (!log_name.empty()) { + platform_file_name = log_name; + } + + if (platform_file_name.empty()) { + return; + } + + EQEmuLogSys::Out( + Logs::General, + Logs::Status, + "Starting File Log 'logs/%s_%i.log'", + platform_file_name.c_str(), + getpid()); + + /** + * Make directory if not exists + */ + EQEmuLogSys::MakeDirectory("logs/zone"); + + /** + * Open file pointer + */ + process_log.open( + StringFormat("logs/zone/%s_%i.log", platform_file_name.c_str(), getpid()), + std::ios_base::app | std::ios_base::out + ); + } + else { + + /** + * All other processes + */ + + if (platform_file_name.empty()) { + return; + } + + EQEmuLogSys::Out( + Logs::General, + Logs::Status, + "Starting File Log 'logs/%s_%i.log'", + platform_file_name.c_str(), + getpid()); + + /** + * Open file pointer + */ + process_log.open( + StringFormat("logs/%s_%i.log", platform_file_name.c_str(), getpid()), + std::ios_base::app | std::ios_base::out + ); + } +} \ No newline at end of file diff --git a/common/eqemu_logsys.h b/common/eqemu_logsys.h index b0afa72f2..be646432a 100644 --- a/common/eqemu_logsys.h +++ b/common/eqemu_logsys.h @@ -1,20 +1,21 @@ - -/* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2015 EQEMu Development Team (http://eqemulator.net) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY except by those people which sell it, which - are required to give you total support for your newly bought product; - without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/** + * EQEmulator: Everquest Server Emulator + * Copyright (C) 2001-2018 EQEmulator Development Team (https://github.com/EQEmu/Server) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY except by those people which sell it, which + * are required to give you total support for your newly bought product; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * */ #ifndef EQEMU_LOGSYS_H @@ -34,130 +35,134 @@ namespace Logs { Detail /* 3 - Use this for extreme detail in logging, usually in extreme debugging in the stack or interprocess communication */ }; - /* - If you add to this, make sure you update LogCategoryName - NOTE: Only add to the bottom of the enum because that is the type ID assignment - */ + /** + * If you add to this, make sure you update LogCategoryName + * + * NOTE: Only add to the bottom of the enum because that is the type ID assignment + */ + enum LogCategory { + None = 0, + AA, + AI, + Aggro, + Attack, + Client_Server_Packet, + Combat, + Commands, + Crash, + Debug, + Doors, + Error, + Guilds, + Inventory, + Launcher, + Netcode, + Normal, + Object, + Pathing, + QS_Server, + Quests, + Rules, + Skills, + Spawns, + Spells, + Status, + TCP_Connection, + Tasks, + Tradeskills, + Trading, + Tribute, + UCS_Server, + WebInterface_Server, + World_Server, + Zone_Server, + MySQLError, + MySQLQuery, + Mercenaries, + QuestDebug, + Server_Client_Packet, + Client_Server_Packet_Unhandled, + Server_Client_Packet_With_Dump, + Client_Server_Packet_With_Dump, + Login_Server, + Client_Login, + Headless_Client, + HP_Update, + FixZ, + Food, + Traps, + NPCRoamBox, + NPCScaling, + MaxCategoryID /* Don't Remove this */ + }; -enum LogCategory { - None = 0, - AA, - AI, - Aggro, - Attack, - Client_Server_Packet, - Combat, - Commands, - Crash, - Debug, - Doors, - Error, - Guilds, - Inventory, - Launcher, - Netcode, - Normal, - Object, - Pathing, - QS_Server, - Quests, - Rules, - Skills, - Spawns, - Spells, - Status, - TCP_Connection, - Tasks, - Tradeskills, - Trading, - Tribute, - UCS_Server, - WebInterface_Server, - World_Server, - Zone_Server, - MySQLError, - MySQLQuery, - Mercenaries, - QuestDebug, - Server_Client_Packet, - Client_Server_Packet_Unhandled, - Server_Client_Packet_With_Dump, - Client_Server_Packet_With_Dump, - Login_Server, - Client_Login, - Headless_Client, - HP_Update, - FixZ, - Food, - Traps, - NPCRoamBox, - MaxCategoryID /* Don't Remove this*/ -}; - -/* If you add to this, make sure you update LogCategory */ -static const char* LogCategoryName[LogCategory::MaxCategoryID] = { - "", - "AA", - "AI", - "Aggro", - "Attack", - "Packet :: Client -> Server", - "Combat", - "Commands", - "Crash", - "Debug", - "Doors", - "Error", - "Guilds", - "Inventory", - "Launcher", - "Netcode", - "Normal", - "Object", - "Pathing", - "QS Server", - "Quests", - "Rules", - "Skills", - "Spawns", - "Spells", - "Status", - "TCP Connection", - "Tasks", - "Tradeskills", - "Trading", - "Tribute", - "UCS Server", - "WebInterface Server", - "World Server", - "Zone Server", - "MySQL Error", - "MySQL Query", - "Mercenaries", - "Quest Debug", - "Packet :: Server -> Client", - "Packet :: Client -> Server Unhandled", - "Packet :: Server -> Client (Dump)", - "Packet :: Client -> Server (Dump)", - "Login Server", - "Client Login", - "Headless Client", - "HP Update", - "FixZ", - "Food", - "Traps", - "NPC Roam Box" -}; + /** + * If you add to this, make sure you update LogCategory + */ + static const char* LogCategoryName[LogCategory::MaxCategoryID] = { + "", + "AA", + "AI", + "Aggro", + "Attack", + "Packet :: Client -> Server", + "Combat", + "Commands", + "Crash", + "Debug", + "Doors", + "Error", + "Guilds", + "Inventory", + "Launcher", + "Netcode", + "Normal", + "Object", + "Pathing", + "QS Server", + "Quests", + "Rules", + "Skills", + "Spawns", + "Spells", + "Status", + "TCP Connection", + "Tasks", + "Tradeskills", + "Trading", + "Tribute", + "UCS Server", + "WebInterface Server", + "World Server", + "Zone Server", + "MySQL Error", + "MySQL Query", + "Mercenaries", + "Quest Debug", + "Packet :: Server -> Client", + "Packet :: Client -> Server Unhandled", + "Packet :: Server -> Client (Dump)", + "Packet :: Client -> Server (Dump)", + "Login Server", + "Client Login", + "Headless Client", + "HP Update", + "FixZ", + "Food", + "Traps", + "NPC Roam Box", + "NPC Scaling" + }; } #define Log(debug_level, log_category, message, ...) do {\ - if (LogSys.log_settings[log_category].is_category_enabled == 1)\ - LogSys.Out(debug_level, log_category, message, ##__VA_ARGS__);\ + if (LogSys.log_settings[log_category].is_category_enabled == 1)\ + LogSys.Out(debug_level, log_category, message, ##__VA_ARGS__);\ } while (0) #define LogF(debug_level, log_category, message, ...) do {\ - if (LogSys.log_settings[log_category].is_category_enabled == 1)\ - LogSys.OutF(debug_level, log_category, message, ##__VA_ARGS__);\ + if (LogSys.log_settings[log_category].is_category_enabled == 1)\ + LogSys.OutF(debug_level, log_category, message, ##__VA_ARGS__);\ } while (0) class EQEmuLogSys { @@ -165,21 +170,30 @@ public: EQEmuLogSys(); ~EQEmuLogSys(); - void CloseFileLogs(); /* Close File Logs wherever necessary, either at zone shutdown or entire process shutdown for everything else. This should be handled on deconstructor but to be safe we use it anyways. */ - void LoadLogSettingsDefaults(); /* Initializes log_settings and sets some defaults if DB is not present */ - void MakeDirectory(const std::string &directory_name); /* Platform independent way of performing a MakeDirectory based on name */ - /* - The one and only Logging function that uses a debug level as a parameter, as well as a log_category - log_category - defined in Logs::LogCategory::[] - log_category name resolution works by passing the enum int ID to Logs::LogCategoryName[category_id] + /** + * Close File Logs wherever necessary, either at zone shutdown or entire process shutdown for everything else. + * This should be handled on deconstructor but to be safe we use it anyways. + */ + void CloseFileLogs(); + void LoadLogSettingsDefaults(); + void MakeDirectory(const std::string &directory_name); - Example: EQEmuLogSys::Out(Logs::General, Logs::Guilds, "This guild has no leader present"); - - This would pipe the same category and debug level to all output formats, but the internal memory reference of log_settings would - be checked against to see if that piped output is set to actually process it for the category and debug level + /** + * The one and only Logging function that uses a debug level as a parameter, as well as a log_category + * log_category - defined in Logs::LogCategory::[] + * log_category name resolution works by passing the enum int ID to Logs::LogCategoryName[category_id] + * + * Example: EQEmuLogSys::Out(Logs::General, Logs::Guilds, "This guild has no leader present"); + * - This would pipe the same category and debug level to all output formats, but the internal memory reference of log_settings would + * be checked against to see if that piped output is set to actually process it for the category and debug level */ void Out(Logs::DebugLevel debug_level, uint16 log_category, std::string message, ...); - void SetCurrentTimeStamp(char* time_stamp); /* Used in file logs to prepend a timestamp entry for logs */ - void StartFileLogs(const std::string &log_name = ""); /* Used to declare the processes file log and to keep it open for later use */ + + /** + * Used in file logs to prepend a timestamp entry for logs + */ + void SetCurrentTimeStamp(char* time_stamp); + void StartFileLogs(const std::string &log_name = ""); template void OutF(Logs::DebugLevel debug_level, uint16 log_category, const char *fmt, const Args&... args) @@ -188,16 +202,16 @@ public: Out(debug_level, log_category, log_str); } - /* - LogSettings Struct - - This struct is the master reference for all settings for each category, and for each output - - log_to_file[category_id] = [1-3] - Sets debug level for category to output to file - log_to_console[category_id] = [1-3] - Sets debug level for category to output to console - log_to_gmsay[category_id] = [1-3] - Sets debug level for category to output to gmsay + /** + * LogSettings Struct + * + * This struct is the master reference for all settings for each category, and for each output + * + * log_to_file[category_id] = [1-3] - Sets debug level for category to output to file + * log_to_console[category_id] = [1-3] - Sets debug level for category to output to console + * log_to_gmsay[category_id] = [1-3] - Sets debug level for category to output to gmsay + * */ - struct LogSettings { uint8 log_to_file; uint8 log_to_console; @@ -205,32 +219,62 @@ public: uint8 is_category_enabled; /* When any log output in a category > 0, set this to 1 as (Enabled) */ }; - /* Internally used memory reference for all log settings per category. - These are loaded via DB and have defaults loaded in LoadLogSettingsDefaults. - Database loaded via Database::LoadLogSettings(log_settings) + /** + * Internally used memory reference for all log settings per category + * These are loaded via DB and have defaults loaded in LoadLogSettingsDefaults + * Database loaded via Database::LoadLogSettings(log_settings) */ LogSettings log_settings[Logs::LogCategory::MaxCategoryID]; - bool file_logs_enabled; /* Set when log settings are loaded to determine if keeping a file open is necessary */ + bool file_logs_enabled; - int log_platform; /* Sets Executable platform (Zone/World/UCS) etc. */ + /** + * Sets Executable platform (Zone/World/UCS) etc. + */ + int log_platform; - std::string platform_file_name; /* File name used in writing logs */ + /** + * File name used in writing logs + */ + std::string platform_file_name; - uint16 GetGMSayColorFromCategory(uint16 log_category); /* GMSay Client Message colors mapped by category */ + /** + * GMSay Client Message colors mapped by category + * + * @param log_category + * @return + */ + uint16 GetGMSayColorFromCategory(uint16 log_category); void OnLogHookCallBackZone(std::function f) { on_log_gmsay_hook = f; } private: - std::function on_log_gmsay_hook; /* Callback pointer to zone process for hooking logs to zone using GMSay */ - std::string FormatOutMessageString(uint16 log_category, const std::string &in_message); /* Formats log messages like '[Category] This is a log message' */ - std::string GetLinuxConsoleColorFromCategory(uint16 log_category); /* Linux console color messages mapped by category */ - uint16 GetWindowsConsoleColorFromCategory(uint16 log_category); /* Windows console color messages mapped by category */ + /** + * Callback pointer to zone process for hooking logs to zone using GMSay + */ + std::function on_log_gmsay_hook; - void ProcessConsoleMessage(uint16 debug_level, uint16 log_category, const std::string &message); /* ProcessConsoleMessage called via Log */ - void ProcessGMSay(uint16 debug_level, uint16 log_category, const std::string &message); /* ProcessGMSay called via Log */ - void ProcessLogWrite(uint16 debug_level, uint16 log_category, const std::string &message); /* ProcessLogWrite called via Log */ + /** + * Formats log messages like '[Category] This is a log message' + */ + std::string FormatOutMessageString(uint16 log_category, const std::string &in_message); + + /** + * Linux console color messages mapped by category + * @param log_category + * @return + */ + std::string GetLinuxConsoleColorFromCategory(uint16 log_category); + + /** + * Windows console color messages mapped by category + */ + uint16 GetWindowsConsoleColorFromCategory(uint16 log_category); + + void ProcessConsoleMessage(uint16 debug_level, uint16 log_category, const std::string &message); + void ProcessGMSay(uint16 debug_level, uint16 log_category, const std::string &message); + void ProcessLogWrite(uint16 debug_level, uint16 log_category, const std::string &message); }; extern EQEmuLogSys LogSys; diff --git a/utils/sql/db_update_manifest.txt b/utils/sql/db_update_manifest.txt index dae319641..587839291 100644 --- a/utils/sql/db_update_manifest.txt +++ b/utils/sql/db_update_manifest.txt @@ -381,8 +381,8 @@ 9125|2018_07_20_task_emote.sql|SHOW COLUMNS FROM `tasks` LIKE 'completion_emote'|empty| 9126|2018_09_07_FastRegen.sql|SHOW COLUMNS FROM `zone` LIKE 'fast_regen_hp'|empty| 9127|2018_09_07_NPCMaxAggroDist.sql|SHOW COLUMNS FROM `zone` LIKE 'npc_max_aggro_dist'|empty| -9128|2018_08_13_inventory_version_update.sql|SHOW TABLES LIKE 'inventory_versions'|empty| -9129|2018_08_13_inventory_update.sql|SELECT * FROM `inventory_versions` WHERE `version` = 2 and `step` = 0|not_empty| +9128|2018_08_13_inventory_version_update.sql|SHOW TABLES LIKE 'inventory_version'|not_empty| +9129|2018_08_13_inventory_update.sql|SHOW TABLES LIKE 'inventory_versions'|empty| # Upgrade conditions: # This won't be needed after this system is implemented, but it is used database that are not diff --git a/utils/sql/git/required/2018_08_13_inventory_update.sql b/utils/sql/git/required/2018_08_13_inventory_update.sql index e02bc3ae0..4aeee6806 100644 --- a/utils/sql/git/required/2018_08_13_inventory_update.sql +++ b/utils/sql/git/required/2018_08_13_inventory_update.sql @@ -1,3 +1,66 @@ +DROP TABLE IF EXISTS `inventory_versions`; +DROP TABLE IF EXISTS `inventory_snapshots`; + + +CREATE TABLE `inventory_versions` ( + `version` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `step` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `bot_step` INT(11) UNSIGNED NOT NULL DEFAULT '0' +) +COLLATE='latin1_swedish_ci' +ENGINE=MyISAM; + +INSERT INTO `inventory_versions` VALUES (2, 0, 0); + + +CREATE TABLE `inventory_snapshots` ( + `time_index` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `charid` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `slotid` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `itemid` INT(11) UNSIGNED NULL DEFAULT '0', + `charges` SMALLINT(3) UNSIGNED NULL DEFAULT '0', + `color` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `augslot1` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `augslot2` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `augslot3` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `augslot4` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `augslot5` MEDIUMINT(7) UNSIGNED NULL DEFAULT '0', + `augslot6` MEDIUMINT(7) NOT NULL DEFAULT '0', + `instnodrop` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0', + `custom_data` TEXT NULL, + `ornamenticon` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `ornamentidfile` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `ornament_hero_model` INT(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`time_index`, `charid`, `slotid`) +) +COLLATE='latin1_swedish_ci' +ENGINE=InnoDB; + + +CREATE TABLE `inventory_snapshots_v1_bak` ( + `time_index` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `charid` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `slotid` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `itemid` INT(11) UNSIGNED NULL DEFAULT '0', + `charges` SMALLINT(3) UNSIGNED NULL DEFAULT '0', + `color` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `augslot1` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `augslot2` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `augslot3` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `augslot4` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', + `augslot5` MEDIUMINT(7) UNSIGNED NULL DEFAULT '0', + `augslot6` MEDIUMINT(7) NOT NULL DEFAULT '0', + `instnodrop` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0', + `custom_data` TEXT NULL, + `ornamenticon` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `ornamentidfile` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `ornament_hero_model` INT(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`time_index`, `charid`, `slotid`) +) +COLLATE='latin1_swedish_ci' +ENGINE=InnoDB; + + -- create inventory v1 backup SELECT @pre_timestamp := UNIX_TIMESTAMP(NOW()); INSERT INTO `inventory_snapshots_v1_bak` diff --git a/utils/sql/git/required/2018_08_13_inventory_version_update.sql b/utils/sql/git/required/2018_08_13_inventory_version_update.sql index f8fc33162..942544544 100644 --- a/utils/sql/git/required/2018_08_13_inventory_version_update.sql +++ b/utils/sql/git/required/2018_08_13_inventory_version_update.sql @@ -1,61 +1 @@ DROP TABLE IF EXISTS `inventory_version`; -DROP TABLE IF EXISTS `inventory_snapshots`; - - -CREATE TABLE `inventory_versions` ( - `version` INT(11) UNSIGNED NOT NULL DEFAULT '0', - `step` INT(11) UNSIGNED NOT NULL DEFAULT '0', - `bot_step` INT(11) UNSIGNED NOT NULL DEFAULT '0' -) -COLLATE='latin1_swedish_ci' -ENGINE=MyISAM; - -INSERT INTO `inventory_versions` VALUES (2, 0, 0); - - -CREATE TABLE `inventory_snapshots` ( - `time_index` INT(11) UNSIGNED NOT NULL DEFAULT '0', - `charid` INT(11) UNSIGNED NOT NULL DEFAULT '0', - `slotid` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', - `itemid` INT(11) UNSIGNED NULL DEFAULT '0', - `charges` SMALLINT(3) UNSIGNED NULL DEFAULT '0', - `color` INT(11) UNSIGNED NOT NULL DEFAULT '0', - `augslot1` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', - `augslot2` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', - `augslot3` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', - `augslot4` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', - `augslot5` MEDIUMINT(7) UNSIGNED NULL DEFAULT '0', - `augslot6` MEDIUMINT(7) NOT NULL DEFAULT '0', - `instnodrop` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0', - `custom_data` TEXT NULL, - `ornamenticon` INT(11) UNSIGNED NOT NULL DEFAULT '0', - `ornamentidfile` INT(11) UNSIGNED NOT NULL DEFAULT '0', - `ornament_hero_model` INT(11) NOT NULL DEFAULT '0', - PRIMARY KEY (`time_index`, `charid`, `slotid`) -) -COLLATE='latin1_swedish_ci' -ENGINE=InnoDB; - - -CREATE TABLE `inventory_snapshots_v1_bak` ( - `time_index` INT(11) UNSIGNED NOT NULL DEFAULT '0', - `charid` INT(11) UNSIGNED NOT NULL DEFAULT '0', - `slotid` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', - `itemid` INT(11) UNSIGNED NULL DEFAULT '0', - `charges` SMALLINT(3) UNSIGNED NULL DEFAULT '0', - `color` INT(11) UNSIGNED NOT NULL DEFAULT '0', - `augslot1` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', - `augslot2` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', - `augslot3` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', - `augslot4` MEDIUMINT(7) UNSIGNED NOT NULL DEFAULT '0', - `augslot5` MEDIUMINT(7) UNSIGNED NULL DEFAULT '0', - `augslot6` MEDIUMINT(7) NOT NULL DEFAULT '0', - `instnodrop` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0', - `custom_data` TEXT NULL, - `ornamenticon` INT(11) UNSIGNED NOT NULL DEFAULT '0', - `ornamentidfile` INT(11) UNSIGNED NOT NULL DEFAULT '0', - `ornament_hero_model` INT(11) NOT NULL DEFAULT '0', - PRIMARY KEY (`time_index`, `charid`, `slotid`) -) -COLLATE='latin1_swedish_ci' -ENGINE=InnoDB; diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 16691e370..13ab441b0 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -1012,7 +1012,12 @@ void Client::Handle_Connect_OP_ReqNewZone(const EQApplicationPacket *app) memcpy(outapp->pBuffer, &zone->newzone_data, sizeof(NewZone_Struct)); strcpy(nz->char_name, m_pp.name); - FastQueuePacket(&outapp); + // This was using FastQueuePacket and the packet was never getting sent... + // Not sure if this was timing.... but the NewZone was never logged until + // I changed it. + outapp->priority = 6; + QueuePacket(outapp); + safe_delete(outapp); return; } @@ -1638,11 +1643,6 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) /* Task Packets */ LoadClientTaskState(); - if (ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { - outapp = new EQApplicationPacket(OP_ReqNewZone, 0); - Handle_Connect_OP_ReqNewZone(outapp); - safe_delete(outapp); - } if (m_ClientVersionBit & EQEmu::versions::bit_UFAndLater) { outapp = new EQApplicationPacket(OP_XTargetResponse, 8); @@ -1668,6 +1668,10 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) QueuePacket(outapp); safe_delete(outapp); + if (ClientVersion() >= EQEmu::versions::ClientVersion::RoF) { + Handle_Connect_OP_ReqNewZone(nullptr); + } + SetAttackTimer(); conn_state = ZoneInfoSent; zoneinpacket_timer.Start(); diff --git a/zone/data_bucket.cpp b/zone/data_bucket.cpp index d1bdcd83c..1ccb21953 100644 --- a/zone/data_bucket.cpp +++ b/zone/data_bucket.cpp @@ -76,6 +76,31 @@ std::string DataBucket::GetData(std::string bucket_key) { return std::string(row[0]); } +/** + * Retrieves data expires time via bucket_name as key + * @param bucket_key + * @return + */ +std::string DataBucket::GetDataExpires(std::string bucket_key) { + std::string query = StringFormat( + "SELECT `expires` from `data_buckets` WHERE `key` = '%s' AND (`expires` > %lld OR `expires` = 0) LIMIT 1", + bucket_key.c_str(), + (long long) std::time(nullptr) + ); + + auto results = database.QueryDatabase(query); + if (!results.Success()) { + return std::string(); + } + + if (results.RowCount() != 1) + return std::string(); + + auto row = results.begin(); + + return std::string(row[0]); +} + /** * Checks for bucket existence by bucket_name key * @param bucket_key @@ -107,7 +132,7 @@ uint64 DataBucket::DoesBucketExist(std::string bucket_key) { */ bool DataBucket::DeleteData(std::string bucket_key) { std::string query = StringFormat( - "DELETE FROM `data_buckets` WHERE `key` = '%s' AND (`expires` > %lld OR `expires` = 0)", + "DELETE FROM `data_buckets` WHERE `key` = '%s'", EscapeString(bucket_key).c_str() ); diff --git a/zone/data_bucket.h b/zone/data_bucket.h index 87d3ab0b3..88a344637 100644 --- a/zone/data_bucket.h +++ b/zone/data_bucket.h @@ -14,6 +14,7 @@ public: static void SetData(std::string bucket_key, std::string bucket_value, std::string expires_time = ""); static bool DeleteData(std::string bucket_key); static std::string GetData(std::string bucket_key); + static std::string GetDataExpires(std::string bucket_key); private: static uint64 DoesBucketExist(std::string bucket_key); static uint32 ParseStringTimeToInt(std::string time_string); diff --git a/zone/embparser_api.cpp b/zone/embparser_api.cpp index 589f1146f..b469731c8 100644 --- a/zone/embparser_api.cpp +++ b/zone/embparser_api.cpp @@ -3596,6 +3596,21 @@ XS(XS__get_data) { XSRETURN(1); } +XS(XS__get_data_expires); +XS(XS__get_data_expires) { + dXSARGS; + if (items != 1) + Perl_croak(aTHX_ "Usage: quest::get_data_expires(string bucket_key)"); + + dXSTARG; + std::string key = (std::string) SvPV_nolen(ST(0)); + + sv_setpv(TARG, DataBucket::GetDataExpires(key).c_str()); + XSprePUSH; + PUSHTARG; + XSRETURN(1); +} + XS(XS__set_data); XS(XS__set_data) { dXSARGS; diff --git a/zone/lua_general.cpp b/zone/lua_general.cpp index bcf597d3e..09ba0b092 100644 --- a/zone/lua_general.cpp +++ b/zone/lua_general.cpp @@ -822,6 +822,10 @@ std::string lua_get_data(std::string bucket_key) { return DataBucket::GetData(bucket_key); } +std::string lua_get_data_expires(std::string bucket_key) { + return DataBucket::GetDataExpires(bucket_key); +} + void lua_set_data(std::string bucket_key, std::string bucket_value) { DataBucket::SetData(bucket_key, bucket_value); } diff --git a/zone/lua_npc.cpp b/zone/lua_npc.cpp index 88def208a..cb12bce23 100644 --- a/zone/lua_npc.cpp +++ b/zone/lua_npc.cpp @@ -328,6 +328,36 @@ void Lua_NPC::AI_SetRoambox(float dist, float max_x, float min_x, float max_y, f self->AI_SetRoambox(dist, max_x, min_x, max_y, min_y, delay, mindelay); } +void Lua_NPC::SetFollowID(int id) { + Lua_Safe_Call_Void(); + self->SetFollowID(id); +} + +void Lua_NPC::SetFollowDistance(int dist) { + Lua_Safe_Call_Void(); + self->SetFollowDistance(dist); +} + +void Lua_NPC::SetFollowCanRun(bool v) { + Lua_Safe_Call_Void(); + self->SetFollowCanRun(v); +} + +int Lua_NPC::GetFollowID() { + Lua_Safe_Call_Int(); + return self->GetFollowID(); +} + +int Lua_NPC::GetFollowDistance() { + Lua_Safe_Call_Int(); + return self->GetFollowDistance(); +} + +bool Lua_NPC::GetFollowCanRun() { + Lua_Safe_Call_Bool(); + return self->GetFollowCanRun(); +} + int Lua_NPC::GetNPCSpellsID() { Lua_Safe_Call_Int(); return self->GetNPCSpellsID(); @@ -566,6 +596,13 @@ luabind::scope lua_register_npc() { .def("IsGuarding", (bool(Lua_NPC::*)(void))&Lua_NPC::IsGuarding) .def("AI_SetRoambox", (void(Lua_NPC::*)(float,float,float,float,float))&Lua_NPC::AI_SetRoambox) .def("AI_SetRoambox", (void(Lua_NPC::*)(float,float,float,float,float,uint32,uint32))&Lua_NPC::AI_SetRoambox) + .def("SetFollowID", (void(Lua_NPC::*)(int))&Lua_NPC::SetFollowID) + .def("SetFollowDistance", (void(Lua_NPC::*)(int))&Lua_NPC::SetFollowDistance) + .def("SetFollowCanRun", (void(Lua_NPC::*)(bool))&Lua_NPC::SetFollowCanRun) + .def("GetFollowID", (int(Lua_NPC::*)(void))&Lua_NPC::GetFollowID) + .def("GetFollowDistance", (int(Lua_NPC::*)(void))&Lua_NPC::GetFollowDistance) + .def("GetFollowCanRun", (bool(Lua_NPC::*)(void))&Lua_NPC::GetFollowCanRun) + .def("GetNPCSpellsID", (int(Lua_NPC::*)(void))&Lua_NPC::GetNPCSpellsID) .def("GetNPCSpellsID", (int(Lua_NPC::*)(void))&Lua_NPC::GetNPCSpellsID) .def("GetSpawnPointID", (int(Lua_NPC::*)(void))&Lua_NPC::GetSpawnPointID) .def("GetSpawnPointX", (float(Lua_NPC::*)(void))&Lua_NPC::GetSpawnPointX) diff --git a/zone/lua_npc.h b/zone/lua_npc.h index 5edb7b68a..4c407b3fa 100644 --- a/zone/lua_npc.h +++ b/zone/lua_npc.h @@ -91,6 +91,12 @@ public: bool IsGuarding(); void AI_SetRoambox(float dist, float max_x, float min_x, float max_y, float min_y); void AI_SetRoambox(float dist, float max_x, float min_x, float max_y, float min_y, uint32 delay, uint32 mindelay); + void SetFollowID(int id); + void SetFollowDistance(int dist); + void SetFollowCanRun(bool v); + int GetFollowID(); + int GetFollowDistance(); + bool GetFollowCanRun(); int GetNPCSpellsID(); int GetSpawnPointID(); float GetSpawnPointX(); diff --git a/zone/mob.cpp b/zone/mob.cpp index a07eed7e3..91fb779a6 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -379,8 +379,9 @@ Mob::Mob(const char* in_name, m_CurrentWayPoint = glm::vec4(); cur_wp_pause = 0; patrol = 0; - follow = 0; + follow_id = 0; follow_dist = 100; // Default Distance for Follow + follow_run = true; // We can run if distance great enough no_target_hotkey = false; flee_mode = false; currently_fleeing = false; diff --git a/zone/mob.h b/zone/mob.h index 9e306c184..66d43ef7c 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -679,10 +679,12 @@ public: virtual bool IsAttackAllowed(Mob *target, bool isSpellAttack = false); bool IsTargeted() const { return (targeted > 0); } inline void IsTargeted(int in_tar) { targeted += in_tar; if(targeted < 0) targeted = 0;} - void SetFollowID(uint32 id) { follow = id; } + void SetFollowID(uint32 id) { follow_id = id; } void SetFollowDistance(uint32 dist) { follow_dist = dist; } - uint32 GetFollowID() const { return follow; } + void SetFollowCanRun(bool v) { follow_run = v; } + uint32 GetFollowID() const { return follow_id; } uint32 GetFollowDistance() const { return follow_dist; } + bool GetFollowCanRun() const { return follow_run; } inline bool IsRareSpawn() const { return rare_spawn; } inline void SetRareSpawn(bool in) { rare_spawn = in; } @@ -1229,8 +1231,9 @@ protected: uint16 ownerid; PetType typeofpet; int16 petpower; - uint32 follow; + uint32 follow_id; uint32 follow_dist; + bool follow_run; bool no_target_hotkey; bool rare_spawn; diff --git a/zone/mob_ai.cpp b/zone/mob_ai.cpp index e1a499e64..a0370d1de 100644 --- a/zone/mob_ai.cpp +++ b/zone/mob_ai.cpp @@ -1523,6 +1523,8 @@ void Mob::AI_Process() { Mob *follow = entity_list.GetMob(static_cast(GetFollowID())); if (!follow) { SetFollowID(0); + SetFollowDistance(100); + SetFollowCanRun(true); } else { @@ -1534,8 +1536,8 @@ void Mob::AI_Process() { */ if (distance >= follow_distance) { bool running = false; - - if (distance >= follow_distance + 150) { + // maybe we want the NPC to only walk doing follow logic + if (GetFollowCanRun() && distance >= follow_distance + 150) { running = true; }