mirror of
https://github.com/mod-playerbots/mod-playerbots.git
synced 2026-01-13 17:09:08 +00:00
Add RemoveAurasWithInterruptFlags call before all TeleportTo operations to prevent race condition crash in battlegrounds. The crash occurs when area auras (like "Entering Battleground") are queued for removal in Aura::UpdateTargetMap's targetsToRemove list, but the unit is deleted before the 500ms update cycle completes, causing SIGSEGV when accessing the dangling pointer. This fix removes auras with AURA_INTERRUPT_FLAG_TELEPORTED and AURA_INTERRUPT_FLAG_CHANGE_MAP before teleporting, matching the behavior in Player::TeleportTo for real players. Affected locations: - BattleGround join/teleport - Spirit healer/graveyard teleport - Corpse resurrection teleport - Meeting stone teleport - Master follow teleport - RPG unstuck teleport - Random bot teleport - Chat command teleport Raid-specific teleports excluded as they require separate testing.
270 lines
7.5 KiB
C++
270 lines
7.5 KiB
C++
/*
|
|
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
|
|
* and/or modify it under version 3 of the License, or (at your option), any later version.
|
|
*/
|
|
|
|
#include "ChatShortcutActions.h"
|
|
|
|
#include "Event.h"
|
|
#include "Formations.h"
|
|
#include "Playerbots.h"
|
|
#include "PositionValue.h"
|
|
|
|
void PositionsResetAction::ResetReturnPosition()
|
|
{
|
|
PositionMap& posMap = context->GetValue<PositionMap&>("position")->Get();
|
|
PositionInfo pos = posMap["return"];
|
|
pos.Reset();
|
|
posMap["return"] = pos;
|
|
}
|
|
|
|
void PositionsResetAction::SetReturnPosition(float x, float y, float z)
|
|
{
|
|
PositionMap& posMap = context->GetValue<PositionMap&>("position")->Get();
|
|
PositionInfo pos = posMap["return"];
|
|
pos.Set(x, y, z, botAI->GetBot()->GetMapId());
|
|
posMap["return"] = pos;
|
|
}
|
|
|
|
void PositionsResetAction::ResetStayPosition()
|
|
{
|
|
PositionMap& posMap = context->GetValue<PositionMap&>("position")->Get();
|
|
PositionInfo pos = posMap["stay"];
|
|
pos.Reset();
|
|
posMap["stay"] = pos;
|
|
}
|
|
|
|
void PositionsResetAction::SetStayPosition(float x, float y, float z)
|
|
{
|
|
PositionMap& posMap = context->GetValue<PositionMap&>("position")->Get();
|
|
PositionInfo pos = posMap["stay"];
|
|
pos.Set(x, y, z, botAI->GetBot()->GetMapId());
|
|
posMap["stay"] = pos;
|
|
}
|
|
|
|
bool FollowChatShortcutAction::Execute(Event event)
|
|
{
|
|
Player* master = GetMaster();
|
|
if (!master)
|
|
return false;
|
|
|
|
// botAI->Reset();
|
|
botAI->ChangeStrategy("+follow,-passive,-grind,-move from group", BOT_STATE_NON_COMBAT);
|
|
botAI->ChangeStrategy("-stay,-follow,-passive,-grind,-move from group", BOT_STATE_COMBAT);
|
|
botAI->GetAiObjectContext()->GetValue<GuidVector>("prioritized targets")->Reset();
|
|
|
|
PositionMap& posMap = context->GetValue<PositionMap&>("position")->Get();
|
|
PositionInfo pos = posMap["return"];
|
|
pos.Reset();
|
|
posMap["return"] = pos;
|
|
|
|
pos = posMap["stay"];
|
|
pos.Reset();
|
|
posMap["stay"] = pos;
|
|
|
|
if (bot->IsInCombat())
|
|
{
|
|
Formation* formation = AI_VALUE(Formation*, "formation");
|
|
std::string const target = formation->GetTargetName();
|
|
bool moved = false;
|
|
if (!target.empty())
|
|
{
|
|
moved = Follow(AI_VALUE(Unit*, target));
|
|
}
|
|
else
|
|
{
|
|
WorldLocation loc = formation->GetLocation();
|
|
if (Formation::IsNullLocation(loc) || loc.GetMapId() == -1)
|
|
return false;
|
|
|
|
MovementPriority priority = botAI->GetState() == BOT_STATE_COMBAT ? MovementPriority::MOVEMENT_COMBAT : MovementPriority::MOVEMENT_NORMAL;
|
|
moved = MoveTo(loc.GetMapId(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ(), false, false, false,
|
|
true, priority);
|
|
}
|
|
|
|
if (Pet* pet = bot->GetPet())
|
|
{
|
|
botAI->PetFollow();
|
|
}
|
|
|
|
if (moved)
|
|
{
|
|
botAI->TellMaster("Following");
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/* Default mechanics takes care of this now.
|
|
if (bot->GetMapId() != master->GetMapId() || (master && bot->GetDistance(master) >
|
|
sPlayerbotAIConfig->sightDistance))
|
|
{
|
|
if (bot->isDead())
|
|
{
|
|
bot->ResurrectPlayer(1.0f, false);
|
|
botAI->TellMasterNoFacing("Back from the grave!");
|
|
}
|
|
else
|
|
botAI->TellMaster("You are too far away from me! I will there soon.");
|
|
|
|
bot->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TELEPORTED | AURA_INTERRUPT_FLAG_CHANGE_MAP);
|
|
bot->TeleportTo(master->GetMapId(), master->GetPositionX(), master->GetPositionY(), master->GetPositionZ(),
|
|
master->GetOrientation()); return true;
|
|
}
|
|
*/
|
|
|
|
botAI->TellMaster("Following");
|
|
return true;
|
|
}
|
|
|
|
bool StayChatShortcutAction::Execute(Event event)
|
|
{
|
|
Player* master = GetMaster();
|
|
if (!master)
|
|
return false;
|
|
|
|
botAI->Reset();
|
|
botAI->ChangeStrategy("+stay,-passive,-move from group", BOT_STATE_NON_COMBAT);
|
|
botAI->ChangeStrategy("+stay,-follow,-passive,-move from group", BOT_STATE_COMBAT);
|
|
|
|
SetReturnPosition(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ());
|
|
SetStayPosition(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ());
|
|
|
|
botAI->TellMaster("Staying");
|
|
return true;
|
|
}
|
|
|
|
bool MoveFromGroupChatShortcutAction::Execute(Event event)
|
|
{
|
|
Player* master = GetMaster();
|
|
if (!master)
|
|
return false;
|
|
|
|
// dont need to remove stay or follow, move from group takes priority over both
|
|
// (see their isUseful() methods)
|
|
botAI->ChangeStrategy("+move from group", BOT_STATE_NON_COMBAT);
|
|
botAI->ChangeStrategy("+move from group", BOT_STATE_COMBAT);
|
|
|
|
botAI->TellMaster("Moving away from group");
|
|
return true;
|
|
}
|
|
|
|
bool FleeChatShortcutAction::Execute(Event event)
|
|
{
|
|
Player* master = GetMaster();
|
|
if (!master)
|
|
return false;
|
|
|
|
botAI->Reset();
|
|
botAI->ChangeStrategy("+follow,-stay,+passive", BOT_STATE_NON_COMBAT);
|
|
botAI->ChangeStrategy("+follow,-stay,+passive", BOT_STATE_COMBAT);
|
|
|
|
ResetReturnPosition();
|
|
ResetStayPosition();
|
|
|
|
if (bot->GetMapId() != master->GetMapId() || bot->GetDistance(master) > sPlayerbotAIConfig->sightDistance)
|
|
{
|
|
botAI->TellError("I will not flee with you - too far away");
|
|
return true;
|
|
}
|
|
|
|
botAI->TellMaster("Fleeing");
|
|
return true;
|
|
}
|
|
|
|
bool GoawayChatShortcutAction::Execute(Event event)
|
|
{
|
|
Player* master = GetMaster();
|
|
if (!master)
|
|
return false;
|
|
|
|
botAI->Reset();
|
|
botAI->ChangeStrategy("+runaway,-stay", BOT_STATE_NON_COMBAT);
|
|
botAI->ChangeStrategy("+runaway,-stay", BOT_STATE_COMBAT);
|
|
|
|
ResetReturnPosition();
|
|
ResetStayPosition();
|
|
|
|
botAI->TellMaster("Running away");
|
|
return true;
|
|
}
|
|
|
|
bool GrindChatShortcutAction::Execute(Event event)
|
|
{
|
|
Player* master = GetMaster();
|
|
if (!master)
|
|
return false;
|
|
|
|
botAI->Reset();
|
|
botAI->ChangeStrategy("+grind,-passive,-stay", BOT_STATE_NON_COMBAT);
|
|
|
|
ResetReturnPosition();
|
|
ResetStayPosition();
|
|
|
|
botAI->TellMaster("Grinding");
|
|
return true;
|
|
}
|
|
|
|
bool TankAttackChatShortcutAction::Execute(Event event)
|
|
{
|
|
Player* master = GetMaster();
|
|
if (!master)
|
|
return false;
|
|
|
|
if (!botAI->IsTank(bot))
|
|
return false;
|
|
|
|
botAI->Reset();
|
|
botAI->ChangeStrategy("-passive", BOT_STATE_NON_COMBAT);
|
|
botAI->ChangeStrategy("-passive", BOT_STATE_COMBAT);
|
|
|
|
ResetReturnPosition();
|
|
ResetStayPosition();
|
|
|
|
botAI->TellMaster("Attacking");
|
|
return true;
|
|
}
|
|
|
|
bool MaxDpsChatShortcutAction::Execute(Event event)
|
|
{
|
|
Player* master = GetMaster();
|
|
if (!master)
|
|
return false;
|
|
|
|
if (!botAI->ContainsStrategy(STRATEGY_TYPE_DPS))
|
|
return false;
|
|
|
|
botAI->Reset();
|
|
|
|
botAI->ChangeStrategy("-threat,-conserve mana,-cast time,+dps debuff,+boost", BOT_STATE_COMBAT);
|
|
botAI->TellMaster("Max DPS!");
|
|
|
|
return true;
|
|
}
|
|
|
|
bool NaxxChatShortcutAction::Execute(Event event)
|
|
{
|
|
Player* master = GetMaster();
|
|
if (!master)
|
|
return false;
|
|
|
|
botAI->Reset();
|
|
botAI->ChangeStrategy("+naxx", BOT_STATE_NON_COMBAT);
|
|
botAI->ChangeStrategy("+naxx", BOT_STATE_COMBAT);
|
|
botAI->TellMasterNoFacing("Add Naxx Strategies!");
|
|
// bot->Say("Add Naxx Strategies!", LANG_UNIVERSAL);
|
|
return true;
|
|
}
|
|
|
|
bool BwlChatShortcutAction::Execute(Event event)
|
|
{
|
|
Player* master = GetMaster();
|
|
if (!master)
|
|
return false;
|
|
|
|
botAI->Reset();
|
|
botAI->ChangeStrategy("+bwl", BOT_STATE_NON_COMBAT);
|
|
botAI->ChangeStrategy("+bwl", BOT_STATE_COMBAT);
|
|
botAI->TellMasterNoFacing("Add Bwl Strategies!");
|
|
return true;
|
|
}
|