Merge pull request #32 from zeb139/add-chat-commands

Added chat commands for GMs
This commit is contained in:
Nathan Handley
2025-10-05 15:38:45 -05:00
committed by GitHub
5 changed files with 147 additions and 1 deletions

View File

@@ -27,7 +27,18 @@ Notes:
- Important! By default, most player crafted items (except glyphs, bolts, maybe a few other things) are disabled from showing up in the auction house in order to encourage player crafting on lower pop servers. If you want different behavior, alter the config variable "AuctionHouseBot.DisabledCraftedItemIDs" by deleting IDs you wish to show up. Note that fish are also disabled to encourage fishing, and that's also managed by disabled lists.
- It takes a few hours for the auction house to fully populate, as only 75 items gets added by default every 'tick'. You can change this in the config with the AuctionHouseBot.ItemsPerCycle variable.
- All price multpliers (along with the advanced pricing, see config) are applied multiplicative. Example: A Category of 1.5x, Quality of 2x, and CategoryQuality of 1.4x would make the multiplier 4.2 (1.5 x 2 x 1.4). The advanced pricing would then multiply that value further. Using item level price multpliers, which create a multiplier of itemlevel x value, is also multiplicitive along with the others. You cannot use item level price multipliers and advanced pricing, as advanced pricing will take priority between the two.
- Bot-listed prices will not exceed 100k gold buyout
- Bot-listed prices will not exceed 100k gold buyout
### In-Game Commands
The AuctionHouseBot module adds the following in-game commands (for GMs only):
| Command | Description |
|----------|--------------|
| `.ahbot reload` | Reloads the AuctionHouseBot configuration file and updates settings. |
| `.ahbot empty` | Removes all AuctionHouseBot auctions from all auction houses.<br>Player auctions are unaffected. Bids on affected items are returned to players.<br>Use with caution! |
| `.ahbot update` | Forces the bot to refresh or repopulate auction listings immediately.<br>Note: If you have multiple minutes configured between Buy/Sell cycles, you may have to run this additional times before you see results. |
## Buying Bot Behavior

View File

@@ -1,5 +1,14 @@
[worldserver]
###################################################################################################
# AUCTION HOUSE BOT IN-GAME COMMANDS
#
# Available GM commands:
# .ahbot reload - Reloads AuctionHouseBot configuration
# .ahbot empty - Clears all AuctionHouseBot auctions from all auction houses
# .ahbot update - Forces an immediate update cycle
###################################################################################################
###############################################################################
# AUCTION HOUSE BOT SETTINGS
# AuctionHouseBot.DEBUG

View File

