fix(Core/Player): prevent crash exploit spam duel starting (#9226)

This commit is contained in:
IntelligentQuantum
2021-11-28 23:12:53 +03:30
committed by GitHub
parent 25ca425357
commit ab761c9865
8 changed files with 144 additions and 112 deletions

View File

@@ -211,8 +211,6 @@ Player::Player(WorldSession* session): Unit(true), m_mover(this)
m_auraRaidUpdateMask = 0;
m_bPassOnGroupLoot = false;
duel = nullptr;
m_GuildIdInvited = 0;
m_ArenaTeamIdInvited = 0;
@@ -6154,18 +6152,20 @@ uint32 Player::GetZoneIdFromDB(ObjectGuid guid)
void Player::CheckDuelDistance(time_t currTime)
{
if (!duel)
{
return;
}
ObjectGuid duelFlagGUID = GetGuidValue(PLAYER_DUEL_ARBITER);
GameObject* obj = GetMap()->GetGameObject(duelFlagGUID);
if (!obj)
return;
if (duel->outOfBound == 0)
if (!duel->OutOfBoundsTime)
{
if (!IsWithinDistInMap(obj, 50))
{
duel->outOfBound = currTime;
duel->OutOfBoundsTime = currTime + 10;
WorldPacket data(SMSG_DUEL_OUTOFBOUNDS, 0);
GetSession()->SendPacket(&data);
@@ -6175,12 +6175,12 @@ void Player::CheckDuelDistance(time_t currTime)
{
if (IsWithinDistInMap(obj, 40))
{
duel->outOfBound = 0;
duel->OutOfBoundsTime = 0;
WorldPacket data(SMSG_DUEL_INBOUNDS, 0);
GetSession()->SendPacket(&data);
}
else if (currTime >= (duel->outOfBound + 10))
else if (currTime >= duel->OutOfBoundsTime)
DuelComplete(DUEL_FLED);
}
}
@@ -6193,57 +6193,76 @@ bool Player::IsOutdoorPvPActive()
void Player::DuelComplete(DuelCompleteType type)
{
// duel not requested
if (!duel || !duel->opponent || !duel->initiator)
if (!duel)
return;
LOG_DEBUG("entities.unit", "Duel Complete %s %s", GetName().c_str(), duel->opponent->GetName().c_str());
// Check if DuelComplete() has been called already up in the stack and in that case don't do anything else here
if (duel->State == DUEL_STATE_COMPLETED)
return;
Player* opponent = duel->Opponent;
duel->State = DUEL_STATE_COMPLETED;
opponent->duel->State = DUEL_STATE_COMPLETED;
LOG_DEBUG("entities.unit", "Player::DuelComplete: Player '%s' (%s), Opponent: '%s' (%s)",
GetName().c_str(), GetGUID().ToString().c_str(), opponent->GetName().c_str(), opponent->GetGUID().ToString().c_str());
WorldPacket data(SMSG_DUEL_COMPLETE, (1));
data << (uint8)((type != DUEL_INTERRUPTED) ? 1 : 0);
GetSession()->SendPacket(&data);
duel->opponent->GetSession()->SendPacket(&data);
data << uint8((type != DUEL_INTERRUPTED) ? 1 : 0);
SendDirectMessage(&data);
if (opponent->GetSession())
{
opponent->SendDirectMessage(&data);
}
if (type != DUEL_INTERRUPTED)
{
data.Initialize(SMSG_DUEL_WINNER, (1 + 20)); // we guess size
data.Initialize(SMSG_DUEL_WINNER, (1+20)); // we guess size
data << uint8(type == DUEL_WON ? 0 : 1); // 0 = just won; 1 = fled
data << duel->opponent->GetName();
data << opponent->GetName();
data << GetName();
SendMessageToSet(&data, true);
}
sScriptMgr->OnPlayerDuelEnd(duel->opponent, this, type);
sScriptMgr->OnPlayerDuelEnd(opponent, this, type);
switch (type)
{
case DUEL_FLED:
// if initiator and opponent are on the same team
// or initiator and opponent are not PvP enabled, forcibly stop attacking
if (duel->initiator->GetTeamId() == duel->opponent->GetTeamId())
if (GetTeamId() == opponent->GetTeamId())
{
duel->initiator->AttackStop();
duel->opponent->AttackStop();
AttackStop();
opponent->AttackStop();
}
else
{
if (!duel->initiator->IsPvP())
duel->initiator->AttackStop();
if (!duel->opponent->IsPvP())
duel->opponent->AttackStop();
if (!IsPvP())
{
AttackStop();
}
if (!opponent->IsPvP())
{
opponent->AttackStop();
}
}
break;
case DUEL_WON:
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL, 1);
duel->opponent->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL, 1);
opponent->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL, 1);
// Credit for quest Death's Challenge
if (getClass() == CLASS_DEATH_KNIGHT && duel->opponent->GetQuestStatus(12733) == QUEST_STATUS_INCOMPLETE)
duel->opponent->CastSpell(duel->opponent, 52994, true);
if (getClass() == CLASS_DEATH_KNIGHT && opponent->GetQuestStatus(12733) == QUEST_STATUS_INCOMPLETE)
{
opponent->CastSpell(opponent, 52994, true);
}
// Honor points after duel (the winner) - ImpConfig
if (uint32 amount = sWorld->getIntConfig(CONFIG_HONOR_AFTER_DUEL))
duel->opponent->RewardHonor(nullptr, 1, amount);
{
opponent->RewardHonor(nullptr, 1, amount);
}
break;
default:
@@ -6251,56 +6270,66 @@ void Player::DuelComplete(DuelCompleteType type)
}
// Victory emote spell
if (type != DUEL_INTERRUPTED && duel->opponent)
duel->opponent->CastSpell(duel->opponent, 52852, true);
if (type != DUEL_INTERRUPTED)
{
opponent->CastSpell(opponent, 52852, true);
}
//Remove Duel Flag object
GameObject* obj = GetMap()->GetGameObject(GetGuidValue(PLAYER_DUEL_ARBITER));
if (obj)
duel->initiator->RemoveGameObject(obj, true);
{
duel->Initiator->RemoveGameObject(obj, true);
}
/* remove auras */
AuraApplicationMap& itsAuras = duel->opponent->GetAppliedAuras();
AuraApplicationMap &itsAuras = opponent->GetAppliedAuras();
for (AuraApplicationMap::iterator i = itsAuras.begin(); i != itsAuras.end();)
{
Aura const* aura = i->second->GetBase();
if (!i->second->IsPositive() && aura->GetCasterGUID() == GetGUID() && aura->GetApplyTime() >= duel->startTime)
duel->opponent->RemoveAura(i);
if (!i->second->IsPositive() && aura->GetCasterGUID() == GetGUID() && aura->GetApplyTime() >= duel->StartTime)
{
opponent->RemoveAura(i);
}
else
{
++i;
}
}
AuraApplicationMap& myAuras = GetAppliedAuras();
AuraApplicationMap &myAuras = GetAppliedAuras();
for (AuraApplicationMap::iterator i = myAuras.begin(); i != myAuras.end();)
{
Aura const* aura = i->second->GetBase();
if (!i->second->IsPositive() && aura->GetCasterGUID() == duel->opponent->GetGUID() && aura->GetApplyTime() >= duel->startTime)
if (!i->second->IsPositive() && aura->GetCasterGUID() == opponent->GetGUID() && aura->GetApplyTime() >= duel->StartTime)
RemoveAura(i);
else
++i;
}
// cleanup combo points
if (GetComboTarget() == duel->opponent->GetGUID())
if (GetComboTarget() == duel->Opponent->GetGUID())
ClearComboPoints();
else if (GetComboTarget() == duel->opponent->GetPetGUID())
else if (GetComboTarget() == duel->Opponent->GetPetGUID())
ClearComboPoints();
if (duel->opponent->GetComboTarget() == GetGUID())
duel->opponent->ClearComboPoints();
else if (duel->opponent->GetComboTarget() == GetPetGUID())
duel->opponent->ClearComboPoints();
if (duel->Opponent->GetComboTarget() == GetGUID())
{
duel->Opponent->ClearComboPoints();
}
else if (duel->Opponent->GetComboTarget() == GetPetGUID())
{
duel->Opponent->ClearComboPoints();
}
//cleanups
SetGuidValue(PLAYER_DUEL_ARBITER, ObjectGuid::Empty);
SetUInt32Value(PLAYER_DUEL_TEAM, 0);
duel->opponent->SetGuidValue(PLAYER_DUEL_ARBITER, ObjectGuid::Empty);
duel->opponent->SetUInt32Value(PLAYER_DUEL_TEAM, 0);
opponent->SetGuidValue(PLAYER_DUEL_ARBITER, ObjectGuid::Empty);
opponent->SetUInt32Value(PLAYER_DUEL_TEAM, 0);
delete duel->opponent->duel;
duel->opponent->duel = nullptr;
delete duel;
duel = nullptr;
opponent->duel.reset(nullptr);
duel.reset(nullptr);
}
//---------------------------------------------------------//
@@ -10668,9 +10697,18 @@ bool Player::IsAlwaysDetectableFor(WorldObject const* seer) const
if (Unit::IsAlwaysDetectableFor(seer))
return true;
if (duel && duel->State != DUEL_STATE_CHALLENGED && duel->Opponent == seer)
{
return false;
}
if (const Player* seerPlayer = seer->ToPlayer())
{
if (IsGroupVisibleFor(seerPlayer))
return !(seerPlayer->duel && seerPlayer->duel->startTime != 0 && seerPlayer->duel->opponent == this);
{
return true;
}
}
return false;
}