Core/Spells: Corrected client control checks in spell packets

Closes #26510
Closes #27863

(cherry picked from commit 0a34290484f3e90a2a642986de682a8b0c7e3815)
This commit is contained in:
Shauren
2026-05-26 23:08:27 +02:00
parent 6bf5eed1b3
commit 708710e109
2 changed files with 16 additions and 40 deletions
+14 -30
View File
@@ -48,10 +48,6 @@
void WorldSession::HandleUseItemOpcode(WorldPackets::Spells::UseItem& packet)
{
// ignore for remote control state
if (_player->GetUnitBeingMoved() != _player)
return;
// Skip casting invalid spells right away
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(packet.Cast.SpellID, _player->GetMap()->GetDifficultyID());
if (!spellInfo)
@@ -71,8 +67,9 @@ void WorldSession::HandleOpenItemOpcode(WorldPackets::Spells::OpenItem& packet)
Player* player = GetPlayer();
// ignore for remote control state
if (player->GetUnitBeingMoved() != player)
if (player->IsCharmed())
return;
TC_LOG_INFO("network", "bagIndex: {}, slot: {}", packet.Slot, packet.PackSlot);
// additional check, client outputs message on its own
@@ -205,8 +202,8 @@ void WorldSession::HandleGameObjectUseOpcode(WorldPackets::GameObject::GameObjUs
if (GameObject* obj = GetPlayer()->GetGameObjectIfCanInteractWith(packet.Guid))
{
// ignore for remote control state
if (GetPlayer()->GetUnitBeingMoved() != GetPlayer())
if (!(GetPlayer()->IsOnVehicle(GetPlayer()->GetUnitBeingMoved()) || GetPlayer()->IsMounted()) && !obj->GetGOInfo()->IsUsableMounted())
if (GetPlayer()->IsCharmed())
if (!(GetPlayer()->IsOnVehicle(GetPlayer()->GetCharmed()) || GetPlayer()->IsMounted()) && !obj->GetGOInfo()->IsUsableMounted())
return;
obj->Use(GetPlayer());
@@ -216,7 +213,7 @@ void WorldSession::HandleGameObjectUseOpcode(WorldPackets::GameObject::GameObjUs
void WorldSession::HandleGameobjectReportUse(WorldPackets::GameObject::GameObjReportUse& packet)
{
// ignore for remote control state
if (_player->GetUnitBeingMoved() != _player)
if (_player->IsCharmed())
return;
if (GameObject* go = GetPlayer()->GetGameObjectIfCanInteractWith(packet.Guid))
@@ -238,33 +235,20 @@ void WorldSession::HandleCastSpellOpcode(WorldPackets::Spells::CastSpell& castRe
return;
}
// ignore for remote control state (for player case)
Unit* mover = _player->GetUnitBeingMoved();
if (mover != _player && mover->GetTypeId() == TYPEID_PLAYER)
return;
Unit* castingUnit = mover;
if (castingUnit->IsCreature() && !castingUnit->ToCreature()->HasSpell(spellInfo->Id))
{
// If the vehicle creature does not have the spell but it allows the passenger to cast own spells
// change caster to player and let him cast
if (!_player->IsOnVehicle(castingUnit) || spellInfo->CheckVehicle(_player) != SPELL_CAST_OK)
return;
castingUnit = _player;
}
if (castRequest.Cast.MoveUpdate.has_value())
HandleMovementOpcode(CMSG_MOVE_STOP, *castRequest.Cast.MoveUpdate);
if (_player->CanRequestSpellCast(spellInfo, castingUnit))
_player->RequestSpellCast(std::make_unique<SpellCastRequest>(std::move(castRequest.Cast), castingUnit->GetGUID()));
if (_player->CanRequestSpellCast(spellInfo, _player))
_player->RequestSpellCast(std::make_unique<SpellCastRequest>(std::move(castRequest.Cast), _player->GetGUID()));
else
Spell::SendCastResult(_player, spellInfo, {}, castRequest.Cast.CastID, SPELL_FAILED_SPELL_IN_PROGRESS);
}
void WorldSession::HandleCancelCastOpcode(WorldPackets::Spells::CancelCast& packet)
{
if (_player->IsCharmed())
return;
if (_player->IsNonMeleeSpellCast(false))
{
_player->InterruptNonMeleeSpells(false, packet.SpellID, false);
@@ -378,7 +362,7 @@ void WorldSession::HandleCancelChanneling(WorldPackets::Spells::CancelChannellin
{
// ignore for remote control state (for player case)
Unit* mover = _player->GetUnitBeingMoved();
if (mover != _player && mover->GetTypeId() == TYPEID_PLAYER)
if (!mover)
return;
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(cancelChanneling.ChannelSpell, mover->GetMap()->GetDifficultyID());
@@ -405,7 +389,7 @@ void WorldSession::HandleSpellEmpowerRelease(WorldPackets::Spells::SpellEmpowerR
{
// ignore for remote control state (for player case)
Unit* mover = _player->GetUnitBeingMoved();
if (mover != _player && mover->GetTypeId() == TYPEID_PLAYER)
if (!mover)
return;
Spell* spell = mover->GetCurrentSpell(CURRENT_CHANNELED_SPELL);
@@ -419,7 +403,7 @@ void WorldSession::HandleSpellEmpowerRestart(WorldPackets::Spells::SpellEmpowerR
{
// ignore for remote control state (for player case)
Unit* mover = _player->GetUnitBeingMoved();
if (mover != _player && mover->GetTypeId() == TYPEID_PLAYER)
if (!mover)
return;
Spell* spell = mover->GetCurrentSpell(CURRENT_CHANNELED_SPELL);
@@ -432,7 +416,7 @@ void WorldSession::HandleSpellEmpowerRestart(WorldPackets::Spells::SpellEmpowerR
void WorldSession::HandleTotemDestroyed(WorldPackets::Totem::TotemDestroyed& totemDestroyed)
{
// ignore for remote control state
if (_player->GetUnitBeingMoved() != _player)
if (_player->IsCharmed())
return;
uint8 slotId = totemDestroyed.Slot;
+2 -10
View File
@@ -6958,16 +6958,8 @@ SpellCastResult Spell::CheckCasterAuras(int32* param1) const
// Get unit state
uint32 const unitflag = unitCaster->m_unitData->Flags;
// this check should only be done when player does cast directly
// (ie not when it's called from a script) Breaks for example PlayerAI when charmed
/*
if (!unitCaster->GetCharmerGUID().IsEmpty())
{
if (Unit* charmer = unitCaster->GetCharmer())
if (charmer->GetUnitBeingMoved() != unitCaster && !CheckSpellCancelsCharm(param1))
result = SPELL_FAILED_CHARMED;
}
*/
if (m_fromClient && unitCaster->IsCharmed() && unitCaster->IsPlayer() && !CheckSpellCancelsCharm(param1))
result = SPELL_FAILED_CHARMED;
// spell has attribute usable while having a cc state, check if caster has allowed mechanic auras, another mechanic types must prevent cast spell
auto mechanicCheck = [&](AuraType type) -> SpellCastResult