Commit Graph
100 Commits
Author SHA1 Message Date
agathoandClaude Opus 4.8 bd51ef8c07 feat(crafting-orders): P4 send the create/claim/cancel/release/reject results
Closes the client round-trip for the order actions built in P2/P3. The
response SMSGs were previously assumed reflection-walled; reading the
client's real deserializers (sub_7FF7290B92D0 / _9640 / _9A90 / _96E0 /
_9B90, reached from the 0x42-family opcode dispatch) shows they are
hand-written and share one byte-aligned layout:

    uint8  Result            // ClientCrafting::CraftingOrderResult
    uint64 CraftingOrderID

The full 49-value CraftingOrderResult enum was extracted from the client
enum registrar and is now declared so the server can report accurate
outcomes (Ok on success; CannotCreate/CannotClaim/CannotCancel/
CannotRelease/CannotReject when the manager rejects the action).

Adds CraftingOrderActionResult (+ the five opcode-specific subclasses)
and sends the matching result from each handler, so the client's order
UI now confirms and updates instead of silently guessing. FULFILL_RESULT
(which additionally carries a second id, a byte, a PackedGUID and three
uint32s) and CRAFT_RESULT (a nested block) are larger and follow with
the crafting/escrow phase; their layouts are recovered and recorded.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-07-06 23:33:24 -03:00
agathoandClaude Opus 4.7 12baf9d120 Housing: retire 7 paired TC-CUSTOM CMSGs + handlers (Lua-API verified dead)
Companion cleanup to commit 6e7b84dbc1. With yesterday's speculative
SMSG response classes gone, the 7 paired CMSGs whose handlers no-oped
are pure dead code — never invoked because the CMSG opcodes are
TC-CUSTOM placeholders that retail never sends.

Cross-checked each against the auto-generated Lua API docs in
wow-ui-source-12.0.5/Blizzard_APIDocumentationGenerated:

  CMSG_HOUSING_DECOR_BATCH_OPERATION         no C_HousingDecor.BatchOperation
  CMSG_HOUSING_DECOR_CATALOG_CREATE_SEARCHER HousingCatalogSearcherAPI is
                                             entirely client-side (filter/
                                             sort/search local catalog data)
  CMSG_HOUSING_DECOR_PLACEMENT_PREVIEW       no PlacementPreview API anywhere
  CMSG_HOUSING_DECOR_START_PLACING_NEW_DECOR C_HousingBasicMode.StartPlacing-
                                             NewDecor is fire-and-forget;
                                             no Returns, no response event
  CMSG_HOUSING_DECOR_START_PLACING_FROM_SRC  same — no API counterpart
  CMSG_HOUSING_REQUEST_EDITOR_AVAILABILITY   C_HouseEditor.GetHouseEditor-
                                             Availability returns synchron-
                                             ously — no server roundtrip
  CMSG_HOUSING_SYSTEM_HOUSE_SNAPSHOT         no C_HouseSnapshot namespace
                                             exists in retail 12.0.5

Removed per CMSG:
  - ClientPacket class declaration (HousingPackets.h)
  - Read() body (HousingPackets.cpp)
  - Handler function (HousingHandler.cpp)
  - Handler declaration (WorldSession.h)
  - Handler registration (Opcodes.cpp)
  - Opcode enum entry (Opcodes.h)

Retirement-marker comments left in each location pointing at the
Lua-API rationale for future readers.

Diff:
  6 files changed
  +43 / -250 = 207-line net deletion

Build-verified clean against the 12.0.5 source tree with VS17 2022
RelWithDebInfo (-j 1 to bypass MSVC PCH virtual-memory exhaustion).
No real code errors.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Signed-off-by: luis <[email protected]>
2026-05-12 08:31:37 -03:00
agathoandClaude Opus 4.7 c6a0fc5af5 Housing: retire 22 speculative SMSGs + fix wire bugs + remap 2 opcodes
Sniff verification across 207k retail packets (11 sessions, builds
65940-67186) confirmed all 22 SMSG opcodes in our internal 0xF1000xxx
placeholder range never appear in retail. Cross-checked against the
auto-generated Lua API docs in wow-ui-source-12.0.5 — none have a
corresponding C_Housing*/C_HouseEditor/C_NeighborhoodInitiative Lua
function or event. Either the feature uses entity-fragment updates
(like the *Added family), uses an existing real opcode that already
covers the same state, or doesn't exist in retail at all.

Two of the 22 had real opcodes hidden in IDA/comment metadata:
  HousingUpdateHouseInfo            remapped 0xF1000012 -> 0x550004
  HousingCatalogStateSync           remapped 0xF1000002 -> 0x56000E
                                    (also reclaims 0x56000E from a
                                    misnamed SMSG_LFG_LIST_UPDATE_BLACKLIST
                                    placeholder with 0 emit-sites; wire
                                    decoded as 4+N*8 catalog entries
                                    matching the documented PackedState
                                    bit layout)

The other 20 retired classes + their emit sites are removed entirely
(retirement-marker comments preserve any IDA-derived opcode hints +
wire shapes for future restoration if real opcodes get discovered):

  4 *Added family (Room/Fixture/Theme/RoomComponentTexture)
  10 Group A zero-emit-site classes in 0xF1000008..0xF1000010
     (HousingSetHouseNameResponse, HousingSvcs{Create,GetDetails,
     GetHouses,HouseExpiration,Move,Search,SetSettings,Swap}*,
     InitiativeTrackedUpdated)
  4 SMSG_INITIATIVE_* (UpdateStatus, PointsUpdate, MilestoneUpdate,
     ChestResult) + their 8 InitiativeManager emit sites — real
     opcodes 0x420364/65/66/68/69/6A/6B already cover every state
     transition
  4 Decor* speculative responses (BatchOperation, CatalogCreateSearcher,
     PlacementPreview, StartPlacingNewDecor) — Lua-API-verified to have
     no retail counterpart (HousingCatalogSearcherAPI is purely
     client-side; StartPlacingNewDecor is fire-and-forget)
  HousingEditorAvailabilityResponse — C_HouseEditor.GetHouseEditorAvailability
     returns synchronously, no server roundtrip
  HousingSystemHouseSnapshotResponse — no C_HouseSnapshot Lua namespace
     exists in retail 12.0.5

Additional behavioral fixes layered in along the way:

  - InitiativeManager: wire decor + quest rewards on milestone claim
    (was TODO no-op; Housing::AddToCatalog + Player::RewardQuest)
  - Post-tutorial auras gated on quest 94455 completion in both
    HousingMap and HouseInteriorMap (was unconditional, applied to
    pre-tutorial players)
  - BuyHouse starter favor (910) now persists server-side via
    Housing::AddFavor with new emitUpdate=false param to suppress
    AddFavor's own packet; the existing sniff-shaped 2-packet
    HousingSvcsUpdateHousesLevelFavor sequence then reads h->GetFavor()
  - Duplicate CMSG_HOUSING_SVCS_RELINQUISH_HOUSE registration deleted

Diff:
  13 files changed
  +204 / -810 = 606-line net deletion

Build-verified clean against the 12.0.5 source tree with VS17 2022
RelWithDebInfo (-j 2 to avoid MSVC PCH virtual-memory exhaustion at
higher parallelism). No real code errors.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Signed-off-by: luis <[email protected]>
2026-05-11 19:43:15 -03:00
agatho ea1391c385 Housing: extend Group A mirrors from 1 per plot to 4 per fixture piece
Audit 2026-04-21 (FINDINGS.md sec 1.1) measured 4 Group A Entity mirrors
per plot at retail idx 9984; we were spawning one. The previous fix
covered only the Type-9 (Base) root, leaving the Roof/Door/Window
companions on retail uncreated.

_houseMirrorEntities is now a vector<unique_ptr<HousingMirrorEntity>>
per plot. SpawnHouseForPlot iterates the same fixture-tier MeshObjects
the Group B pass walks (ExteriorComponent Type 9/10/11/12) and pairs a
Group A mirror with each. All four share AttachParent = Housing/2 room
identity (sniff-decoded "01 c1 XX 12 40 dc" - subType=2, arg2=18) and
local pos (0,0,0) - the room is positioned at the plot centre, so the
chain resolves there for every piece.

Tagging is now an enum (None / Piece / PieceAndRoot) on HousingMirror
Entity::InitPositionData. The Type-9 root (pieceIndex 0) keeps both
Tag_HouseExteriorPiece and Tag_HouseExteriorRoot - this is the canonical
GUID referenced by FHousingPlayerHouse_C.EntityGUID and the world-map
icon picker. The other three (Roof/Door/Window) carry only
Tag_HouseExteriorPiece. Group B per-mesh mirrors switch to Tagging::None
which is identical behaviour to the prior isExteriorRoot=false path.

MakeHouseMirrorGuid gains a pieceIndex parameter (default 0) and packs
(bnetId<<16)|(plot<<8)|piece so each per-piece GUID is unique while the
default-arg call site that proxy emission uses still resolves to the
root mirror's GUID.

Player::BuildCreateUpdateBlockForPlayer iterates the new
GetHouseMirrors() list so all four Group A mirrors land in the initial
UPDATE_OBJECT bundle alongside the four Group B ones (8 mirrors per
plot total, matching retail idx 9984).
2026-04-27 23:49:35 +02:00
agatho 674a8c2fe8 Housing: bounded HousingMap visibility + always-active critical infra
Audit 2026-04-21 (README sec 1) measured ~20x over-emission of
CREATE_OBJECT on housing maps because HousingMap::InitVisibilityDistance
forced m_VisibleDistance = MAX_VISIBILITY_DISTANCE (533y). Every player
on the map received CREATEs for every plot AT, cornerstone GO, room
identity, component mesh, and decor on every other plot - completely
unbounded.

Drop the map's visibility distance to 200y (wide enough for adjacent
plots to still render naturally as the player walks the neighborhood,
narrow enough to bound per-player update traffic). Adjacent decor and
component meshes now stream in via grid visibility instead of being
broadcast to every player at all times.

The persistent infra entities - plot AreaTriggers, cornerstone
GameObjects, and Housing/2 room identity entities - must be in the
client's entity registry at any distance, otherwise lookups for
ENTER_PLOT / IsInsidePlot / OutsidePlotBounds / OPEN_CORNERSTONE_UI
fail when the player is far from the relevant plot. Mark each of those
three with setActive(true) + SetFarVisible(true) at spawn time so they
broadcast regardless of player position. The previous workaround for
the lookup-fail bug was to keep visibility at MAX, which fixed lookups
at the cost of the over-emission this commit removes.

