Skip to content

MultiBot: improve bridge synchronization, strategy controls and persistent favorites - #49

Merged
Wishmaster117 merged 4 commits into
mainfrom
MultiBot-improve-bridge-synchronization,-strategy-controls-and-persistent-favorites
Aug 7, 2026
Merged

MultiBot: improve bridge synchronization, strategy controls and persistent favorites#49
Wishmaster117 merged 4 commits into
mainfrom
MultiBot-improve-bridge-synchronization,-strategy-controls-and-persistent-favorites

Conversation

@Wishmaster117

@Wishmaster117 Wishmaster117 commented Aug 7, 2026

Copy link
Copy Markdown
Owner

Summary

This PR consolidates the current MultiBot addon-side work for the gradual migration from legacy chat-driven bot control toward the MultiBot Bridge architecture.

The main goals are to improve bridge synchronization, make strategy controls more reliable, and keep bot/favorite UI state consistent across connection changes and reloads.

Main changes

Bridge-backed bot state

  • Improves synchronization between the addon roster and bridge-provided bot state.
  • Keeps existing bot buttons updated when bridge roster information changes.
  • Uses bridge classId and level information to refresh:
    • class icon;
    • localized class tooltip;
    • bot level;
    • runtime button metadata.
  • Preserves the existing addon behavior for functionality that has not yet been migrated away from chat.

Strategy controls

  • Improves strategy state synchronization and refresh behavior.
  • Keeps strategy UI state consistent after bridge commands and acknowledgements.
  • Validated with multiple classes and strategy operations, including:
    • loot;
    • gather;
    • tank assist;
    • cure.

Favorites

  • Favorites stored in SavedVariables can now be represented in the Favorites roster even when the bot is offline.
  • Offline favorite buttons remain clickable and can still be used to connect the bot.
  • Favorite buttons are reused when the corresponding bot becomes available instead of requiring a UI reload.
  • Fixes the case where connecting several favorite bots successively could leave the second bot without its class bar until /reload.

Favorite metadata synchronization

  • Bot details received from the bridge are persisted through the existing global bot store.
  • Normalizes bridge gender metadata to the format already expected by the addon store:
    • Male -> [M]
    • Female -> [F]
  • Reuses the existing profile.bots SavedVariables structure instead of introducing another persistence table.
  • Requests bot details when required to populate metadata for newly added favorites.
  • Adds a bounded/rearmable roster refresh after connecting an offline favorite so successive bot connections are detected without an addon reload.

Compatibility

Target environment:

  • World of Warcraft 3.3.5a
  • AzerothCore WotLK
  • mod-playerbots
  • mod-multibot-bridge

No modern WoW Lua APIs are introduced.

Validation

Validated with:

  • addon reloads;
  • reconnects;
  • offline favorites;
  • successive connection of multiple favorite bots;
  • class icon/tooltip refresh;
  • persisted bot metadata;
  • strategy enable/disable operations;
  • multiple bots;
  • zero Lua errors during the final in-game tests.

The latest Favorites synchronization runtime test confirmed:

  • offline favorite buttons: OK;
  • successive bot connections: OK;
  • second bot bar without /reload: OK;
  • class icon synchronization: OK;
  • class tooltip synchronization: OK;
  • Lua errors: none.

Scope

This PR intentionally does not attempt to remove every remaining chat-based Playerbots command.

The migration is incremental: legacy chat mechanisms are kept where a validated bridge replacement is not available yet.

Summary by CodeRabbit

  • New Features

    • Added automatic class-based group formation with invitations, retries, timeouts, and roster tracking.
    • Improved favorite roster handling, including offline favorites and refreshed class, level, and gender details.
    • Added synchronized strategy updates for targets and groups when supported.
    • Added reliable state transfers with validation, acknowledgements, timeout handling, and fallback support.
  • Bug Fixes

    • Favorites now refresh correctly when reopening or refreshing the Units display.
    • Unit buttons immediately reflect saved detail changes.

…stent favorites

## Summary

