Skip to content

Addon: [1.10.0] - Per-slot cast time and HasCastBar/Item inference#799

Merged
Xian55 merged 5 commits intodevfrom
feature/actionbarslot-infer-castbar
Apr 27, 2026
Merged

Addon: [1.10.0] - Per-slot cast time and HasCastBar/Item inference#799
Xian55 merged 5 commits intodevfrom
feature/actionbarslot-infer-castbar

Conversation

@Xian55
Copy link
Copy Markdown
Owner

@Xian55 Xian55 commented Apr 27, 2026

Summary

  • Auto-detect HasCastBar/Item routing from the addon. New per-slot cast time queue (cell 112) driven by GetSpellInfo / GetItemSpell — so cast routing tracks talents (e.g. 5/5 Improved Corruption flips Corruption to instant without a JSON edit). Item flag is derived from IsAutoRepeatAction + macro-wraps-item detection, which also picks up Shoot/Auto Shot without Item:true in JSON. JSON HasCastBar/Item fields are still parsed for back-compat but ignored by the routing.
  • Per-spell cast event queue (cells 113/114). Replaces the global lastCastEvent cell as the source of truth for item / auto-repeat retries. Closes the gap where an ERR_BADATTACKFACING was overwritten by a later pet-cast / auto-shoot success on the global cell and masked the failure. CastEventReader.TryConsume(spellId) reads + clears so a stale event from a previous attempt can't fire twice.
  • Supporting fixes. Cold-start init race that left class-conditional tables empty until /reload; kill-credit cleared per UNIT_DIED instead of on combat exit; miss/parry/dodge damage now sources the attacker; SpellInQueue rewritten for actual GCD-tail queueing (was gating on HalfSpellQueueTimeMs which both wasted presses and skipped the SQW window).
  • Frontend visualization. GoapGoalView paints the casting row as a left→right yellow gradient that fills with RemainCastMs. SpellBookComponent gains an Action Bar panel listing every populated slot with cast time and routing badge (CastInstant / CastCastbar), and the spellbook table shows cast time per spell.
  • New Wrath Classic build target (DataToColor_Wrath.toc, interface 34300). Addon version bumped to 1.10.0 across all toc files (frame count 114 → 117 for the three new cells).
  • Profiles. Warlock_66_Demo_pet_pull migrated to AfterCastWaitCastbar + Interrupt/CancelOnInterrupt rules, switched to Items_Healthstone array. Warlock_1 introduces IntVariables for thresholds. New Warlock_1_10 profile added.

Test plan

  • Run with Warlock_66_Demo_pet_pull and confirm cast-time spells (Shadow Bolt, Incinerate, Drain Life, Health Funnel) route through CastCastbar with the new visualization filling the row.
  • With 5/5 Improved Corruption talented, confirm Corruption routes through CastInstant (not CastCastbar) — visible as the "Instant" badge in the SpellBook Action Bar panel.
  • Hunter / Warlock with wand: fire Auto Shot / Shoot from out-of-range and confirm ERR_BADATTACKFACING / OUT_OF_RANGE retries fire (no false success masking even when a pet cast or auto-shoot tick lands between polls).
  • SpellBook view: confirm Action Bar panel populates on login, updates on slot rebind, and badges match game state. Cast Time column on the spellbook table populates for slot-bound spells.
  • GoapGoalView: confirm the casting row paints a left→right gradient that completes with the cast bar; no double-paint with table-warning highlight.
  • Cold-start: load addon before PLAYER_ENTERING_WORLD finishes (e.g. quick relog) and confirm Pull/Combat range bits set correctly without /reload.
  • Wrath Classic 3.4.3 client: verify DataToColor_Wrath.toc loads and the addon emits frames.
  • CombatGoal: while a cast is in progress, confirm items / auto-repeat actions are skipped (no ERR_SPELL_FAILED_ANOTHER_IN_PROGRESS spam) but cast-time spells still queue via the SQW window.

🤖 Generated with Claude Code

Xian55 and others added 5 commits April 27, 2026 21:32
…/lifecycle fixes