Decor / fixtures / component meshes are not active - they only need to
be visible when the player is on or near the plot, which grid
visibility handles correctly at 200y.
2026-04-27 23:29:18 +02:00
agatho e62aabb735 Housing: fix Visit teleport for offline owners + spawn 4 Group B mirrors per plot
Visit teleport (TELEPORT_TO_PLOT, TeleportType=5):
  CanVisitorAccess() returned false whenever the plot owner was offline
  because the helper takes Player const* and aborts on null. Result: the
  client received PERMISSION_DENIED and never teleported, even on plots
  whose settings were "ANYONE".

  Fix: add CanVisitorAccessPlot(visitor, ownerGuid, settingsFlags, isInterior)
  that resolves friend / guild / neighborhood relationships from the
  visitor side + sCharacterCache, so the check works for offline owners.
  Settings come from a new PlotInfo::HouseSettingsFlags mirrored from
  character_housing.settingsFlags at neighborhood preload, refreshed when
  Housing::SaveSettings runs while the owner is online.

  TeleportToPlot now passes the persisted plot settings into the new
  helper instead of bailing on a null Player*.

Group B Entity mirrors:
  Audit 2026-04-21 (FINDINGS.md sec 1.2) found retail emits 4 per-piece
  Entity mirrors per plot - one FMirroredPositionData_C-only mirror
  attached to each visible exterior fixture MeshObject (Base/Roof/Door/
  Window - ExteriorComponent Type 9/10/11/12). We were emitting one,
  anchored to the root only.

  _houseMeshMirrorEntities is now a vector<unique_ptr<HousingMirrorEntity>>
  per plot. SpawnHouseForPlot iterates the plot's MeshObjects, and pairs
  one Group B mirror per fixture-tier mesh. MakeHouseMeshMirrorGuid now
  packs (bnetId << 16) | (plot << 8) | piece so each mirror has a unique
  GUID. Player::BuildCreateUpdateBlockForPlayer iterates the new
  GetHouseMeshMirrors() list so all per-piece mirrors land in the
  initial UPDATE_OBJECT bundle.

Schema:
  CHAR_SEL_NEIGHBORHOOD_MEMBERS extended with ch.settingsFlags so
  Neighborhood::LoadFromDB can populate PlotInfo::HouseSettingsFlags
  for every member's plot at startup.
2026-04-27 21:12:18 +02:00
agatho dc1a9167dc Housing import: add missing CHAR_SEL_NEIGHBORHOOD_MEMBER_FIXTURES/DECOR/ROOMS prepared statements
These three CharacterDatabase prepared statements feed
Neighborhood::LoadFromDB so it can pre-populate every occupied plot's
fixtures, decor, and room data at neighborhood init (without requiring
each owner to be online). They were dropped during the cross-fork
transplant because the surrounding hunk had already been partially
applied. Also extends CHAR_SEL_NEIGHBORHOOD_MEMBERS projection with
ch.houseLevel/favor/houseName/houseType so the loader can mirror per-plot
data onto the neighborhood plot table for the world map tooltip.
2026-04-27 19:50:26 +02:00
agatho acdd2afa7c Housing import: resolve .rej hunks + dedupe duplicate enum/statement blocks
Follow-up to e16cb5f0. The squash patch left 5 .rej files; investigation
showed all 5 either:
  (a) were redundant — other hunks of the same patch had already added the
      content elsewhere, OR
  (b) duplicated entries the target already had from its own prior
      housing-system experimentation.

Changes in this commit:

src/server/game/Server/Protocol/Opcodes.h
  - Hand-applied the rejected hunks from Opcodes.h.rej:
    * Inserted CMSG_GET_NEIGHBORHOOD_INITIATIVE_INFO_REQUEST (0x380003) and
      the CMSG_NEIGHBORHOOD_INITIATIVE_OPCODE_01..0F catalogue between
      CMSG_GET_INITIATIVE_ACTIVITY_LOG_REQUEST and CMSG_GET_ITEM_PURCHASE_DATA.
    * Inserted the TC-CUSTOM housing CMSG block (HOUSING_DECOR_*,
      HOUSING_FIXTURE_*, HOUSING_REQUEST_*, HOUSING_SVCS_*, HOUSING_SYSTEM_*,
      NEIGHBORHOOD_*) right before the closing brace of OpcodeClient.
    * Inserted the TC-CUSTOM housing SMSG block (placeholders in 0xF1000000+
      range) right before the closing brace of OpcodeServer.

src/server/database/Database/Implementation/HotfixDatabase.h
  - Removed three patch-added duplicate blocks that conflicted with target's
    alphabetically-sorted entries.
  - Re-added HOTFIX_SEL_HOUSE / _DECOR / _DECOR_MATERIAL / _DECOR_THEME_SET /
    _EXTERIOR_WMO_DATA / _LEVEL_DATA / _LEVEL_REWARD_INFO / _ROOM / _THEME
    (and their _MAX_ID / _LOCALE variants) which were unique to our patch.
    Inserted in alphabetical position right after HOTFIX_SEL_HOLIDAYS.

src/server/database/Database/Implementation/HotfixDatabase.cpp
  - Removed the entire "WowCommunity" duplicate PrepareStatement block
    (lines 2374-3005, ~630 lines). All 30+ housing-related PrepareStatement
    calls there duplicated target's existing entries elsewhere in
    DoPrepareStatements (queries are byte-identical, so the dedup is safe).

Status:
  - Working tree clean (.rej files all resolved).
  - feature/import-housing branch is local-only (not pushed yet).
  - The repo is structurally consistent — enum entries no longer redefine,
    PrepareStatement calls are unique. Need a real CMake build cycle on the
    target to surface remaining type/template/include issues from the
    cross-fork transplant.

Next steps for human review:
  1. cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo
  2. cmake --build build --target worldserver --parallel
  3. Resolve remaining compile errors (likely method-signature drift between
     source's TC version and target's customizations to Player.cpp,
     WorldSession.cpp, Account.cpp, etc.)
  4. Test runtime — the housing system has its own initialisation flow that
     must succeed before any housing CMSG handler is reachable
  5. git push -u origin feature/import-housing (only after build is green)

Do NOT merge to main until the build is verified.
2026-04-27 17:35:56 +02:00
agatho e16cb5f0de Import housing system from agatho/TrinityCore feature/housing-system
Squash transplant of 433 commits from agatho/TrinityCore feature/housing-system
(c4775862d1d "Re-CREATE HousingPlayerHouseEntity on move so plot icon updates")
onto WowCommunityProject main. Source and target share no git ancestry — this
import is delivered as a single 3-way patch apply with --reject for residual
conflicts.

What's in this commit:
- Full housing subsystem: Housing/, Entities/Housing/, Entities/MeshObject/,
  HousingMap, HouseInteriorMap, HousingMgr, NeighborhoodMgr, NeighborhoodHandler.
- New SMSG/CMSG packet families (0x33xxxx, 0x39xxxx, 0x55xxxx, 0x5Cxxxx,
  0x5Bxxxx, plus 0x42xxxx initiative & decor opcodes) wired into Opcodes.cpp,
  HousingHandler, NeighborhoodHandler, WorldSession.
- DB2 stores for HouseDecor*, HouseRoom*, HouseTheme*, HouseLevel*,
  HouseExteriorWmoData, NeighborhoodPlot, NeighborhoodInitiative*, etc.