@@ -1584,6 +1584,70 @@ void AuctionHouseBot::InitializeConfiguration()
NeutralConfig.SetMaxItems(sConfigMgr->GetOption<uint32>("AuctionHouseBot.Neutral.MaxItems", 15000));
}
void AuctionHouseBot::EmptyAuctionHouses()
{
struct AuctionInfo {
uint32 itemID {0};
uint32 characterGUID {0};
uint32 houseID {0};
};
vector<AuctionInfo> ahBotActiveAuctions;
auto trans = CharacterDatabase.BeginTransaction();
// Get all auctions owned by AHBots
std::string queryString = "SELECT id, buyguid, houseid FROM auctionhouse WHERE itemowner IN ({})";
QueryResult result = CharacterDatabase.Query(queryString, AHCharactersGUIDsForQuery);
if (!result)
return;
if (result->GetRowCount() > 0)
{
// Load results into vector<AuctionInfo> for lookups later
do
{
Field* fields = result->Fetch();
AuctionInfo ai = {
fields[0].Get<uint32>(),
fields[1].Get<uint32>(),
fields[2].Get<uint32>()
};
ahBotActiveAuctions.push_back(ai);
} while (result->NextRow());
// For each auction, refund bidder where possible, delete entry from AH
AuctionHouseObject* auctionHouse;
for (auto iter = ahBotActiveAuctions.begin(); iter != ahBotActiveAuctions.end(); ++iter)
{
AuctionInfo& ai = *iter;
// Get Auction House and Auction references
auctionHouse = nullptr;
switch (ai.houseID) {
case 2: auctionHouse = sAuctionMgr->GetAuctionsMap(AllianceConfig.GetAHFID()); break;
case 6: auctionHouse = sAuctionMgr->GetAuctionsMap(HordeConfig.GetAHFID()); break;
case 7: auctionHouse = sAuctionMgr->GetAuctionsMap(NeutralConfig.GetAHFID()); break;
}
if (auctionHouse == nullptr)
continue;
AuctionEntry* auction = auctionHouse->GetAuction(ai.itemID);
if (!auction)
continue;
// If auction has a bidder, refund that character
if (ai.characterGUID != 0)
sAuctionMgr->SendAuctionCancelledToBidderMail(auction, trans);
// Remove item from AH
auction->DeleteFromDB(trans);
sAuctionMgr->RemoveAItem(auction->item_guid);
auctionHouse->RemoveAuction(auction);
}
}
CharacterDatabase.CommitTransaction(trans);
}
uint32 AuctionHouseBot::GetRandomStackValue(std::string configKeyString, uint32 defaultValue)
{
uint32 stackValue = sConfigMgr->GetOption<uint32>(configKeyString, defaultValue);

View File

@@ -298,6 +298,7 @@ public:
void Update();
void InitializeConfiguration();
void EmptyAuctionHouses();
uint32 GetRandomStackValue(std::string configKeyString, uint32 defaultValue);
uint32 GetRandomStackIncrementValue(std::string configKeyString, uint32 defaultValue);
void SetCyclesBetweenBuyOrSell();

View File

@@ -2,6 +2,7 @@
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
*/
#include "Chat.h"
#include "ScriptMgr.h"
#include "AuctionHouseBot.h"
#include "Log.h"
@@ -118,9 +119,69 @@ public:
}
};
class AHBot_CommandScript : public CommandScript
{
public:
AHBot_CommandScript() : CommandScript("AHBot_CommandScript") { }
Acore::ChatCommands::ChatCommandTable GetCommands() const override
{
static Acore::ChatCommands::ChatCommandTable AHBotCommandTable = {
{"update", HandleAHBotUpdateCommand, SEC_GAMEMASTER, Acore::ChatCommands::Console::Yes},
{"reload", HandleAHBotReloadCommand, SEC_GAMEMASTER, Acore::ChatCommands::Console::Yes},
{"empty", HandleAHBotEmptyCommand, SEC_GAMEMASTER, Acore::ChatCommands::Console::Yes},
{"help", HandleAHBotHelpCommand, SEC_GAMEMASTER, Acore::ChatCommands::Console::Yes}
};
static Acore::ChatCommands::ChatCommandTable commandTable = {
{"ahbot", AHBotCommandTable},
};
return commandTable;
}
static bool HandleAHBotUpdateCommand(ChatHandler* handler, const char* /*args*/)
{
LOG_INFO("module", "AuctionHouseBot: Updating Auction House...");
handler->PSendSysMessage("AuctionHouseBot: Updating Auction House...");
AuctionHouseBot::instance()->Update();
return true;
}
static bool HandleAHBotReloadCommand(ChatHandler* handler, char const* /*args*/)
{
LOG_INFO("module", "AuctionHouseBot: Reloading Config...");
handler->PSendSysMessage("AuctionHouseBot: Reloading Config...");
// Reload config file with isReload = true
sConfigMgr->LoadModulesConfigs(true, false);
AuctionHouseBot::instance()->InitializeConfiguration();
AuctionHouseBot::instance()->PopulateItemCandidatesAndProportions();
return true;
}
static bool HandleAHBotEmptyCommand(ChatHandler* handler, char const* /*args*/)
{
LOG_INFO("module", "AuctionHouseBot: Emptying Auction House...");
handler->PSendSysMessage("AuctionHouseBot: Emptying Auction House...");
AuctionHouseBot::instance()->EmptyAuctionHouses();
return true;
}
static bool HandleAHBotHelpCommand(ChatHandler* handler, char const* /*args*/)
{
handler->PSendSysMessage("AuctionHouseBot commands:");
handler->PSendSysMessage(" .ahbot reload - Reloads configuration");
handler->PSendSysMessage(" .ahbot empty - Removes all AuctionHouseBot auctions");
handler->PSendSysMessage(" .ahbot update - Runs an update cycle");
return true;
}
};
void AddAHBotScripts()
{
new AHBot_WorldScript();
new AHBot_AuctionHouseScript();
new AHBot_MailScript();
new AHBot_CommandScript();
}