Per-slot cast time queue (cell 112)
- populateActionbarCastTime queries GetSpellInfo / GetItemSpell per action
  bar slot. Encoded as slotIndex*100000 + castTimeMs, with an item-flag
  offset of 50000 added when the slot resolves to an item, a macro that
  wraps an item, or an auto-repeat action (Auto Shot, Shoot).
- Lets the bot derive HasCastBar / Item routing from live game state
  instead of JSON declarations, including talent-modified casts (e.g. 5/5
  Improved Corruption flipping Corruption to instant).
- Hooked into ActionbarSlotChanged so removed/replaced slots clear stale
  state (publish 0 on empty slot).

Per-spell cast event queue (cells 113, 114)
- TimedQueue of encoded (spellId, eventCode) pairs drained one-per-tick
  into cell 113, plus a monotonic seq counter on cell 114 so the bot can
  detect repeats (same encoded value pushed twice).
- PushCastEvent wired into UNIT_SPELLCAST_SENT/SUCCEEDED/FAILED and
  SoM_OnCastStart, plus the combat-log SPELL_CAST_FAILED branch (which
  carries the failure reason via select(15, ...)).
- Replaces the global lastCastEvent cell as the source of truth for
  per-action result, since the global cell is overwrite-prone when
  events fire close together (pet cast, auto-shoot tick, etc.).
- Layout: encoded = spellId%65536 + eventCode*65536. Codes 251/252/253
  map to CAST_SENT/CAST_START/CAST_SUCCESS; codes 1..18 are direct
  errorList indices (BADATTACKFACING, OUT_OF_RANGE, ...).

Cold-start init fix
- Wrap player class/race detection in DataToColor:DetectPlayerCharacter()
  and re-run it from OnEnteringWorld. The addon-load-time read in
  Constants.lua may run before UnitClass returns valid data on a cold
  start, leaving every class-conditional table empty (e.g.
  S.spellInRangeTarget) until /reload — symptom: Pull/Combat range
  always false, autoattack never engages.
- Re-run InitStorage on OnEnteringWorld and FushState so class-keyed
  tables get rebuilt against the now-known class.
- Reorder OnSpellsChanged to call PopulateSpellBookInfo first so the
  icon->id map is fresh before InitActionBarCostQueue / range refresh
  read it. Without this the map can be stale if SPELLS_CHANGED hasn't
  fully synced yet — symptom: Warlock spell range bit never sets.

Kill-credit + miss-source fixes
- Clear eligibleKillCredit[destGUID] at UNIT_DIED instead of wiping the
  whole table on OnLeftCombat. Prevents losing eligibility for kills
  landed in the same encounter and keeps per-target tracking clean.
- Include playerDamageMiss alongside playerDamageTakenEvents in the
  source-damage filter so missed/parried/dodged hits still register the
  attacker for combat threat tracking.

Frame count bumped 114 -> 117 to accommodate cells 112, 113, 114.
New DataToColor_Wrath.toc target for Wrath Classic (interface 34300).
Version bumped to 1.10.0 across all toc files.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ActionBarCastTimeReader (cell 112)
- Decodes the per-slot cast time the addon publishes each tick into a
  fixed-size array keyed by slot index. Cast time is castTimeMs % 50000;
  values >= 50000 carry the item-flag offset, which the addon sets for
  true items, macros wrapping items, and auto-repeat actions (Shoot,
  Auto Shot).
- Public surface: Get(KeyAction) / HasCastBar(KeyAction) / IsItem(KeyAction)
  for the casting pipeline, plus GetBySlotIndex(int) so frontend views
  can scan all slots without a KeyAction in hand.
- Replaces JSON-driven HasCastBar/Item declarations once consumers are
  wired through (next commit). Talent-aware: a spell that becomes
  instant via talents is observed as castTimeMs == 0.

CastEventReader (cells 113, 114)
- Maintains a per-spell-id event log by draining cell 113 (encoded
  spellId+eventCode) gated on cell 114 (monotonic sequence). The seq
  counter lets the reader distinguish a fresh push of the same encoded
  value from an unchanged repeat tick, which a value-only watch would
  miss.
