From 3a575d8cac79a0eeb35af85c5a0b8017ba427fc9 Mon Sep 17 00:00:00 2001 From: FrancescoBorzi Date: Sun, 24 May 2026 20:05:35 +0200 Subject: [PATCH] feat: use PlayerSettings + flat command --- README.md | 19 ++++--- conf/mod-bg-auto-queue.conf.dist | 6 +++ .../db-characters/base/mod_bg_auto_queue.sql | 7 --- src/BgAutoQueue.cpp | 53 +++++-------------- src/BgAutoQueue.h | 20 +++---- src/PlayerScript_bg_auto_queue.cpp | 28 ---------- src/cs_bg_auto_queue.cpp | 43 +++++---------- src/mod_bg_auto_queue_loader.cpp | 2 - src/mod_bg_auto_queue_scripts.cpp | 6 --- 9 files changed, 55 insertions(+), 129 deletions(-) delete mode 100644 data/sql/db-characters/base/mod_bg_auto_queue.sql delete mode 100644 src/PlayerScript_bg_auto_queue.cpp diff --git a/README.md b/README.md index d181215..3c3cc0b 100644 --- a/README.md +++ b/README.md @@ -69,11 +69,13 @@ Things to be aware of when running this on a live server: `Interval`, the next automatic pass is pushed back each time and may never fire — use `.bgevents run` to trigger one on demand, or avoid reloading right before a pass is due. -- **Opt-out state is read once at startup.** The opt-out set is loaded from - `mod_bg_auto_queue_optout` on server startup and is thereafter the in-memory - source of truth (mutated by `.bgevents on`/`off` and kept in sync with the - table). Editing the table directly while the server is running has **no - effect until the next restart**. +- **Opt-out is stored per character via the core PlayerSettings system** + (`source = "mod-bg-auto-queue"`, index 0; `1` = opted out). The core loads it + on login, saves it on logout, and deletes it when the character is deleted — + the module keeps no table of its own. **This requires the core config + `EnablePlayerSettings = 1` for the opt-out to persist across logins.** With it + `0` (the core default), `.bgevents off` still works but only for the current + session, and a warning is logged at startup. ## Installation @@ -81,8 +83,9 @@ Things to be aware of when running this on a live server: 2. Re-run CMake and rebuild the worldserver. 3. Copy `mod-bg-auto-queue.conf.dist` to `mod-bg-auto-queue.conf` in your worldserver's configuration directory and adjust as needed. -4. The module installs its characters-database table automatically through the - AzerothCore SQL updater on first run. +4. For per-character opt-out to persist across logins, set the core config + `EnablePlayerSettings = 1` (see the dependency note in the conf). The module + creates no database tables of its own. ## Configuration @@ -102,5 +105,5 @@ All options are documented in `conf/mod-bg-auto-queue.conf.dist`: - `.bgevents on` — opt the current character back into battleground events. - `.bgevents off` — opt the current character out (future passes only; does not dequeue an existing queue). -- `.bgevents status` — show the opt-in state and the time until the next scheduled pass. +- `.bgevents` — *(no argument)* show the opt-in state and the time until the next scheduled pass. - `.bgevents run` — *(GM, console-capable)* run a queue pass immediately, even when the automatic schedule is disabled. Does not reset the periodic timer. diff --git a/conf/mod-bg-auto-queue.conf.dist b/conf/mod-bg-auto-queue.conf.dist index 61f4ae3..8c3ed38 100644 --- a/conf/mod-bg-auto-queue.conf.dist +++ b/conf/mod-bg-auto-queue.conf.dist @@ -7,6 +7,12 @@ ################################################################################################### # mod-bg-auto-queue # +# DEPENDENCY: per-character ".bgevents" opt-out is stored via the core +# PlayerSettings system, which only persists across logins when the core +# config "EnablePlayerSettings" is set to 1. With it 0 (the core default), +# ".bgevents off" still works but lasts only for the current session, and a +# warning is logged at startup. This module does not change the core config. +# # BgAutoQueue.Enable # Description: Enable the automatic, periodic battleground queue pass. # When enabled, the module periodically gathers eligible diff --git a/data/sql/db-characters/base/mod_bg_auto_queue.sql b/data/sql/db-characters/base/mod_bg_auto_queue.sql deleted file mode 100644 index ce078d4..0000000 --- a/data/sql/db-characters/base/mod_bg_auto_queue.sql +++ /dev/null @@ -1,7 +0,0 @@ --- --- Table tracking characters that opted out from the automatic battleground queue performed by mod-bg-auto-queue --- -CREATE TABLE IF NOT EXISTS `mod_bg_auto_queue_optout` ( - `guid` INT UNSIGNED NOT NULL, - PRIMARY KEY (`guid`) -) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci; diff --git a/src/BgAutoQueue.cpp b/src/BgAutoQueue.cpp index 3ef3e79..ce21743 100644 --- a/src/BgAutoQueue.cpp +++ b/src/BgAutoQueue.cpp @@ -12,7 +12,6 @@ #include "Config.h" #include "Containers.h" #include "DBCStores.h" -#include "DatabaseEnv.h" #include "DisableMgr.h" #include "LFGMgr.h" #include "Log.h" @@ -129,50 +128,26 @@ void BgAutoQueue::LoadConfig() LOG_INFO("module", "mod-bg-auto-queue: enabled={}, levels=[{}-{}], pool size={}, interval={} min, initialDelay={} s, warningLead={} s, crossFaction={}, skipGM={}.", _enabled, _levelMin, _levelMax, _pool.size(), intervalMin, initialDelaySec, warningLeadSec, _crossFaction, _skipGameMasters); -} - -void BgAutoQueue::LoadOptOutData() -{ - _optedOut.clear(); - - QueryResult result = CharacterDatabase.Query("SELECT guid FROM mod_bg_auto_queue_optout"); - if (!result) - return; - - do - { - Field* fields = result->Fetch(); - _optedOut.insert(fields[0].Get()); - } while (result->NextRow()); - LOG_INFO("module", "mod-bg-auto-queue: loaded {} opt-out entries.", _optedOut.size()); + // Opt-out is stored via the core PlayerSettings system, which only persists + // across logins when EnablePlayerSettings is on. Without it, .bgevents + // opt-out still works but only for the current session. + if (!sWorld->getBoolConfig(CONFIG_PLAYER_SETTINGS_ENABLED)) + LOG_WARN("module", "mod-bg-auto-queue: EnablePlayerSettings is 0; " + ".bgevents opt-out works only for the current session and will not " + "persist across logins until an administrator sets EnablePlayerSettings = 1."); } -bool BgAutoQueue::IsOptedOut(ObjectGuid guid) const +bool BgAutoQueue::IsOptedOut(Player* player) const { - return _optedOut.find(guid.GetCounter()) != _optedOut.end(); -} - -void BgAutoQueue::SetOptOut(ObjectGuid guid, bool optedOut) -{ - uint32 low = guid.GetCounter(); - - if (optedOut) - { - if (_optedOut.insert(low).second) - CharacterDatabase.Execute("INSERT IGNORE INTO mod_bg_auto_queue_optout (guid) VALUES ({})", low); - } - else - { - if (_optedOut.erase(low) > 0) - CharacterDatabase.Execute("DELETE FROM mod_bg_auto_queue_optout WHERE guid = {}", low); - } + // GetPlayerSetting is non-const (it lazily creates a zero-default entry), + // but the constness here is on BgAutoQueue, not on the Player* argument. + return player->GetPlayerSetting("mod-bg-auto-queue", BG_AUTO_QUEUE_SETTING_OPT_OUT).IsEnabled(); } -void BgAutoQueue::DeleteOptOut(CharacterDatabaseTransaction trans, uint32 guidLow) +void BgAutoQueue::SetOptOut(Player* player, bool optedOut) { - _optedOut.erase(guidLow); - trans->Append("DELETE FROM mod_bg_auto_queue_optout WHERE guid = {}", guidLow); + player->UpdatePlayerSetting("mod-bg-auto-queue", BG_AUTO_QUEUE_SETTING_OPT_OUT, optedOut ? 1u : 0u); } bool BgAutoQueue::IsLevelEligible(uint8 level) const @@ -187,7 +162,7 @@ bool BgAutoQueue::IsEligible(Player* player) const std::string const& name = player->GetName(); - if (IsOptedOut(player->GetGUID())) + if (IsOptedOut(player)) { LOG_DEBUG("module", "mod-bg-auto-queue: skip {}: opted out.", name); return false; diff --git a/src/BgAutoQueue.h b/src/BgAutoQueue.h index 4ea3aeb..e1db726 100644 --- a/src/BgAutoQueue.h +++ b/src/BgAutoQueue.h @@ -6,32 +6,34 @@ #define _MOD_BG_AUTO_QUEUE_H_ #include "DBCEnums.h" -#include "DatabaseEnvFwd.h" #include "ObjectGuid.h" #include "SharedDefines.h" #include -#include #include class Battleground; class Player; +// PlayerSettings layout for this module. source = "mod-bg-auto-queue". +enum BgAutoQueueSetting +{ + BG_AUTO_QUEUE_SETTING_OPT_OUT = 0 // value: 0 = opted in (default), 1 = opted out +}; + class BgAutoQueue { public: static BgAutoQueue* instance(); void LoadConfig(); - void LoadOptOutData(); bool IsEnabled() const { return _enabled; } - bool IsOptedOut(ObjectGuid guid) const; - void SetOptOut(ObjectGuid guid, bool optedOut); - // Called from PlayerScript::OnPlayerDeleteFromDB. The DELETE is appended to - // the character-deletion transaction so it commits atomically with it. - void DeleteOptOut(CharacterDatabaseTransaction trans, uint32 guidLow); + // Opt-out is stored as a per-character core PlayerSetting; these are thin + // wrappers over Player::GetPlayerSetting/UpdatePlayerSetting. + bool IsOptedOut(Player* player) const; + void SetOptOut(Player* player, bool optedOut); bool IsLevelEligible(uint8 level) const; @@ -99,8 +101,6 @@ class BgAutoQueue uint32 _elapsedMs = 0; bool _warningSent = false; bool _firstPass = true; - - std::unordered_set _optedOut; // characters guid::low values }; #define sBgAutoQueue BgAutoQueue::instance() diff --git a/src/PlayerScript_bg_auto_queue.cpp b/src/PlayerScript_bg_auto_queue.cpp deleted file mode 100644 index 0e416bb..0000000 --- a/src/PlayerScript_bg_auto_queue.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license - */ - -#include "BgAutoQueue.h" - -#include "ScriptMgr.h" - -class mod_bg_auto_queue_playerscript : public PlayerScript -{ -public: - mod_bg_auto_queue_playerscript() : PlayerScript("mod_bg_auto_queue_playerscript", { - PLAYERHOOK_ON_DELETE_FROM_DB - }) { } - - // guid is the character GUID-low; drop any opt-out row so the table does - // not accumulate orphans when a character is deleted. The DELETE joins the - // character-deletion transaction so it commits atomically with it. - void OnPlayerDeleteFromDB(CharacterDatabaseTransaction trans, uint32 guid) override - { - sBgAutoQueue->DeleteOptOut(trans, guid); - } -}; - -void AddSC_bg_auto_queue_playerscript() -{ - new mod_bg_auto_queue_playerscript(); -} diff --git a/src/cs_bg_auto_queue.cpp b/src/cs_bg_auto_queue.cpp index e3a4b44..43707c6 100644 --- a/src/cs_bg_auto_queue.cpp +++ b/src/cs_bg_auto_queue.cpp @@ -20,10 +20,8 @@ class bg_auto_queue_commandscript : public CommandScript { static ChatCommandTable bgAutoQueueTable = { - { "on", HandleBgAutoQueueOnCommand, SEC_PLAYER, Console::No }, - { "off", HandleBgAutoQueueOffCommand, SEC_PLAYER, Console::No }, - { "status", HandleBgAutoQueueStatusCommand, SEC_PLAYER, Console::No }, - { "run", HandleBgAutoQueueRunCommand, SEC_GAMEMASTER, Console::Yes }, + { "run", HandleBgAutoQueueRunCommand, SEC_GAMEMASTER, Console::Yes }, + { "", HandleBgAutoQueueCommand, SEC_PLAYER, Console::No }, }; static ChatCommandTable commandTable = @@ -34,7 +32,9 @@ class bg_auto_queue_commandscript : public CommandScript return commandTable; } - static bool HandleBgAutoQueueOnCommand(ChatHandler* handler) + // Default subcommand: `.bgevents on`/`off` toggles opt state; `.bgevents` + // with no argument prints the current state and time to the next event. + static bool HandleBgAutoQueueCommand(ChatHandler* handler, Optional enable) { Player* player = handler->GetPlayer(); if (!player) @@ -43,35 +43,20 @@ class bg_auto_queue_commandscript : public CommandScript return false; } - sBgAutoQueue->SetOptOut(player->GetGUID(), false); - handler->SendSysMessage("Battleground events enabled for your character."); - return true; - } - - static bool HandleBgAutoQueueOffCommand(ChatHandler* handler) - { - Player* player = handler->GetPlayer(); - if (!player) + if (enable.has_value()) { - handler->SendErrorMessage("This command must be used in-game."); - return false; - } + // enable == true means opt IN, i.e. not opted out. + sBgAutoQueue->SetOptOut(player, !*enable); - sBgAutoQueue->SetOptOut(player->GetGUID(), true); - handler->SendSysMessage("Battleground events disabled for your character. You will not be auto-queued. Use .bgevents on to opt back in."); - return true; - } + if (*enable) + handler->SendSysMessage("Battleground events enabled for your character."); + else + handler->SendSysMessage("Battleground events disabled for your character. You will not be auto-queued. Use .bgevents on to opt back in."); - static bool HandleBgAutoQueueStatusCommand(ChatHandler* handler) - { - Player* player = handler->GetPlayer(); - if (!player) - { - handler->SendErrorMessage("This command must be used in-game."); - return false; + return true; } - if (sBgAutoQueue->IsOptedOut(player->GetGUID())) + if (sBgAutoQueue->IsOptedOut(player)) handler->SendSysMessage("Battleground events are currently DISABLED for your character."); else handler->SendSysMessage("Battleground events are currently ENABLED for your character."); diff --git a/src/mod_bg_auto_queue_loader.cpp b/src/mod_bg_auto_queue_loader.cpp index 313a82f..3736c8e 100644 --- a/src/mod_bg_auto_queue_loader.cpp +++ b/src/mod_bg_auto_queue_loader.cpp @@ -4,11 +4,9 @@ void AddSC_mod_bg_auto_queue(); void AddSC_bg_auto_queue_commandscript(); -void AddSC_bg_auto_queue_playerscript(); void Addmod_bg_auto_queueScripts() { AddSC_mod_bg_auto_queue(); AddSC_bg_auto_queue_commandscript(); - AddSC_bg_auto_queue_playerscript(); } diff --git a/src/mod_bg_auto_queue_scripts.cpp b/src/mod_bg_auto_queue_scripts.cpp index 68271bb..5e4b44f 100644 --- a/src/mod_bg_auto_queue_scripts.cpp +++ b/src/mod_bg_auto_queue_scripts.cpp @@ -11,7 +11,6 @@ class mod_bg_auto_queue_world : public WorldScript public: mod_bg_auto_queue_world() : WorldScript("mod_bg_auto_queue_world", { WORLDHOOK_ON_AFTER_CONFIG_LOAD, - WORLDHOOK_ON_STARTUP, WORLDHOOK_ON_UPDATE }) { } @@ -20,11 +19,6 @@ class mod_bg_auto_queue_world : public WorldScript sBgAutoQueue->LoadConfig(); } - void OnStartup() override - { - sBgAutoQueue->LoadOptOutData(); - } - void OnUpdate(uint32 diff) override { sBgAutoQueue->Update(diff);