- Character DB schema for character_housing*, neighborhood_*, including
  decor/rooms/fixtures/catalog tables (sql/updates/characters/master/*).
- World DB updates for housing GO templates, AT scripts, NPCs.
- Spell scripts for housing-related spell effects (npc_housing_steward,
  spell_housing, at_housing_plot, go_housing_door).
- Project documentation and analysis dumps under docs/.

Files NOT in this commit (5 .rej files left in the working tree for manual
integration — the target's diverged versions of these list/enum files
prevented automatic apply):

  src/server/database/Database/Implementation/CharacterDatabase.cpp.rej
  src/server/database/Database/Implementation/CharacterDatabase.h.rej
  src/server/database/Database/Implementation/HotfixDatabase.h.rej
  src/server/game/DataStores/DB2Metadata.h.rej
  src/server/game/Server/Protocol/Opcodes.h.rej

Each .rej is a "list insertion" conflict where our patch wants to add new
enum/statement entries between target lines whose neighbours diverged.
Resolution is mechanical (paste the rejected hunks into the right slots in
the target version) but should be done with awareness of the target's local
ordering. Until those are resolved the build will fail on missing opcodes,
DB statements, and DB2 metadata for housing tables.
2026-04-27 16:59:04 +02:00
agatho afb1d1a86f Convert remaining AI files to spatial grid health/position reads
Signed-off-by: luis <[email protected]>
2026-03-31 19:52:57 -03:00
agatho 2600feca84 Convert combat position/distance reads to spatial grid
Added GetBotPosition(), GetBotDistanceTo(), GetBotDistance2dTo() to
SpatialGridQueryHelpers for thread-safe position reads.

Converted position reads in:
- PositionManager: 15 GetPosition/GetExactDist calls
- CombatStateAnalyzer: 4 GetPositionX/Y/Z calls

Combat distance calculations now use the spatial grid position which
is updated every 100ms from the main thread, eliminating stale position
data that caused bots to walk through walls and air.

Signed-off-by: luis <[email protected]>
2026-03-31 19:51:21 -03:00
agathoandClaude Opus 4.6 f48786f599 fix(delves): compilation fixes - worldserver builds clean
Build fixes for Visual Studio 2022 (RelWithDebInfo):

- Fix GetBattlenetAccountId: use player->GetSession()->GetBattlenetAccountId()
  (method is on WorldSession, not Player)
- Fix GetHomebind: use player->m_homebind (public member, not a method)
- Fix REACT_HELPER -> REACT_ASSIST (correct enum value)
- Fix DoMeleeAttackIfReady: use me->DoMeleeAttackIfReady() (Unit method)
- Fix DoSpellAttackIfReady: replace with me->DoMeleeAttackIfReady() as
  fallback (spell IDs not yet configured)
- Fix InstanceMapScript.h -> ScriptMgr.h include in all 13 delve scripts
- Remove duplicate ScriptMgr.h includes
- Remove Player.cpp death hook (use InstanceScript::OnUnitDeath instead)
- Remove delves_common.h include from Player.cpp (scripts dir not in
  game include path)

Verified: worldserver.exe builds successfully with zero errors.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Signed-off-by: luis <[email protected]>
2026-03-27 19:19:42 -03:00
agathoandClaude Opus 4.6 800f7f58f6 fix(delves): correct map IDs, add DifficultyID/ScenarioType constants
Data corrections from DB2 deep analysis:

- DelvesDefines.h: add DELVE_DIFFICULTY_ID=208 and DELVE_SCENARIO_TYPE=8
  (delves use their own difficulty and scenario type, not generic Solo)
- The Sinkhole: fix primary mapId from 2687 to 2767 (2687 is alt variant)
- delve_template SQL: add verified zoneIDs from AreaTable.db2 for all 13
  delves, add comments about alternate variant maps
- Confirmed: MapChallengeMode is NOT used by delves (field stays 0)

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Signed-off-by: luis <[email protected]>
2026-03-27 19:13:48 -03:00
agathoandClaude Opus 4.6 306d9caa70 feat(delves): Phase 6 - All 13 delve instance scripts with real map IDs
Add instance scripts for all 13 TWW Season 1 delves with verified
map IDs extracted from Map.db2:

Isle of Dorn:
- Earthcrawl Mines (2680), Fungal Folly (2664), Kriegval's Rest (2681)

The Ringing Deeps:
- The Waterworks (2683), The Dread Pit (2684)

Hallowfall:
- Nightfall Sanctum (2686), Mycomancer Cavern (2679),
  Skittering Breach (2685), The Sinkhole (2687)

Azj-Kahet:
- The Spiral Weave (2688), Tak-Rethan Abyss (2689),
  The Underkeep (2690), Zekvir's Lair (2682)

All scripts extend DelveInstanceScript with boss encounter data,
delve lifecycle hooks, and are registered in the KhazAlgar
script loader. SQL populates delve_template with verified map IDs.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
Signed-off-by: luis <[email protected]>
2026-03-27 19:09:56 -03:00
agatho b202639b7d Fix MotionMaster corruption from worker thread Clear() call
BotMovementController::MoveToPosition called MotionMaster::Clear() from
the worker thread while Player::Update() on the main thread was also
using the MotionMaster. This data race corrupted the motion type to
invalid value 19, preventing all bot movement.

Removed the Clear() call — MovePoint() handles the active motion
internally without needing an explicit clear.

Also added NeedsFood diagnostic and downgraded ObjectiveTracker logs.

Signed-off-by: luis <[email protected]>
2026-03-27 08:44:57 -03:00
agatho b00b00a753 Blacklist quest givers that return 0 quests to prevent infinite loop
Bots repeatedly interacted with the same NPC (Image of Archmage Xylem)
every tick, getting 0 accepted quests each time but never trying other
NPCs. The spatial grid scan always picked the closest quest giver.

Now tracks NPCs that returned 0 quests in _failedQuestGiverGuids and
skips them in future scans. When all nearby NPCs are blacklisted, the
search falls through to the quest hub / teleport path. The blacklist
clears on teleport (new zone has new NPCs).

Signed-off-by: luis <[email protected]>
2026-03-26 13:30:17 -03:00
agatho 9755fd11c0 Fix MINIMAL budget tier permanently blocking strategy execution
RPG states IDLE/RESTING/INACTIVE mapped to MINIMAL budget tier which
skipped UpdateStrategies entirely via goto throttled_update_complete.
After death+respawn at spirit healer, the RPG routine classified the
bot as IDLE -> MINIMAL -> strategies never ran -> bot idle forever.

Strategies are what drive bots OUT of idle state (find quest givers,
accept quests, start grinding). They must always run regardless of
budget tier.

Signed-off-by: luis <[email protected]>
2026-03-26 08:35:49 -03:00
agatho 3098d3b6d0 Run quest strategy every frame while walking to quest giver
Signed-off-by: luis <[email protected]>
2026-03-26 08:34:46 -03:00
agatho a65ae5b177 Fix RestStrategy using stale health/mana — GetBotAI always returned null
BotAI doesn't extend PlayerAI/UnitAI, so dynamic_cast<BotAI*>(GetAI())
always returned nullptr. The cached health/mana values were never read,
falling back to stale bot->GetHealthPct() on the worker thread.

RestStrategy already receives BotAI* ai as a parameter — use
ai->GetCachedHealthPct() and ai->GetCachedManaPct() directly instead
of trying to look up BotAI from the Player.

Signed-off-by: luis <[email protected]>
2026-03-26 08:34:00 -03:00
agatho 58335d9b20 Initialize cached state in BotAI constructor to prevent 0,0,0 position on first tick
Signed-off-by: luis <[email protected]>
2026-03-26 08:33:18 -03:00
agatho 6619d78fbc Move bot state snapshot from worker thread to main thread
The state cache (health, mana, position, map, combat) was being
populated at the start of UpdateAI on the worker thread, reading the
same stale data it was trying to avoid. Health showed 53% for hours
while actually 100% because GetHealthPct() returns the value from the
last Player::Update() call on the main thread.

Now BotSession::SnapshotBotState() runs on the main thread from
BotWorldSessionMgr::ProcessAllDeferredPackets(), after Player::Update()
has already run. Worker threads read these cached values which are
guaranteed current.

Uses movespline->ComputePosition() for accurate interpolated position
instead of FinalDestination() which only gives the endpoint.

Signed-off-by: luis <[email protected]>
2026-03-25 19:28:57 -03:00
agatho cbdab1cc13 Cache health/mana/map/combat state for worker thread safety
All bot stats read via GetHealthPct(), GetPowerPct(), GetMapId(),
IsInCombat() are only updated on the main thread during Player::Update.
Worker threads reading them directly get stale data — health showing
53% when actually 100%, causing rest strategy to idle bots for hours.

BotAI now caches health, mana, map ID, and combat state at the start
of each UpdateAI tick. RestStrategy uses these cached values instead
of reading from the bot directly.

Signed-off-by: luis <[email protected]>
2026-03-25 19:27:46 -03:00
agatho 819706874b Accept quests immediately when already at quest giver
When SearchForQuestGivers found a quest giver at 0yd distance, it
deferred to the pending system which required another UpdateBehavior
tick. With the 150ms throttle and only ~6 calls per session, the
follow-up never happened.

Now resolves the creature and calls ProcessQuestGiver immediately
when the bot is already within interaction distance, instead of
deferring to the next tick.

Signed-off-by: luis <[email protected]>
2026-03-24 02:36:52 -03:00
agatho 8042cd9da8 Fix AbandonQuest not removing quests — add RemoveActiveQuest before every AbandonQuest call
Signed-off-by: luis <[email protected]>
2026-03-24 02:36:24 -03:00
agatho cca29fdfa0 Fix remaining bot idle issues and clean up diagnostic logging
- Abandon quests with no ender in DB immediately on first attempt
  instead of waiting for 3 failures (fixes quest 55660 blocking)
- Loot strategy only activates on game objects within INTERACTION_DISTANCE
  preventing distant spatial grid objects from blocking quest strategy
- Rest threshold lowered to 15-25% for no-consumable resting
  (was 30-50%, causing bots at 50% health to idle without food)
- Downgrade 275 TC_LOG_ERROR calls to TC_LOG_DEBUG in QuestStrategy
- Downgrade STRAT-SELECT diagnostic to TRACE
- Downgrade target scanner evaluation log to TRACE
- Downgrade auto-accept check diagnostic to DEBUG

Signed-off-by: luis <[email protected]>
2026-03-24 02:35:27 -03:00
agatho 1e9be20087 Add worker-thread-safe position cache from movespline to BotAI
bot->GetPositionX/Y/Z() is only updated on the main thread during
Player::Update(). Worker threads reading it mid-spline get stale data.

BotAI now caches the current position at the start of each UpdateAI():
- If a movespline is active: uses FinalDestination() as effective position
- If idle: uses last known server position

GetCurrentPosition() provides this cached value for any worker thread
code that needs accurate bot location. Quest strategy's pending quest
giver distance check now uses this instead of bot->GetPositionX/Y/Z().

Also re-added navmesh reachability check to spatial grid quest giver
scan to skip unreachable NPCs (towers, cliffs) before selection.

Signed-off-by: luis <[email protected]>
2026-03-24 02:34:40 -03:00
agatho c127948a26 Fix quest giver distance using spline destination instead of stale position
bot->GetPositionX/Y() returns the server-side position which lags behind
the client during active spline movement. The bot visually stands at the
NPC but GetExactDist2d reports 77yd because the position hasn't been
updated by the main thread yet.

Now uses movespline->FinalDestination() as the bot's effective position
when a spline is active. This matches where the client renders the bot.

Also re-added navmesh reachability check to the spatial grid scan to
skip unreachable NPCs (towers, cliffs) before selection.

Signed-off-by: luis <[email protected]>
2026-03-23 09:24:19 -03:00
agatho a5c8d85089 Rewrite SearchForQuestGivers to use spatial grid instead of live grid
SafeGridOperations::GetCreatureListSafe accessed the live grid which
returned stale creatures from the old map after teleports (worker thread
data race on m_currMap). The bot searched for quest givers on the wrong
continent.

Now uses DoubleBufferedSpatialGrid which provides lock-free atomic
snapshots updated by the main thread. Worker threads always read current
map data. The scan uses creature snapshot fields (hasQuestGiver, entry,
position, isDead) and quest relation DB lookups (thread-safe static data)
to find quest givers without touching any live creature pointers.

Quest acceptance still uses live creature pointers but only in the
pending quest giver arrival phase, when the bot is physically at the NPC
and the data is guaranteed current.

Signed-off-by: luis <[email protected]>
2026-03-23 09:21:44 -03:00
agatho 6746649e95 Revert quest log cleanup — bots earned their quests legitimately
Signed-off-by: luis <[email protected]>
2026-03-23 09:21:04 -03:00
agatho 7fb99f6fa8 Clear pre-loaded quest log on first quest strategy run
Signed-off-by: luis <[email protected]>
2026-03-23 09:20:31 -03:00
agatho 6566e59412 Add teleport cooldown and auto-accept diagnostics
Worker thread reads stale map/grid data after TeleportTo, causing quest
giver searches to return creatures from the old map. Added 5-second
cooldown after each teleport to let the main thread process the map
change before the quest strategy runs again.

Also added diagnostic logging to ProcessQuestGiver auto-accept phase
to trace why quests aren't being accepted (alreadyHas, blacklisted,
canTake, canAdd checks).

Added navmesh reachability check to quest giver selection and position
diagnostic for pending quest giver distance debugging.

Signed-off-by: luis <[email protected]>
2026-03-23 09:19:27 -03:00
agatho 572f6826af Validate quest giver navmesh reachability before selection
Bots walked to quest givers on unreachable terrain (towers, cliffs)
because SearchForQuestGivers selected by straight-line distance without
checking if the navmesh could path there. The bot stopped at the
closest navmesh point, 77+ yards from the NPC.

Now uses PathGenerator to verify navmesh reachability before selecting
a quest giver. Unreachable NPCs are skipped in favor of reachable ones.

Also allows interaction when the NPC is found via grid scan (within
50yd) even if the stored position distance is larger, handling cases
where navmesh pathing ends at a different point than the stored coords.

Signed-off-by: luis <[email protected]>
2026-03-23 09:17:23 -03:00
agatho 88e61e37bb Replace CastSpell hearthstone with TeleportTo for bot homebind travel
CastSpell(8690) failed silently for bots without a hearthstone item in
inventory (gear application failed at creation). Bots stood idle in
wrong zones because the hearthstone cast did nothing.

Use Player::TeleportTo(m_homebind) directly — no item required, no
cooldown, no cast time. This is already used elsewhere in the module
(AdvancedBehaviorManager, PlayerbotCommands, TravelRouteManager).

Signed-off-by: luis <[email protected]>
2026-03-23 09:16:49 -03:00
agatho a15abe4cc0 Refine stale route timeout to only fire when stuck walking to first dock
The 2-minute timeout incorrectly killed routes where the bot was
waiting for a ship, riding a transport, or on later legs. Now only
fires when stuck in WALKING_TO_TRANSPORT state on leg 0 — the specific
case caused by worker thread GetMapId() staleness after teleport.

Signed-off-by: luis <[email protected]>
2026-03-23 09:16:16 -03:00
agatho 8fdbe66c57 Add timeout-based stale route detection for worker thread map staleness
bot->GetMapId() returns stale data on worker threads after a teleport
because m_mapId is updated on the main thread only. The existing map
comparison check fails — the worker still sees the old map ID.

Added a 2-minute timeout: if the travel route has been active for over
2 minutes without completing the first leg, it's considered stale and
cleared. This handles the case where the bot hearthstoned to a
different map but the worker thread can't detect the map change.

Signed-off-by: luis <[email protected]>
2026-03-23 09:15:40 -03:00
agatho 017e21d98f Fix quest giver arrival check using 3D distance instead of 2D
Bots stopped 30+ yards from quest givers because 3D distance included
Z-height difference (stairs, ramps, platforms). The bot was visually
at the NPC but the 3D dist of 31yd > INTERACTION_DISTANCE of 5yd.

Switched all pending quest giver distance checks to 2D, matching how
WoW's gossip interaction works. Also widened grid scan to 50yd for
finding NPCs when ObjectAccessor fails.

Signed-off-by: luis <[email protected]>
2026-03-23 09:13:27 -03:00
agatho 04c06abf21 Fix false falling state blocking all bot movement
IsOnGround() returned false when GroundValidator::GetGroundHeight
returned INVALID_HEIGHT (map data not loaded), causing the state
machine to set MOVEMENTFLAG_FALLING. This permanently blocked
MovePoint from generating splines — bots stood idle despite movement
commands being issued every tick.

Changed INVALID_HEIGHT to assume on-ground (safe default). A bot at
a spawn point is never falling.

Also added INFO diagnostic to HandleOnTransport for travel visibility.

Signed-off-by: luis <[email protected]>
2026-03-23 09:12:39 -03:00
agatho 8d65207489 Fix stale travel route blocking bots already on destination map
The stale route check only compared origin map, missing cases where
the bot spawned on the destination map (e.g. quest ender on same
continent). Route to Ratchet dock (Kalimdor) blocked a bot in
Northshire (Eastern Kingdoms) because originMapId matched.

Now also clears the route when the bot is already on the destination
map — no cross-map travel needed, just walk directly.

Added diagnostic logging to travel check for visibility.

Signed-off-by: luis <[email protected]>
2026-03-20 01:18:28 -03:00
agatho 2eaca0645a Clear stale travel route after map change from hearthstone
After hearthstoning to a new map, the travel manager's route (planned
for the old map) stayed active and blocked all quest processing. The
bot stood idle forever because UpdateBehavior returned early every tick.

Now detects when the bot's current map differs from the route's origin
map and clears the stale travel manager, allowing quest processing to
resume on the new map.

Also added INFO-level diagnostic to HandleOnTransport for travel
movement visibility.

Signed-off-by: luis <[email protected]>
2026-03-20 01:17:56 -03:00
agatho 0bf86c6aa0 Handle auto-accept quests (QUEST_FLAGS_AUTO_ACCEPT) for bots
Starting zone quests like Reclaiming Sunstrider Isle use the auto-accept
flag (0x80000) which bypasses the normal gossip menu. PrepareQuestMenu
doesn't include them, so bots stood idle at quest givers like Magistrix
Erona without accepting anything.

SearchForQuestGivers now also checks quest relations for auto-accept
quests when evaluating NPCs. ProcessQuestGiver runs auto-accept quests
first via AddQuestAndCheckCompletion before processing the gossip menu
for normal quests.

Signed-off-by: luis <[email protected]>
2026-03-20 01:17:25 -03:00
agatho 6dc54587b1 Fix quest giver interaction failing when ObjectAccessor can't find NPC
ObjectAccessor::GetCreature fails for some NPCs even when the bot is
standing next to them. Added grid scan fallback using creature entry
from the GUID to find the actual NPC within interaction range.

Also switched to 2D distance for position-based checks to prevent
Z-height differences from causing false "too far" results.

Signed-off-by: luis <[email protected]>
2026-03-20 01:16:51 -03:00
agatho 5614394566 Allow cross-map quest hub search and hearthstone travel
QuestHubDatabase::IsAppropriateFor no longer restricts to same map,
so bots stranded on a continent with no level-appropriate content can
find hubs on other maps. Cross-map hubs get a 0.5x scoring penalty to
prefer same-map when available.

When no quest hubs or quest givers are found nearby, bots now:
1. Search QuestHubDatabase across all maps
2. If best hub is cross-map and hearthstone goes there, cast hearthstone
3. If best hub needs multi-leg travel, use TravelRouteManager
4. If no hubs at all, use hearthstone as last resort

Signed-off-by: luis <[email protected]>
2026-03-20 01:16:13 -03:00
agatho 94a0a769d5 Use PrepareQuestMenu for quest eligibility instead of CanTakeQuest
CanTakeQuest returned true for quests that weren't actually available
in-game because ContentTuning data was missing, making GetQuestMinLevel
return 0. Bots walked to NPCs that had no quests to offer.

Replace manual quest relation iteration + CanTakeQuest with
Player::PrepareQuestMenu which is TrinityCore's authoritative check
for quest availability. This is the same system that renders quest
exclamation marks for real players and properly handles ContentTuning,
phase visibility, conditions, and all edge cases.

Applied to both SearchForQuestGivers (scan phase) and ProcessQuestGiver
(acceptance phase).

Signed-off-by: luis <[email protected]>
2026-03-20 01:15:31 -03:00
agatho facd9e31e0 Fix pending quest giver lost when ObjectAccessor fails
The pending quest giver check used ObjectAccessor::GetCreature which
can fail for phased/special NPCs like Image of Archmage Xylem, causing
the GUID to be cleared and the bot to stop walking mid-path.

Now stores the NPC position alongside the GUID. The bot walks to the
stored position even if creature lookup fails, and attempts grid scan
for quest givers on arrival. Also logs at INFO level for diagnosis.

Signed-off-by: luis <[email protected]>
2026-03-20 01:14:53 -03:00
agatho cd2722498d Fix rest threshold randomized every tick causing inconsistent behavior
The critical rest threshold (no consumables path) was calling frand()
on every IsActive() check, producing a different threshold each tick.
Bots at moderate health (49-53%) would flicker between rest and other
strategies because the random threshold kept changing.

Moved to a per-bot threshold assigned once at construction (30-50%)
so each bot has a stable, unique resting personality.

Signed-off-by: luis <[email protected]>
2026-03-20 01:14:25 -03:00
agatho 281f8ac25e Fix corpses not marked as looted after bot picks up items
Add SendLootRelease() after looting all items from a corpse. Without
this, the corpse stayed "lootable" forever and FindLootableCorpses kept
returning it, causing loot strategy to permanently block quest strategy.

Signed-off-by: luis <[email protected]>
2026-03-20 01:13:46 -03:00
agatho eb35be730d Fix quest giver interaction lost between ticks and stuck turn-ins
Add persistent _pendingQuestGiverGuid so the bot completes walking to
and interacting with a quest giver across multiple UpdateBehavior ticks,
even when other quests are active in the log.

Also track FindQuestEnderLocation failures in TurnInQuest — after 3
consecutive failures the bot abandons the quest and blacklists it,
preventing infinite turn-in loops on quests with missing ender data.

Signed-off-by: luis <[email protected]>
2026-03-20 01:13:05 -03:00
agatho 6bf07a0dd1 Fix ValidatedPathGenerator failing on long-distance paths
PathGenerator returns NOPATH beyond navmesh query range limits, causing
bots to stand idle during long travel. ValidatedPathGenerator now
segments long paths with 200yd intermediate waypoints. The travel
manager re-evaluates every 500ms for incremental progress.

Added INFO-level path validation failure logging.

Signed-off-by: luis <[email protected]>
2026-03-20 01:11:59 -03:00
agatho 4341bcc1cd Gate loot and rest strategies on actual need in IsActive
LootStrategy::IsActive now checks for nearby lootable corpses with
permission before returning true, preventing it from permanently
blocking lower-priority strategies like quest when nothing to loot.

RestStrategy::IsActive now checks health/mana levels and consumable
availability. With consumables it activates normally. Without them it
only activates below a randomized 30-50% threshold per check, allowing
bots to quest/grind at moderate health while still waiting for passive
regen when critically low.

Signed-off-by: luis <[email protected]>
2026-03-17 20:34:45 -03:00
agatho 1e7a5c3632 Fix missing includes after BotMovement relocation to module
Files previously compiled in the game library had implicit access to
all game headers via PCH. Now in the playerbot module they need explicit
includes for: Position.h, Map.h, Creature.h, CreatureAI.h, G3D/Vector3.h,
and VMapFactory.h.

Signed-off-by: luis <[email protected]>
2026-03-17 13:54:01 -03:00
agatho 0a3a69b19e Move BotMovement system from game/ to Playerbot module
Relocate 44 BotMovement files (Controller, StuckDetector, StateMachine,
Pathfinding, Generators, Validation) from src/server/game/Movement/ into
src/modules/Playerbot/Movement/BotMovement/ to comply with module-first
architecture. All playerbot code must live in the module directory.

Updated CMakeLists.txt with all source files in playerbot-gameplay lib
and added 6 include directories for the BotMovement subdirectories.

Also fixes StuckDetector::Reset() to clear position history, preventing
an infinite stuck detection loop where bots were immediately re-detected
as stuck after recovery due to stale position snapshots.

Signed-off-by: luis <[email protected]>
2026-03-16 20:16:50 -03:00
agathoandClaude Opus 4.6 ef377b2246 Housing: Fix tutorial sending HouseStatus=1 without a house
The StartTutorial handler was sending HouseStatus=1 (active house)
with populated owner GUIDs but no HouseGuid and PlotIndex=0xFF.
The client interprets HouseStatus=1 as "player owns a house," which
prevents the Cornerstone "For Sale" purchase UI from displaying —
the client thinks the player is already a homeowner.

During the tutorial the player has no house yet, so send the default
empty response (HouseStatus=0, all GUIDs empty). The neighborhood
context is already provided by SMSG_HOUSING_GET_CURRENT_HOUSE_INFO_RESPONSE
when the player enters the HousingMap.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-19 21:06:52 -03:00
agathoandClaude Opus 4.6 210ca3bf70 Housing: Don't populate owner GUIDs in HouseStatus when player has no house
The no-house path was setting OwnerBNetGuid and OwnerPlayerGuid in
SMSG_HOUSING_HOUSE_STATUS_RESPONSE even though HouseGuid was empty
and HouseStatus was 0. This is inconsistent — a response with no
house should have all-empty GUIDs and PlotIndex=0xFF (the default).

Neighborhood context is already provided separately via
SMSG_HOUSING_GET_CURRENT_HOUSE_INFO_RESPONSE sent in
HousingMap::AddPlayerToMap().

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-19 21:05:50 -03:00
agathoandClaude Opus 4.6 612c75a683 Housing: Send neighborhood context on map entry and import AT 37358
Two fixes to enable Cornerstone click interaction:

1. Send SMSG_HOUSING_GET_CURRENT_HOUSE_INFO_RESPONSE proactively in
   HousingMap::AddPlayerToMap() so the client can call
   SetViewingNeighborhood() and populate its global housing context.
   Without this, GetCornerstoneNeighborhoodInfo() returns empty data
   and the Cornerstone purchase UI cannot display.

2. Add SQL migration for AreaTrigger entry 37358 (housing plot AT)
   with ScriptName='at_housing_plot', Shape=Sphere, radius=40 yards.
   Without this in the database, CreateStaticAreaTrigger() silently
   fails and SMSG_NEIGHBORHOOD_PLAYER_ENTER_PLOT never fires.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-19 21:05:05 -03:00
agathoandClaude Opus 4.6 1d4aca4fd2 Housing: Fix plot rendering - use Cornerstone GO with GOState toggle
Retail packet sniff analysis proves that ALL housing plots use a single
Cornerstone GameObject (entry 457142, DisplayID 110660, Type 48/UILink)
with GOState toggling to communicate ownership:
  - GOState 0 (ACTIVE) = For Sale / unoccupied
  - GOState 1 (READY) = Owned / occupied
  - All Cornerstones have Flags=32 (GO_FLAG_NODESPAWN)

The previous implementation spawned a fabricated "For Sale" sign
(entry 417487, DisplayID 8206) for unoccupied plots. DisplayID 8206 is
a vanilla-era model that renders as a flat brown rectangle.

Changes:
- SpawnPlotGameObjects: Always use CornerstoneGameObjectID, set GOState
  based on ownership, apply GO_FLAG_NODESPAWN
- Replace SwapPlotGameObject (destroy/recreate) with SetPlotOwnershipState
  (GOState toggle on existing Cornerstone)
- Simplify all 3 callers (ReservePlot, BuyHouse, EvictPlot) to pass
  bool ownership instead of GO entry IDs
- Remove fabricated entry 417487 from world SQL

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-19 21:00:32 -03:00
agathoandClaude Opus 4.6 98795165b0 Housing: Add ALTER TABLE migration for 3 new character_housing columns
Adds exteriorLocked, houseSize, and houseType columns to existing
character_housing tables via ALTER TABLE (the schema file was updated
in the prior commit but existing databases need this migration).

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-19 20:59:33 -03:00
agathoandClaude Opus 4.6 34afbe0564 Housing: Route debug logging to 'housing' channel
The 'maps' logger is at WARNING level by default, suppressing
all DEBUG messages. Route HousingMap and MapManager neighborhood
logging to the 'housing' channel which is at TRACE level and
writes to Housing.log.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-19 20:36:09 -03:00
agathoandClaude Opus 4.6 70823e16fd Housing: Add Alliance neighborhood world data for Map 2735
Creature templates, spawns, models, gameobject templates, spawns,
gossip menus, vendor inventories, quest data, and trainer spells
for the Alliance housing neighborhood (The Aerie).

Column names adapted to current TrinityCore creature_template schema
(type/family/Classification, 64-bit npcflag).

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-19 20:22:26 -03:00
agathoandClaude Opus 4.6 682cf56f05 Housing: Add GO swap on plot purchase/eviction and fix HouseFinder
Track plot GameObjects in HousingMap so for-sale-signs can be swapped
to cornerstones on purchase and reverted on eviction. Previously the
visual GO never changed after PurchasePlot(), leaving stale for-sale
signs on owned plots.

Fix HouseFinder neighborhood detail to show all 55 DB2 plots with
availability and cost instead of only listing occupied plots, so the
client can render the full plot grid.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-19 20:13:03 -03:00
agathoandClaude Opus 4.6 f33729555d Core/GameObject: Use PlayerInteractionType field for UILink GameObjects
The GAMEOBJECT_TYPE_UI_LINK handler only mapped UILinkType values 0-3
to PlayerInteractionType via a hardcoded switch. UILinkType is deprecated
in favor of the PlayerInteractionType field (Data[7]) which allows
direct mapping to any PlayerInteractionType enum value.

When PlayerInteractionType (Data[7]) is set, send
SMSG_NPC_INTERACTION_OPEN_RESULT with the GO's GUID and the specified
interaction type. Also cast UILink.spell (Data[8]) when present, which
is required for interactions like Cornerstones that need a placement
spell to trigger the client UI.

Fixes Cornerstones (Data[7]=70, spell 1266097) and Bulletin Boards
(Data[7]=72) not opening their respective housing UIs.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-16 09:41:54 -03:00
agathoandClaude Opus 4.6 ce86384926 Gossip/Vendor: Fix Sell All Junk by deferring vendor inventory to second round-trip
The client's IsSellAllJunkEnabled requires PlayerInteractionManager+48 to be
set to Merchant(5). NIOR(Merchant) case 5 queues a UI event that sets this
field, but it does not set it synchronously during packet processing. When
VendorInventory was sent in the same flush as NIOR, MerchantFrame opened
before the event fired, so PIM+48 was not yet 5 and IsSellAllJunkEnabled
returned false.

Fix: On gossip vendor click, send only NIOR(Merchant) and start the
interaction. The client event handler sets PIM+48, opens MerchantFrame,
which then sends CMSG_LIST_INVENTORY to fetch vendor data in a second
round-trip. Also handle direct CMSG_LIST_INVENTORY (non-gossip vendors)
by sending NIOR first if the interaction is not yet started.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-12 20:11:53 -03:00
agathoandClaude Opus 4.6 50be1cc73f Gossip: Send NPCInteractionOpenResult(Merchant) before vendor inventory
Send SMSG_NPC_INTERACTION_OPEN_RESULT with PlayerInteractionType::Merchant
from the gossip handler instead of from SendListInventory. This sets PIM+48
to the value the client expects for IsSellAllJunkEnabled() without causing
an infinite CMSG_LIST_INVENTORY loop (the client's MerchantFrame OnShow
re-requests the item list, which would re-trigger NIOR if placed inside
SendListInventory).

Also closes the gossip dialog before opening the vendor frame, matching
the PetitionVendor pattern.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-12 20:10:49 -03:00
agathoandClaude Opus 4.6 697cffb0a3 Playerbot/Movement: Add road network pathfinding system
Adds the source code for the road network navigation system:
- RoadNetworkManager: Loads and manages road graph data per map
- RoadGraphPathfinder: A* pathfinding on the road graph with
  spatial index acceleration for nearest-node lookups
- RoadSpatialIndex: Grid-based spatial index for fast node queries
- RoadNetworkTypes: Shared type definitions (nodes, edges, paths)

Companion to 41e62e15a4 which added the road network data files.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 21:08:04 -03:00
agathoandClaude Opus 4.6 8b75ac1a33 Playerbot/Movement: Add road network data for bot pathfinding (337 maps)
Pre-generated road graph data extracted from WoW map ADT terrain
textures. Contains 337 .roadnet binary files covering all maps with
road infrastructure (Eastern Kingdoms, Kalimdor, Draenor, Broken
Isles, etc.).

## Install Instructions

1. Extract `src/modules/Playerbot/conf/roads.zip` into a `roads/`
   folder in your worldserver working directory (same location as
   `maps/`, `vmaps/`, `mmaps/`, `dbc/`, `gt/`):

       cd <server-directory>
       unzip roads.zip -d roads/

   On Windows (PowerShell):

       Expand-Archive -Path roads.zip -DestinationPath roads\

2. Verify the folder contains 337 `.roadnet` files (e.g. 0000.roadnet,
   0001.roadnet, ...).

3. Start worldserver. Confirm loading in the log:

       RoadNetworkManager: Initializing from 'roads'
       RoadNetworkManager: Loaded 337 maps (X nodes, Y edges)

4. If using a custom data directory, set the absolute path in
   playerbots.conf:

       Playerbot.RoadNetwork.DataPath = "C:/path/to/roads"

## Configuration (playerbots.conf)

    Playerbot.RoadNetwork.Enable = true        (default)
    Playerbot.RoadNetwork.DataPath = "roads"   (default, relative to CWD)
    Playerbot.RoadNetwork.MinDistance = 200     (yards, below this use direct navmesh)
    Playerbot.RoadNetwork.MaxDetourRatio = 1.5  (max road/direct distance ratio)
    Playerbot.RoadNetwork.MaxEntryDistance = 200 (max yards to nearest road node)

## Data Summary

    Archive: 3.2 MB (12 MB uncompressed)
    Files:   337 .roadnet binary files
    Format:  RNET v1 (header + nodes + edges + shape points + adjacency)
    Largest: Map 0 (Eastern Kingdoms) - 16,585 nodes, 13,037 edges

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 20:36:36 -03:00
agathoandClaude Opus 4.6 03602eb6d1 fix(bg): Fix BotActionProcessor GUID lookup + add BG overpopulation trim
BotActionProcessor::GetBot() used ObjectAccessor::GetPlayer(nullptr, guid)
which compares player->GetMap() == nullptr — always false for bots on BG
maps. This caused 100% action failure rate (39/39 failed). All deferred
actions (orb pickup, flag capture, node interaction) were silently dropped.

Fix: Use ObjectAccessor::FindPlayer(guid) which does a global lookup
without map comparison.

Also adds TrimExcessBotsLocked() to detect and remove excess bots when
teams are overpopulated, called from both PopulateBattlegroundLocked()
and ProcessPendingPopulations().

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:49:37 -03:00
agathoandClaude Opus 4.6 055b2dd985 fix(travel): Eliminate terrain loading from PortalDatabase init entirely
Replace TerrainMgr::GetZoneId() calls with direct reads from the
gameobject table's zoneId/areaId columns. This avoids loading 62+ map
terrain trees (with recursive child maps, grid file I/O, and VMap/MMap
load/unload cycles) during startup.

destinationZoneId is unused by any consumer — the travel route planner
already uses exact destinationPosition coordinates for distance-based
routing, which is strictly more precise than zone-level comparison.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:49:03 -03:00
agathoandClaude Opus 4.6 b8f545a467 feat(currency): Implement CMSG_SET_CURRENCY_FLAGS handler
Implements the previously unhandled CMSG_SET_CURRENCY_FLAGS opcode, which
allows players to toggle per-currency display preferences (e.g. "Show on
Backpack"). Wire format decoded from IDA disassembly of WoW 12.x client:
{ uint32 CurrencyID; uint8 Flags; }

Changes:
- Add SetCurrencyFlags ClientPacket class (MiscPackets.h/cpp)
- Add Player::SetCurrencyFlags() with ClientFlags mask validation
- Add WorldSession::HandleSetCurrencyFlags() with DB2 currency validation
- Wire opcode as STATUS_LOGGEDIN, PROCESS_THREADUNSAFE

The flags (CurrencyDbFlags::InBackpack, UnusedInUI) are persisted via the
existing _SaveCurrency() path — no schema changes needed.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:47:07 -03:00
agathoandClaude Opus 4.6 8d4a383430 fix(travel): Cache terrain refs during PortalDatabase init to prevent thrashing
GetZoneIdForPosition() calls sTerrainMgr.GetZoneId() per portal, which
uses weak_ptr caching. During startup no Map objects hold terrain refs,
so each call loads the entire terrain tree from disk (including all child
instance maps) then immediately unloads it. For continent maps with dozens
of children, this repeats hundreds of times causing extreme startup delay.

Hold shared_ptr<TerrainInfo> in a temporary cache during initialization so
each map's terrain is loaded exactly once.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:45:30 -03:00
agathoandClaude Opus 4.6 112eff8ac5 fix(bg): Wire BotActionMgr ProcessActions + fix BG death corpse run
Two critical bugs fixed:

1. BotActionManager::ProcessActions() was never called in production.
   The BotActionManagerSubsystem had updateOrder=0 (never updated) and
   no Update() method. All deferred actions (INTERACT_OBJECT, ENTER_VEHICLE,
   etc.) queued by worker threads accumulated forever without execution.
   This broke ToK orb pickup, CTF flag return, node captures, vehicle
   boarding, and all other deferred GO interactions added in Phase 1A.
   Fix: Added Update() override with updateOrder=250.

2. Dead bots in BGs ran to their corpse instead of resurrecting.
   HandleResurrecting with AUTO_RESURRECT passively waited 30s for
   IsAlive(), but BG spirit guides require gossip interaction that bots
   never perform. After timeout, retry via GHOST_DECIDING could choose
   CORPSE_RUN if BG ended during the wait (InBattleground() false).
   Fix: Force-resurrect bots in BGs after 30s wave timer instead of
   falling through to corpse run retry path.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:44:13 -03:00
agathoandClaude Opus 4.6 cc9eb95f68 feat(bg-scripts): Comprehensive BG script enhancement - 14-phase plan
Complete overhaul of all 13 battleground scripts with behavioral,
strategic, and thread-safety improvements across 6 major phases:

Phase 1 - Base class fixes:
- Fix TryInteractWithGameObject phase mismatch + thread-safety
- Add pending interaction framework to BGScriptBase
- Fix CTFScriptBase ReturnDroppedFlag and EscortFriendlyFC
- Add fight-on-flag leash to DominationScriptBase::DefendNode

Phase 2 - Universal behavioral enhancements:
- Node defense commitment timer for all Domination BGs
- Reinforcement routing (INC response) for contested nodes
- Distance-weighted node priority for smarter objective selection
- Score-driven strategy amplification with momentum tracking
- Phase transition hysteresis to prevent oscillation

Phase 3 - CTF-specific enhancements:
- Activate FC route evasion (WSG + Twin Peaks)
- Dropped flag priority with mid-field return
- Defense allocation rebalance for opening phase
- EOTS FC protection escort at 4-cap

Phase 4 - Per-BG domination fixes:
- Arathi Basin: proximity-based opening rush
- Seething Shore: dynamic node spawn response
- Deepwind Gorge: cart/mine mechanics verification

Phase 5 - Siege & Epic BG enhancements:
- AV: Boss NPC targeting with tank/healer awareness
- SOTA: Vehicle boarding system (demolishers + turrets)
- IOC: Vehicle mounting + parachute assault from Hangar
- SSM: Cart capture, track following, intersection handling
- Ashran: Dynamic road progression, event cycling, boss targeting

Phase 6 - Thread-safety & quality:
- Add std::atomic for cross-thread state variables
- Add std::shared_mutex for container protection
- Fix atomic-to-atomic assignments and fmt::format compatibility
- Make cached phase enums atomic in 4 scripts

47 files changed, +2837/-470 lines across all BG script types.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:43:35 -03:00
agathoandClaude Opus 4.6 fc6d363b2a fix(bg-tok): Fix 6 ToK runtime bugs - deferred Use(), orb split, combat, cleanup
- Fix silent orb pickup failure: deferred Use() via BotActionMgr caused bots
  to move away before main thread processed the spell cast. Added
  m_pendingOrbPickup hold-position state so bots stay at orb for up to 2s
  until the main thread processes the deferred GO interaction.

- Fix uneven orb split (1 vs 8+ bots): replaced race-prone m_orbTargeters
  map with GUID-based deterministic slot assignment (GUID % ORB_COUNT with
  round-robin fallback) for even distribution without shared mutable state.

- Fix missing combat engagement: bots now check for nearby enemies via
  coordinator during orb approach movement and initiate Attack().

- Fix claim-aware hasFreeOrb: ExecuteStrategy Priority 2 now skips orbs
  with active m_orbClaimedUntil and m_orbSearchFailed cooldowns, so bots
  correctly fall through to escort/hunt instead of re-entering PickupOrb.

- Fix carrier waypoint oscillation: replaced forward-only waypoint scan
  with center-distance comparison so carriers don't oscillate between
  midway waypoint and center.

- Fix missing OnBattlegroundEnd hook: PlayerbotBGScript now detects
  STATUS_WAIT_LEAVE transition and calls BGBotManager::OnBattlegroundEnd()
  to prevent resource leaks and dangling pointers.

- Fix Map::SendObjectUpdates crash: RemovePlayerBot now clears Account
  and Item BaseEntity objects from _updateObjects, not just Player.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:41:59 -03:00
agathoandClaude Opus 4.6 1c943acd36 fix(bg-runtime): Fix 4 runtime bugs - faction cache, population, orb race, carrier circling
Bug 1: BG under-population (7v4) - Skip bots on wrong map in in-transit
counting. Bots that failed teleport sit on their home map but were
counted as "in-transit", making teams appear full prematurely.

Bug 2 (CRITICAL): Spatial cache faction bug - BGSpatialQueryCache used a
single _faction from the first bot for ALL enemy/ally queries. Half the
bots saw their own team as enemies and enemies as allies. Added
callerFaction parameter to all 8 spatial query methods and excludeGuid
to GetNearestEnemy to prevent self-targeting. Updated all 15 call sites
across BGScriptBase, CTFScriptBase, and TempleOfKotmoguScript.

Bug 3: Dual orb pickup race - Two bots at orb location could both call
Use() in the same tick before RefreshOrbState() detected the aura. Added
m_orbClaimedUntil timestamp map with 3-second claim window.

Bug 4: Carrier circling - Fully caused by Bug 2. Carrier's
GetNearestEnemy() returned itself, causing self-attack which disrupted
movement. Resolved by callerFaction + excludeGuid parameters.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:41:19 -03:00
agathoandClaude Opus 4.6 2e3bdfef66 fix(bg-queue): Fix 5 cascading bugs preventing BG population
When a human queued for a BG, warm pool bots failed to populate the
queue due to 5 cascading failures:

1. Human player was only registered in _humanPlayers after botsQueued>0,
   but warm pool bots are async so botsQueued=0 — human never tracked,
   breaking GetQueuedHumanForBG() for all warm pool bots
2. Dead bots from previous sessions silently failed IsBotAvailable()
   with no logging — 10/19 warm pool bots rejected
3. IsBotAvailable() had no diagnostic logging for any rejection path
4. QueueStatePoller immediately unregistered after warm pool claimed
   success, with no verification that bots actually queued

Fixes:
- Move human registration before bot loop (always register)
- Resurrect dead bots in BotPostLoginConfigurator before BG queue
- Add TC_LOG_DEBUG to every IsBotAvailable rejection path
- Replace immediate unregister with 30s verification re-poll that
  re-registers the queue if actual counts are insufficient

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:40:46 -03:00
agathoandClaude Opus 4.6 5a989f6117 refactor(packet): Replace polling ACK scanner with reactive event-driven system
BotPacketSimulator previously polled every 100ms scanning all 9 speed types
plus teleport/knockback/magnitude flags for every bot. Now BotSession::SendPacket()
intercepts outgoing SMSGs and sets atomic flags via OnPacketSent(), and Update()
processes only the flagged ACKs with O(1) cost when idle.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:40:22 -03:00
agathoandClaude Opus 4.6 9377b2b540 feat(systems): Add 6 new systems - raid coordination, combat logging, reagents, transmog, archaeology
- TankSwapCoordinator: Automated tank swap detection with taunt rotation and debuff tracking
- CooldownSyncCoordinator: Raid-wide defensive/offensive CD synchronization with priority queuing
- StructuredCombatLog: Ring-buffer combat event logging with DPS/HPS metrics and encounter tracking
- ReagentManager: Reagent/consumable inventory management with auto-purchase and crafting support
- TransmogManager: Per-bot transmog outfit management with appearance collection and themed outfits
- ArchaeologyManager: Full archaeology profession state machine (survey/triangulate/collect/solve)

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:39:57 -03:00
agathoandClaude Opus 4.6 af30e56008 feat(coordination): Add GroupBuffCoordinator for raid-wide buff deduplication
Prevents duplicate raid-wide buff casting when multiple bots of the same
class are in a group. Uses claim-based system: bot claims buff responsibility,
others skip. Tracks 7 WoW 12.0 categories (Intellect, Stamina, Versatility,
Attack Power, Physical/Magic damage, Movement Speed).

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:39:16 -03:00
agathoandClaude Opus 4.6 a967ea495c feat(performance): Add bandwidth telemetry for per-bot network monitoring
Tracks packet counts, bytes sent/received, and filter savings per bot
session. Provides per-opcode breakdown, top-N bots by bandwidth, and
formatted reports. Uses sharded atomic counters for lock-free recording.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:38:36 -03:00
agathoandClaude Opus 4.6 a52471c22a feat(movement): Add swimming and breath management for underwater bots
Tracks water state (DRY/WADING/SWIMMING/UNDERWATER/SURFACING/DROWNING),
monitors breath timer, and triggers proactive surfacing at 30% breath.
Detects water breathing auras and aquatic form availability for druids.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:37:23 -03:00
agathoandClaude Opus 4.6 b06dc3eda7 feat(diagnostics): Add per-bot log filtering for targeted debugging
Enables operators to set verbose log levels (DEBUG/TRACE) for individual
bots without flooding logs from hundreds of other bots. Supports category
filters, timed auto-expiry, and convenience macros (BOT_LOG_DEBUG, etc.).

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:36:50 -03:00
agathoandClaude Opus 4.6 2fe7dfe9e8 feat(combat): Add proc expiry urgency monitor for all classes
Tracks active proc auras and escalates rotation priority when procs are
about to expire unused. Covers all major class procs (Hot Streak, Brain
Freeze, Rime, Art of War, Maelstrom Weapon, etc.) with configurable
urgency thresholds and stack-aware consumption logic.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:36:16 -03:00
agathoandClaude Opus 4.6 93d7da138a feat(social): Add summon/meeting stone response manager for bot summon handling
Bots now auto-respond to warlock summons and meeting stone requests with
human-like delays (1.5-4s randomized). Evaluates combat state, CC, BG/arena,
and group membership before accepting. Tracks summon history and statistics.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:35:17 -03:00
agathoandClaude Opus 4.6 94b8377714 feat(combat): Add racial ability manager for all playable races
Implements RacialAbilityManager with complete database of racial abilities
for all 25+ playable races including TWW Earthen. Evaluates racials by
priority: CC-break > defensive > offensive (burst-aligned) > resource >
AoE CC. Includes spell availability validation, cooldown tracking, burst
window detection, and CC-state awareness.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:34:16 -03:00
agathoandClaude Opus 4.6 194348d4a7 feat(dungeon): Add delve behavior manager for TWW delve content support
Implements DelveBehaviorManager with state machine (IDLE -> ENTERING ->
EXPLORING -> OBJECTIVE -> COMBAT -> BOSS -> LOOTING -> COMPLETED),
tier-aware difficulty scaling (1-11), NPC companion tracking (Brann),
objective tracking, loot chest discovery, and combat behavior adaptation.
Integrates with existing ConsumableManager content type awareness.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:33:19 -03:00
agathoandClaude Opus 4.6 2ddf731715 feat(commands): Add .bot config reload command for hot-reloading configuration
Adds a .bot config reload chat command that reloads playerbots.conf,
synchronizes runtime ConfigManager, refreshes BotSpawner config, and
reloads trade configuration. Reports per-subsystem success/failure with
step counts. Also available from server console.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:32:49 -03:00
agathoandClaude Opus 4.6 baf1155cd5 feat(combat): Add DPS/HPS combat metrics tracker with spell breakdowns
Implements CombatMetricsTracker providing WoW-style damage/healing meters:
rolling-window DPS/HPS/DTPS, per-spell breakdowns with crit rates and
efficiency, encounter tracking with auto-detect, formatted reports for
chat commands, and session history. Uses fixed-size circular buffer for
zero-allocation combat event recording.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:31:57 -03:00
agathoandClaude Opus 4.6 028e29e49c feat(performance): Add thread-safe string interning pool for memory deduplication
Implements StringInterningPool with shared_mutex for read-heavy concurrent access,
FNV-1a hashing, transparent heterogeneous lookup via string_view, and per-category
profiling. Pre-interns common class/spec/resource names at startup. Eliminates
duplicate string allocations across all bot instances (~6.4MB savings at 500 bots).

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:30:55 -03:00
agathoandClaude Opus 4.6 552e674c0a feat(combat): Add proactive LOS fixing with smart repositioning
Implements ProactiveLoSFixer component that intercepts spell cast
attempts, checks LOS, and repositions the bot to a valid position
before casting. Completes all missing LineOfSightManager method
implementations and upgrades MovementIntegration to use smart
position-finding instead of naive movement toward target.

Key additions:
- ProactiveLoSFixer: pre-cast LOS check with queued cast + reposition
- Healer group LOS maintenance: proactive repositioning to see group
- 30+ missing LineOfSightManager method implementations completed
- LoSUtils::DoLinesIntersect segment intersection implementation
- MovementIntegration::CheckLineOfSight upgraded to use FindBestLoSPosition

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:30:10 -03:00
agathoandClaude Opus 4.6 88f3e121fa feat(combat): Add TrinketUsageManager for automated on-use trinket activation
Per-bot component that scans EQUIPMENT_SLOT_TRINKET1/TRINKET2 for
items with ITEM_SPELLTRIGGER_ON_USE effects and activates them at
optimal times during combat:

- Offensive trinkets: aligned with burst/opener windows, then on-CD
- Defensive trinkets: reactive when health drops below 35%
- PvP trinkets: reactive CC-break on stun/fear/charm/confuse
- Utility trinkets: used on cooldown for maximum uptime

Features:
- SpellInfo-based effect classification (aura types determine category)
- Equipment change detection via lightweight checksum comparison
- Cooldown tracking via SpellHistory::HasCooldown()
- CastSpellExtraArgs(item) for proper item-sourced spell casting
- 500ms update throttle to minimize per-bot overhead
- Debug summary for diagnostics

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:29:04 -03:00
agathoandClaude Opus 4.6 8d935c9895 fix(mail): Add MailInteractionManager to build with API fixes
Existing MailInteractionManager (829 lines) was complete but not
compiled. Fixed multiple API issues for TrinityCore 11.x compatibility:

- Add missing DetermineMailRecommendations() declaration in header
- Fix mail ID type: uint32 -> uint64 (matches Mail::messageID)
- Rename inner MailItemInfo to BotMailItemInfo (avoids TC name collision)
- Fix item_guid type: uint32 -> uint64 (ObjectGuid::LowType)
- Fix sender check: mail->sender.IsEmpty() -> mail->sender == 0
- Fix ReturnMail: use MAIL_RETURNED_TO_SENDER + MAIL_CHECK_MASK_RETURNED
- Convert all printf logging (%s/%u/%llu) to fmt-style ({})
- Fix ModifyMoney cast: uint64 -> int64 for money take
- Use module.playerbot log channel consistently
- Add to CMakeLists.txt Interaction section

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:26:22 -03:00
agathoandClaude Opus 4.6 0e16dd2f10 feat(combat): Add CombatPhaseDetector for unified opener/execute phase logic across all 39 specs
Provides per-bot combat phase detection (Opener/Sustained/Execute/Finishing)
with spec-specific thresholds and rotation guidance for all 39 specializations.
Each spec has configured execute threshold (20-35%), opener duration (3-8s),
stealth opener flags, execute spell IDs, opener burst CD sequences, and
resource pooling guidance. Integrates with rotation systems via
ShouldPrioritizeSpell() and IsExecuteAbility() queries.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:25:46 -03:00
agathoandClaude Opus 4.6 365a4843ce feat(perf): Add GUID-sharded metrics collector and replace recursive_mutex with shared_mutex
Introduces ShardedMetricsCollector with 256 independent shards for per-bot
performance metrics (AI decision, combat rotation, target selection, etc.).
Each shard has its own std::shared_mutex enabling parallel reader access
(3-5x faster than recursive_mutex for 500+ bots). Also upgrades the existing
Session/BotPerformanceMonitor to use std::shared_mutex for its system-level
tick metrics, replacing OrderedRecursiveMutex. All read-only operations
(reports, queries, degradation checks) now use shared_lock for zero-contention
concurrent access.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:25:17 -03:00
agathoandClaude Opus 4.6 044aa95ea1 feat(combat): Add PreBurstResourcePooling for resource-aware burst CD preparation
Detects when major burst cooldowns are 3-5 seconds from ready and signals
rotation systems to pool resources (energy/rage/mana/etc.) so bots enter
burst windows at 80-95% resource. Supports all 25+ DPS specs with per-spec
burst CD definitions and progressive pooling intensity (light/moderate/aggressive).

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:23:30 -03:00
agathoandClaude Opus 4.6 fa9268d5be feat(combat): Add context-aware AddPrioritySystem for intelligent add targeting
Automatically classifies nearby hostile creatures by combat role (healer,
explosive, fixate, enraged, shielding, summoner, berserker) using creature
template data and active spell/aura analysis. Generates role-adjusted
priority scores so tanks pick up loose adds, ranged DPS handle explosives,
and all DPS focus healer adds first. Supports M+ affix awareness
(bolstering, bursting, raging, spiteful) and encounter context scaling.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:21:46 -03:00
agathoandClaude Opus 4.6 e76f7068bc feat(combat): Add IncomingDamagePredictor for proactive defensive CD usage
Bridges InterruptAwareness spell cast detection to damage estimation,
enabling bots to trigger defensive cooldowns BEFORE damage lands rather
than reactively after health drops. Three-phase prediction: active spell
casts via SpellInfo analysis, melee attackers via threat list, and
historical DPS extrapolation. Produces time-bucketed forecasts (1/2/3/5s)
with severity classification and role-aware defensive recommendations.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:19:59 -03:00
agathoandClaude Opus 4.6 7450e2cebb feat(validation): Add SpellIdValidator for startup spell ID validation against SpellDB
Two-phase validation system that catches stale/invalid spell IDs at server
startup instead of silently failing during combat:

Phase 1 - ClassSpellDatabase: Validates all spell IDs stored in rotation,
defensive, cooldown, healing tier, fallback chain, and interrupt maps for
all 39 specs across 13 classes.

Phase 2 - Constexpr SpellValidation: Validates ~1925 constexpr spell ID
definitions from SpellValidation_WoW120.h and SpellValidation_WoW120_Part2.h
via per-class registration functions for all 13 classes.

Uses sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE) for validation.
Logs per-spec breakdowns for specs with errors plus aggregate summary.
Called automatically at end of ClassSpellDatabase::Initialize().

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:19:18 -03:00
agathoandClaude Opus 4.6 2c62d3f912 refactor(bg): Migrate all BG bot behavior from BattlegroundAI into individual script ExecuteStrategy()
Replace the broken role-based system (SetRoleRequirement never called, all bots
default to ROAMER) with dynamic behavior trees in each BG script. This extends
the Temple of Kotmogu "lighthouse pattern" to all 13 battlegrounds.

Phase 1 - Shared utilities added to base classes:
- BGScriptBase: EngageTarget, FindNearestEnemyPlayer, PatrolAroundPosition
- CTFScriptBase: RefreshFlagState, RunFlagHome, PickupEnemyFlag, HuntEnemyFC,
  EscortFriendlyFC, DefendOwnFlagRoom, ReturnDroppedFlag
- DominationScriptBase: RefreshNodeState, CaptureNode, DefendNode,
  FindNearestCapturableNode, GetBestAssaultTarget

Phase 2-7 - ExecuteStrategy behavior trees for all 13 BGs:
- CTF: WarsongGulch, TwinPeaks (phase-aware flag priority trees)
- Domination: ArathiBasin (3-cap), BattleForGilneas (2-cap), DeepwindGorge,
  SeethingShore (dynamic nodes), EyeOfTheStorm (hybrid CTF/domination)
- Siege: AlteracValley (phase-based), StrandOfTheAncients, IsleOfConquest
- ResourceRace: SilvershardMines (cart escort + lane control)
- Epic: Ashran (road push with event objectives)

Phase 8 - BattlegroundAI.cpp cleanup:
- Reduced from 2,418 to 429 lines (-82%), header from 463 to 164 lines (-65%)
- Removed all legacy behavior methods, strategy structs, role management
- Kept thin dispatch layer, coordinator registration, profiles, metrics

Key patterns applied from ToK lighthouse:
- GUID-hash duty split for deterministic task distribution
- RefreshState throttled to 1s at top of each ExecuteStrategy
- EngageTarget (SetSelection + Attack) at every engagement point
- Phase-ignoring GO search for dynamically spawned BG objects
- Thin delegation: if (script->ExecuteStrategy(player)) return

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-11 19:18:27 -03:00
agathoandClaude Opus 4.6 d5a2aaf267 feat(consumables): Add ConsumableManager for pre-combat buffing and combat potions
Implements comprehensive consumable management system:
- Pre-combat buffing: flasks/phials, food (Well Fed), augment runes
  with context-aware usage (only in dungeons/raids/delves)
- Combat emergency: health potions at <=30% HP, healthstones at <=35% HP,
  mana potions at <=20% mana for healers/casters
- Combat DPS potions: role-appropriate potions during burst windows
- Content-type detection: Open World, Dungeon, Raid, PvP, Delve
- Role detection: Tank, Healer, Melee DPS, Ranged DPS, Caster DPS

Consumable databases cover TWW, Dragonflight, Shadowlands, BfA, Legion,
WoD, and Classic-era items with priority-based selection (best first).
Buff state detection scans active auras for flask/food/rune patterns.

Per-bot instance owned by GameSystemsManager, updated at REDUCED+ tier
with internal throttling (5s out of combat, 500ms in combat).

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-10 21:48:41 -03:00
agathoandClaude Opus 4.6 901b0d3a63 feat(ai): Complete proc reaction logic for 7 specs missing consumption
Add proc tracking and rotation-integrated consumption for:
- Devastation Evoker: Essence Burst (free Disintegrate/Pyre in ST/AoE/burst)
- Preservation Evoker: Essence Burst (free Emerald Blossom/Verdant Embrace)
- Restoration Shaman: Tidal Waves (2-stack system from Riptide/Chain Heal,
  consumed by Healing Surge for +40% crit or Healing Wave for +20% speed)
- Shadow Priest: Surge of Insanity (from Devouring Plague, consumed as
  Mind Flay: Insanity or Mind Spike: Insanity based on talent detection)
- Subtlety Rogue: Shadow Techniques (passive auto-attack proc granting
  1 combo point + 8 energy with edge detection)
- Guardian Druid: Gore (Mangle reset + 4 extra rage, priority over normal Mangle)
- Restoration Druid: Clearcasting/Omen of Clarity (free instant Regrowth
  on most injured group member)

Also adds GORE, CLEARCASTING_RESTO, SURGE_OF_INSANITY, MIND_FLAY_INSANITY,
MIND_SPIKE_INSANITY, and DEATHSPEAKER spell IDs to validation registries.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-10 21:46:41 -03:00
agathoandClaude Opus 4.6 9bfd9312ee feat(ai): Add hero talent rotation integration for all 39 specializations
Implements runtime hero talent detection and rotation branches for every
WoW 12.0 specialization. Each spec's UpdateRotation() now lazily detects
the bot's hero talent tree via HeroTalentCache and prioritizes the
corresponding hero-talent-specific ability before the standard rotation.

Hero talent mappings per class:
- Warrior: Slayer/Mountain Thane (Arms), Slayer/Mountain Thane (Fury), Colossus/Mountain Thane (Prot)
- Paladin: Herald of the Sun/Lightsmith (Holy), Lightsmith/Templar (Prot), Templar/Herald of the Sun (Ret)
- DK: Deathbringer/Rider of the Apocalypse (Blood), Deathbringer/Rider (Frost), San'layn/Rider (Unholy)
- DH: Aldrachi Reaver/Fel-Scarred (Havoc), Aldrachi Reaver/Fel-Scarred (Vengeance)
- Druid: Keeper of the Grove/Elune's Chosen (Balance), Druid of the Claw/Wildstalker (Feral),
         Druid of the Claw/Elune's Chosen (Guardian), Keeper of the Grove/Wildstalker (Resto)
- Evoker: Flameshaper/Scalecommander (Dev), Chronowarden/Flameshaper (Pres), Chronowarden/Scalecommander (Aug)
- Hunter: Pack Leader/Dark Ranger (BM), Sentinel/Dark Ranger (MM), Pack Leader/Sentinel (SV)
- Mage: Spellslinger/Sunfury (Arcane), Frostfire/Sunfury (Fire), Frostfire/Spellslinger (Frost)
- Monk: Conduit of the Celestials/Shado-Pan (BrM), Conduit/Master of Harmony (MW),
        Conduit/Shado-Pan (WW)
- Priest: Oracle/Voidweaver (Disc), Oracle/Archon (Holy), Voidweaver/Archon (Shadow)
- Rogue: Deathstalker/Fatebound (Assassination), Trickster/Fatebound (Outlaw),
         Deathstalker/Trickster (Subtlety)
- Shaman: Farseer/Stormbringer (Elemental), Totemic/Stormbringer (Enhancement),
          Farseer/Totemic (Restoration)
- Warlock: Hellcaller/Soul Harvester (Affliction), Diabolist/Soul Harvester (Demonology),
           Hellcaller/Diabolist (Destruction)

Also fixes:
- BGScriptBase.cpp/CTFScriptBase.cpp: Add missing BGSpatialQueryCache.h include
- BotMovementManager.h: Fix PathCache.h include path ambiguity

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-10 21:46:12 -03:00
agathoandClaude Opus 4.6 a91933499c feat(perf): Add save tiering, differential saves, idle memory reduction, and anti-cluster dispersal
Implement 4 enhancement gaps identified from mod-playerbots comparison:
- P6: Budget-tier-based save frequency (FULL=5min, REDUCED=15min, MINIMAL=30min)
- P3: Coarse differential saves skip unchanged bot state (FNV-1a checksums)
- P5: ObjectCache::ClearNonEssential() prunes caches on MINIMAL transition
- R1: BotClusterDetector disperses 8+ bot clusters via MoveRandom

Also fixes pre-existing PathCache.h/.cpp shared_lock/unique_lock type
mismatch with OrderedSharedMutex (CTAD fix).

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Signed-off-by: luis <[email protected]>
2026-02-10 21:45:21 -03:00