- Public surface:
  - Latest(spellId): peek the most recent event for a spell without
    consuming it.
  - TryConsume(spellId, out ev): peek + clear, so a stale event from a
    previous attempt can't fire twice on a later cast of the same
    spell.
- Sentinel event codes 251/252/253 are remapped on read back to
  UI_ERROR.CAST_SENT/CAST_START/CAST_SUCCESS so consumers compare
  against the same enum used by the global CastState reader.

DI wiring
- Both registered as forwarded singletons that also satisfy IReader, so
  the AddonReader update loop ticks them every frame (AddAddonComponents
  + AddStartupIoC). Mirror the existing ActionBarCostReader / CooldownReader
  registration pattern.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…t log

Cast routing now reads the addon
- HasCastBar / Item routing decisions in CastingHandler now read
  castTimeReader.HasCastBar(item) / castTimeReader.IsItem(item) at every
  call site (CastInstant strategy selection, BeforeCastDelay stop-moving
  guard, AfterCast GCD pad). KeyAction.HasCastBar / KeyAction.Item JSON
  fields are no longer consulted by the routing — a talented-instant
  spell now skips the cast-bar wait without the user touching JSON, and
  a wand/auto-shot is auto-detected as item-like via IsAutoRepeatAction.

Per-spell event consumption for items
- After CAST_SENT for an item / auto-repeat action, briefly wait
  (DoubleNetworkLatency) for either Any_AutoAttack to toggle (success
  signal) or UIErrorTime to advance (failure echoed via combat log).
  Then call castEventReader.TryConsume(item.SpellId) to read this
  item's most recent event without cross-spell contamination.
- Closes the gap where a BADATTACKFACING was overwritten by a later
  pet-cast/auto-shoot success on the global CastEvent cell, masking
  the failure and letting the bot believe the attack landed.
- Falls back to the global CastEvent cell when item.SpellId == 0 (item
  never fired before, or no known spell ID), with a cross-spell guard
  on CastSpellId.
- New private static WaitForItemCastResolution helper extracted to keep
  CastInstant readable (mirrors existing WaitCurrentAction shape).

SpellInQueue() rewritten for actual GCD-tail queueing
- Old: returned true while GCD < HalfSpellQueueTimeMs, which both
  wasted presses before the SQW window opened and skipped the SQW
  window itself — the bot would never queue against the GCD boundary.
- New: returns true while RemainCastMs > SQW or GCD > SQW. Inside the
  last SQW ms of the cast/GCD, returns false so the next press queues
  against the WoW SpellQueueWindow CVar window.

Cast-bar wait floor
- AfterCastWaitCastbar now uses Max(actual remaining, expected from
  cast-time reader) - SQW. A press that hasn't been observed by the
  cast-bar reader yet still gets the right wait floor instead of
  returning early on stale RemainCastMs == 0.

CombatGoal: gate items during in-progress casts
- Skip non-base items / auto-repeat actions while playerReader.IsCasting().
  These can't queue at the server (ERR_SPELL_FAILED_ANOTHER_IN_PROGRESS)
  so pressing them just wastes input. Cast-time spells can still queue
  via SQW so they're not gated.

README
- HasCastBar field documented as auto-detected from GetSpellInfo. The
  JSON field is still parsed (back-compat) but ignored by routing. The
  example block updated to drop the explicit HasCastBar=true.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
