The server rejects any PBC frame with seq == 0 (AddonControl envelope
check), so GEAR_BAGS_REQ/GEAR_EQUIP_REQ were silently dropped and the panel
rendered with no data. Send uses an incrementing seq like PlayerbotControl.
- BotCommandParser: accept 'role' (addon verb) and 'role_all'/'roleall' as
aliases for 'setrole'/'setrole_all' so the PlayerbotControl roster role menu
works (was refused as unknown verb).
- BotGear.lua: create frames/buttons with 'BackdropTemplate' so SetBackdrop
doesn't throw (retail 11.x+ requirement) — /botgear did nothing because the
frame build errored out. Also fix the goldText/bagScroll/bagContent locals
being declared after first use.
AddonControl.o was never pulled into the worldserver binary: nothing in the
worldserver link referenced its symbols (OnAddonWhisper is only called from the
scripts module, OnSessionLogout was declared but never called), so -rdynamic
could not export OnAddonWhisper and libscripts_commands.so failed to load with
'undefined symbol'. OnPlayerLogout now calls AddonControl::OnSessionLogout for
real players (its documented purpose), anchoring AddonControl.o into the
worldserver link so both symbols are exported.
Server (AddonControl.cpp):
- GEAR_BAGS_REQ now returns gold, the four equipped bag containers (entry+size),
and items from the backpack AND all bags (bagNum 0..4).
- GEAR_EQUIP_ITEM accepts items from any bag slot (not just the backpack).
- New GEAR_DESTROY_ITEM <guid> <bag> <slot> — permanent item destruction.
- New GEAR_MOVE_ITEM <guid> <srcBag> <srcSlot> <dstBag> <dstSlot> — rearrange
items between bag slots (empty destination only).
Addon (BotGear.lua):
- Full 3D character preview (ModelScene) of the targeted bot, live-updating.
- Renders backpack + real bag containers with gold display.
- Left-click pick up / left-click place to move items between slots.
- Right-click bag item to equip; shift+right-click to destroy; right-click
equipped item to unequip.
OnAbandonQuest was checking/removing the owner's raw quest_id on the bots, but
bots hold the class/race VARIANT (ResolveBotQuestId, same as OnAcceptQuest). For
variants like 28767 -> 28763 the status check hit NONE and the bot kept the
quest. Resolve the bot's equivalent before taking source items / removing the
active quest, and use the variant's template for timed/PvP cleanup.
- OnAcceptQuest parks class-equivalent quests for companions still mid-login
(connected but not in-world); OnPlayerLogin drains them once the bot lands.
- Tighten AltFollow to match mod-playerbots (formation slots 1.5y, slot
tolerance 2y, min recall radius 2y); default formation Spread (ring 2.5y).
- Fix O(n²) formation-slot reassignment in the companion tick (was re-iterating
every alt for every alt every 250ms).
- QUEST_OBJECTIVE_FLAG_2_QUEST_BOUND_ITEM objectives are never stored in
inventory and the core rejects AddItem for them ('inventory full or
unplaceable' despite free space). Grant by ticking the objective counter via
SetQuestObjectiveData instead, unblocking chains like Westfall 112 -> 114.
cs_playerbot_v2.cpp is compiled into the scripts_commands shared lib,
whose body is gated on #if TRINITY_PLAYERBOT_V2. That macro only ever
reached the module sub-libs linked into worldserver, so the command
script compiled to an empty stub and .playerbot was never registered.
Propagate the define to every SCRIPT_MODULE target when
BUILD_PLAYERBOT_V2 is on so GM commands/live PBC listener register.
Connected altbots whose AI was never attached by OnPlayerLogin (stale
core hook or is_bot false at login time) never got has_intents, so the
companion loop skipped them forever. Late-register them idempotently on
the next companion tick so they can follow without a relog.
Throttled (5s) log lines give the exact gate when a spawned altbot does
not follow: different_map / no_intents skip, combat skip, and the
formation decision (formed slot_dist vs owner_dist vs rad) that decides
move_to_slot vs follow_intent vs hold-in-place.
HandleAltCreate submitted the login via SessionMgr().LoginBot immediately
after BotCharacterFactory::Create. SaveToDB is async, so the character
row is not committed yet: BeginLogin's holder loads nothing, the BotSession
never completes and never leaves sessions_ — the bot appears 'stuck in
login' and every later .playerbot login fails with 'login already in
flight'. The .playerbot squad path already avoided this; alt create now
matches it by deferring to DrainAltFinalizes, which submits the login on
the next world tick against the committed row + CharacterCache entry.
Also hardened DrainAltFinalizes: an in-flight session older than 25s is a
wedged zombie — reap it (LogoutBot) and resubmit once so a leftover zombie
from a pre-fix build (or any future race) self-heals instead of wedging
that bot forever.
BotNamePool reads {Playerbot.SharedDatabase}.playerbots_names (default
'playerbot'), but migration 0015 created+seeded an unqualified
playerbots_names which the PlayerbotMigrationMgr executes against the
CHARACTERS DB. On a fresh install (or any server where the shared
playerbot schema was not hand-imported) the shared table stays empty,
so every bot name came from the syllable-generator fallback instead of
the curated pool ('Serpil', 'Ghielstan', ...).
0015 now targets playerbot.playerbots_names like migration 0000 does.
Existing installs must backfill once:
INSERT IGNORE INTO playerbot.playerbots_names (name,gender,race_mask)
SELECT name,gender,race_mask FROM characters.playerbots_names;
Start the next PBV2_NNNN pool index past BOTH the realm-local counter and
any PBV2_* bnet account already present in the shared auth DB, so a fresh
or renamed characters DB no longer restarts numbering at 1 and collides
with the existing fleet (AOR_NAME_ALREADY_EXIST x8 -> pool starvation).
utf8mb4_uca1400_ai_ci (MariaDB-only) breaks bootstrap on MySQL, where
CREATE DATABASE/CREATE TABLE fails outright. Switch the shared playerbot
schema and bootstrapped tables to utf8mb4_general_ci, matching the rest
of the playerbot_v2 migrations.
The LEFT JOIN characters.characters cross-DB qualifier hardcoded the
characters schema name, breaking installs with a renamed characters
database. Read it from CharacterDatabase.GetConnectionInfo() (worldserver.conf
CharacterDatabaseInfo) instead, falling back to 'characters'.
- ConfigReader: add PlayerbotsV2.FleetBots switch (default 0) + fleet_bots() accessor
- Module::Init/OnWorldUpdate: skip population shaper, bot guilds, craft-order
board, BG/LFG queue auto-fill, and AutoResume/AutoSpawn when fleet disabled
- Services: FleetThread is not started in alt-bot-only mode
- conf/playerbot.conf.dist + README document the new key