This PR consolidates the current MultiBot addon-side work for the gradual migration from legacy chat-driven bot control toward the MultiBot Bridge architecture.

The main goals are to improve bridge synchronization, make strategy controls more reliable, and keep bot/favorite UI state consistent across connection changes and reloads.

## Main changes

### Bridge-backed bot state

- Improves synchronization between the addon roster and bridge-provided bot state.
- Keeps existing bot buttons updated when bridge roster information changes.
- Uses bridge `classId` and level information to refresh:
  - class icon;
  - localized class tooltip;
  - bot level;
  - runtime button metadata.
- Preserves the existing addon behavior for functionality that has not yet been migrated away from chat.

### Strategy controls

- Improves strategy state synchronization and refresh behavior.
- Keeps strategy UI state consistent after bridge commands and acknowledgements.
- Validated with multiple classes and strategy operations, including:
  - loot;
  - gather;
  - tank assist;
  - cure.

### Favorites

- Favorites stored in SavedVariables can now be represented in the Favorites roster even when the bot is offline.
- Offline favorite buttons remain clickable and can still be used to connect the bot.
- Favorite buttons are reused when the corresponding bot becomes available instead of requiring a UI reload.
- Fixes the case where connecting several favorite bots successively could leave the second bot without its class bar until `/reload`.

### Favorite metadata synchronization

- Bot details received from the bridge are persisted through the existing global bot store.
- Normalizes bridge gender metadata to the format already expected by the addon store:
  - `Male` -> `[M]`
  - `Female` -> `[F]`
- Reuses the existing `profile.bots` SavedVariables structure instead of introducing another persistence table.
- Requests bot details when required to populate metadata for newly added favorites.
- Adds a bounded/rearmable roster refresh after connecting an offline favorite so successive bot connections are detected without an addon reload.

## Compatibility

Target environment:

- World of Warcraft 3.3.5a
- AzerothCore WotLK
- mod-playerbots
- mod-multibot-bridge

No modern WoW Lua APIs are introduced.

## Validation

Validated with:

- addon reloads;
- reconnects;
- offline favorites;
- successive connection of multiple favorite bots;
- class icon/tooltip refresh;
- persisted bot metadata;
- strategy enable/disable operations;
- multiple bots;
- zero Lua errors during the final in-game tests.

The latest Favorites synchronization runtime test confirmed:

- offline favorite buttons: OK;
- successive bot connections: OK;
- second bot bar without `/reload`: OK;
- class icon synchronization: OK;
- class tooltip synchronization: OK;
- Lua errors: none.

## Scope

This PR intentionally does not attempt to remove every remaining chat-based Playerbots command.

The migration is incremental: legacy chat mechanisms are kept where a validated bridge replacement is not available yet.
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 841b7509-48db-43df-8be4-18c98ccde72c

📥 Commits

Reviewing files that changed from the base of the PR and between 197f72d and e67f2da.

📒 Files selected for processing (2)
  • Core/MultiBot.lua
  • Core/MultiBotComm.lua
🚧 Files skipped from review as they are similar to previous changes (2)
  • Core/MultiBotComm.lua
  • Core/MultiBot.lua

📝 Walkthrough

Walkthrough

The PR adds favorite synchronization, class-based auto-group transactions, framed bridge state transfers, and validated bridge strategy mutations. Engine actions use bridge execution when available and retain chat fallbacks.

Changes

Favorites and Auto-Group

Layer / File(s) Summary
Favorite metadata and roster synchronization
Core/MultiBot.lua, UI/MultiBotUnitsRootUI.lua, .luacheckrc
Favorites resolve class and level metadata, maintain hidden offline placeholders, refresh roster data, normalize persisted gender values, and update unit buttons.
Class-based auto-group transactions
Core/MultiBot.lua
The add-class wrapper starts transactions that detect roster candidates, retry invitations, enforce pending limits and timeouts, convert raids when needed, and process roster updates.

Bridge State and Strategy Transactions

