mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-13 14:41:28 +00:00
[Discord Integration] Native Discord Integration (#2140)
* Start of discord integration work * more testing * Discord client work * More discord work * Cleanup * Handle retry timer response and max retries * Update base retry timer * Move Discord queue handler to UCS, add queuer to own thread * Post merge * Send up Zone::SendDiscordMessage * Start of discord integration work * more testing * Discord client work * More discord work * Cleanup * Move Discord queue handler to UCS, add queuer to own thread * Post merge * Push up tables * Quest API stuff. * Update 2022_05_07_discord_webhooks.sql * Post merge fixes * Push up manifest * Flip logging signs in logic from copy / paste of inverse logic before * Make sure we add new line to quest api sourced messages Co-authored-by: Kinglykrab <kinglykrab@gmail.com>
This commit is contained in:
parent
8ef3e87370
commit
4639405fdf
@ -7,6 +7,7 @@ SET(common_sources
|
|||||||
compression.cpp
|
compression.cpp
|
||||||
condition.cpp
|
condition.cpp
|
||||||
content/world_content_service.cpp
|
content/world_content_service.cpp
|
||||||
|
discord/discord.cpp
|
||||||
crash.cpp
|
crash.cpp
|
||||||
crc16.cpp
|
crc16.cpp
|
||||||
crc32.cpp
|
crc32.cpp
|
||||||
@ -34,6 +35,7 @@ SET(common_sources
|
|||||||
event_sub.cpp
|
event_sub.cpp
|
||||||
expedition_lockout_timer.cpp
|
expedition_lockout_timer.cpp
|
||||||
extprofile.cpp
|
extprofile.cpp
|
||||||
|
discord_manager.cpp
|
||||||
faction.cpp
|
faction.cpp
|
||||||
file_util.cpp
|
file_util.cpp
|
||||||
guild_base.cpp
|
guild_base.cpp
|
||||||
@ -491,6 +493,8 @@ SET(common_headers
|
|||||||
database_schema.h
|
database_schema.h
|
||||||
dbcore.h
|
dbcore.h
|
||||||
deity.h
|
deity.h
|
||||||
|
discord/discord.h
|
||||||
|
discord_manager.h
|
||||||
dynamic_zone_base.h
|
dynamic_zone_base.h
|
||||||
emu_constants.h
|
emu_constants.h
|
||||||
emu_limits.h
|
emu_limits.h
|
||||||
|
|||||||
@ -167,7 +167,7 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
|
|||||||
if (LogSys.log_settings[Logs::MySQLQuery].is_category_enabled == 1) {
|
if (LogSys.log_settings[Logs::MySQLQuery].is_category_enabled == 1) {
|
||||||
if ((strncasecmp(query, "select", 6) == 0)) {
|
if ((strncasecmp(query, "select", 6) == 0)) {
|
||||||
LogMySQLQuery(
|
LogMySQLQuery(
|
||||||
"{0} ({1} row{2} returned) ({3}s)",
|
"{0}; -- ({1} row{2} returned) ({3}s)",
|
||||||
query,
|
query,
|
||||||
requestResult.RowCount(),
|
requestResult.RowCount(),
|
||||||
requestResult.RowCount() == 1 ? "" : "s",
|
requestResult.RowCount() == 1 ? "" : "s",
|
||||||
@ -176,7 +176,7 @@ MySQLRequestResult DBcore::QueryDatabase(const char *query, uint32 querylen, boo
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LogMySQLQuery(
|
LogMySQLQuery(
|
||||||
"{0} ({1} row{2} affected) ({3}s)",
|
"{0}; -- ({1} row{2} affected) ({3}s)",
|
||||||
query,
|
query,
|
||||||
requestResult.RowsAffected(),
|
requestResult.RowsAffected(),
|
||||||
requestResult.RowsAffected() == 1 ? "" : "s",
|
requestResult.RowsAffected() == 1 ? "" : "s",
|
||||||
|
|||||||
91
common/discord/discord.cpp
Normal file
91
common/discord/discord.cpp
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
#include "discord.h"
|
||||||
|
#include "../http/httplib.h"
|
||||||
|
#include "../json/json.h"
|
||||||
|
#include "../string_util.h"
|
||||||
|
#include "../eqemu_logsys.h"
|
||||||
|
|
||||||
|
constexpr int MAX_RETRIES = 10;
|
||||||
|
|
||||||
|
void Discord::SendWebhookMessage(const std::string &message, const std::string &webhook_url)
|
||||||
|
{
|
||||||
|
// validate
|
||||||
|
if (webhook_url.empty()) {
|
||||||
|
LogDiscord("[webhook_url] is empty");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate
|
||||||
|
if (webhook_url.find("http://") == std::string::npos && webhook_url.find("https://") == std::string::npos) {
|
||||||
|
LogDiscord("[webhook_url] [{}] does not contain a valid http/s prefix.", webhook_url);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// split
|
||||||
|
auto s = SplitString(webhook_url, '/');
|
||||||
|
|
||||||
|
// url
|
||||||
|
std::string base_url = fmt::format("{}//{}", s[0], s[2]);
|
||||||
|
std::string endpoint = replace_string(webhook_url, base_url, "");
|
||||||
|
|
||||||
|
// client
|
||||||
|
httplib::Client cli(base_url.c_str());
|
||||||
|
cli.set_connection_timeout(0, 15000000); // 15 sec
|
||||||
|
cli.set_read_timeout(15, 0); // 15 seconds
|
||||||
|
cli.set_write_timeout(15, 0); // 15 seconds
|
||||||
|
httplib::Headers headers = {
|
||||||
|
{"Content-Type", "application/json"}
|
||||||
|
};
|
||||||
|
|
||||||
|
// payload
|
||||||
|
Json::Value p;
|
||||||
|
p["content"] = message;
|
||||||
|
std::stringstream payload;
|
||||||
|
payload << p;
|
||||||
|
|
||||||
|
bool retry = true;
|
||||||
|
int retries = 0;
|
||||||
|
int retry_timer = 1000;
|
||||||
|
while (retry) {
|
||||||
|
if (auto res = cli.Post(endpoint.c_str(), payload.str(), "application/json")) {
|
||||||
|
if (res->status != 200 && res->status != 204) {
|
||||||
|
LogError("[Discord Client] Code [{}] Error [{}]", res->status, res->body);
|
||||||
|
}
|
||||||
|
if (res->status == 429) {
|
||||||
|
if (!res->body.empty()) {
|
||||||
|
std::stringstream ss(res->body);
|
||||||
|
Json::Value response;
|
||||||
|
|
||||||
|
try {
|
||||||
|
ss >> response;
|
||||||
|
}
|
||||||
|
catch (std::exception const &ex) {
|
||||||
|
LogDiscord("JSON serialization failure [{}] via [{}]", ex.what(), res->body);
|
||||||
|
}
|
||||||
|
|
||||||
|
retry_timer = std::stoi(response["retry_after"].asString()) + 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogDiscord("Rate limited... retrying message in [{}ms]", retry_timer);
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(retry_timer + 500));
|
||||||
|
}
|
||||||
|
if (res->status == 204) {
|
||||||
|
retry = false;
|
||||||
|
}
|
||||||
|
if (retries > MAX_RETRIES) {
|
||||||
|
LogDiscord("Retries exceeded for message [{}]", message);
|
||||||
|
retry = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
retries++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Discord::FormatDiscordMessage(uint16 category_id, const std::string &message)
|
||||||
|
{
|
||||||
|
if (category_id == Logs::LogCategory::MySQLQuery) {
|
||||||
|
return fmt::format("```sql\n{}\n```", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return message + "\n";
|
||||||
|
}
|
||||||
15
common/discord/discord.h
Normal file
15
common/discord/discord.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef EQEMU_DISCORD_H
|
||||||
|
#define EQEMU_DISCORD_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "../types.h"
|
||||||
|
|
||||||
|
class Discord {
|
||||||
|
public:
|
||||||
|
static void SendWebhookMessage(const std::string& message, const std::string& webhook_url);
|
||||||
|
static std::string FormatDiscordMessage(uint16 category_id, const std::string& message);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //EQEMU_DISCORD_H
|
||||||
65
common/discord_manager.cpp
Normal file
65
common/discord_manager.cpp
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
#include "discord_manager.h"
|
||||||
|
#include "../common/discord/discord.h"
|
||||||
|
#include "../common/eqemu_logsys.h"
|
||||||
|
#include "../common/string_util.h"
|
||||||
|
|
||||||
|
void DiscordManager::QueueWebhookMessage(uint32 webhook_id, const std::string &message)
|
||||||
|
{
|
||||||
|
webhook_queue_lock.lock();
|
||||||
|
webhook_message_queue[webhook_id].emplace_back(message);
|
||||||
|
webhook_queue_lock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr int MAX_MESSAGE_LENGTH = 1900;
|
||||||
|
|
||||||
|
void DiscordManager::ProcessMessageQueue()
|
||||||
|
{
|
||||||
|
if (webhook_message_queue.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
webhook_queue_lock.lock();
|
||||||
|
for (auto &q: webhook_message_queue) {
|
||||||
|
LogDiscord("Processing [{}] messages in queue for webhook ID [{}]...", q.second.size(), q.first);
|
||||||
|
|
||||||
|
auto webhook = LogSys.discord_webhooks[q.first];
|
||||||
|
std::string message;
|
||||||
|
|
||||||
|
for (auto &m: q.second) {
|
||||||
|
// next message would become too large
|
||||||
|
bool next_message_too_large = ((int) m.length() + (int) message.length()) > MAX_MESSAGE_LENGTH;
|
||||||
|
if (next_message_too_large) {
|
||||||
|
Discord::SendWebhookMessage(
|
||||||
|
message,
|
||||||
|
webhook.webhook_url
|
||||||
|
);
|
||||||
|
message = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
message += m;
|
||||||
|
|
||||||
|
// one single message was too large
|
||||||
|
// this should rarely happen but the message will need to be split
|
||||||
|
if ((int) message.length() > MAX_MESSAGE_LENGTH) {
|
||||||
|
for (unsigned mi = 0; mi < message.length(); mi += MAX_MESSAGE_LENGTH) {
|
||||||
|
Discord::SendWebhookMessage(
|
||||||
|
message.substr(mi, MAX_MESSAGE_LENGTH),
|
||||||
|
webhook.webhook_url
|
||||||
|
);
|
||||||
|
}
|
||||||
|
message = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// final flush
|
||||||
|
if (!message.empty()) {
|
||||||
|
Discord::SendWebhookMessage(
|
||||||
|
message,
|
||||||
|
webhook.webhook_url
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
webhook_message_queue.erase(q.first);
|
||||||
|
}
|
||||||
|
webhook_queue_lock.unlock();
|
||||||
|
}
|
||||||
19
common/discord_manager.h
Normal file
19
common/discord_manager.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef EQEMU_DISCORD_MANAGER_H
|
||||||
|
#define EQEMU_DISCORD_MANAGER_H
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include "../common/types.h"
|
||||||
|
|
||||||
|
class DiscordManager {
|
||||||
|
public:
|
||||||
|
void QueueWebhookMessage(uint32 webhook_id, const std::string& message);
|
||||||
|
void ProcessMessageQueue();
|
||||||
|
private:
|
||||||
|
std::mutex webhook_queue_lock{};
|
||||||
|
std::map<uint32, std::vector<std::string>> webhook_message_queue{};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -23,6 +23,8 @@
|
|||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "string_util.h"
|
#include "string_util.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
#include "discord/discord.h"
|
||||||
|
#include "repositories/discord_webhooks_repository.h"
|
||||||
#include "repositories/logsys_categories_repository.h"
|
#include "repositories/logsys_categories_repository.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@ -46,6 +48,7 @@ std::ofstream process_log;
|
|||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -89,7 +92,7 @@ namespace Console {
|
|||||||
EQEmuLogSys::EQEmuLogSys()
|
EQEmuLogSys::EQEmuLogSys()
|
||||||
{
|
{
|
||||||
on_log_gmsay_hook = [](uint16 log_type, const std::string &) {};
|
on_log_gmsay_hook = [](uint16 log_type, const std::string &) {};
|
||||||
on_log_console_hook = [](uint16 debug_level, uint16 log_type, const std::string &) {};
|
on_log_console_hook = [](uint16 log_type, const std::string &) {};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -108,6 +111,7 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
|
|||||||
log_settings[log_category_id].log_to_console = 0;
|
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_file = 0;
|
||||||
log_settings[log_category_id].log_to_gmsay = 0;
|
log_settings[log_category_id].log_to_gmsay = 0;
|
||||||
|
log_settings[log_category_id].log_to_discord = 0;
|
||||||
log_settings[log_category_id].is_category_enabled = 0;
|
log_settings[log_category_id].is_category_enabled = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,6 +139,7 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
|
|||||||
log_settings[Logs::ChecksumVerification].log_to_console = static_cast<uint8>(Logs::General);
|
log_settings[Logs::ChecksumVerification].log_to_console = static_cast<uint8>(Logs::General);
|
||||||
log_settings[Logs::ChecksumVerification].log_to_gmsay = static_cast<uint8>(Logs::General);
|
log_settings[Logs::ChecksumVerification].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||||
log_settings[Logs::CombatRecord].log_to_gmsay = static_cast<uint8>(Logs::General);
|
log_settings[Logs::CombatRecord].log_to_gmsay = static_cast<uint8>(Logs::General);
|
||||||
|
log_settings[Logs::Discord].log_to_console = static_cast<uint8>(Logs::General);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RFC 5424
|
* RFC 5424
|
||||||
@ -154,7 +159,8 @@ EQEmuLogSys *EQEmuLogSys::LoadLogSettingsDefaults()
|
|||||||
const bool log_to_console = log_settings[log_category_id].log_to_console > 0;
|
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_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 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;
|
const bool log_to_discord = log_settings[log_category_id].log_to_discord > 0;
|
||||||
|
const bool is_category_enabled = log_to_console || log_to_file || log_to_gmsay || log_to_discord;
|
||||||
if (is_category_enabled) {
|
if (is_category_enabled) {
|
||||||
log_settings[log_category_id].is_category_enabled = 1;
|
log_settings[log_category_id].is_category_enabled = 1;
|
||||||
}
|
}
|
||||||
@ -221,41 +227,12 @@ std::string EQEmuLogSys::FormatOutMessageString(
|
|||||||
return return_string + "[" + Logs::LogCategoryName[log_category] + "] " + in_message;
|
return return_string + "[" + Logs::LogCategoryName[log_category] + "] " + in_message;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @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) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Processes that actually support hooks
|
|
||||||
*/
|
|
||||||
if (EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformZone ||
|
|
||||||
EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformWorld
|
|
||||||
) {
|
|
||||||
on_log_gmsay_hook(log_category, message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param debug_level
|
* @param debug_level
|
||||||
* @param log_category
|
* @param log_category
|
||||||
* @param message
|
* @param message
|
||||||
*/
|
*/
|
||||||
void EQEmuLogSys::ProcessLogWrite(
|
void EQEmuLogSys::ProcessLogWrite(
|
||||||
uint16 debug_level,
|
|
||||||
uint16 log_category,
|
uint16 log_category,
|
||||||
const std::string &message
|
const std::string &message
|
||||||
)
|
)
|
||||||
@ -273,10 +250,9 @@ void EQEmuLogSys::ProcessLogWrite(
|
|||||||
crash_log.close();
|
crash_log.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
char time_stamp[80];
|
|
||||||
EQEmuLogSys::SetCurrentTimeStamp(time_stamp);
|
|
||||||
|
|
||||||
if (process_log) {
|
if (process_log) {
|
||||||
|
char time_stamp[80];
|
||||||
|
EQEmuLogSys::SetCurrentTimeStamp(time_stamp);
|
||||||
process_log << time_stamp << " " << message << std::endl;
|
process_log << time_stamp << " " << message << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -372,7 +348,7 @@ uint16 EQEmuLogSys::GetGMSayColorFromCategory(uint16 log_category)
|
|||||||
* @param log_category
|
* @param log_category
|
||||||
* @param message
|
* @param message
|
||||||
*/
|
*/
|
||||||
void EQEmuLogSys::ProcessConsoleMessage(uint16 debug_level, uint16 log_category, const std::string &message)
|
void EQEmuLogSys::ProcessConsoleMessage(uint16 log_category, const std::string &message)
|
||||||
{
|
{
|
||||||
#ifdef _WINDOWS
|
#ifdef _WINDOWS
|
||||||
HANDLE console_handle;
|
HANDLE console_handle;
|
||||||
@ -390,7 +366,7 @@ void EQEmuLogSys::ProcessConsoleMessage(uint16 debug_level, uint16 log_category,
|
|||||||
std::cout << EQEmuLogSys::GetLinuxConsoleColorFromCategory(log_category) << message << LC_RESET << std::endl;
|
std::cout << EQEmuLogSys::GetLinuxConsoleColorFromCategory(log_category) << message << LC_RESET << std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
on_log_console_hook(debug_level, log_category, message);
|
on_log_console_hook(log_category, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -447,28 +423,28 @@ void EQEmuLogSys::Out(
|
|||||||
...
|
...
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
bool log_to_console = true;
|
bool log_to_console = log_settings[log_category].log_to_console > 0 &&
|
||||||
if (log_settings[log_category].log_to_console < debug_level) {
|
log_settings[log_category].log_to_console >= debug_level;
|
||||||
log_to_console = false;
|
bool log_to_file = log_settings[log_category].log_to_file > 0 &&
|
||||||
}
|
log_settings[log_category].log_to_file >= debug_level;
|
||||||
|
bool log_to_gmsay = log_settings[log_category].log_to_gmsay > 0 &&
|
||||||
|
log_settings[log_category].log_to_gmsay >= debug_level &&
|
||||||
|
log_category != Logs::LogCategory::Netcode &&
|
||||||
|
(EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformZone ||
|
||||||
|
EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformWorld);
|
||||||
|
bool log_to_discord = EQEmuLogSys::log_platform == EQEmuExePlatform::ExePlatformZone &&
|
||||||
|
log_settings[log_category].log_to_discord > 0 &&
|
||||||
|
log_settings[log_category].log_to_discord >= debug_level &&
|
||||||
|
log_settings[log_category].discord_webhook_id > 0 &&
|
||||||
|
log_settings[log_category].discord_webhook_id < MAX_DISCORD_WEBHOOK_ID;
|
||||||
|
|
||||||
bool log_to_file = true;
|
// bail out if nothing to log
|
||||||
if (log_settings[log_category].log_to_file < debug_level) {
|
const bool nothing_to_log = !log_to_console && !log_to_file && !log_to_gmsay && !log_to_discord;
|
||||||
log_to_file = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool log_to_gmsay = true;
|
|
||||||
if (log_settings[log_category].log_to_gmsay < debug_level) {
|
|
||||||
log_to_gmsay = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool nothing_to_log = !log_to_console && !log_to_file && !log_to_gmsay;
|
|
||||||
if (nothing_to_log) {
|
if (nothing_to_log) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string prefix;
|
std::string prefix;
|
||||||
|
|
||||||
if (RuleB(Logging, PrintFileFunctionAndLine)) {
|
if (RuleB(Logging, PrintFileFunctionAndLine)) {
|
||||||
prefix = fmt::format("[{0}::{1}:{2}] ", base_file_name(file), func, line);
|
prefix = fmt::format("[{0}::{1}:{2}] ", base_file_name(file), func, line);
|
||||||
}
|
}
|
||||||
@ -481,13 +457,16 @@ void EQEmuLogSys::Out(
|
|||||||
std::string output_debug_message = EQEmuLogSys::FormatOutMessageString(log_category, prefix + output_message);
|
std::string output_debug_message = EQEmuLogSys::FormatOutMessageString(log_category, prefix + output_message);
|
||||||
|
|
||||||
if (log_to_console) {
|
if (log_to_console) {
|
||||||
EQEmuLogSys::ProcessConsoleMessage(debug_level, log_category, output_debug_message);
|
EQEmuLogSys::ProcessConsoleMessage(log_category, output_debug_message);
|
||||||
}
|
}
|
||||||
if (log_to_gmsay) {
|
if (log_to_gmsay) {
|
||||||
EQEmuLogSys::ProcessGMSay(debug_level, log_category, output_debug_message);
|
on_log_gmsay_hook(log_category, message);
|
||||||
}
|
}
|
||||||
if (log_to_file) {
|
if (log_to_file) {
|
||||||
EQEmuLogSys::ProcessLogWrite(debug_level, log_category, output_debug_message);
|
EQEmuLogSys::ProcessLogWrite(log_category, output_debug_message);
|
||||||
|
}
|
||||||
|
if (log_to_discord && on_log_discord_hook) {
|
||||||
|
on_log_discord_hook(log_category, log_settings[log_category].discord_webhook_id, output_message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -630,16 +609,20 @@ EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_settings[c.log_category_id].log_to_console = static_cast<uint8>(c.log_to_console);
|
log_settings[c.log_category_id].log_to_console = static_cast<uint8>(c.log_to_console);
|
||||||
log_settings[c.log_category_id].log_to_file = static_cast<uint8>(c.log_to_file);
|
log_settings[c.log_category_id].log_to_file = static_cast<uint8>(c.log_to_file);
|
||||||
log_settings[c.log_category_id].log_to_gmsay = static_cast<uint8>(c.log_to_gmsay);
|
log_settings[c.log_category_id].log_to_gmsay = static_cast<uint8>(c.log_to_gmsay);
|
||||||
|
log_settings[c.log_category_id].log_to_discord = static_cast<uint8>(c.log_to_discord);
|
||||||
|
log_settings[c.log_category_id].discord_webhook_id = c.discord_webhook_id;
|
||||||
|
|
||||||
// Determine if any output method is enabled for the category
|
// 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
|
// and set it to 1 so it can used to check if category is enabled
|
||||||
const bool log_to_console = log_settings[c.log_category_id].log_to_console > 0;
|
const bool log_to_console = log_settings[c.log_category_id].log_to_console > 0;
|
||||||
const bool log_to_file = log_settings[c.log_category_id].log_to_file > 0;
|
const bool log_to_file = log_settings[c.log_category_id].log_to_file > 0;
|
||||||
const bool log_to_gmsay = log_settings[c.log_category_id].log_to_gmsay > 0;
|
const bool log_to_gmsay = log_settings[c.log_category_id].log_to_gmsay > 0;
|
||||||
const bool is_category_enabled = log_to_console || log_to_file || log_to_gmsay;
|
const bool log_to_discord = log_settings[c.log_category_id].log_to_discord > 0 &&
|
||||||
|
log_settings[c.log_category_id].discord_webhook_id > 0;
|
||||||
|
const bool is_category_enabled = log_to_console || log_to_file || log_to_gmsay || log_to_discord;
|
||||||
|
|
||||||
if (is_category_enabled) {
|
if (is_category_enabled) {
|
||||||
log_settings[c.log_category_id].is_category_enabled = 1;
|
log_settings[c.log_category_id].is_category_enabled = 1;
|
||||||
@ -669,6 +652,7 @@ EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings()
|
|||||||
new_category.log_to_console = log_settings[i].log_to_console;
|
new_category.log_to_console = log_settings[i].log_to_console;
|
||||||
new_category.log_to_gmsay = log_settings[i].log_to_gmsay;
|
new_category.log_to_gmsay = log_settings[i].log_to_gmsay;
|
||||||
new_category.log_to_file = log_settings[i].log_to_file;
|
new_category.log_to_file = log_settings[i].log_to_file;
|
||||||
|
new_category.log_to_discord = log_settings[i].log_to_discord;
|
||||||
|
|
||||||
LogsysCategoriesRepository::InsertOne(*m_database, new_category);
|
LogsysCategoriesRepository::InsertOne(*m_database, new_category);
|
||||||
}
|
}
|
||||||
@ -676,6 +660,14 @@ EQEmuLogSys *EQEmuLogSys::LoadLogDatabaseSettings()
|
|||||||
|
|
||||||
LogInfo("Loaded [{}] log categories", categories.size());
|
LogInfo("Loaded [{}] log categories", categories.size());
|
||||||
|
|
||||||
|
auto webhooks = DiscordWebhooksRepository::All(*m_database);
|
||||||
|
if (!webhooks.empty()) {
|
||||||
|
for (auto &w: webhooks) {
|
||||||
|
discord_webhooks[w.id] = {w.id, w.webhook_name, w.webhook_url};
|
||||||
|
}
|
||||||
|
LogInfo("Loaded [{}] Discord webhooks", webhooks.size());
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -685,3 +677,4 @@ EQEmuLogSys *EQEmuLogSys::SetDatabase(Database *db)
|
|||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -130,6 +130,7 @@ namespace Logs {
|
|||||||
ChecksumVerification,
|
ChecksumVerification,
|
||||||
CombatRecord,
|
CombatRecord,
|
||||||
Hate,
|
Hate,
|
||||||
|
Discord,
|
||||||
MaxCategoryID /* Don't Remove this */
|
MaxCategoryID /* Don't Remove this */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -218,6 +219,7 @@ namespace Logs {
|
|||||||
"ChecksumVerification",
|
"ChecksumVerification",
|
||||||
"CombatRecord",
|
"CombatRecord",
|
||||||
"Hate",
|
"Hate",
|
||||||
|
"Discord",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,6 +227,8 @@ namespace Logs {
|
|||||||
|
|
||||||
class Database;
|
class Database;
|
||||||
|
|
||||||
|
constexpr uint16 MAX_DISCORD_WEBHOOK_ID = 300;
|
||||||
|
|
||||||
class EQEmuLogSys {
|
class EQEmuLogSys {
|
||||||
public:
|
public:
|
||||||
EQEmuLogSys();
|
EQEmuLogSys();
|
||||||
@ -287,9 +291,19 @@ public:
|
|||||||
uint8 log_to_file;
|
uint8 log_to_file;
|
||||||
uint8 log_to_console;
|
uint8 log_to_console;
|
||||||
uint8 log_to_gmsay;
|
uint8 log_to_gmsay;
|
||||||
|
uint8 log_to_discord;
|
||||||
|
int discord_webhook_id;
|
||||||
uint8 is_category_enabled; /* When any log output in a category > 0, set this to 1 as (Enabled) */
|
uint8 is_category_enabled; /* When any log output in a category > 0, set this to 1 as (Enabled) */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct OriginationInfo {
|
||||||
|
std::string zone_short_name;
|
||||||
|
std::string zone_long_name;
|
||||||
|
int instance_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
OriginationInfo origination_info{};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internally used memory reference for all log settings per category
|
* Internally used memory reference for all log settings per category
|
||||||
* These are loaded via DB and have defaults loaded in LoadLogSettingsDefaults
|
* These are loaded via DB and have defaults loaded in LoadLogSettingsDefaults
|
||||||
@ -297,24 +311,38 @@ public:
|
|||||||
*/
|
*/
|
||||||
LogSettings log_settings[Logs::LogCategory::MaxCategoryID]{};
|
LogSettings log_settings[Logs::LogCategory::MaxCategoryID]{};
|
||||||
|
|
||||||
|
struct DiscordWebhooks {
|
||||||
|
int id;
|
||||||
|
std::string webhook_name;
|
||||||
|
std::string webhook_url;
|
||||||
|
};
|
||||||
|
|
||||||
|
DiscordWebhooks discord_webhooks[MAX_DISCORD_WEBHOOK_ID]{};
|
||||||
|
|
||||||
bool file_logs_enabled = false;
|
bool file_logs_enabled = false;
|
||||||
|
|
||||||
int log_platform = 0;
|
int log_platform = 0;
|
||||||
std::string platform_file_name;
|
std::string platform_file_name;
|
||||||
|
|
||||||
|
|
||||||
// gmsay
|
// gmsay
|
||||||
uint16 GetGMSayColorFromCategory(uint16 log_category);
|
uint16 GetGMSayColorFromCategory(uint16 log_category);
|
||||||
|
|
||||||
EQEmuLogSys * SetGMSayHandler(std::function<void(uint16 log_type, const std::string &)> f) {
|
EQEmuLogSys *SetGMSayHandler(std::function<void(uint16 log_type, const std::string &)> f)
|
||||||
|
{
|
||||||
on_log_gmsay_hook = f;
|
on_log_gmsay_hook = f;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EQEmuLogSys *SetDiscordHandler(std::function<void(uint16 log_category, int webhook_id, const std::string &)> f)
|
||||||
|
{
|
||||||
|
on_log_discord_hook = f;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
// console
|
// console
|
||||||
void SetConsoleHandler(
|
void SetConsoleHandler(
|
||||||
std::function<void(
|
std::function<void(
|
||||||
uint16 debug_level,
|
|
||||||
uint16 log_type,
|
uint16 log_type,
|
||||||
const std::string &
|
const std::string &
|
||||||
)> f
|
)> f
|
||||||
@ -328,18 +356,17 @@ public:
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
// reference to database
|
// reference to database
|
||||||
Database *m_database;
|
Database *m_database;
|
||||||
|
std::function<void(uint16 log_category, const std::string &)> on_log_gmsay_hook;
|
||||||
std::function<void(uint16 log_category, const std::string &)> on_log_gmsay_hook;
|
std::function<void(uint16 log_category, int webhook_id, const std::string &)> on_log_discord_hook;
|
||||||
std::function<void(uint16 debug_level, uint16 log_category, const std::string &)> on_log_console_hook;
|
std::function<void(uint16 log_category, const std::string &)> on_log_console_hook;
|
||||||
|
|
||||||
std::string FormatOutMessageString(uint16 log_category, const std::string &in_message);
|
std::string FormatOutMessageString(uint16 log_category, const std::string &in_message);
|
||||||
std::string GetLinuxConsoleColorFromCategory(uint16 log_category);
|
std::string GetLinuxConsoleColorFromCategory(uint16 log_category);
|
||||||
uint16 GetWindowsConsoleColorFromCategory(uint16 log_category);
|
uint16 GetWindowsConsoleColorFromCategory(uint16 log_category);
|
||||||
|
|
||||||
void ProcessConsoleMessage(uint16 debug_level, uint16 log_category, const std::string &message);
|
void ProcessConsoleMessage(uint16 log_category, const std::string &message);
|
||||||
void ProcessGMSay(uint16 debug_level, uint16 log_category, const std::string &message);
|
void ProcessLogWrite(uint16 log_category, const std::string &message);
|
||||||
void ProcessLogWrite(uint16 debug_level, uint16 log_category, const std::string &message);
|
|
||||||
bool IsRfc5424LogCategory(uint16 log_category);
|
bool IsRfc5424LogCategory(uint16 log_category);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -726,6 +726,16 @@
|
|||||||
OutF(LogSys, Logs::Detail, Logs::Hate, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
OutF(LogSys, Logs::Detail, Logs::Hate, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
#define LogDiscord(message, ...) do {\
|
||||||
|
if (LogSys.log_settings[Logs::Discord].is_category_enabled == 1)\
|
||||||
|
OutF(LogSys, Logs::General, Logs::Discord, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define LogDiscordDetail(message, ...) do {\
|
||||||
|
if (LogSys.log_settings[Logs::Discord].is_category_enabled == 1)\
|
||||||
|
OutF(LogSys, Logs::Detail, Logs::Discord, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define Log(debug_level, log_category, message, ...) do {\
|
#define Log(debug_level, log_category, message, ...) do {\
|
||||||
if (LogSys.log_settings[log_category].is_category_enabled == 1)\
|
if (LogSys.log_settings[log_category].is_category_enabled == 1)\
|
||||||
LogSys.Out(debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
LogSys.Out(debug_level, log_category, __FILE__, __func__, __LINE__, message, ##__VA_ARGS__);\
|
||||||
|
|||||||
336
common/repositories/base/base_discord_webhooks_repository.h
Normal file
336
common/repositories/base/base_discord_webhooks_repository.h
Normal file
@ -0,0 +1,336 @@
|
|||||||
|
/**
|
||||||
|
* DO NOT MODIFY THIS FILE
|
||||||
|
*
|
||||||
|
* This repository was automatically generated and is NOT to be modified directly.
|
||||||
|
* Any repository modifications are meant to be made to the repository extending the base.
|
||||||
|
* Any modifications to base repositories are to be made by the generator only
|
||||||
|
*
|
||||||
|
* @generator ./utils/scripts/generators/repository-generator.pl
|
||||||
|
* @docs https://eqemu.gitbook.io/server/in-development/developer-area/repositories
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EQEMU_BASE_DISCORD_WEBHOOKS_REPOSITORY_H
|
||||||
|
#define EQEMU_BASE_DISCORD_WEBHOOKS_REPOSITORY_H
|
||||||
|
|
||||||
|
#include "../../database.h"
|
||||||
|
#include "../../string_util.h"
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
class BaseDiscordWebhooksRepository {
|
||||||
|
public:
|
||||||
|
struct DiscordWebhooks {
|
||||||
|
int id;
|
||||||
|
std::string webhook_name;
|
||||||
|
std::string webhook_url;
|
||||||
|
time_t created_at;
|
||||||
|
time_t deleted_at;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::string PrimaryKey()
|
||||||
|
{
|
||||||
|
return std::string("id");
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::string> Columns()
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
"id",
|
||||||
|
"webhook_name",
|
||||||
|
"webhook_url",
|
||||||
|
"created_at",
|
||||||
|
"deleted_at",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::string> SelectColumns()
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
"id",
|
||||||
|
"webhook_name",
|
||||||
|
"webhook_url",
|
||||||
|
"UNIX_TIMESTAMP(created_at)",
|
||||||
|
"UNIX_TIMESTAMP(deleted_at)",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string ColumnsRaw()
|
||||||
|
{
|
||||||
|
return std::string(implode(", ", Columns()));
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string SelectColumnsRaw()
|
||||||
|
{
|
||||||
|
return std::string(implode(", ", SelectColumns()));
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string TableName()
|
||||||
|
{
|
||||||
|
return std::string("discord_webhooks");
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string BaseSelect()
|
||||||
|
{
|
||||||
|
return fmt::format(
|
||||||
|
"SELECT {} FROM {}",
|
||||||
|
SelectColumnsRaw(),
|
||||||
|
TableName()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string BaseInsert()
|
||||||
|
{
|
||||||
|
return fmt::format(
|
||||||
|
"INSERT INTO {} ({}) ",
|
||||||
|
TableName(),
|
||||||
|
ColumnsRaw()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DiscordWebhooks NewEntity()
|
||||||
|
{
|
||||||
|
DiscordWebhooks entry{};
|
||||||
|
|
||||||
|
entry.id = 0;
|
||||||
|
entry.webhook_name = "";
|
||||||
|
entry.webhook_url = "";
|
||||||
|
entry.created_at = 0;
|
||||||
|
entry.deleted_at = 0;
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DiscordWebhooks GetDiscordWebhooksEntry(
|
||||||
|
const std::vector<DiscordWebhooks> &discord_webhookss,
|
||||||
|
int discord_webhooks_id
|
||||||
|
)
|
||||||
|
{
|
||||||
|
for (auto &discord_webhooks : discord_webhookss) {
|
||||||
|
if (discord_webhooks.id == discord_webhooks_id) {
|
||||||
|
return discord_webhooks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
static DiscordWebhooks FindOne(
|
||||||
|
Database& db,
|
||||||
|
int discord_webhooks_id
|
||||||
|
)
|
||||||
|
{
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{} WHERE id = {} LIMIT 1",
|
||||||
|
BaseSelect(),
|
||||||
|
discord_webhooks_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
auto row = results.begin();
|
||||||
|
if (results.RowCount() == 1) {
|
||||||
|
DiscordWebhooks entry{};
|
||||||
|
|
||||||
|
entry.id = atoi(row[0]);
|
||||||
|
entry.webhook_name = row[1] ? row[1] : "";
|
||||||
|
entry.webhook_url = row[2] ? row[2] : "";
|
||||||
|
entry.created_at = strtoll(row[3] ? row[3] : "-1", nullptr, 10);
|
||||||
|
entry.deleted_at = strtoll(row[4] ? row[4] : "-1", nullptr, 10);
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewEntity();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int DeleteOne(
|
||||||
|
Database& db,
|
||||||
|
int discord_webhooks_id
|
||||||
|
)
|
||||||
|
{
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"DELETE FROM {} WHERE {} = {}",
|
||||||
|
TableName(),
|
||||||
|
PrimaryKey(),
|
||||||
|
discord_webhooks_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int UpdateOne(
|
||||||
|
Database& db,
|
||||||
|
DiscordWebhooks discord_webhooks_entry
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::vector<std::string> update_values;
|
||||||
|
|
||||||
|
auto columns = Columns();
|
||||||
|
|
||||||
|
update_values.push_back(columns[1] + " = '" + EscapeString(discord_webhooks_entry.webhook_name) + "'");
|
||||||
|
update_values.push_back(columns[2] + " = '" + EscapeString(discord_webhooks_entry.webhook_url) + "'");
|
||||||
|
update_values.push_back(columns[3] + " = FROM_UNIXTIME(" + (discord_webhooks_entry.created_at > 0 ? std::to_string(discord_webhooks_entry.created_at) : "null") + ")");
|
||||||
|
update_values.push_back(columns[4] + " = FROM_UNIXTIME(" + (discord_webhooks_entry.deleted_at > 0 ? std::to_string(discord_webhooks_entry.deleted_at) : "null") + ")");
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"UPDATE {} SET {} WHERE {} = {}",
|
||||||
|
TableName(),
|
||||||
|
implode(", ", update_values),
|
||||||
|
PrimaryKey(),
|
||||||
|
discord_webhooks_entry.id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DiscordWebhooks InsertOne(
|
||||||
|
Database& db,
|
||||||
|
DiscordWebhooks discord_webhooks_entry
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::vector<std::string> insert_values;
|
||||||
|
|
||||||
|
insert_values.push_back(std::to_string(discord_webhooks_entry.id));
|
||||||
|
insert_values.push_back("'" + EscapeString(discord_webhooks_entry.webhook_name) + "'");
|
||||||
|
insert_values.push_back("'" + EscapeString(discord_webhooks_entry.webhook_url) + "'");
|
||||||
|
insert_values.push_back("FROM_UNIXTIME(" + (discord_webhooks_entry.created_at > 0 ? std::to_string(discord_webhooks_entry.created_at) : "null") + ")");
|
||||||
|
insert_values.push_back("FROM_UNIXTIME(" + (discord_webhooks_entry.deleted_at > 0 ? std::to_string(discord_webhooks_entry.deleted_at) : "null") + ")");
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{} VALUES ({})",
|
||||||
|
BaseInsert(),
|
||||||
|
implode(",", insert_values)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (results.Success()) {
|
||||||
|
discord_webhooks_entry.id = results.LastInsertedID();
|
||||||
|
return discord_webhooks_entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
discord_webhooks_entry = NewEntity();
|
||||||
|
|
||||||
|
return discord_webhooks_entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int InsertMany(
|
||||||
|
Database& db,
|
||||||
|
std::vector<DiscordWebhooks> discord_webhooks_entries
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::vector<std::string> insert_chunks;
|
||||||
|
|
||||||
|
for (auto &discord_webhooks_entry: discord_webhooks_entries) {
|
||||||
|
std::vector<std::string> insert_values;
|
||||||
|
|
||||||
|
insert_values.push_back(std::to_string(discord_webhooks_entry.id));
|
||||||
|
insert_values.push_back("'" + EscapeString(discord_webhooks_entry.webhook_name) + "'");
|
||||||
|
insert_values.push_back("'" + EscapeString(discord_webhooks_entry.webhook_url) + "'");
|
||||||
|
insert_values.push_back("FROM_UNIXTIME(" + (discord_webhooks_entry.created_at > 0 ? std::to_string(discord_webhooks_entry.created_at) : "null") + ")");
|
||||||
|
insert_values.push_back("FROM_UNIXTIME(" + (discord_webhooks_entry.deleted_at > 0 ? std::to_string(discord_webhooks_entry.deleted_at) : "null") + ")");
|
||||||
|
|
||||||
|
insert_chunks.push_back("(" + implode(",", insert_values) + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> insert_values;
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{} VALUES {}",
|
||||||
|
BaseInsert(),
|
||||||
|
implode(",", insert_chunks)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<DiscordWebhooks> All(Database& db)
|
||||||
|
{
|
||||||
|
std::vector<DiscordWebhooks> all_entries;
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{}",
|
||||||
|
BaseSelect()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
all_entries.reserve(results.RowCount());
|
||||||
|
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
DiscordWebhooks entry{};
|
||||||
|
|
||||||
|
entry.id = atoi(row[0]);
|
||||||
|
entry.webhook_name = row[1] ? row[1] : "";
|
||||||
|
entry.webhook_url = row[2] ? row[2] : "";
|
||||||
|
entry.created_at = strtoll(row[3] ? row[3] : "-1", nullptr, 10);
|
||||||
|
entry.deleted_at = strtoll(row[4] ? row[4] : "-1", nullptr, 10);
|
||||||
|
|
||||||
|
all_entries.push_back(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return all_entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<DiscordWebhooks> GetWhere(Database& db, std::string where_filter)
|
||||||
|
{
|
||||||
|
std::vector<DiscordWebhooks> all_entries;
|
||||||
|
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"{} WHERE {}",
|
||||||
|
BaseSelect(),
|
||||||
|
where_filter
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
all_entries.reserve(results.RowCount());
|
||||||
|
|
||||||
|
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||||
|
DiscordWebhooks entry{};
|
||||||
|
|
||||||
|
entry.id = atoi(row[0]);
|
||||||
|
entry.webhook_name = row[1] ? row[1] : "";
|
||||||
|
entry.webhook_url = row[2] ? row[2] : "";
|
||||||
|
entry.created_at = strtoll(row[3] ? row[3] : "-1", nullptr, 10);
|
||||||
|
entry.deleted_at = strtoll(row[4] ? row[4] : "-1", nullptr, 10);
|
||||||
|
|
||||||
|
all_entries.push_back(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return all_entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int DeleteWhere(Database& db, std::string where_filter)
|
||||||
|
{
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"DELETE FROM {} WHERE {}",
|
||||||
|
TableName(),
|
||||||
|
where_filter
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int Truncate(Database& db)
|
||||||
|
{
|
||||||
|
auto results = db.QueryDatabase(
|
||||||
|
fmt::format(
|
||||||
|
"TRUNCATE TABLE {}",
|
||||||
|
TableName()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return (results.Success() ? results.RowsAffected() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //EQEMU_BASE_DISCORD_WEBHOOKS_REPOSITORY_H
|
||||||
@ -24,6 +24,8 @@ public:
|
|||||||
int log_to_console;
|
int log_to_console;
|
||||||
int log_to_file;
|
int log_to_file;
|
||||||
int log_to_gmsay;
|
int log_to_gmsay;
|
||||||
|
int log_to_discord;
|
||||||
|
int discord_webhook_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::string PrimaryKey()
|
static std::string PrimaryKey()
|
||||||
@ -39,6 +41,8 @@ public:
|
|||||||
"log_to_console",
|
"log_to_console",
|
||||||
"log_to_file",
|
"log_to_file",
|
||||||
"log_to_gmsay",
|
"log_to_gmsay",
|
||||||
|
"log_to_discord",
|
||||||
|
"discord_webhook_id",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,6 +54,8 @@ public:
|
|||||||
"log_to_console",
|
"log_to_console",
|
||||||
"log_to_file",
|
"log_to_file",
|
||||||
"log_to_gmsay",
|
"log_to_gmsay",
|
||||||
|
"log_to_discord",
|
||||||
|
"discord_webhook_id",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,6 +101,8 @@ public:
|
|||||||
entry.log_to_console = 0;
|
entry.log_to_console = 0;
|
||||||
entry.log_to_file = 0;
|
entry.log_to_file = 0;
|
||||||
entry.log_to_gmsay = 0;
|
entry.log_to_gmsay = 0;
|
||||||
|
entry.log_to_discord = 0;
|
||||||
|
entry.discord_webhook_id = 0;
|
||||||
|
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
@ -135,6 +143,8 @@ public:
|
|||||||
entry.log_to_console = atoi(row[2]);
|
entry.log_to_console = atoi(row[2]);
|
||||||
entry.log_to_file = atoi(row[3]);
|
entry.log_to_file = atoi(row[3]);
|
||||||
entry.log_to_gmsay = atoi(row[4]);
|
entry.log_to_gmsay = atoi(row[4]);
|
||||||
|
entry.log_to_discord = atoi(row[5]);
|
||||||
|
entry.discord_webhook_id = atoi(row[6]);
|
||||||
|
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
@ -173,6 +183,8 @@ public:
|
|||||||
update_values.push_back(columns[2] + " = " + std::to_string(logsys_categories_entry.log_to_console));
|
update_values.push_back(columns[2] + " = " + std::to_string(logsys_categories_entry.log_to_console));
|
||||||
update_values.push_back(columns[3] + " = " + std::to_string(logsys_categories_entry.log_to_file));
|
update_values.push_back(columns[3] + " = " + std::to_string(logsys_categories_entry.log_to_file));
|
||||||
update_values.push_back(columns[4] + " = " + std::to_string(logsys_categories_entry.log_to_gmsay));
|
update_values.push_back(columns[4] + " = " + std::to_string(logsys_categories_entry.log_to_gmsay));
|
||||||
|
update_values.push_back(columns[5] + " = " + std::to_string(logsys_categories_entry.log_to_discord));
|
||||||
|
update_values.push_back(columns[6] + " = " + std::to_string(logsys_categories_entry.discord_webhook_id));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@ -199,6 +211,8 @@ public:
|
|||||||
insert_values.push_back(std::to_string(logsys_categories_entry.log_to_console));
|
insert_values.push_back(std::to_string(logsys_categories_entry.log_to_console));
|
||||||
insert_values.push_back(std::to_string(logsys_categories_entry.log_to_file));
|
insert_values.push_back(std::to_string(logsys_categories_entry.log_to_file));
|
||||||
insert_values.push_back(std::to_string(logsys_categories_entry.log_to_gmsay));
|
insert_values.push_back(std::to_string(logsys_categories_entry.log_to_gmsay));
|
||||||
|
insert_values.push_back(std::to_string(logsys_categories_entry.log_to_discord));
|
||||||
|
insert_values.push_back(std::to_string(logsys_categories_entry.discord_webhook_id));
|
||||||
|
|
||||||
auto results = db.QueryDatabase(
|
auto results = db.QueryDatabase(
|
||||||
fmt::format(
|
fmt::format(
|
||||||
@ -233,6 +247,8 @@ public:
|
|||||||
insert_values.push_back(std::to_string(logsys_categories_entry.log_to_console));
|
insert_values.push_back(std::to_string(logsys_categories_entry.log_to_console));
|
||||||
insert_values.push_back(std::to_string(logsys_categories_entry.log_to_file));
|
insert_values.push_back(std::to_string(logsys_categories_entry.log_to_file));
|
||||||
insert_values.push_back(std::to_string(logsys_categories_entry.log_to_gmsay));
|
insert_values.push_back(std::to_string(logsys_categories_entry.log_to_gmsay));
|
||||||
|
insert_values.push_back(std::to_string(logsys_categories_entry.log_to_discord));
|
||||||
|
insert_values.push_back(std::to_string(logsys_categories_entry.discord_webhook_id));
|
||||||
|
|
||||||
insert_chunks.push_back("(" + implode(",", insert_values) + ")");
|
insert_chunks.push_back("(" + implode(",", insert_values) + ")");
|
||||||
}
|
}
|
||||||
@ -271,6 +287,8 @@ public:
|
|||||||
entry.log_to_console = atoi(row[2]);
|
entry.log_to_console = atoi(row[2]);
|
||||||
entry.log_to_file = atoi(row[3]);
|
entry.log_to_file = atoi(row[3]);
|
||||||
entry.log_to_gmsay = atoi(row[4]);
|
entry.log_to_gmsay = atoi(row[4]);
|
||||||
|
entry.log_to_discord = atoi(row[5]);
|
||||||
|
entry.discord_webhook_id = atoi(row[6]);
|
||||||
|
|
||||||
all_entries.push_back(entry);
|
all_entries.push_back(entry);
|
||||||
}
|
}
|
||||||
@ -300,6 +318,8 @@ public:
|
|||||||
entry.log_to_console = atoi(row[2]);
|
entry.log_to_console = atoi(row[2]);
|
||||||
entry.log_to_file = atoi(row[3]);
|
entry.log_to_file = atoi(row[3]);
|
||||||
entry.log_to_gmsay = atoi(row[4]);
|
entry.log_to_gmsay = atoi(row[4]);
|
||||||
|
entry.log_to_discord = atoi(row[5]);
|
||||||
|
entry.discord_webhook_id = atoi(row[6]);
|
||||||
|
|
||||||
all_entries.push_back(entry);
|
all_entries.push_back(entry);
|
||||||
}
|
}
|
||||||
|
|||||||
70
common/repositories/discord_webhooks_repository.h
Normal file
70
common/repositories/discord_webhooks_repository.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/**
|
||||||
|
* EQEmulator: Everquest Server Emulator
|
||||||
|
* Copyright (C) 2001-2020 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_DISCORD_WEBHOOKS_REPOSITORY_H
|
||||||
|
#define EQEMU_DISCORD_WEBHOOKS_REPOSITORY_H
|
||||||
|
|
||||||
|
#include "../database.h"
|
||||||
|
#include "../string_util.h"
|
||||||
|
#include "base/base_discord_webhooks_repository.h"
|
||||||
|
|
||||||
|
class DiscordWebhooksRepository: public BaseDiscordWebhooksRepository {
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file was auto generated and can be modified and extended upon
|
||||||
|
*
|
||||||
|
* Base repository methods are automatically
|
||||||
|
* generated in the "base" version of this repository. The base repository
|
||||||
|
* is immutable and to be left untouched, while methods in this class
|
||||||
|
* are used as extension methods for more specific persistence-layer
|
||||||
|
* accessors or mutators.
|
||||||
|
*
|
||||||
|
* Base Methods (Subject to be expanded upon in time)
|
||||||
|
*
|
||||||
|
* Note: Not all tables are designed appropriately to fit functionality with all base methods
|
||||||
|
*
|
||||||
|
* InsertOne
|
||||||
|
* UpdateOne
|
||||||
|
* DeleteOne
|
||||||
|
* FindOne
|
||||||
|
* GetWhere(std::string where_filter)
|
||||||
|
* DeleteWhere(std::string where_filter)
|
||||||
|
* InsertMany
|
||||||
|
* All
|
||||||
|
*
|
||||||
|
* Example custom methods in a repository
|
||||||
|
*
|
||||||
|
* DiscordWebhooksRepository::GetByZoneAndVersion(int zone_id, int zone_version)
|
||||||
|
* DiscordWebhooksRepository::GetWhereNeverExpires()
|
||||||
|
* DiscordWebhooksRepository::GetWhereXAndY()
|
||||||
|
* DiscordWebhooksRepository::DeleteWhereXAndY()
|
||||||
|
*
|
||||||
|
* Most of the above could be covered by base methods, but if you as a developer
|
||||||
|
* find yourself re-using logic for other parts of the code, its best to just make a
|
||||||
|
* method that can be re-used easily elsewhere especially if it can use a base repository
|
||||||
|
* method and encapsulate filters there
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Custom extended repository methods here
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //EQEMU_DISCORD_WEBHOOKS_REPOSITORY_H
|
||||||
@ -219,6 +219,7 @@
|
|||||||
#define ServerOP_UCSServerStatusReply 0x4005
|
#define ServerOP_UCSServerStatusReply 0x4005
|
||||||
#define ServerOP_UCSServerStatusRequest 0x4006
|
#define ServerOP_UCSServerStatusRequest 0x4006
|
||||||
#define ServerOP_UpdateSchedulerEvents 0x4007
|
#define ServerOP_UpdateSchedulerEvents 0x4007
|
||||||
|
#define ServerOP_DiscordWebhookMessage 0x4008
|
||||||
|
|
||||||
#define ServerOP_ReloadAAData 0x4100
|
#define ServerOP_ReloadAAData 0x4100
|
||||||
#define ServerOP_ReloadAlternateCurrencies 0x4101
|
#define ServerOP_ReloadAlternateCurrencies 0x4101
|
||||||
@ -1449,6 +1450,11 @@ struct QSMerchantLogTransaction_Struct {
|
|||||||
QSTransactionItems_Struct items[0];
|
QSTransactionItems_Struct items[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct DiscordWebhookMessage_Struct {
|
||||||
|
uint32 webhook_id;
|
||||||
|
char message[2000];
|
||||||
|
};
|
||||||
|
|
||||||
struct QSGeneralQuery_Struct {
|
struct QSGeneralQuery_Struct {
|
||||||
char QueryString[0];
|
char QueryString[0];
|
||||||
};
|
};
|
||||||
|
|||||||
@ -34,7 +34,7 @@
|
|||||||
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define CURRENT_BINARY_DATABASE_VERSION 9184
|
#define CURRENT_BINARY_DATABASE_VERSION 9185
|
||||||
|
|
||||||
#ifdef BOTS
|
#ifdef BOTS
|
||||||
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9028
|
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9028
|
||||||
|
|||||||
@ -1,18 +1,18 @@
|
|||||||
CMAKE_MINIMUM_REQUIRED(VERSION 3.2)
|
CMAKE_MINIMUM_REQUIRED(VERSION 3.2)
|
||||||
|
|
||||||
SET(qserv_sources
|
SET(qserv_sources
|
||||||
database.cpp
|
database.cpp
|
||||||
lfguild.cpp
|
lfguild.cpp
|
||||||
queryserv.cpp
|
queryserv.cpp
|
||||||
queryservconfig.cpp
|
queryservconfig.cpp
|
||||||
worldserver.cpp
|
worldserver.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
SET(qserv_headers
|
SET(qserv_headers
|
||||||
database.h
|
database.h
|
||||||
lfguild.h
|
lfguild.h
|
||||||
queryservconfig.h
|
queryservconfig.h
|
||||||
worldserver.h
|
worldserver.h
|
||||||
)
|
)
|
||||||
|
|
||||||
ADD_EXECUTABLE(queryserv ${qserv_sources} ${qserv_headers})
|
ADD_EXECUTABLE(queryserv ${qserv_sources} ${qserv_headers})
|
||||||
|
|||||||
@ -24,6 +24,7 @@
|
|||||||
#include "../common/servertalk.h"
|
#include "../common/servertalk.h"
|
||||||
#include "../common/platform.h"
|
#include "../common/platform.h"
|
||||||
#include "../common/crash.h"
|
#include "../common/crash.h"
|
||||||
|
#include "../common/string_util.h"
|
||||||
#include "../common/event/event_loop.h"
|
#include "../common/event/event_loop.h"
|
||||||
#include "../common/timer.h"
|
#include "../common/timer.h"
|
||||||
#include "database.h"
|
#include "database.h"
|
||||||
@ -32,21 +33,24 @@
|
|||||||
#include "worldserver.h"
|
#include "worldserver.h"
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
volatile bool RunLoops = true;
|
volatile bool RunLoops = true;
|
||||||
|
|
||||||
Database database;
|
Database database;
|
||||||
LFGuildManager lfguildmanager;
|
LFGuildManager lfguildmanager;
|
||||||
std::string WorldShortName;
|
std::string WorldShortName;
|
||||||
const queryservconfig *Config;
|
const queryservconfig *Config;
|
||||||
WorldServer *worldserver = 0;
|
WorldServer *worldserver = 0;
|
||||||
EQEmuLogSys LogSys;
|
EQEmuLogSys LogSys;
|
||||||
|
|
||||||
void CatchSignal(int sig_num) {
|
void CatchSignal(int sig_num)
|
||||||
|
{
|
||||||
RunLoops = false;
|
RunLoops = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main()
|
||||||
|
{
|
||||||
RegisterExecutablePlatform(ExePlatformQueryServ);
|
RegisterExecutablePlatform(ExePlatformQueryServ);
|
||||||
LogSys.LoadLogSettingsDefaults();
|
LogSys.LoadLogSettingsDefaults();
|
||||||
set_exception_handler();
|
set_exception_handler();
|
||||||
@ -58,7 +62,7 @@ int main() {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Config = queryservconfig::get();
|
Config = queryservconfig::get();
|
||||||
WorldShortName = Config->ShortName;
|
WorldShortName = Config->ShortName;
|
||||||
|
|
||||||
LogInfo("Connecting to MySQL");
|
LogInfo("Connecting to MySQL");
|
||||||
@ -69,7 +73,8 @@ int main() {
|
|||||||
Config->QSDatabaseUsername.c_str(),
|
Config->QSDatabaseUsername.c_str(),
|
||||||
Config->QSDatabasePassword.c_str(),
|
Config->QSDatabasePassword.c_str(),
|
||||||
Config->QSDatabaseDB.c_str(),
|
Config->QSDatabaseDB.c_str(),
|
||||||
Config->QSDatabasePort)) {
|
Config->QSDatabasePort
|
||||||
|
)) {
|
||||||
LogInfo("Cannot continue without a database connection");
|
LogInfo("Cannot continue without a database connection");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -78,11 +83,11 @@ int main() {
|
|||||||
->LoadLogDatabaseSettings()
|
->LoadLogDatabaseSettings()
|
||||||
->StartFileLogs();
|
->StartFileLogs();
|
||||||
|
|
||||||
if (signal(SIGINT, CatchSignal) == SIG_ERR) {
|
if (signal(SIGINT, CatchSignal) == SIG_ERR) {
|
||||||
LogInfo("Could not set signal handler");
|
LogInfo("Could not set signal handler");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (signal(SIGTERM, CatchSignal) == SIG_ERR) {
|
if (signal(SIGTERM, CatchSignal) == SIG_ERR) {
|
||||||
LogInfo("Could not set signal handler");
|
LogInfo("Could not set signal handler");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -94,10 +99,11 @@ int main() {
|
|||||||
/* Load Looking For Guild Manager */
|
/* Load Looking For Guild Manager */
|
||||||
lfguildmanager.LoadDatabase();
|
lfguildmanager.LoadDatabase();
|
||||||
|
|
||||||
while(RunLoops) {
|
while (RunLoops) {
|
||||||
Timer::SetCurrentTime();
|
Timer::SetCurrentTime();
|
||||||
if(LFGuildExpireTimer.Check())
|
if (LFGuildExpireTimer.Check()) {
|
||||||
lfguildmanager.ExpireEntries();
|
lfguildmanager.ExpireEntries();
|
||||||
|
}
|
||||||
|
|
||||||
EQ::EventLoop::Get().Process();
|
EQ::EventLoop::Get().Process();
|
||||||
Sleep(5);
|
Sleep(5);
|
||||||
@ -105,7 +111,8 @@ int main() {
|
|||||||
LogSys.CloseFileLogs();
|
LogSys.CloseFileLogs();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateWindowTitle(char* iNewTitle) {
|
void UpdateWindowTitle(char *iNewTitle)
|
||||||
|
{
|
||||||
#ifdef _WINDOWS
|
#ifdef _WINDOWS
|
||||||
char tmp[500];
|
char tmp[500];
|
||||||
if (iNewTitle) {
|
if (iNewTitle) {
|
||||||
|
|||||||
@ -37,10 +37,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
extern WorldServer worldserver;
|
extern WorldServer worldserver;
|
||||||
extern const queryservconfig *Config;
|
extern const queryservconfig *Config;
|
||||||
extern Database database;
|
extern Database database;
|
||||||
extern LFGuildManager lfguildmanager;
|
extern LFGuildManager lfguildmanager;
|
||||||
|
|
||||||
WorldServer::WorldServer()
|
WorldServer::WorldServer()
|
||||||
{
|
{
|
||||||
@ -52,7 +52,13 @@ WorldServer::~WorldServer()
|
|||||||
|
|
||||||
void WorldServer::Connect()
|
void WorldServer::Connect()
|
||||||
{
|
{
|
||||||
m_connection = std::make_unique<EQ::Net::ServertalkClient>(Config->WorldIP, Config->WorldTCPPort, false, "QueryServ", Config->SharedKey);
|
m_connection = std::make_unique<EQ::Net::ServertalkClient>(
|
||||||
|
Config->WorldIP,
|
||||||
|
Config->WorldTCPPort,
|
||||||
|
false,
|
||||||
|
"QueryServ",
|
||||||
|
Config->SharedKey
|
||||||
|
);
|
||||||
m_connection->OnMessage(std::bind(&WorldServer::HandleMessage, this, std::placeholders::_1, std::placeholders::_2));
|
m_connection->OnMessage(std::bind(&WorldServer::HandleMessage, this, std::placeholders::_1, std::placeholders::_2));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,109 +86,109 @@ bool WorldServer::Connected() const
|
|||||||
void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||||
{
|
{
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case 0: {
|
case 0: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ServerOP_KeepAlive: {
|
case ServerOP_KeepAlive: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ServerOP_Speech: {
|
case ServerOP_Speech: {
|
||||||
Server_Speech_Struct *SSS = (Server_Speech_Struct*)p.Data();
|
Server_Speech_Struct *SSS = (Server_Speech_Struct *) p.Data();
|
||||||
std::string tmp1 = SSS->from;
|
std::string tmp1 = SSS->from;
|
||||||
std::string tmp2 = SSS->to;
|
std::string tmp2 = SSS->to;
|
||||||
database.AddSpeech(tmp1.c_str(), tmp2.c_str(), SSS->message, SSS->minstatus, SSS->guilddbid, SSS->type);
|
database.AddSpeech(tmp1.c_str(), tmp2.c_str(), SSS->message, SSS->minstatus, SSS->guilddbid, SSS->type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ServerOP_QSPlayerLogTrades: {
|
case ServerOP_QSPlayerLogTrades: {
|
||||||
QSPlayerLogTrade_Struct *QS = (QSPlayerLogTrade_Struct*)p.Data();
|
QSPlayerLogTrade_Struct *QS = (QSPlayerLogTrade_Struct *) p.Data();
|
||||||
database.LogPlayerTrade(QS, QS->_detail_count);
|
database.LogPlayerTrade(QS, QS->_detail_count);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ServerOP_QSPlayerDropItem: {
|
case ServerOP_QSPlayerDropItem: {
|
||||||
QSPlayerDropItem_Struct *QS = (QSPlayerDropItem_Struct *) p.Data();
|
QSPlayerDropItem_Struct *QS = (QSPlayerDropItem_Struct *) p.Data();
|
||||||
database.LogPlayerDropItem(QS);
|
database.LogPlayerDropItem(QS);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ServerOP_QSPlayerLogHandins: {
|
case ServerOP_QSPlayerLogHandins: {
|
||||||
QSPlayerLogHandin_Struct *QS = (QSPlayerLogHandin_Struct*)p.Data();
|
QSPlayerLogHandin_Struct *QS = (QSPlayerLogHandin_Struct *) p.Data();
|
||||||
database.LogPlayerHandin(QS, QS->_detail_count);
|
database.LogPlayerHandin(QS, QS->_detail_count);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ServerOP_QSPlayerLogNPCKills: {
|
case ServerOP_QSPlayerLogNPCKills: {
|
||||||
QSPlayerLogNPCKill_Struct *QS = (QSPlayerLogNPCKill_Struct*)p.Data();
|
QSPlayerLogNPCKill_Struct *QS = (QSPlayerLogNPCKill_Struct *) p.Data();
|
||||||
uint32 Members = (uint32)(p.Length() - sizeof(QSPlayerLogNPCKill_Struct));
|
uint32 Members = (uint32) (p.Length() - sizeof(QSPlayerLogNPCKill_Struct));
|
||||||
if (Members > 0) Members = Members / sizeof(QSPlayerLogNPCKillsPlayers_Struct);
|
if (Members > 0) { Members = Members / sizeof(QSPlayerLogNPCKillsPlayers_Struct); }
|
||||||
database.LogPlayerNPCKill(QS, Members);
|
database.LogPlayerNPCKill(QS, Members);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ServerOP_QSPlayerLogDeletes: {
|
case ServerOP_QSPlayerLogDeletes: {
|
||||||
QSPlayerLogDelete_Struct *QS = (QSPlayerLogDelete_Struct*)p.Data();
|
QSPlayerLogDelete_Struct *QS = (QSPlayerLogDelete_Struct *) p.Data();
|
||||||
uint32 Items = QS->char_count;
|
uint32 Items = QS->char_count;
|
||||||
database.LogPlayerDelete(QS, Items);
|
database.LogPlayerDelete(QS, Items);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ServerOP_QSPlayerLogMoves: {
|
case ServerOP_QSPlayerLogMoves: {
|
||||||
QSPlayerLogMove_Struct *QS = (QSPlayerLogMove_Struct*)p.Data();
|
QSPlayerLogMove_Struct *QS = (QSPlayerLogMove_Struct *) p.Data();
|
||||||
uint32 Items = QS->char_count;
|
uint32 Items = QS->char_count;
|
||||||
database.LogPlayerMove(QS, Items);
|
database.LogPlayerMove(QS, Items);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ServerOP_QSPlayerLogMerchantTransactions: {
|
case ServerOP_QSPlayerLogMerchantTransactions: {
|
||||||
QSMerchantLogTransaction_Struct *QS = (QSMerchantLogTransaction_Struct*)p.Data();
|
QSMerchantLogTransaction_Struct *QS = (QSMerchantLogTransaction_Struct *) p.Data();
|
||||||
uint32 Items = QS->char_count + QS->merchant_count;
|
uint32 Items = QS->char_count + QS->merchant_count;
|
||||||
database.LogMerchantTransaction(QS, Items);
|
database.LogMerchantTransaction(QS, Items);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ServerOP_QueryServGeneric: {
|
case ServerOP_QueryServGeneric: {
|
||||||
/*
|
/*
|
||||||
The purpose of ServerOP_QueryServerGeneric is so that we don't have to add code to world just to relay packets
|
The purpose of ServerOP_QueryServerGeneric is so that we don't have to add code to world just to relay packets
|
||||||
each time we add functionality to queryserv.
|
each time we add functionality to queryserv.
|
||||||
|
|
||||||
A ServerOP_QueryServGeneric packet has the following format:
|
A ServerOP_QueryServGeneric packet has the following format:
|
||||||
|
|
||||||
uint32 SourceZoneID
|
uint32 SourceZoneID
|
||||||
uint32 SourceInstanceID
|
uint32 SourceInstanceID
|
||||||
char OriginatingCharacterName[0]
|
char OriginatingCharacterName[0]
|
||||||
- Null terminated name of the character this packet came from. This could be just
|
- Null terminated name of the character this packet came from. This could be just
|
||||||
- an empty string if it has no meaning in the context of a particular packet.
|
- an empty string if it has no meaning in the context of a particular packet.
|
||||||
uint32 Type
|
uint32 Type
|
||||||
|
|
||||||
The 'Type' field is a 'sub-opcode'. A value of 0 is used for the LFGuild packets. The next feature to be added
|
The 'Type' field is a 'sub-opcode'. A value of 0 is used for the LFGuild packets. The next feature to be added
|
||||||
to queryserv would use 1, etc.
|
to queryserv would use 1, etc.
|
||||||
|
|
||||||
Obviously, any fields in the packet following the 'Type' will be unique to the particular type of packet. The
|
Obviously, any fields in the packet following the 'Type' will be unique to the particular type of packet. The
|
||||||
'Generic' in the name of this ServerOP code relates to the four header fields.
|
'Generic' in the name of this ServerOP code relates to the four header fields.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
auto from = p.GetCString(8);
|
auto from = p.GetCString(8);
|
||||||
uint32 Type = p.GetUInt32(8 + from.length() + 1);
|
uint32 Type = p.GetUInt32(8 + from.length() + 1);
|
||||||
|
|
||||||
switch (Type) {
|
switch (Type) {
|
||||||
case QSG_LFGuild: {
|
case QSG_LFGuild: {
|
||||||
|
ServerPacket pack;
|
||||||
|
pack.pBuffer = (uchar *) p.Data();
|
||||||
|
pack.opcode = opcode;
|
||||||
|
pack.size = (uint32) p.Length();
|
||||||
|
lfguildmanager.HandlePacket(&pack);
|
||||||
|
pack.pBuffer = nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
LogInfo("Received unhandled ServerOP_QueryServGeneric", Type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ServerOP_QSSendQuery: {
|
||||||
|
/* Process all packets here */
|
||||||
ServerPacket pack;
|
ServerPacket pack;
|
||||||
pack.pBuffer = (uchar*)p.Data();
|
pack.pBuffer = (uchar *) p.Data();
|
||||||
pack.opcode = opcode;
|
pack.opcode = opcode;
|
||||||
pack.size = (uint32)p.Length();
|
pack.size = (uint32) p.Length();
|
||||||
lfguildmanager.HandlePacket(&pack);
|
|
||||||
|
database.GeneralQueryReceive(&pack);
|
||||||
pack.pBuffer = nullptr;
|
pack.pBuffer = nullptr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
LogInfo("Received unhandled ServerOP_QueryServGeneric", Type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ServerOP_QSSendQuery: {
|
|
||||||
/* Process all packets here */
|
|
||||||
ServerPacket pack;
|
|
||||||
pack.pBuffer = (uchar*)p.Data();
|
|
||||||
pack.opcode = opcode;
|
|
||||||
pack.size = (uint32)p.Length();
|
|
||||||
|
|
||||||
database.GeneralQueryReceive(&pack);
|
|
||||||
pack.pBuffer = nullptr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,24 +18,25 @@
|
|||||||
#ifndef WORLDSERVER_H
|
#ifndef WORLDSERVER_H
|
||||||
#define WORLDSERVER_H
|
#define WORLDSERVER_H
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
#include "../common/eq_packet_structs.h"
|
#include "../common/eq_packet_structs.h"
|
||||||
#include "../common/net/servertalk_client_connection.h"
|
#include "../common/net/servertalk_client_connection.h"
|
||||||
|
|
||||||
class WorldServer
|
class WorldServer {
|
||||||
{
|
public:
|
||||||
public:
|
WorldServer();
|
||||||
WorldServer();
|
~WorldServer();
|
||||||
~WorldServer();
|
|
||||||
|
|
||||||
void Connect();
|
void Connect();
|
||||||
bool SendPacket(ServerPacket* pack);
|
bool SendPacket(ServerPacket *pack);
|
||||||
std::string GetIP() const;
|
std::string GetIP() const;
|
||||||
uint16 GetPort() const;
|
uint16 GetPort() const;
|
||||||
bool Connected() const;
|
bool Connected() const;
|
||||||
|
|
||||||
|
void HandleMessage(uint16 opcode, const EQ::Net::Packet &p);
|
||||||
|
private:
|
||||||
|
std::unique_ptr<EQ::Net::ServertalkClient> m_connection;
|
||||||
|
|
||||||
void HandleMessage(uint16 opcode, const EQ::Net::Packet &p);
|
|
||||||
private:
|
|
||||||
std::unique_ptr<EQ::Net::ServertalkClient> m_connection;
|
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
10
ucs/ucs.cpp
10
ucs/ucs.cpp
@ -37,12 +37,14 @@
|
|||||||
|
|
||||||
#include "../common/net/tcp_server.h"
|
#include "../common/net/tcp_server.h"
|
||||||
#include "../common/net/servertalk_client_connection.h"
|
#include "../common/net/servertalk_client_connection.h"
|
||||||
|
#include "../common/discord_manager.h"
|
||||||
|
|
||||||
ChatChannelList *ChannelList;
|
ChatChannelList *ChannelList;
|
||||||
Clientlist *g_Clientlist;
|
Clientlist *g_Clientlist;
|
||||||
EQEmuLogSys LogSys;
|
EQEmuLogSys LogSys;
|
||||||
Database database;
|
Database database;
|
||||||
WorldServer *worldserver = nullptr;
|
WorldServer *worldserver = nullptr;
|
||||||
|
DiscordManager discord_manager;
|
||||||
|
|
||||||
const ucsconfig *Config;
|
const ucsconfig *Config;
|
||||||
|
|
||||||
@ -87,6 +89,12 @@ void CatchSignal(int sig_num) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DiscordQueueListener() {
|
||||||
|
while (caught_loop == 0) {
|
||||||
|
discord_manager.ProcessMessageQueue();
|
||||||
|
Sleep(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
RegisterExecutablePlatform(ExePlatformUCS);
|
RegisterExecutablePlatform(ExePlatformUCS);
|
||||||
@ -165,6 +173,8 @@ int main() {
|
|||||||
std::signal(SIGKILL, CatchSignal);
|
std::signal(SIGKILL, CatchSignal);
|
||||||
std::signal(SIGSEGV, CatchSignal);
|
std::signal(SIGSEGV, CatchSignal);
|
||||||
|
|
||||||
|
std::thread(DiscordQueueListener).detach();
|
||||||
|
|
||||||
worldserver = new WorldServer;
|
worldserver = new WorldServer;
|
||||||
|
|
||||||
// uncomment to simulate timed crash for catching SIGSEV
|
// uncomment to simulate timed crash for catching SIGSEV
|
||||||
|
|||||||
@ -26,6 +26,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#include "clientlist.h"
|
#include "clientlist.h"
|
||||||
#include "ucsconfig.h"
|
#include "ucsconfig.h"
|
||||||
#include "database.h"
|
#include "database.h"
|
||||||
|
#include "../common/discord_manager.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -35,10 +36,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
extern WorldServer worldserver;
|
extern WorldServer worldserver;
|
||||||
extern Clientlist *g_Clientlist;
|
extern Clientlist *g_Clientlist;
|
||||||
extern const ucsconfig *Config;
|
extern const ucsconfig *Config;
|
||||||
extern Database database;
|
extern Database database;
|
||||||
|
extern DiscordManager discord_manager;
|
||||||
|
|
||||||
void ProcessMailTo(Client *c, std::string from, std::string subject, std::string message);
|
void ProcessMailTo(Client *c, std::string from, std::string subject, std::string message);
|
||||||
|
|
||||||
@ -72,6 +74,16 @@ void WorldServer::ProcessMessage(uint16 opcode, EQ::Net::Packet &p)
|
|||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ServerOP_DiscordWebhookMessage: {
|
||||||
|
auto *q = (DiscordWebhookMessage_Struct *) p.Data();
|
||||||
|
|
||||||
|
discord_manager.QueueWebhookMessage(
|
||||||
|
q->webhook_id,
|
||||||
|
q->message
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
case ServerOP_UCSMessage:
|
case ServerOP_UCSMessage:
|
||||||
{
|
{
|
||||||
char *Buffer = (char *)pack->pBuffer;
|
char *Buffer = (char *)pack->pBuffer;
|
||||||
|
|||||||
@ -438,6 +438,7 @@
|
|||||||
9182|2022_05_02_npc_types_int64.sql|SHOW COLUMNS FROM `npc_types` LIKE 'hp'|missing|bigint
|
9182|2022_05_02_npc_types_int64.sql|SHOW COLUMNS FROM `npc_types` LIKE 'hp'|missing|bigint
|
||||||
9183|2022_05_07_merchant_data_buckets.sql|SHOW COLUMNS FROM `merchantlist` LIKE 'bucket_comparison'|empty
|
9183|2022_05_07_merchant_data_buckets.sql|SHOW COLUMNS FROM `merchantlist` LIKE 'bucket_comparison'|empty
|
||||||
9184|2022_05_21_schema_consistency.sql|SELECT * FROM db_version WHERE version >= 9184|empty|
|
9184|2022_05_21_schema_consistency.sql|SELECT * FROM db_version WHERE version >= 9184|empty|
|
||||||
|
9185|2022_05_07_discord_webhooks.sql|SHOW TABLES LIKE 'discord_webhooks'|empty|
|
||||||
|
|
||||||
# Upgrade conditions:
|
# Upgrade conditions:
|
||||||
# This won't be needed after this system is implemented, but it is used database that are not
|
# This won't be needed after this system is implemented, but it is used database that are not
|
||||||
|
|||||||
15
utils/sql/git/required/2022_05_07_discord_webhooks.sql
Normal file
15
utils/sql/git/required/2022_05_07_discord_webhooks.sql
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
CREATE TABLE discord_webhooks
|
||||||
|
(
|
||||||
|
id INT auto_increment primary key NULL,
|
||||||
|
webhook_name varchar(100) NULL,
|
||||||
|
webhook_url varchar(255) NULL,
|
||||||
|
created_at DATETIME NULL,
|
||||||
|
deleted_at DATETIME NULL
|
||||||
|
) ENGINE=InnoDB
|
||||||
|
DEFAULT CHARSET=utf8mb4
|
||||||
|
COLLATE=utf8mb4_general_ci;
|
||||||
|
|
||||||
|
ALTER TABLE logsys_categories
|
||||||
|
ADD log_to_discord smallint(11) default 0 AFTER log_to_gmsay;
|
||||||
|
ALTER TABLE logsys_categories
|
||||||
|
ADD discord_webhook_id int(11) default 0 AFTER log_to_discord;
|
||||||
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "world_server_command_handler.h"
|
#include "world_server_command_handler.h"
|
||||||
#include "../common/eqemu_logsys.h"
|
#include "../common/eqemu_logsys.h"
|
||||||
|
#include "../common/discord/discord.h"
|
||||||
#include "../common/json/json.h"
|
#include "../common/json/json.h"
|
||||||
#include "../common/version.h"
|
#include "../common/version.h"
|
||||||
#include "worlddb.h"
|
#include "worlddb.h"
|
||||||
@ -30,6 +31,7 @@
|
|||||||
#include "../common/rulesys.h"
|
#include "../common/rulesys.h"
|
||||||
#include "../common/repositories/instance_list_repository.h"
|
#include "../common/repositories/instance_list_repository.h"
|
||||||
#include "../common/repositories/zone_repository.h"
|
#include "../common/repositories/zone_repository.h"
|
||||||
|
#include "../zone/queryserv.h"
|
||||||
|
|
||||||
namespace WorldserverCommandHandler {
|
namespace WorldserverCommandHandler {
|
||||||
|
|
||||||
@ -157,14 +159,14 @@ namespace WorldserverCommandHandler {
|
|||||||
*/
|
*/
|
||||||
void DatabaseGetSchema(int argc, char **argv, argh::parser &cmd, std::string &description)
|
void DatabaseGetSchema(int argc, char **argv, argh::parser &cmd, std::string &description)
|
||||||
{
|
{
|
||||||
description = "Displays server database schema";
|
description = "Displays server database schema";
|
||||||
|
|
||||||
if (cmd[{"-h", "--help"}]) {
|
if (cmd[{"-h", "--help"}]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Json::Value player_tables_json;
|
Json::Value player_tables_json;
|
||||||
std::vector<std::string> player_tables = DatabaseSchema::GetPlayerTables();
|
std::vector<std::string> player_tables = DatabaseSchema::GetPlayerTables();
|
||||||
for (const auto &table: player_tables) {
|
for (const auto &table: player_tables) {
|
||||||
player_tables_json.append(table);
|
player_tables_json.append(table);
|
||||||
}
|
}
|
||||||
@ -176,19 +178,19 @@ namespace WorldserverCommandHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Json::Value server_tables_json;
|
Json::Value server_tables_json;
|
||||||
std::vector<std::string> server_tables = DatabaseSchema::GetServerTables();
|
std::vector<std::string> server_tables = DatabaseSchema::GetServerTables();
|
||||||
for (const auto &table: server_tables) {
|
for (const auto &table: server_tables) {
|
||||||
server_tables_json.append(table);
|
server_tables_json.append(table);
|
||||||
}
|
}
|
||||||
|
|
||||||
Json::Value login_tables_json;
|
Json::Value login_tables_json;
|
||||||
std::vector<std::string> login_tables = DatabaseSchema::GetLoginTables();
|
std::vector<std::string> login_tables = DatabaseSchema::GetLoginTables();
|
||||||
for (const auto &table: login_tables) {
|
for (const auto &table: login_tables) {
|
||||||
login_tables_json.append(table);
|
login_tables_json.append(table);
|
||||||
}
|
}
|
||||||
|
|
||||||
Json::Value state_tables_json;
|
Json::Value state_tables_json;
|
||||||
std::vector<std::string> state_tables = DatabaseSchema::GetStateTables();
|
std::vector<std::string> state_tables = DatabaseSchema::GetStateTables();
|
||||||
for (const auto &table: state_tables) {
|
for (const auto &table: state_tables) {
|
||||||
state_tables_json.append(table);
|
state_tables_json.append(table);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1245,6 +1245,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
|
|||||||
loginserverlist.SendAccountUpdate(pack);
|
loginserverlist.SendAccountUpdate(pack);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ServerOP_DiscordWebhookMessage:
|
||||||
case ServerOP_UCSMailMessage: {
|
case ServerOP_UCSMailMessage: {
|
||||||
UCSLink.SendPacket(pack);
|
UCSLink.SendPacket(pack);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -888,9 +888,8 @@ Json::Value ApiSetLoggingLevel(EQ::Net::WebsocketServerConnection *connection, J
|
|||||||
void RegisterApiLogEvent(std::unique_ptr<EQ::Net::WebsocketServer> &server)
|
void RegisterApiLogEvent(std::unique_ptr<EQ::Net::WebsocketServer> &server)
|
||||||
{
|
{
|
||||||
LogSys.SetConsoleHandler(
|
LogSys.SetConsoleHandler(
|
||||||
[&](uint16 debug_level, uint16 log_category, const std::string &msg) {
|
[&](uint16 log_category, const std::string &msg) {
|
||||||
Json::Value data;
|
Json::Value data;
|
||||||
data["debug_level"] = debug_level;
|
|
||||||
data["log_category"] = log_category;
|
data["log_category"] = log_category;
|
||||||
data["msg"] = msg;
|
data["msg"] = msg;
|
||||||
server->DispatchEvent(EQ::Net::SubscriptionEventLog, data, 50);
|
server->DispatchEvent(EQ::Net::SubscriptionEventLog, data, 50);
|
||||||
|
|||||||
@ -2465,7 +2465,7 @@ XS(XS__istaskenabled) {
|
|||||||
} else {
|
} else {
|
||||||
Perl_croak(aTHX_ "Usage: quest::istaskenabled(int task_id)");
|
Perl_croak(aTHX_ "Usage: quest::istaskenabled(int task_id)");
|
||||||
}
|
}
|
||||||
|
|
||||||
ST(0) = boolSV(RETVAL);
|
ST(0) = boolSV(RETVAL);
|
||||||
sv_2mortal(ST(0));
|
sv_2mortal(ST(0));
|
||||||
XSRETURN(1);
|
XSRETURN(1);
|
||||||
@ -2483,7 +2483,7 @@ XS(XS__istaskactive) {
|
|||||||
} else {
|
} else {
|
||||||
Perl_croak(aTHX_ "Usage: quest::istaskactive(int task_id)");
|
Perl_croak(aTHX_ "Usage: quest::istaskactive(int task_id)");
|
||||||
}
|
}
|
||||||
|
|
||||||
ST(0) = boolSV(RETVAL);
|
ST(0) = boolSV(RETVAL);
|
||||||
sv_2mortal(ST(0));
|
sv_2mortal(ST(0));
|
||||||
XSRETURN(1);
|
XSRETURN(1);
|
||||||
@ -2502,7 +2502,7 @@ XS(XS__istaskactivityactive) {
|
|||||||
} else {
|
} else {
|
||||||
Perl_croak(aTHX_ "Usage: quest::istaskactivityactive(int task_id, int activity_id)");
|
Perl_croak(aTHX_ "Usage: quest::istaskactivityactive(int task_id, int activity_id)");
|
||||||
}
|
}
|
||||||
|
|
||||||
ST(0) = boolSV(RETVAL);
|
ST(0) = boolSV(RETVAL);
|
||||||
sv_2mortal(ST(0));
|
sv_2mortal(ST(0));
|
||||||
XSRETURN(1);
|
XSRETURN(1);
|
||||||
@ -2818,7 +2818,7 @@ XS(XS__istaskappropriate) {
|
|||||||
} else {
|
} else {
|
||||||
Perl_croak(aTHX_ "Usage: quest::istaskaappropriate(int task_id)");
|
Perl_croak(aTHX_ "Usage: quest::istaskaappropriate(int task_id)");
|
||||||
}
|
}
|
||||||
|
|
||||||
ST(0) = boolSV(RETVAL);
|
ST(0) = boolSV(RETVAL);
|
||||||
sv_2mortal(ST(0));
|
sv_2mortal(ST(0));
|
||||||
XSRETURN(1);
|
XSRETURN(1);
|
||||||
@ -3386,7 +3386,7 @@ XS(XS__CheckInstanceByCharID) {
|
|||||||
|
|
||||||
uint16 instance_id = (int) SvUV(ST(0));
|
uint16 instance_id = (int) SvUV(ST(0));
|
||||||
uint32 char_id = (int) SvUV(ST(1));
|
uint32 char_id = (int) SvUV(ST(1));
|
||||||
RETVAL = quest_manager.CheckInstanceByCharID(instance_id, char_id);
|
RETVAL = quest_manager.CheckInstanceByCharID(instance_id, char_id);
|
||||||
ST(0) = boolSV(RETVAL);
|
ST(0) = boolSV(RETVAL);
|
||||||
sv_2mortal(ST(0));
|
sv_2mortal(ST(0));
|
||||||
XSRETURN(1);
|
XSRETURN(1);
|
||||||
@ -3660,7 +3660,7 @@ XS(XS__IsRunning) {
|
|||||||
bool RETVAL;
|
bool RETVAL;
|
||||||
dXSTARG;
|
dXSTARG;
|
||||||
|
|
||||||
RETVAL = quest_manager.IsRunning();
|
RETVAL = quest_manager.IsRunning();
|
||||||
ST(0) = boolSV(RETVAL);
|
ST(0) = boolSV(RETVAL);
|
||||||
sv_2mortal(ST(0));
|
sv_2mortal(ST(0));
|
||||||
XSRETURN(1);
|
XSRETURN(1);
|
||||||
@ -8426,20 +8426,34 @@ XS(XS__commify) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
XS(XS__checknamefilter);
|
XS(XS__checknamefilter);
|
||||||
XS(XS__checknamefilter) {
|
XS(XS__checknamefilter)
|
||||||
|
{
|
||||||
dXSARGS;
|
dXSARGS;
|
||||||
if (items != 1) {
|
if (items != 1) {
|
||||||
Perl_croak(aTHX_ "Usage: quest::checknamefilter(string name)");
|
Perl_croak(aTHX_ "Usage: quest::checknamefilter(string name)");
|
||||||
}
|
}
|
||||||
|
|
||||||
dXSTARG;
|
dXSTARG;
|
||||||
std::string name = (std::string) SvPV_nolen(ST(0));
|
std::string name = (std::string) SvPV_nolen(ST(0));
|
||||||
bool passes = database.CheckNameFilter(name);
|
bool passes = database.CheckNameFilter(name);
|
||||||
ST(0) = boolSV(passes);
|
ST(0) = boolSV(passes);
|
||||||
sv_2mortal(ST(0));
|
sv_2mortal(ST(0));
|
||||||
XSRETURN(1);
|
XSRETURN(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
XS(XS__discordsend);
|
||||||
|
XS(XS__discordsend) {
|
||||||
|
dXSARGS;
|
||||||
|
if (items != 2)
|
||||||
|
Perl_croak(aTHX_ "Usage: quest::discordsend(string webhook_name, string message)");
|
||||||
|
{
|
||||||
|
std::string webhook_name = (std::string) SvPV_nolen(ST(0));
|
||||||
|
std::string message = (std::string) SvPV_nolen(ST(1));
|
||||||
|
zone->SendDiscordMessage(webhook_name, message);
|
||||||
|
}
|
||||||
|
XSRETURN_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This is the callback perl will look for to setup the
|
This is the callback perl will look for to setup the
|
||||||
quest package's XSUBs
|
quest package's XSUBs
|
||||||
@ -8704,6 +8718,7 @@ EXTERN_C XS(boot_quest) {
|
|||||||
newXS(strcpy(buf, "disable_spawn2"), XS__disable_spawn2, file);
|
newXS(strcpy(buf, "disable_spawn2"), XS__disable_spawn2, file);
|
||||||
newXS(strcpy(buf, "disablerecipe"), XS__disablerecipe, file);
|
newXS(strcpy(buf, "disablerecipe"), XS__disablerecipe, file);
|
||||||
newXS(strcpy(buf, "disabletask"), XS__disabletask, file);
|
newXS(strcpy(buf, "disabletask"), XS__disabletask, file);
|
||||||
|
newXS(strcpy(buf, "discordsend"), XS__discordsend, file);
|
||||||
newXS(strcpy(buf, "doanim"), XS__doanim, file);
|
newXS(strcpy(buf, "doanim"), XS__doanim, file);
|
||||||
newXS(strcpy(buf, "echo"), XS__echo, file);
|
newXS(strcpy(buf, "echo"), XS__echo, file);
|
||||||
newXS(strcpy(buf, "emote"), XS__emote, file);
|
newXS(strcpy(buf, "emote"), XS__emote, file);
|
||||||
|
|||||||
@ -3392,10 +3392,16 @@ std::string lua_commify(std::string number) {
|
|||||||
return commify(number);
|
return commify(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lua_check_name_filter(std::string name) {
|
bool lua_check_name_filter(std::string name)
|
||||||
|
{
|
||||||
return database.CheckNameFilter(name);
|
return database.CheckNameFilter(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void lua_discord_send(std::string webhook_name, std::string message)
|
||||||
|
{
|
||||||
|
zone->SendDiscordMessage(webhook_name, message);
|
||||||
|
}
|
||||||
|
|
||||||
#define LuaCreateNPCParse(name, c_type, default_value) do { \
|
#define LuaCreateNPCParse(name, c_type, default_value) do { \
|
||||||
cur = table[#name]; \
|
cur = table[#name]; \
|
||||||
if(luabind::type(cur) != LUA_TNIL) { \
|
if(luabind::type(cur) != LUA_TNIL) { \
|
||||||
@ -3850,6 +3856,7 @@ luabind::scope lua_register_general() {
|
|||||||
luabind::def("get_environmental_damage_name", &lua_get_environmental_damage_name),
|
luabind::def("get_environmental_damage_name", &lua_get_environmental_damage_name),
|
||||||
luabind::def("commify", &lua_commify),
|
luabind::def("commify", &lua_commify),
|
||||||
luabind::def("check_name_filter", &lua_check_name_filter),
|
luabind::def("check_name_filter", &lua_check_name_filter),
|
||||||
|
luabind::def("discord_send", &lua_discord_send),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Cross Zone
|
Cross Zone
|
||||||
|
|||||||
@ -24,12 +24,14 @@ Copyright (C) 2001-2014 EQEMu Development Team (http://eqemulator.net)
|
|||||||
|
|
||||||
|
|
||||||
extern WorldServer worldserver;
|
extern WorldServer worldserver;
|
||||||
extern QueryServ* QServ;
|
extern QueryServ *QServ;
|
||||||
|
|
||||||
QueryServ::QueryServ(){
|
QueryServ::QueryServ()
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
QueryServ::~QueryServ(){
|
QueryServ::~QueryServ()
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueryServ::SendQuery(std::string Query)
|
void QueryServ::SendQuery(std::string Query)
|
||||||
@ -44,7 +46,9 @@ void QueryServ::SendQuery(std::string Query)
|
|||||||
void QueryServ::PlayerLogEvent(int Event_Type, int Character_ID, std::string Event_Desc)
|
void QueryServ::PlayerLogEvent(int Event_Type, int Character_ID, std::string Event_Desc)
|
||||||
{
|
{
|
||||||
std::string query = StringFormat(
|
std::string query = StringFormat(
|
||||||
"INSERT INTO `qs_player_events` (event, char_id, event_desc, time) VALUES (%i, %i, '%s', UNIX_TIMESTAMP(now()))",
|
"INSERT INTO `qs_player_events` (event, char_id, event_desc, time) VALUES (%i, %i, '%s', UNIX_TIMESTAMP(now()))",
|
||||||
Event_Type, Character_ID, EscapeString(Event_Desc).c_str());
|
Event_Type,
|
||||||
|
Character_ID,
|
||||||
|
EscapeString(Event_Desc).c_str());
|
||||||
SendQuery(query);
|
SendQuery(query);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,7 +21,7 @@ enum PlayerGenericLogEventTypes {
|
|||||||
Player_Log_Issued_Commands,
|
Player_Log_Issued_Commands,
|
||||||
Player_Log_Money_Transactions,
|
Player_Log_Money_Transactions,
|
||||||
Player_Log_Alternate_Currency_Transactions,
|
Player_Log_Alternate_Currency_Transactions,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class QueryServ{
|
class QueryServ{
|
||||||
@ -32,4 +32,4 @@ class QueryServ{
|
|||||||
void PlayerLogEvent(int Event_Type, int Character_ID, std::string Event_Desc);
|
void PlayerLogEvent(int Event_Type, int Character_ID, std::string Event_Desc);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* QUERYSERV_ZONE_H */
|
#endif /* QUERYSERV_ZONE_H */
|
||||||
|
|||||||
@ -57,6 +57,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|||||||
#include "../common/shared_tasks.h"
|
#include "../common/shared_tasks.h"
|
||||||
#include "shared_task_zone_messaging.h"
|
#include "shared_task_zone_messaging.h"
|
||||||
#include "dialogue_window.h"
|
#include "dialogue_window.h"
|
||||||
|
#include "queryserv.h"
|
||||||
|
|
||||||
extern EntityList entity_list;
|
extern EntityList entity_list;
|
||||||
extern Zone* zone;
|
extern Zone* zone;
|
||||||
@ -208,6 +209,8 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
|||||||
else {
|
else {
|
||||||
LogInfo("World assigned Port: [{}] for this zone", sci->port);
|
LogInfo("World assigned Port: [{}] for this zone", sci->port);
|
||||||
ZoneConfig::SetZonePort(sci->port);
|
ZoneConfig::SetZonePort(sci->port);
|
||||||
|
|
||||||
|
LogSys.SetDiscordHandler(&Zone::DiscordWebhookMessageHandler);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -655,7 +655,7 @@ void Zone::LoadNewMerchantData(uint32 merchantid) {
|
|||||||
|
|
||||||
void Zone::GetMerchantDataForZoneLoad() {
|
void Zone::GetMerchantDataForZoneLoad() {
|
||||||
LogInfo("Loading Merchant Lists");
|
LogInfo("Loading Merchant Lists");
|
||||||
|
|
||||||
auto query = fmt::format(
|
auto query = fmt::format(
|
||||||
SQL (
|
SQL (
|
||||||
SELECT
|
SELECT
|
||||||
@ -1209,6 +1209,11 @@ bool Zone::Init(bool is_static) {
|
|||||||
//MODDING HOOK FOR ZONE INIT
|
//MODDING HOOK FOR ZONE INIT
|
||||||
mod_init();
|
mod_init();
|
||||||
|
|
||||||
|
// logging origination information
|
||||||
|
LogSys.origination_info.zone_short_name = zone->short_name;
|
||||||
|
LogSys.origination_info.zone_long_name = zone->long_name;
|
||||||
|
LogSys.origination_info.instance_id = zone->instanceid;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2776,3 +2781,32 @@ void Zone::SendReloadMessage(std::string reload_type)
|
|||||||
).c_str()
|
).c_str()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Zone::SendDiscordMessage(int webhook_id, const std::string& message)
|
||||||
|
{
|
||||||
|
if (worldserver.Connected()) {
|
||||||
|
auto pack = new ServerPacket(ServerOP_DiscordWebhookMessage, sizeof(DiscordWebhookMessage_Struct) + 1);
|
||||||
|
auto *q = (DiscordWebhookMessage_Struct *) pack->pBuffer;
|
||||||
|
|
||||||
|
strn0cpy(q->message, message.c_str(), 2000);
|
||||||
|
q->webhook_id = webhook_id;
|
||||||
|
|
||||||
|
worldserver.SendPacket(pack);
|
||||||
|
safe_delete(pack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Zone::SendDiscordMessage(const std::string& webhook_name, const std::string &message)
|
||||||
|
{
|
||||||
|
bool not_found = true;
|
||||||
|
for (auto & w : LogSys.discord_webhooks) {
|
||||||
|
if (w.webhook_name == webhook_name) {
|
||||||
|
SendDiscordMessage(w.id, message + "\n");
|
||||||
|
not_found = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not_found) {
|
||||||
|
LogDiscord("[SendDiscordMessage] Did not find valid webhook by webhook name [{}]", webhook_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
66
zone/zone.h
66
zone/zone.h
@ -35,6 +35,8 @@
|
|||||||
#include "aa_ability.h"
|
#include "aa_ability.h"
|
||||||
#include "pathfinder_interface.h"
|
#include "pathfinder_interface.h"
|
||||||
#include "global_loot_manager.h"
|
#include "global_loot_manager.h"
|
||||||
|
#include "queryserv.h"
|
||||||
|
#include "../common/discord/discord.h"
|
||||||
|
|
||||||
class DynamicZone;
|
class DynamicZone;
|
||||||
|
|
||||||
@ -147,9 +149,10 @@ public:
|
|||||||
const char *GetSpellBlockedMessage(uint32 spell_id, const glm::vec3 &location);
|
const char *GetSpellBlockedMessage(uint32 spell_id, const glm::vec3 &location);
|
||||||
|
|
||||||
EQ::Random random;
|
EQ::Random random;
|
||||||
EQTime zone_time;
|
EQTime zone_time;
|
||||||
|
|
||||||
ZonePoint *GetClosestZonePoint(const glm::vec3 &location, const char *to_name, Client *client, float max_distance = 40000.0f);
|
ZonePoint *
|
||||||
|
GetClosestZonePoint(const glm::vec3 &location, const char *to_name, Client *client, float max_distance = 40000.0f);
|
||||||
|
|
||||||
inline bool BuffTimersSuspended() const { return newzone_data.SuspendBuffs != 0; };
|
inline bool BuffTimersSuspended() const { return newzone_data.SuspendBuffs != 0; };
|
||||||
inline bool HasMap() { return zonemap != nullptr; }
|
inline bool HasMap() { return zonemap != nullptr; }
|
||||||
@ -179,7 +182,7 @@ public:
|
|||||||
void DumpMerchantList(uint32 npcid);
|
void DumpMerchantList(uint32 npcid);
|
||||||
int SaveTempItem(uint32 merchantid, uint32 npcid, uint32 item, int32 charges, bool sold = false);
|
int SaveTempItem(uint32 merchantid, uint32 npcid, uint32 item, int32 charges, bool sold = false);
|
||||||
int32 MobsAggroCount() { return aggroedmobs; }
|
int32 MobsAggroCount() { return aggroedmobs; }
|
||||||
DynamicZone* GetDynamicZone();
|
DynamicZone *GetDynamicZone();
|
||||||
|
|
||||||
IPathfinder *pathing;
|
IPathfinder *pathing;
|
||||||
LinkedList<NPC_Emote_Struct *> NPCEmoteList;
|
LinkedList<NPC_Emote_Struct *> NPCEmoteList;
|
||||||
@ -187,31 +190,31 @@ public:
|
|||||||
LinkedList<ZonePoint *> zone_point_list;
|
LinkedList<ZonePoint *> zone_point_list;
|
||||||
std::vector<ZonePointsRepository::ZonePoints> virtual_zone_point_list;
|
std::vector<ZonePointsRepository::ZonePoints> virtual_zone_point_list;
|
||||||
|
|
||||||
Map *zonemap;
|
Map *zonemap;
|
||||||
MercTemplate *GetMercTemplate(uint32 template_id);
|
MercTemplate *GetMercTemplate(uint32 template_id);
|
||||||
NewZone_Struct newzone_data;
|
NewZone_Struct newzone_data;
|
||||||
QGlobalCache *CreateQGlobals()
|
QGlobalCache *CreateQGlobals()
|
||||||
{
|
{
|
||||||
qGlobals = new QGlobalCache();
|
qGlobals = new QGlobalCache();
|
||||||
return qGlobals;
|
return qGlobals;
|
||||||
}
|
}
|
||||||
QGlobalCache *GetQGlobals() { return qGlobals; }
|
QGlobalCache *GetQGlobals() { return qGlobals; }
|
||||||
SpawnConditionManager spawn_conditions;
|
SpawnConditionManager spawn_conditions;
|
||||||
SpawnGroupList spawn_group_list;
|
SpawnGroupList spawn_group_list;
|
||||||
|
|
||||||
std::list<AltCurrencyDefinition_Struct> AlternateCurrencies;
|
std::list<AltCurrencyDefinition_Struct> AlternateCurrencies;
|
||||||
std::list<InternalVeteranReward> VeteranRewards;
|
std::list<InternalVeteranReward> VeteranRewards;
|
||||||
std::map<uint32, LDoNTrapTemplate *> ldon_trap_list;
|
std::map<uint32, LDoNTrapTemplate *> ldon_trap_list;
|
||||||
std::map<uint32, MercTemplate> merc_templates;
|
std::map<uint32, MercTemplate> merc_templates;
|
||||||
std::map<uint32, NPCType *> merctable;
|
std::map<uint32, NPCType *> merctable;
|
||||||
std::map<uint32, NPCType *> npctable;
|
std::map<uint32, NPCType *> npctable;
|
||||||
std::map<uint32, std::list<LDoNTrapTemplate *> > ldon_trap_entry_list;
|
std::map<uint32, std::list<LDoNTrapTemplate *> > ldon_trap_entry_list;
|
||||||
std::map<uint32, std::list<MerchantList> > merchanttable;
|
std::map<uint32, std::list<MerchantList> > merchanttable;
|
||||||
std::map<uint32, std::list<MercSpellEntry> > merc_spells_list;
|
std::map<uint32, std::list<MercSpellEntry> > merc_spells_list;
|
||||||
std::map<uint32, std::list<MercStanceInfo> > merc_stance_list;
|
std::map<uint32, std::list<MercStanceInfo> > merc_stance_list;
|
||||||
std::map<uint32, std::list<TempMerchantList> > tmpmerchanttable;
|
std::map<uint32, std::list<TempMerchantList> > tmpmerchanttable;
|
||||||
std::map<uint32, std::string> adventure_entry_list_flavor;
|
std::map<uint32, std::string> adventure_entry_list_flavor;
|
||||||
std::map<uint32, ZoneEXPModInfo> level_exp_mod;
|
std::map<uint32, ZoneEXPModInfo> level_exp_mod;
|
||||||
|
|
||||||
std::pair<AA::Ability *, AA::Rank *> GetAlternateAdvancementAbilityAndRank(int id, int points_spent);
|
std::pair<AA::Ability *, AA::Rank *> GetAlternateAdvancementAbilityAndRank(int id, int points_spent);
|
||||||
|
|
||||||
@ -223,7 +226,7 @@ public:
|
|||||||
std::vector<GridEntriesRepository::GridEntry> zone_grid_entries;
|
std::vector<GridEntriesRepository::GridEntry> zone_grid_entries;
|
||||||
|
|
||||||
std::unordered_map<uint32, std::unique_ptr<DynamicZone>> dynamic_zone_cache;
|
std::unordered_map<uint32, std::unique_ptr<DynamicZone>> dynamic_zone_cache;
|
||||||
std::unordered_map<uint32, std::unique_ptr<Expedition>> expedition_cache;
|
std::unordered_map<uint32, std::unique_ptr<Expedition>> expedition_cache;
|
||||||
|
|
||||||
time_t weather_timer;
|
time_t weather_timer;
|
||||||
Timer spawn2_timer;
|
Timer spawn2_timer;
|
||||||
@ -344,10 +347,11 @@ public:
|
|||||||
fmt::format(
|
fmt::format(
|
||||||
"--- {}",
|
"--- {}",
|
||||||
message_split[iter]
|
message_split[iter]
|
||||||
).c_str()
|
).c_str()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
entity_list.MessageStatus(
|
entity_list.MessageStatus(
|
||||||
0,
|
0,
|
||||||
AccountStatus::QuestTroupe,
|
AccountStatus::QuestTroupe,
|
||||||
@ -357,6 +361,22 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void SendDiscordMessage(int webhook_id, const std::string& message);
|
||||||
|
static void SendDiscordMessage(const std::string& webhook_name, const std::string& message);
|
||||||
|
static void DiscordWebhookMessageHandler(uint16 log_category, int webhook_id, const std::string &message)
|
||||||
|
{
|
||||||
|
std::string message_prefix;
|
||||||
|
if (!LogSys.origination_info.zone_short_name.empty()) {
|
||||||
|
message_prefix = fmt::format(
|
||||||
|
"[**{}**] **Zone** [**{}**] ",
|
||||||
|
Logs::LogCategoryName[log_category],
|
||||||
|
LogSys.origination_info.zone_short_name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
SendDiscordMessage(webhook_id, message_prefix + Discord::FormatDiscordMessage(log_category, message));
|
||||||
|
};
|
||||||
|
|
||||||
double GetMaxMovementUpdateRange() const { return max_movement_update_range; }
|
double GetMaxMovementUpdateRange() const { return max_movement_update_range; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user