Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,20 +69,23 @@ 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

1. Clone this folder into `modules/mod-bg-auto-queue/` of your AzerothCore source.
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

Expand All @@ -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.
6 changes: 6 additions & 0 deletions conf/mod-bg-auto-queue.conf.dist
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 0 additions & 7 deletions data/sql/db-characters/base/mod_bg_auto_queue.sql

This file was deleted.

53 changes: 14 additions & 39 deletions src/BgAutoQueue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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<uint32>());
} 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
Expand All @@ -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;
Expand Down
20 changes: 10 additions & 10 deletions src/BgAutoQueue.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,34 @@
#define _MOD_BG_AUTO_QUEUE_H_

#include "DBCEnums.h"
#include "DatabaseEnvFwd.h"
#include "ObjectGuid.h"
#include "SharedDefines.h"

#include <string>
#include <unordered_set>
#include <vector>

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;

Expand Down Expand Up @@ -99,8 +101,6 @@ class BgAutoQueue
uint32 _elapsedMs = 0;
bool _warningSent = false;
bool _firstPass = true;

std::unordered_set<uint32> _optedOut; // characters guid::low values
};

#define sBgAutoQueue BgAutoQueue::instance()
Expand Down
28 changes: 0 additions & 28 deletions src/PlayerScript_bg_auto_queue.cpp

This file was deleted.

43 changes: 14 additions & 29 deletions src/cs_bg_auto_queue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand All @@ -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<bool> enable)
{
Player* player = handler->GetPlayer();
if (!player)
Expand All @@ -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.");
Expand Down
2 changes: 0 additions & 2 deletions src/mod_bg_auto_queue_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
6 changes: 0 additions & 6 deletions src/mod_bg_auto_queue_scripts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
}) { }

Expand All @@ -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);
Expand Down
Loading