Layer / File(s) Summary
Framed state transfer protocol
Core/MultiBotComm.lua
Capability negotiation enables bounded, tokenized state transactions with validation, duplicate and freshness checks, size limits, abort handling, and legacy fallback.
Strategy mutation commands and acknowledgements
Core/MultiBotComm.lua
RunStrategyCommand validates changes, tracks pending commands, processes acknowledgements and errors, and resets transaction state on disconnect or world entry.
Engine bridge routing and fallback
Core/MultiBotEngine.lua
Target, party, and raid actions use bridge strategy mutations when supported. Existing chat fallbacks remain available.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MultiBotUnitsRootUI
  participant MultiBot
  participant Bridge
  MultiBotUnitsRootUI->>MultiBot: UpdateFavoritesIndex()
  MultiBot->>MultiBot: EnsureFavoriteButtons()
  MultiBot->>Bridge: request favorite roster data
  Bridge->>MultiBot: roster response
  MultiBot->>MultiBotUnitsRootUI: update favorite button metadata
Loading
sequenceDiagram
  participant MultiBotEngine
  participant MultiBotComm
  participant Bridge
  MultiBotEngine->>MultiBotComm: RunStrategyCommand(scope, target, stateScope, changes)
  MultiBotComm->>Bridge: send strategy mutation
  Bridge->>MultiBotComm: STRATEGY_ACK or protocol error
  MultiBotComm->>MultiBotEngine: invoke mutation callback
  MultiBotEngine->>MultiBotComm: request state refresh
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the pull request's main changes to bridge synchronization, strategy controls, and persistent favorites.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch MultiBot-improve-bridge-synchronization,-strategy-controls-and-persistent-favorites

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3591f232db

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Core/MultiBotComm.lua

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (5)
Core/MultiBot.lua (2)

1510-1622: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Optional: remove the duplicated time and name helpers.

GetAddClassAutoGroupNow and NormalizeAddClassAutoGroupName duplicate GetFavoriteRosterRefreshNow and NormalizeFavoriteRosterRefreshName at lines 1338-1356. The bodies are identical. Extract one shared local pair and reuse it in both blocks.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Core/MultiBot.lua` around lines 1510 - 1622, Remove the duplicate helper
definitions GetAddClassAutoGroupNow and NormalizeAddClassAutoGroupName, and
extract a single shared local implementation from the equivalent
GetFavoriteRosterRefreshNow and NormalizeFavoriteRosterRefreshName helpers.
Update both the favorite roster refresh flow and the add-class auto-group flow
to call the shared helpers without changing their behavior.

1645-1652: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Use GetNumRaidMembers for raid detection.

IsInRaid is not part of the WoW 3.3.5a API, so the type guard makes inRaid false in that client. Use GetNumRaidMembers() and set inRaid from that count before applying the party-count condition.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Core/MultiBot.lua` around lines 1645 - 1652, Update the raid detection in the
surrounding conversion logic to use GetNumRaidMembers() rather than IsInRaid,
setting inRaid from the returned raid-member count before evaluating the
partyCount >= 4 condition. Preserve the existing ConvertToRaid call and delay
behavior.

Source: Coding guidelines

Core/MultiBotComm.lua (3)

314-337: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Consider a longer or progress-based deadline for global state transactions.

scheduleStateTimeout applies the same fixed STATE_TIMEOUT_SECONDS = 5.0 to a single-bot request and to a global STATES request. A global request can carry up to STATE_MAX_BOTS = 128 bots, and each bot needs STATE_BEGIN, one STATE_ITEM per strategy, and STATE_END. Addon message throughput is throttled by the client, so a large roster can exceed 5 seconds. When the timer fires, clearStateRequest drops the request and all later frames are discarded, so the roster silently keeps stale states.

Two options: use a larger timeout for global requests, or refresh the deadline whenever a frame for that token arrives.

♻️ Sketch: separate the global deadline
-local function scheduleStateTimeout(token)
+local function scheduleStateTimeout(token, isGlobal)
   if not (MultiBot and type(MultiBot.TimerAfter) == "function") then
     return
   end
 