GoapGoalView
- Highlight the currently-casting goal/key row with a left-to-right
  yellow gradient that grows as RemainCastMs ticks down. Filled colour
  matches Bootstrap's table-warning solid (#ffc107) so the row still
  reads as "the bot is doing this", and the empty section uses
  table-warning subtle (#fff3cd) so it stays visually consistent with
  the standard selected-row highlight.
- Detection: SpellId match against playerReader.SpellBeingCast, falling
  through when SpellId == 0 (key never cast yet) or when not casting.
- New cast-bar-row class + scoped style block forces transparent table
  cells so the row-level inline gradient shows through Bootstrap's
  per-cell --bs-table-bg. transition on background-image keeps the
  paint smooth at the addon's poll rate.
- Helper RowClass(current, cooldown, casting) suppresses the existing
  table-warning/table-info paint while a row is casting so the gradient
  is the only visible background.

SpellBookComponent
- New "Action Bar" panel listing every populated slot with: slot
  number, icon, resolved name (via texture -> spell name lookup),
  cast time in ms + seconds, and a routing badge (CastInstant /
  CastCastbar). Rebuilt on AddonDataChanged and TextureChanged so
  newly-bound slots appear without a manual refresh.
- Header counters: Populated / Instant / Cast Bar so the user can
  sanity-check at a glance that talents are being respected (e.g. an
  Improved Corruption Warlock should show Corruption under Instant).
- Spellbook table extended with a Cast Time column. Cast time is
  attributed via shared-texture lookup (BuildSpellCastTimeLookup): all
  ranks of a spell share the same texture, so any rank that's bound to
  a slot lights up cast time for every rank. Spells unbound to any
  slot show "—" with a tooltip explaining the source.
- Replaced the inline GetSortedSpells call site with a cached
  cachedSpells list rebuilt on hash change, so repeated re-renders
  during a single tick don't re-sort the spell list.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…l 10

Warlock_66_Demo_pet_pull
- Replace HasCastBar:true with AfterCastWaitCastbar:true on cast-time
  spells. HasCastBar is now derived by the bot from the addon's per-slot
  cast time, so leaving it in is just noise; AfterCastWaitCastbar is the
  setting that actually changes behaviour (wait for the cast bar to
  finish before evaluating the next entry).
- Add Interrupt + CancelOnInterrupt rules on Drain Soul, Drain Life,
  Health Funnel, Immolate, Incinerate, Shadow Bolt so wasted casts
  abort early when the precondition flips (target dies, dot already
  applied, pet healed, mana threshold hit, Shadow Trance proc available).
- Switch Item_Healthstone (single id) to Items_Healthstone (array of all
  15 healthstone item IDs across ranks/qualities). The new IntVariable-
  array form lets BagItem:Items_Healthstone match any rank in inventory.
- Add DRAIN_STOP_HP% (90) and FUNNEL_STOP_PET_HP% (90) thresholds for
  the new Interrupt expressions.
- New User Wait gate so the rotation pauses when the menu or chat input
  is open (MenuOpen || ChatInputVisible).
- Drop Item:true / PressDuration on Shoot — auto-detected now, since
  IsAutoRepeatAction marks the slot as item-like and the bot picks the
  right press-duration default.

Warlock_1
- Introduce IntVariables (MIN_WATER%=20, MIN_MANA_SHADOWBOLT%=40) so
  thresholds are tweakable in one place. Replace the magic 50% on
  Food/Drink with MIN_WATER%, gate Shadow Bolt on MIN_MANA_SHADOWBOLT%
  in both Pull and Combat.
- Refine engagement: gate AutoAttack on InMeleeRange (don't spam
  AutoAttack from out of range), refine Approach to !MeleeSwinging
  (don't reposition mid-swing) and !SoftTargetDead (don't chase a
  corpse). TargetHealth%>20 added on Combat Shadow Bolt to stop
  burning mana on a dying mob.
- Comment out PathFilename on the Repair / Sell vendor entries.

Warlock_1_10
- New profile for Warlock at level 10.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Xian55 Xian55 added documentation Improvements or additions to documentation enhancement This pull request implements a new feature. ai Artificial Intelligence tool has been contributed. labels Apr 27, 2026
@Xian55 Xian55 merged commit 14c1485 into dev Apr 27, 2026
1 check passed
@Xian55 Xian55 deleted the feature/actionbarslot-infer-castbar branch April 27, 2026 19:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai Artificial Intelligence tool has been contributed. documentation Improvements or additions to documentation enhancement This pull request implements a new feature.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant