// Copyright (C) 2007 EQ2EMulator Development Team, GPL v3 #pragma once #include #include #include #include #include #include #include #include "types.hpp" enum eEQEMuError { EQEMuError_NoError, EQEMuError_Mysql_1405, EQEMuError_Mysql_2003, EQEMuError_Mysql_2005, EQEMuError_Mysql_2007, EQEMuError_MaxErrorID }; // Error message lookup table for predefined error codes const char* EQEMuErrorText[EQEMuError_MaxErrorID] = { "ErrorID# 0, No Error", "MySQL Error #1405 or #2001 means your mysql server rejected the username and password you presented it.", "MySQL Error #2003 means you were unable to connect to the mysql server.", "MySQL Error #2005 means you there are too many connections on the mysql server. The server is overloaded.", "MySQL Error #2007 means you the server is out of memory. The server is overloaded.", }; // Error storage structure to handle both enum and string errors struct ErrorEntry { bool is_enum_error; // True if this is an enum error, false for string error int32 error_id; // Used only for enum errors std::string message; // Used for string errors or can store enum converted to string ErrorEntry(eEQEMuError error) : is_enum_error(true), error_id(error) {} ErrorEntry(const std::string& msg) : is_enum_error(false), error_id(0), message(msg) {} }; // Global error list and mutex for thread-safe error collection std::vector g_error_list; std::mutex g_error_mutex; // Forward declaration for signal handling void CatchSignal(int sig_num); // Retrieves the error text for a given error ID // Returns the corresponding error message or out of range message const char* GetErrorText(int32 iError) { if (iError >= EQEMuError_MaxErrorID) return "ErrorID# out of range"; else return EQEMuErrorText[iError]; } // Adds an enumerated error to the error list with optional immediate exit // Checks for duplicate enum errors before adding to prevent spam void AddEQEMuError(eEQEMuError iError, bool iExitNow = false) { if (!iError) return; std::lock_guard lock(g_error_mutex); // Check for duplicate enum errors auto it = std::find_if(g_error_list.begin(), g_error_list.end(), [iError](const ErrorEntry& entry) { return entry.is_enum_error && entry.error_id == iError; }); if (it != g_error_list.end()) return; // Duplicate found, don't add g_error_list.emplace_back(iError); if (iExitNow) CatchSignal(2); } // Adds a string-based error to the error list with optional immediate exit // String errors are not deduplicated as they may contain unique information void AddEQEMuError(const char* iError, bool iExitNow = false) { if (!iError) return; std::lock_guard lock(g_error_mutex); g_error_list.emplace_back(std::string(iError)); if (iExitNow) CatchSignal(2); } // Checks and displays all accumulated errors, then clears the error list // Returns the number of errors that were found and displayed int32 CheckEQEMuError() { std::lock_guard lock(g_error_mutex); if (g_error_list.empty()) return 0; bool header_printed = false; int32 error_count = 0; for (const auto& entry : g_error_list) { if (!header_printed) { std::fprintf(stdout, "===============================\nRuntime errors:\n\n"); header_printed = true; } if (entry.is_enum_error) { std::fprintf(stdout, "%s\n", GetErrorText(entry.error_id)); } else { std::fprintf(stdout, "%s\n\n", entry.message.c_str()); } error_count++; } g_error_list.clear(); return error_count; } // Checks for errors and pauses for user input if any errors were found // Useful for keeping console windows open to display error messages void CheckEQEMuErrorAndPause() { if (CheckEQEMuError()) { std::fprintf(stdout, "Hit any key to exit\n"); std::getchar(); } }