-  MultiBot.TimerAfter(STATE_TIMEOUT_SECONDS, function()
+  local timeout = isGlobal and STATES_TIMEOUT_SECONDS or STATE_TIMEOUT_SECONDS
+  MultiBot.TimerAfter(timeout, function()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Core/MultiBotComm.lua` around lines 314 - 337, Update scheduleStateTimeout
and its caller beginStateRequest so global state requests use a longer deadline
than single-bot requests, while preserving STATE_TIMEOUT_SECONDS for single-bot
requests. Ensure the timeout selection is based on the isGlobal flag and the
resulting timer still clears the request and records STATE_TIMEOUT~token when
the applicable deadline expires.

4239-4255: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider handling the STATE request type in the same ERR branch.

The branch resolves a pending strategy mutation when requestType == "STRATEGY". A protocol error for a framed state request leaves the entry in state.stateRequests until scheduleStateTimeout fires 5 seconds later. Calling clearStateRequest for requestType == "STATE" would free the slot against STATE_MAX_ACTIVE immediately.

This branch also uses the lenient urlDecodeField, while the framed handlers use urlDecodeFieldStrict. Using the strict decoder here keeps the parsing rules uniform.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Core/MultiBotComm.lua` around lines 4239 - 4255, Update the ERR parsing
branch around requestType to use urlDecodeFieldStrict for the request type and
reason, and handle requestType == "STATE" by calling clearStateRequest with the
parsed token and protocol-error reason. Preserve the existing STRATEGY
finishStrategyMutationCommand behavior and error fields.

666-736: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Comm.RunStrategyCommand returns a token string, not a boolean. Confirm the contract with all callers.

The function returns false for every rejection and a token string on success. Core/MultiBotEngine.lua handles this with token ~= false and token ~= nil, which is correct. Confirm no other caller assumes a boolean.

Also consider recording the outbound token in state.lastError-independent diagnostics is not needed; the current failure paths return false without a reason, so the caller cannot distinguish "not connected" from "too many active commands". Setting state.lastError on the rejection paths, as Comm.RequestState does with STATE_TOO_MANY_REQUESTS, would make the failures observable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Core/MultiBotComm.lua` around lines 666 - 736, Audit all callers of
Comm.RunStrategyCommand and preserve its token-or-false contract, updating any
caller that treats the result as a boolean; retain the existing token handling
in MultiBotEngine.lua. Add distinct state.lastError diagnostics for each
rejection path, including disconnected/incapable state, invalid inputs, missing
changes, and active-command limits, following the pattern used by
Comm.RequestState.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Core/MultiBot.lua`:
- Around line 2046-2048: Update the bracketed-value pass-through condition in
BuildBridgeDetailStoreValue to reject any value containing a comma, allowing
only bracketed strings without commas to return unchanged. Preserve the existing
handling for non-bracketed and comma-free values so cached metadata fields
remain correctly aligned when GetFavoriteCachedMetadata splits them.
- Around line 1461-1507: Update UpdateBridgeUnitButton so an unknown or missing
incoming class does not overwrite an existing resolved button.class; retain the
prior class instead. When preserving that known class, also skip the
unknown-class presentation update so the existing icon and metadata remain
unchanged, while still applying valid incoming class values normally.
- Around line 2034-2051: Update NormalizeBridgeDetailStoreGender to explicitly
map the bridge’s numeric gender convention, using 0 for male and 1 for female as
documented by the add-class command comment. Preserve the existing textual
mappings, bracketed-value handling, and "[?]" fallback.

In `@Core/MultiBotComm.lua`:
- Around line 1505-1506: Update Comm.MarkDisconnected to drain all entries in
state.strategyMutationCommands through finishStrategyMutationCommand with a
terminal result before clearing the table, so registered callbacks and waiting
callers are completed. Also reset stateFramingCapable and clear stateRequests,
stateActive, and stateLatestByBot alongside the existing capability reset,
preventing framed state requests until the next capability announcement.
- Around line 4101-4119: Update the STRATEGY_ACK parsing flow to decode field 8
with empty values allowed, so successful acknowledgements with reason "" pass
validation while timeout reasons such as "TIMEOUT" remain supported. Change the
allowEmpty argument in urlDecodeFieldStrict and preserve the existing validation
and STRATEGY_ACK_INVALID handling for genuinely missing or invalid fields.
- Around line 1843-1856: Update Comm.ApplyStateAbortPayload to decode fields[2]
as the targeted bot name and abort only that bot’s transaction for the token,
rather than calling abortStateRequest in a way that clears every matching
transaction. Preserve fields[1] as the token and fields[3] as the reason, and
leave other bot transactions for the same request active.

In `@Core/MultiBotEngine.lua`:
- Around line 500-523: Update _mbRunBridgeStrategyMutation to handle
acknowledgement failures such as no_match, failed, timeout, and error instead of
only reacting to result.matched > 0. Reuse the established FORMATION_ACK failure
behavior to notify the user or restore the affected UI state, while preserving
successful state-refresh handling for matched mutations and ensuring callers do
not leave optimistic button or toggle state applied after rejection.

---

Nitpick comments:
In `@Core/MultiBot.lua`:
- Around line 1510-1622: Remove the duplicate helper definitions
GetAddClassAutoGroupNow and NormalizeAddClassAutoGroupName, and extract a single
shared local implementation from the equivalent GetFavoriteRosterRefreshNow and
NormalizeFavoriteRosterRefreshName helpers. Update both the favorite roster
refresh flow and the add-class auto-group flow to call the shared helpers
without changing their behavior.
- Around line 1645-1652: Update the raid detection in the surrounding conversion
logic to use GetNumRaidMembers() rather than IsInRaid, setting inRaid from the
returned raid-member count before evaluating the partyCount >= 4 condition.
Preserve the existing ConvertToRaid call and delay behavior.

In `@Core/MultiBotComm.lua`:
- Around line 314-337: Update scheduleStateTimeout and its caller
beginStateRequest so global state requests use a longer deadline than single-bot
requests, while preserving STATE_TIMEOUT_SECONDS for single-bot requests. Ensure
the timeout selection is based on the isGlobal flag and the resulting timer
still clears the request and records STATE_TIMEOUT~token when the applicable
deadline expires.
- Around line 4239-4255: Update the ERR parsing branch around requestType to use
urlDecodeFieldStrict for the request type and reason, and handle requestType ==
"STATE" by calling clearStateRequest with the parsed token and protocol-error
reason. Preserve the existing STRATEGY finishStrategyMutationCommand behavior
and error fields.
- Around line 666-736: Audit all callers of Comm.RunStrategyCommand and preserve
its token-or-false contract, updating any caller that treats the result as a
boolean; retain the existing token handling in MultiBotEngine.lua. Add distinct
state.lastError diagnostics for each rejection path, including
disconnected/incapable state, invalid inputs, missing changes, and
active-command limits, following the pattern used by Comm.RequestState.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8de43895-ce94-4db2-929b-a105193e709a

📥 Commits

Reviewing files that changed from the base of the PR and between c2a6937 and 3591f23.

📒 Files selected for processing (4)
  • Core/MultiBot.lua
  • Core/MultiBotComm.lua
  • Core/MultiBotEngine.lua
  • UI/MultiBotUnitsRootUI.lua

Comment thread Core/MultiBot.lua
Comment thread Core/MultiBot.lua
Comment thread Core/MultiBot.lua Outdated
Comment thread Core/MultiBotComm.lua
Comment thread Core/MultiBotComm.lua
Comment thread Core/MultiBotComm.lua
Comment thread Core/MultiBotEngine.lua
@Wishmaster117
Wishmaster117 merged commit 1d21b4a into main Aug 7, 2026
5 checks passed
@Wishmaster117
Wishmaster117 deleted the MultiBot-improve-bridge-synchronization,-strategy-controls-and-persistent-favorites branch August 7, 2026 19:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant