diff --git a/common/events/player_event_logs.cpp b/common/events/player_event_logs.cpp index 9288db854..f39242901 100644 --- a/common/events/player_event_logs.cpp +++ b/common/events/player_event_logs.cpp @@ -536,6 +536,20 @@ std::string PlayerEventLogs::GetDiscordWebhookUrlFromEventType(int32_t event_typ return ""; } +void PlayerEventLogs::LoadPlayerEventSettingsFromQS( + const std::vector &settings +) +{ + for (const auto &e : settings) { + if (e.id >= PlayerEvent::MAX || e.id < 0) { + continue; + } + m_settings[e.id] = e; + } + + LogInfo("Applied [{}] player event log settings from QS", settings.size()); +} + // GM_COMMAND | [x] Implemented Formatter // ZONING | [x] Implemented Formatter // AA_GAIN | [x] Implemented Formatter diff --git a/common/events/player_event_logs.h b/common/events/player_event_logs.h index 8a9ccb202..cbc455666 100644 --- a/common/events/player_event_logs.h +++ b/common/events/player_event_logs.h @@ -73,9 +73,11 @@ public: return BuildPlayerEventPacket(c); } - [[nodiscard]] const PlayerEventLogSettingsRepository::PlayerEventLogSettings *GetSettings() const; - bool IsEventDiscordEnabled(int32_t event_type_id); - std::string GetDiscordWebhookUrlFromEventType(int32_t event_type_id); + [[nodiscard]] const PlayerEventLogSettingsRepository::PlayerEventLogSettings * GetSettings() const; + bool IsEventDiscordEnabled(int32_t event_type_id); + std::string GetDiscordWebhookUrlFromEventType(int32_t event_type_id); + + void LoadPlayerEventSettingsFromQS(const std::vector& settings); static std::string GetDiscordPayloadFromEvent(const PlayerEvent::PlayerEventContainer &e); diff --git a/common/repositories/base/base_player_event_log_settings_repository.h b/common/repositories/base/base_player_event_log_settings_repository.h index 4a2457576..94a53b981 100644 --- a/common/repositories/base/base_player_event_log_settings_repository.h +++ b/common/repositories/base/base_player_event_log_settings_repository.h @@ -15,7 +15,7 @@ #include "../../database.h" #include "../../strings.h" #include - +#include class BasePlayerEventLogSettingsRepository { public: struct PlayerEventLogSettings { @@ -25,6 +25,20 @@ public: int32_t retention_days; int32_t discord_webhook_id; uint8_t etl_enabled; + + // cereal + template + void serialize(Archive &ar) + { + ar( + CEREAL_NVP(id), + CEREAL_NVP(event_name), + CEREAL_NVP(event_enabled), + CEREAL_NVP(retention_days), + CEREAL_NVP(discord_webhook_id), + CEREAL_NVP(etl_enabled) + ); + } }; static std::string PrimaryKey() diff --git a/common/servertalk.h b/common/servertalk.h index 3680ac76d..9985c875c 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -273,8 +273,9 @@ #define ServerOP_WWTaskUpdate 0x4758 // player events -#define ServerOP_QSSendQuery 0x5000 +#define ServerOP_QSSendQuery 0x5000 #define ServerOP_PlayerEvent 0x5100 +#define ServerOP_SendPlayerEventSettings 0x5101 enum { CZUpdateType_Character, @@ -1778,6 +1779,7 @@ struct BazaarPurchaseMessaging_Struct { uint32 id; }; + #pragma pack() #endif diff --git a/queryserv/worldserver.cpp b/queryserv/worldserver.cpp index 948ab931e..e2270c57c 100644 --- a/queryserv/worldserver.cpp +++ b/queryserv/worldserver.cpp @@ -21,10 +21,13 @@ #include #include +#include "zonelist.h" + extern WorldServer worldserver; extern const queryservconfig *Config; extern QSDatabase qs_database; extern LFGuildManager lfguildmanager; +extern ZSList zs_list; WorldServer::WorldServer() { @@ -78,6 +81,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) if (o->type == ServerReload::Type::Logs) { LogSys.LoadLogDatabaseSettings(); player_event_logs.ReloadSettings(); + zs_list.SendPlayerEventLogSettings(); } break; diff --git a/queryserv/zonelist.cpp b/queryserv/zonelist.cpp index d06cfefe8..16ad65371 100644 --- a/queryserv/zonelist.cpp +++ b/queryserv/zonelist.cpp @@ -5,6 +5,8 @@ void ZSList::Add(ZoneServer* zoneserver) { zone_server_list.emplace_back(std::unique_ptr(zoneserver)); zoneserver->SetIsZoneConnected(true); + + zoneserver->SendPlayerEventLogSettings(); } void ZSList::Remove(const std::string &uuid) @@ -18,3 +20,10 @@ void ZSList::Remove(const std::string &uuid) iter++; } } + +void ZSList::SendPlayerEventLogSettings() +{ + for (auto &zs : zone_server_list) { + zs->SendPlayerEventLogSettings(); + } +} diff --git a/queryserv/zonelist.h b/queryserv/zonelist.h index c63d1c211..3fc41676d 100644 --- a/queryserv/zonelist.h +++ b/queryserv/zonelist.h @@ -12,9 +12,10 @@ class ZoneServer; class ZSList { public: - std::list> &GetZsList() { return zone_server_list; } - void Add(ZoneServer *zoneserver); - void Remove(const std::string &uuid); + std::list>& GetZsList() { return zone_server_list; } + void Add(ZoneServer* zoneserver); + void Remove(const std::string& uuid); + void SendPlayerEventLogSettings(); private: std::list> zone_server_list; diff --git a/queryserv/zoneserver.cpp b/queryserv/zoneserver.cpp index 2c3fd92d4..b540cf63f 100644 --- a/queryserv/zoneserver.cpp +++ b/queryserv/zoneserver.cpp @@ -7,6 +7,7 @@ extern DiscordManager discord_manager; + ZoneServer::ZoneServer( std::shared_ptr in_connection, EQ::Net::ConsoleServer *in_console @@ -46,3 +47,27 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) } } } + +void ZoneServer::SendPlayerEventLogSettings() +{ + EQ::Net::DynamicPacket dyn_pack; + std::vector settings( + player_event_logs.GetSettings(), + player_event_logs.GetSettings() + PlayerEvent::EventType::MAX + ); + + dyn_pack.PutSerialize(0, settings); + + auto packet_size = sizeof(ServerSendPlayerEvent_Struct) + dyn_pack.Length(); + + auto pack = std::make_unique( + ServerOP_SendPlayerEventSettings, + static_cast(packet_size) + ); + + auto* buf = reinterpret_cast(pack->pBuffer); + buf->cereal_size = static_cast(dyn_pack.Length()); + memcpy(buf->cereal_data, dyn_pack.Data(), dyn_pack.Length()); + + SendPacket(pack.release()); +} diff --git a/queryserv/zoneserver.h b/queryserv/zoneserver.h index db36bd4ff..f4a4b08e6 100644 --- a/queryserv/zoneserver.h +++ b/queryserv/zoneserver.h @@ -16,11 +16,12 @@ class ZoneServer : public WorldTCPConnection { public: ZoneServer(std::shared_ptr in_connection, EQ::Net::ConsoleServer *in_console); ~ZoneServer(); - void SendPacket(ServerPacket *pack) { m_connection->SendPacket(pack); } - void SetIsZoneConnected(bool in) { m_is_zone_connected = in; } - bool GetIsZoneConnected() { return m_is_zone_connected; } - void HandleMessage(uint16 opcode, const EQ::Net::Packet &p); + void SendPacket(ServerPacket *pack) { m_connection->SendPacket(pack); } + void SetIsZoneConnected(bool in) { m_is_zone_connected = in; } + bool GetIsZoneConnected() { return m_is_zone_connected; } + void HandleMessage(uint16 opcode, const EQ::Net::Packet &p); std::string GetUUID() const { return m_connection->GetUUID(); } + void SendPlayerEventLogSettings(); private: std::shared_ptr m_connection{}; diff --git a/utils/scripts/generators/repository-generator.pl b/utils/scripts/generators/repository-generator.pl index 6cb6a137c..3def50506 100644 --- a/utils/scripts/generators/repository-generator.pl +++ b/utils/scripts/generators/repository-generator.pl @@ -114,7 +114,8 @@ if ($requested_table_to_generate ne "all") { my @cereal_enabled_tables = ( "data_buckets", - "player_event_logs" + "player_event_logs", + "player_event_log_settings" ); my $generated_base_repository_files = ""; diff --git a/world/zonelist.cpp b/world/zonelist.cpp index 386f5c781..9394a205e 100644 --- a/world/zonelist.cpp +++ b/world/zonelist.cpp @@ -37,6 +37,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "dynamic_zone_manager.h" #include "ucs.h" #include "clientlist.h" +#include "queryserv.h" #include "../common/repositories/trader_repository.h" #include "../common/repositories/buyer_repository.h" @@ -44,6 +45,7 @@ extern uint32 numzones; extern WebInterfaceList web_interface; extern SharedTaskManager shared_task_manager; extern ClientList client_list; +extern QueryServConnection QSLink; volatile bool UCSServerAvailable_ = false; void CatchSignal(int sig_num); @@ -984,6 +986,7 @@ void ZSList::SendServerReload(ServerReload::Type type, uchar *packet) LogSys.LoadLogDatabaseSettings(); player_event_logs.ReloadSettings(); UCSLink.SendPacket(&pack); + QSLink.SendPacket(&pack); } else if (type == ServerReload::Type::Tasks) { shared_task_manager.LoadTaskData(); } else if (type == ServerReload::Type::DzTemplates) { diff --git a/zone/queryserv.cpp b/zone/queryserv.cpp index c94d88795..77a00b8e2 100644 --- a/zone/queryserv.cpp +++ b/zone/queryserv.cpp @@ -1,12 +1,13 @@ #include "../common/global_define.h" #include "../common/servertalk.h" #include "../common/strings.h" +#include "../common/events/player_event_logs.h" #include "queryserv.h" #include "worldserver.h" extern WorldServer worldserver; -extern QueryServ *QServ; +extern QueryServ* QServ; QueryServ::QueryServ() { @@ -20,18 +21,29 @@ void QueryServ::SendQuery(std::string Query) { auto pack = new ServerPacket(ServerOP_QSSendQuery, Query.length() + 5); pack->WriteUInt32(Query.length()); /* Pack Query String Size so it can be dynamically broken out at queryserv */ - pack->WriteString(Query.c_str()); /* Query */ + pack->WriteString(Query.c_str()); /* Query */ worldserver.SendPacket(pack); safe_delete(pack); } void QueryServ::Connect() { - m_connection = std::make_unique(Config->QSHost, Config->QSPort, false, "Zone", Config->SharedKey); + m_connection = std::make_unique( + Config->QSHost, + Config->QSPort, + false, + "Zone", + Config->SharedKey + ); m_connection->OnMessage(std::bind(&QueryServ::HandleMessage, this, std::placeholders::_1, std::placeholders::_2)); - m_connection->OnConnect([this](EQ::Net::ServertalkClient *client) { + m_connection->OnConnect([this](EQ::Net::ServertalkClient* client) + { m_is_qs_connected = true; - LogInfo("Query Server connection established to [{}] [{}]", client->Handle()->RemoteIP(), client->Handle()->RemotePort()); + LogInfo( + "Query Server connection established to [{}] [{}]", + client->Handle()->RemoteIP(), + client->Handle()->RemotePort() + ); }); LogInfo( @@ -41,7 +53,7 @@ void QueryServ::Connect() ); } -bool QueryServ::SendPacket(ServerPacket *pack) +bool QueryServ::SendPacket(ServerPacket* pack) { if (m_connection.get() == nullptr) { Connect(); @@ -59,14 +71,50 @@ bool QueryServ::SendPacket(ServerPacket *pack) return false; } -void QueryServ::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) +void QueryServ::HandleMessage(uint16 opcode, const EQ::Net::Packet& p) { ServerPacket tpack(opcode, p); - auto pack = &tpack; + auto pack = &tpack; switch (opcode) { - default: { - LogInfo("Unknown ServerOP Received [{}]", opcode); + case ServerOP_SendPlayerEventSettings: + { + if (pack->size < sizeof(ServerSendPlayerEvent_Struct)) { + LogError("ServerOP_SendPlayerEventSettings: packet too small"); + break; + } + + auto* data = reinterpret_cast(pack->pBuffer); + const uint32_t expected_size = sizeof(ServerSendPlayerEvent_Struct) + data->cereal_size; + + if (pack->size < expected_size) { + LogError( + "ServerOP_SendPlayerEventSettings: packet size mismatch, expected {}, got {}", expected_size, + pack->size + ); + break; + } + + std::vector settings; + + try { + EQ::Util::MemoryStreamReader ms(const_cast(data->cereal_data), data->cereal_size); + cereal::BinaryInputArchive ar(ms); + ar(settings); + } + catch (const std::exception& ex) { + LogError("Failed to deserialize PlayerEventLogSettings: {}", ex.what()); + break; + } + + player_event_logs.LoadPlayerEventSettingsFromQS(settings); + LogInfo("Loaded {} PlayerEventLogSettings from queryserv", settings.size()); + break; + } + + default: + { + LogInfo("Unknown ServerOP Received [{}]", opcode); break; } } diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index 7bac46737..9cab52849 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -4591,7 +4591,10 @@ void WorldServer::ProcessReload(const ServerReload::Request& request) case ServerReload::Type::Logs: LogSys.LoadLogDatabaseSettings(); - player_event_logs.ReloadSettings(); + // if QS process is enabled, we get settings from QS + if (!RuleB(Logging, PlayerEventsQSProcess)) { + player_event_logs.ReloadSettings(); + } break; case ServerReload::Type::Loot: