fix(Core): scope AddPlayerBot loading count to master account#2307
Conversation
Master update from Test-staging: Fix ObjectAccessor retrieval, optimize EquipActions, and implement RaidBossHelpers
This reverts commit c86032f.
Master update from Test staging
Update master from Test staging and Core Update
Test staging to master
Test staging to master
The MaxAddedBots check in AddPlayerBot() uses botLoading.size() to include bots currently in the async login pipeline. However, botLoading is a global static set shared by both PlayerbotMgr (per-player) and RandomPlayerbotMgr (singleton). When RandomPlayerbotMgr loads hundreds of random bots at startup, their entries inflate the count for every player, causing false "You have added too many bots" rejections even when the player has zero personal bots. Fix: change botLoading from unordered_set<ObjectGuid> to unordered_map<ObjectGuid, uint32> where the value is the masterAccountId passed to AddPlayerBot(). Random bots are loaded with masterAccountId=0. The count check now filters to only count entries matching the requesting player's master account. All existing callsites (find, erase, empty) are compatible with the map type and required no changes. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
|
How common is this issue for other people? I do recall running into it before but it's incredibly rare, even when I login and add alts while randoms are still logging in. I login 4000 to 8000 bots, DisableWithoutRealPlayer = 1, and RandomBotsPerInterval = 500 |
Very common for me. Basically whenever I use rndbots. |
|
Interesting. What is your bot population and DisableWithoutRealPlayer/RandomBotsPerInterval values? |
AiPlayerbot.MinRandomBots = 2000 AiPlayerbot.DisabledWithoutRealPlayer = 0 |
|
I run 1500 and the default RandomBotsPerInterval. I think that is 60? I do use DisabledWithoutRealPlayer. I've moved the value around some, but I think I have to be in the process of random bots logging in for the issue to occur. It's been a long time since I used random bots so I don't recall exactly. For sure sometimes I would not be able to log in altbots immediately upon entering the world (because I use Multibot, which immediately logs in all bots in your party when you log in, and logging them in would be blocked). I'm not sure if the configured delay starts from actually entering the world though or from logging into your account (even if you remain at the character selection screen), though I figure you know the answer to that. I can actually sometimes get a few altbot invites in during the process of random bots being logged in, but I haven't noticed a trend as to when that works and doesn't, other than it seems to be more effective as more random bots have been logged on. |
Yes the patterns are similar on my side. |
|
Quick note on the timing behavior for anyone confused by it: botLoading isn't a count of loaded bots, it's a buffer of bots currently mid-load. An entry is added right before the async DB query fires, and removed once the bot has finished logging in. At startup, RandomPlayerbotMgr queues dozens of bots per tick. Adding entries is instant, but each DB load takes a few hundred ms to resolve, so the set fills faster than it drains and easily climbs over 40 during the initial flood. Once the queue stops feeding, the callbacks catch up and the set drains back to zero. That's why .playerbot add fails at login and works a minute later, same check, different snapshot of the buffer. This PR doesn't change that pipeline; it just filters the count by masterAccountId so the randombot flood (allmasterAccountId = 0) stops counting against a real player's personal limit. |
ce1adeb
into
mod-playerbots:test-staging
Problem
AddPlayerBot()falsely rejects player bot additions with "You have added too many bots (more than 40)" even when the player has zero personal bots.This happens because the
MaxAddedBotscheck atPlayerbotMgr.cpp:124addsbotLoading.size()to the player's personal bot count:uint32 count = mgr->GetPlayerbotsCount() + botLoading.size();botLoadingis astatic std::unordered_set<ObjectGuid>onPlayerbotHolder— shared by bothPlayerbotMgr(per-player) andRandomPlayerbotMgr(singleton). WhenRandomPlayerbotMgrloads random bots at startup (up to 60 per interval viaRandomBotsPerInterval), their GUIDs go into the same global set. During the startup loading window,botLoading.size()can easily reach 100–300, far exceeding the defaultMaxAddedBots = 40limit.The result: any player who logs in during the random bot loading window and tries
.playerbot add <name>gets blocked, even though the limit is intended to be per-player.How to reproduce
AiPlayerbot.RandomBotAutologin = 1(default) with 500 random bots.playerbot add <character_name>for an offline character on your accountRoot cause
PlayerbotHolder::botLoadingis declaredstaticatPlayerbotMgr.h:60, so bothPlayerbotMgrandRandomPlayerbotMgrshare the same setAddPlayerBot()inserts intobotLoadingat line 147 for ALL callers — both player-initiated adds (masterAccountId > 0) and random bot spawns (masterAccountId = 0)botLoading.size()(the entire global set) instead of filtering to bots being loaded for the requesting playerFix
Change
botLoadingfromunordered_set<ObjectGuid>tounordered_map<ObjectGuid, uint32>where the value is themasterAccountIdpassed toAddPlayerBot(). Random bots are loaded withmasterAccountId = 0.The count check now iterates the map and only counts entries matching the current player's
masterAccountId:Callsite compatibility
All 10 existing
botLoadingcallsites were audited:PlayerbotMgr.cpp:85find()by keyPlayerbotMgr.cpp:153emplace()(wasinsert())PlayerbotMgr.cpp:174erase()by keyPlayerbotMgr.cpp:209erase()by keyPlayerbotMgr.cpp:229erase()by keyPlayerbotMgr.cpp:1163find()by keyRandomPlayerbotMgr.cpp:429empty()The six unchanged callsites use
find(),erase(), andempty()which operate on keys identically for bothunordered_setandunordered_map.Files changed
src/Bot/PlayerbotMgr.hbotLoadingtype:unordered_set<ObjectGuid>→unordered_map<ObjectGuid, uint32>src/Bot/PlayerbotMgr.cppinsert→emplacewithmasterAccountId, count check filters bymasterAccountIdWhat is NOT changed
MaxAddedBotsconfig key and default value (40) — unchangedbotLoading.empty()throttle inRandomPlayerbotMgr— unchangedAddPlayerBot)