mirror of
https://github.com/liyunfan1223/mod-playerbots.git
synced 2026-02-21 02:20:00 +01:00
Compare commits
No commits in common. "c9b4cfa184f021abf38436a6c8739a458339891e" and "b661264c539228d804fe99cdc2ee683ae316d1a7" have entirely different histories.
c9b4cfa184
...
b661264c53
@ -1985,15 +1985,13 @@ AiPlayerbot.AllowedLogFiles = ""
|
|||||||
####################################################################################################
|
####################################################################################################
|
||||||
# A list of gameObject GUID's that are not allowed for bots to interact with.
|
# A list of gameObject GUID's that are not allowed for bots to interact with.
|
||||||
#
|
#
|
||||||
AiPlayerbot.DisallowedGameObjects = 176213,17155,2656,74448,19020,3719,3658,3705,3706,105579,75293,2857,179490,141596,160836,160845,179516,176224,181085,176112,128308,128403,165739,165738,175245,175970,176325,176327,123329
|
AiPlayerbot.DisallowedGameObjects = 176213,17155,2656,74448,19020,3719,3658,3705,3706,105579,75293,17155,2857,179490
|
||||||
#
|
#
|
||||||
# List of GUID's:
|
# List of GUID's:
|
||||||
# QuestItems:
|
# QuestItems:
|
||||||
# 176213 = Blood of Heroes, 17155 = Defias Gunpowder, 2656 = Waterlogged Envelope, 123329 = Baelogs Chest
|
# 176213 = Blood of Heroes, 17155 = Defias Gunpowder, 2656 = Waterlogged Envelope
|
||||||
# Chests:
|
# Chests:
|
||||||
# Large Solid Chest = 74448, Box of Assorted Parts = 19020, Food Crate = 3719, Water Barrel = 3658, Barrel of Milk = 3705, Barrel of sweet Nectar = 3706, Tattered Chest = 105579, Large bettered Chest = 75293, Solid Chest = 2857, Battered Foodlocker = 179490, Witch Doctor's Chest = 141596, Relic Coffer = 160836, Dark Coffer = 160845, Fengus's Chest = 179516, Supply Crate = 176224/181085, Malor's Strongbox = 176112
|
# Large Solid Chest = 74448, Box of Assorted Parts = 19020, Food Crate = 3719, Water Barrel = 3658, Barrel of Milk = 3705, Barrel of sweet Nectar = 3706, Tattered Chest = 105579, Large bettered Chest = 75293, Solid Chest = 2857, Battered Foodlocker = 179490
|
||||||
# Other:
|
|
||||||
# Shallow Grave (Zul'Farrak) = 128308/128403, Grim Guzzler Boar (Blackrock Depths) = 165739, Dark Iron Ale Mug (Blackrock Depths) = 165738, Father Flame (Blackrock Spire) = 175245, Unforged Runic Breastplate (Blackrock Spire) = 175970, Blacksmithing Plans (Stratholme) = 176325/176327
|
|
||||||
# Feel free to edit and help to complete.
|
# Feel free to edit and help to complete.
|
||||||
#
|
#
|
||||||
####################################################################################################
|
####################################################################################################
|
||||||
|
|||||||
@ -4124,15 +4124,37 @@ bool IsAlliance(uint8 race)
|
|||||||
|
|
||||||
bool PlayerbotAI::HasRealPlayerMaster()
|
bool PlayerbotAI::HasRealPlayerMaster()
|
||||||
{
|
{
|
||||||
if (master)
|
// if (master)
|
||||||
{
|
// {
|
||||||
PlayerbotAI* masterBotAI = GET_PLAYERBOT_AI(master);
|
// PlayerbotAI* masterBotAI = GET_PLAYERBOT_AI(master);
|
||||||
return !masterBotAI || masterBotAI->IsRealPlayer();
|
// return !masterBotAI || masterBotAI->IsRealPlayer();
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
// return false;
|
||||||
|
|
||||||
|
// Removes a long-standing crash (0xC0000005 ACCESS_VIOLATION)
|
||||||
|
/* 1) The "master" pointer can be null if the bot was created
|
||||||
|
without a master player or if the master was just removed. */
|
||||||
|
if (!master)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* 2) Is the master player still present in the world?
|
||||||
|
If FindPlayer fails, we invalidate "master" and stop here. */
|
||||||
|
if (!ObjectAccessor::FindPlayer(master->GetGUID()))
|
||||||
|
{
|
||||||
|
master = nullptr; // avoids repeating the check on the next tick
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 3) If the master is a bot, we check that it is itself controlled
|
||||||
|
by a real player. Otherwise, it's already a real player → true. */
|
||||||
|
if (PlayerbotAI* masterBotAI = GET_PLAYERBOT_AI(master))
|
||||||
|
return masterBotAI->IsRealPlayer(); // bot controlled by a player?
|
||||||
|
|
||||||
|
return true; // master = real player
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PlayerbotAI::HasActivePlayerMaster() { return master && !GET_PLAYERBOT_AI(master); }
|
bool PlayerbotAI::HasActivePlayerMaster() { return master && !GET_PLAYERBOT_AI(master); }
|
||||||
|
|
||||||
bool PlayerbotAI::IsAlt() { return HasRealPlayerMaster() && !sRandomPlayerbotMgr->IsRandomBot(bot); }
|
bool PlayerbotAI::IsAlt() { return HasRealPlayerMaster() && !sRandomPlayerbotMgr->IsRandomBot(bot); }
|
||||||
|
|||||||
@ -157,11 +157,7 @@ bool PlayerbotAIConfig::Initialize()
|
|||||||
sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotQuestIds", "7848,3802,5505,6502,7761"),
|
sConfigMgr->GetOption<std::string>("AiPlayerbot.RandomBotQuestIds", "7848,3802,5505,6502,7761"),
|
||||||
randomBotQuestIds);
|
randomBotQuestIds);
|
||||||
|
|
||||||
LoadSet<std::set<uint32>>(
|
LoadSet<std::set<uint32>>(sConfigMgr->GetOption<std::string>("AiPlayerbot.DisallowedGameObjects", "176213,17155"),
|
||||||
sConfigMgr->GetOption<std::string>("AiPlayerbot.DisallowedGameObjects",
|
|
||||||
"176213,17155,2656,74448,19020,3719,3658,3705,3706,105579,75293,2857,"
|
|
||||||
"179490,141596,160836,160845,179516,176224,181085,176112,128308,128403,"
|
|
||||||
"165739,165738,175245,175970,176325,176327,123329"),
|
|
||||||
disallowedGameObjects);
|
disallowedGameObjects);
|
||||||
botAutologin = sConfigMgr->GetOption<bool>("AiPlayerbot.BotAutologin", false);
|
botAutologin = sConfigMgr->GetOption<bool>("AiPlayerbot.BotAutologin", false);
|
||||||
randomBotAutologin = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotAutologin", true);
|
randomBotAutologin = sConfigMgr->GetOption<bool>("AiPlayerbot.RandomBotAutologin", true);
|
||||||
|
|||||||
@ -38,6 +38,8 @@
|
|||||||
#include "WorldSessionMgr.h"
|
#include "WorldSessionMgr.h"
|
||||||
#include "DatabaseEnv.h" // Added for gender choice
|
#include "DatabaseEnv.h" // Added for gender choice
|
||||||
#include <algorithm> // Added for gender choice
|
#include <algorithm> // Added for gender choice
|
||||||
|
#include "Log.h" // removes a long-standing crash (0xC0000005 ACCESS_VIOLATION)
|
||||||
|
#include <shared_mutex> // removes a long-standing crash (0xC0000005 ACCESS_VIOLATION)
|
||||||
|
|
||||||
class BotInitGuard
|
class BotInitGuard
|
||||||
{
|
{
|
||||||
@ -1726,23 +1728,72 @@ void PlayerbotsMgr::RemovePlayerBotData(ObjectGuid const& guid, bool is_AI)
|
|||||||
|
|
||||||
PlayerbotAI* PlayerbotsMgr::GetPlayerbotAI(Player* player)
|
PlayerbotAI* PlayerbotsMgr::GetPlayerbotAI(Player* player)
|
||||||
{
|
{
|
||||||
if (!(sPlayerbotAIConfig->enabled) || !player)
|
// if (!(sPlayerbotAIConfig->enabled) || !player)
|
||||||
{
|
// {
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
// if (player->GetSession()->isLogingOut() || player->IsDuringRemoveFromWorld()) {
|
|
||||||
// return nullptr;
|
// return nullptr;
|
||||||
// }
|
// }
|
||||||
auto itr = _playerbotsAIMap.find(player->GetGUID());
|
// // if (player->GetSession()->isLogingOut() || player->IsDuringRemoveFromWorld()) {
|
||||||
if (itr != _playerbotsAIMap.end())
|
// // return nullptr;
|
||||||
|
// // }
|
||||||
|
// auto itr = _playerbotsAIMap.find(player->GetGUID());
|
||||||
|
// if (itr != _playerbotsAIMap.end())
|
||||||
|
// {
|
||||||
|
// if (itr->second->IsBotAI())
|
||||||
|
// return reinterpret_cast<PlayerbotAI*>(itr->second);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return nullptr;
|
||||||
|
|
||||||
|
// removes a long-standing crash (0xC0000005 ACCESS_VIOLATION)
|
||||||
|
if (!player || !sPlayerbotAIConfig->enabled)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// First read the GUID into a local variable, but ONLY after the check!
|
||||||
|
ObjectGuid guid = player->GetGUID(); // <-- OK here, we know that player != nullptr
|
||||||
{
|
{
|
||||||
if (itr->second->IsBotAI())
|
std::shared_lock rlock(_aiMutex);
|
||||||
return reinterpret_cast<PlayerbotAI*>(itr->second);
|
auto it = _playerbotsAIMap.find(guid);
|
||||||
|
if (it != _playerbotsAIMap.end() && it->second->IsBotAI())
|
||||||
|
return static_cast<PlayerbotAI*>(it->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Transient state: NEVER break the master ⇄ bots relationship here.
|
||||||
|
if (!ObjectAccessor::FindPlayer(guid))
|
||||||
|
{
|
||||||
|
RemovePlayerbotAI(guid, /*removeMgrEntry=*/false);
|
||||||
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// removes a long-standing crash (0xC0000005 ACCESS_VIOLATION)
|
||||||
|
PlayerbotAI* PlayerbotsMgr::GetPlayerbotAIByGuid(ObjectGuid guid)
|
||||||
|
{
|
||||||
|
if (!sPlayerbotAIConfig->enabled)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
std::shared_lock rlock(_aiMutex);
|
||||||
|
auto it = _playerbotsAIMap.find(guid);
|
||||||
|
if (it != _playerbotsAIMap.end() && it->second->IsBotAI())
|
||||||
|
return static_cast<PlayerbotAI*>(it->second);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerbotsMgr::RemovePlayerbotAI(ObjectGuid const& guid, bool removeMgrEntry /*= true*/)
|
||||||
|
{
|
||||||
|
std::unique_lock wlock(_aiMutex);
|
||||||
|
|
||||||
|
if (auto it = _playerbotsAIMap.find(guid); it != _playerbotsAIMap.end())
|
||||||
|
{
|
||||||
|
delete it->second;
|
||||||
|
_playerbotsAIMap.erase(it);
|
||||||
|
LOG_DEBUG("playerbots", "Removed stale AI for GUID {}",
|
||||||
|
static_cast<uint64>(guid.GetRawValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (removeMgrEntry)
|
||||||
|
_playerbotsMgrMap.erase(guid); // we NO longer touch the relation in a "soft" purge
|
||||||
|
}
|
||||||
|
|
||||||
PlayerbotMgr* PlayerbotsMgr::GetPlayerbotMgr(Player* player)
|
PlayerbotMgr* PlayerbotsMgr::GetPlayerbotMgr(Player* player)
|
||||||
{
|
{
|
||||||
if (!(sPlayerbotAIConfig->enabled) || !player)
|
if (!(sPlayerbotAIConfig->enabled) || !player)
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
#include "PlayerbotAIBase.h"
|
#include "PlayerbotAIBase.h"
|
||||||
#include "QueryHolder.h"
|
#include "QueryHolder.h"
|
||||||
#include "QueryResult.h"
|
#include "QueryResult.h"
|
||||||
|
#include <shared_mutex> // removes a long-standing crash (0xC0000005 ACCESS_VIOLATION)
|
||||||
|
|
||||||
class ChatHandler;
|
class ChatHandler;
|
||||||
class PlayerbotAI;
|
class PlayerbotAI;
|
||||||
@ -114,13 +115,38 @@ public:
|
|||||||
void RemovePlayerBotData(ObjectGuid const& guid, bool is_AI);
|
void RemovePlayerBotData(ObjectGuid const& guid, bool is_AI);
|
||||||
|
|
||||||
PlayerbotAI* GetPlayerbotAI(Player* player);
|
PlayerbotAI* GetPlayerbotAI(Player* player);
|
||||||
|
PlayerbotAI* GetPlayerbotAIByGuid(ObjectGuid guid); // removes a long-standing crash (0xC0000005 ACCESS_VIOLATION)
|
||||||
|
// void RemovePlayerbotAI(ObjectGuid const& guid); // removes a long-standing crash (0xC0000005 ACCESS_VIOLATION)
|
||||||
|
// removeMgrEntry = true => "hard" purge (AI + manager relation), for real logouts
|
||||||
|
// removeMgrEntry = false => "soft" purge (AI only), for detected "stale" cases
|
||||||
|
void RemovePlayerbotAI(ObjectGuid const& guid, bool removeMgrEntry = true);
|
||||||
PlayerbotMgr* GetPlayerbotMgr(Player* player);
|
PlayerbotMgr* GetPlayerbotMgr(Player* player);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<ObjectGuid, PlayerbotAIBase*> _playerbotsAIMap;
|
std::unordered_map<ObjectGuid, PlayerbotAIBase*> _playerbotsAIMap;
|
||||||
std::unordered_map<ObjectGuid, PlayerbotAIBase*> _playerbotsMgrMap;
|
std::unordered_map<ObjectGuid, PlayerbotAIBase*> _playerbotsMgrMap;
|
||||||
|
mutable std::shared_mutex _aiMutex; // removes a long-standing crash (0xC0000005 ACCESS_VIOLATION)
|
||||||
};
|
};
|
||||||
|
|
||||||
#define sPlayerbotsMgr PlayerbotsMgr::instance()
|
#define sPlayerbotsMgr PlayerbotsMgr::instance()
|
||||||
|
|
||||||
|
// Temporary addition If it keeps crashing, we will use them.
|
||||||
|
// Like
|
||||||
|
// BEFORE : PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
||||||
|
// AFTER (safe) : PlayerbotAI* botAI = GET_PLAYERBOT_AI_SAFE(bot);
|
||||||
|
// BEFORE : if (PlayerbotAI* botAI = GET_PLAYERBOT_AI(player)) { ... }
|
||||||
|
// AFTER (safe) : if (PlayerbotAI* botAI = GET_PLAYERBOT_AI_SAFE(player)) { ... }
|
||||||
|
// --- SAFE helpers (append to PlayerbotMgr.h) ---
|
||||||
|
inline PlayerbotAI* GET_PLAYERBOT_AI_SAFE(Player* p)
|
||||||
|
{
|
||||||
|
// Avoid any dereference during transient states (nullptr, teleport, flight, etc.)
|
||||||
|
return p ? sPlayerbotsMgr->GetPlayerbotAI(p) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline PlayerbotMgr* GET_PLAYERBOT_MGR_SAFE(Player* p)
|
||||||
|
{
|
||||||
|
return p ? sPlayerbotsMgr->GetPlayerbotMgr(p) : nullptr;
|
||||||
|
}
|
||||||
|
// --- end SAFE helpers ---
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -377,6 +377,10 @@ public:
|
|||||||
|
|
||||||
void OnPlayerbotLogout(Player* player) override
|
void OnPlayerbotLogout(Player* player) override
|
||||||
{
|
{
|
||||||
|
// immediate purge of the bot's AI upon disconnection
|
||||||
|
if (player && player->GetSession()->IsBot())
|
||||||
|
sPlayerbotsMgr->RemovePlayerbotAI(player->GetGUID()); // removes a long-standing crash (0xC0000005 ACCESS_VIOLATION)
|
||||||
|
|
||||||
if (PlayerbotMgr* playerbotMgr = GET_PLAYERBOT_MGR(player))
|
if (PlayerbotMgr* playerbotMgr = GET_PLAYERBOT_MGR(player))
|
||||||
{
|
{
|
||||||
PlayerbotAI* botAI = GET_PLAYERBOT_AI(player);
|
PlayerbotAI* botAI = GET_PLAYERBOT_AI(player);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user