Commit Graph
36 Commits
Author SHA1 Message Date
devbox 75c0cc46a6 Playerbot: hearthstone party port + priest keeps healing spec at L10
- Hearthstone/return-to-inn sync: module teleports every owned bot to its
  (owner-synced) homebind when the owner spell-ports to their own homebind.
- Leveling spec for Priest now Holy (257) instead of Shadow (258): the L10
  real-spec promotion was forcing Shadow, flipping her role to Dps and
  stopping her healing.
- Add the TeleportTo hearthstone hunk to the core-hooks patch.
2026-08-22 21:19:28 +10:00
devbox 1867d77c70 Playerbot: single quest-item propagation path + bot spec control
- OnLootUnit's corpse-open quest-item scan double-granted every creature
  quest item (owner opens corpse -> +1, owner takes item -> +1 via
  OnLootItem). Remove the redundant scan; OnLootItem is now the single
  propagation path (covers creature AND GO loot). Fixes double loot.
- BotGear: add specialization control. New GEAR_SPECS_REQ lists the bot's
  specs; GEAR_SET_SPEC switches via Player::ActivateTalentGroup. Addon
  renders a spec button row on the panel; active spec is highlighted.
2026-08-22 20:55:09 +10:00
devbox 2e2913ca78 Playerbot: never down-level bots below their natural level
The alt/companion finalize paths used 'bot->GetLevel() != targetLevel' and
called GiveLevel(owner level) — a bot that naturally out-leveled the owner
(e.g. hit 10 while owner was 9) got reset back DOWN to the owner's level,
wiping XP and breaking progression, and jumbling the bot's stats (the
recurring 'bots show the player's 1110/1000 stats' bug). Only level UP:
change the guards to '<' so bots are never reset below where they already
are.
2026-08-22 19:35:55 +10:00
devbox 196880c593 Playerbot: skip grouped bots for ALL kill/NPC-click credit (fix double count)
The core's party-share credits every grouped bot for BOTH combat kills AND
NPC-click objectives (Fear No Evil click fires OnKillCredit for each grouped
bot once, guid empty or not). The empty-guid special case pushed to all bots
and double-counted. Simplify: skip grouped bots unconditionally (the core
handles them); only ungrouped owned bots need the module push.
2026-08-21 21:45:14 +10:00
devbox bf9392dea2 Playerbot: distinguish combat kills vs NPC-click credit in OnKillCredit
Combat kills carry a creature guid and are ALREADY shared to grouped bots by
the core — pushing again double-counts, so skip grouped bots for those (only
ungrouped bots get the push). NPC-click credits (Fear No Evil etc.) pass guid
EMPTY and are single-caster/not reliably shared, so push to ALL owned bots for
those. Distinguishes on guid.IsEmpty(): combat kill (non-empty) -> skip
grouped; click (empty) -> push all.
2026-08-20 18:38:01 +10:00
devbox 9ab5265e0c Playerbot: REVERT save-bots-on-logout — it corrupts player data
LogoutBot's LogoutPlayer(true) ran the FULL account-scoped SaveToDB on a
headless bot sharing the owner's account, corrupting player/character data on
logout and server-reset (confirmed: corruption started exactly with this
change; fresh characters then crash the client at world-enter with
CombatLogEntry empty-guid-type). Revert to LogoutPlayer(false) (the safe,
long-standing behaviour).
2026-08-20 18:22:17 +10:00
devbox 802acdfc3a Playerbot: push kill/click credit to ALL owned bots (fix missed clicks)
NPC-click objectives (quest 63447 'Fear No Evil') are single-caster spell-script
credits the core does not reliably share to party members — when the owner
rushed the clicks, an out-of-range/sync bot (Lica) missed a click. Pushing
KilledMonsterCredit to every owned in-world bot regardless of group makes it
robust; it is idempotent (core ignores already-complete objectives) and the
per-bot OnKillCredit re-entry is filtered by IsBot(), so no double count.
2026-08-20 18:01:26 +10:00
devbox 80667a6bf7 Playerbot: stop double-crediting grouped bots on kill/NPC-click credit
The core's party-shared credit fires OnKillCredit for every grouped bot on the
quest for both combat kills and non-combat NPC-click objectives. The module
only skipped grouped bots IN combat, so non-combat credits (quest 63447 'Fear
No Evil' clicking Injured Stormwind Infantry) were pushed again ->
KilledMonsterCredit -> double count. Skip the push for any grouped bot; only
ungrouped bots need the module's credit.
2026-08-18 18:39:37 +10:00
devbox 877866f122 Playerbot: honour blacklisted turn-ins when the bot is already at the ender
The wedge-remediation blacklists a turn-in the bot can't path to, and the
picker then skips it — but that also strands a bot that HAS reached the NPC:
it stands next to the quest giver with a complete quest, current_quest_id=0
([picker_none]), and never turns in (so the chain stalls). If the bot is
within ~40y of the resolved ender, the turn-in is trivially reachable — let
the picker select it despite the blacklist.
2026-08-18 18:32:51 +10:00
devbox c2a1632d6c Playerbot: save bots on logout so quests/progress persist
LogoutBot called LogoutPlayer(false), which skips SaveToDB — a quest pushed
and progressed this session was lost on logout unless a 15-min autosave
happened to fire first. Bots then couldn't complete the quest the player
finished, breaking the chain (follow-up quest un-pushable). Use
LogoutPlayer(true), matching the BotSession idle-timeout path.
2026-08-18 14:51:50 +10:00
devbox 0e96c7798e Playerbot: only assist targets the owner is actually fighting
ResolveOwnerAssistTarget preferred GetSelectedUnit() over the victim, so
merely targeting a neutral/yellow mob made every bot attack it. Now the
victim (real combat target) is preferred, and the selected-unit fallback
only counts when the owner is IN combat and targeting that unit (a cast
in flight) — a selected-but-unattacked mob never pulls the squad.
2026-08-18 11:11:46 +10:00
devbox 00f65c7b89 Playerbot: sell_trash — drop the 4y vendor proximity gate + result log
Bots follow the owner at formation distance (2.5-8y), so when the owner uses
sell-all-junk the bot is usually beyond GetNPCIfCanInteractWith's ~4y range and
sell_trash bailed with InvalidTarget — nothing was ever sold. Bots are
headless, so look the vendor up directly (flag-checked) without the proximity
requirement, and log the sold-item count.
2026-08-17 20:10:11 +10:00
devbox 4e0240603b Playerbot: log the real reason a quest-source item grant is rejected
'bag full' was misleading — with free slots AddItem can still return false
via CanStoreNewItem/StoreNewItem rejection (bound-item guard etc). Include the
CanStoreNewItem result (ir), noSpace, actual free backpack slots, and current
item count in the failure log so the rejection reason is visible.
2026-08-17 19:53:51 +10:00
devbox ba096ba8d3 Playerbot: grant quest-source items so item-started quests push to bots
Item-started quests (e.g. item 1307 'Gold Pickup Schedule' -> quest 123 'The
Collector') require the source item in the bag for CanAddQuest to pass, but
the module only copied quest-OBJECTIVE items — so the push was skipped with
'(CanAddQuest)' and the bots never got the quest.

- GiveQuestItem (loot path): when the owner loots an item whose template
  starts a quest (GetStartQuest()>0), grant one to each bot.
- TryPushQuestToBot (accept path): backstop — grant the quest's SrcItemId
  if the bot lacks it before the CanAddQuest check.
2026-08-17 19:39:13 +10:00
devbox 4fa66b3ac3 Playerbot: BotGear addon — register the PBC addon-message prefix
The client only fires CHAT_MSG_ADDON events for prefixes registered via
RegisterAddonMessagePrefix. BotGear never registered 'PBC' (PlayerbotControl
does), so the server's GEAR_BAGS_RESP / GEAR_EQUIP_RESP replies were dropped
client-side and the panel stayed blank even though the round-trip reached the
server. Register the prefix on PLAYER_LOGIN.
2026-08-17 19:20:40 +10:00
devbox 9a0a32f42d Playerbot: BotGear addon — self-whisper to the owner (the only working target)
The server's addon OnChat hook only fires inside Player::WhisperAddon, which
requires the whisper target to resolve to a real connected player. The fake
'PBCFLEET' name is dropped before the hook, so BotGear requests never reached
the server. Whisper the OWNER's own name instead (self-whisper) — the exact
path PlayerbotControl uses (it re-points its fleet target at UnitName('player')
on PLAYER_LOGIN). The bot identity rides in the payload.
2026-08-17 19:05:23 +10:00
devbox 1f25f119ec Playerbot: BotGear uses bot name end-to-end + retry first-open resolution
The client's UnitGUID format is unreliable across builds (the parser kept
extracting the realm/sub field), so the request resolved the wrong player and
no GEAR response was ever returned. The bot's NAME is stable, so:
- Server: GEAR_* handlers resolve fields[0] as a name OR numeric guid-low via
  ResolveGearBot(), and authorize via the resolved bot's guid.
- Addon: ResolveTarget returns UnitName('target'); all requests send the name;
  responses are matched by name; slash handler retries RefreshTarget after
  0.25s so the first open still populates when the unit is transiently
  unavailable right after targeting.
2026-08-17 18:42:08 +10:00
devbox d137727d3c Playerbot: BotGear addon — fix target guid extraction
The UnitGUID parser grabbed the realm/sub field (-(%d+)-%x+$) instead of the
low counter, so the request carried the owner's guid (1) and the server
resolved the owner, not the bot — FindConnectedPlayer + IsOwner both failed
and no GEAR response was ever sent. Parse the LAST '-' group as hex (the
character counter), and reset the title hint when no target resolves.
2026-08-17 18:25:29 +10:00
devbox deef9544bf Playerbot: BotGear addon — send via PBCFLEET target, not the bot's name
Whispering the bot's character name routes the server's OnChat hook to the
headless bot's session (pool account), so GEAR responses were never sent to
the owner. Match PlayerbotControl: whisper the magic 'PBCFLEET' target; the
bot guid is carried in the payload and the handlers authorize via Owners().
2026-08-17 18:20:11 +10:00
devbox 41ebd14db9 Playerbot: BotGear addon — use a non-zero sequence number
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.
2026-08-17 18:15:46 +10:00
devbox 8b3c826c16 Playerbot: fix role verb alias + BotGear addon frame build
- 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.
2026-08-17 08:04:35 +10:00
devbox ef35de35e5 Playerbot: wire AddonControl::OnSessionLogout on owner logout (fixes .so load)
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.
2026-08-17 07:48:33 +10:00
devbox 07d2a49395 Playerbot: bot character & inventory controller (gear, bags, destroy, move)
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.
2026-08-16 22:11:06 +10:00
devbox 2638d9ac61 Playerbot: abandon the bot's class-equivalent quest when owner abandons
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.
2026-08-16 21:44:29 +10:00
devbox dd8c93bbdf Playerbot: defer quest push for not-in-world bots; tighten follow formation; grant bound quest items
- 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.
2026-08-16 21:39:14 +10:00
devbox bfb544fcd7 Regenerate thordekk core-hooks patch against thordekk/main b8a06fe8ba 2026-08-15 10:08:03 +10:00
devbox ef95f084d4 Fix core-hooks patches: correct cs_playerbot_v2.cpp hunk count/hash 2026-08-14 15:21:07 +10:00
devbox 8bedbc1311 Define TRINITY_PLAYERBOT_V2 for the scripts command target
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.
2026-08-14 13:01:08 +10:00
devbox e565bd9734 Register connected altbots missing intents in the follow loop
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.
2026-08-14 12:22:23 +10:00
devbox 20f590ccb1 Add [AltFollow] diagnostics to the companion follow loop
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.
2026-08-13 21:53:51 +10:00
devbox fb0723b653 Fix alt-create zombie login (never 'login already in flight' again)
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.
2026-08-12 17:02:36 +10:00
devbox 2e9c165e97 Seed name pool into the SHARED playerbot schema (fixes generated bot names)
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;
2026-08-12 16:35:01 +10:00
devbox bbe7c54e3c Fix pool-account starvation on fresh/renamed characters DBs
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).
2026-08-12 15:16:54 +10:00
devbox b14ebad3fb Use utf8mb4_general_ci for shared playerbot schema
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.
2026-08-12 14:29:00 +10:00
devbox 75090e50b4 Source characters DB name from server config in BotNamePool orphan sweep
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'.
2026-08-12 13:15:36 +10:00
devbox 9ed80ca65a Gate ambient fleet behind PlayerbotsV2.FleetBots (default off: alt-bot-only mode)
- 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
2026-08-12 11:17:54 +10:00