Skip to content

Commit

Permalink
Core/Object: Range check vol. 2 (#23226)
Browse files Browse the repository at this point in the history
* Core/Object: Fix all missing parts for #23062

* Update GameObject.cpp
  • Loading branch information
d0d0 authored and jackpoz committed May 2, 2019
1 parent fe3bf57 commit 7807016
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 69 deletions.
86 changes: 36 additions & 50 deletions src/server/game/Entities/GameObject/GameObject.cpp
Expand Up @@ -2554,14 +2554,35 @@ float GameObject::GetInteractionDistance() const
{
switch (GetGoType())
{
/// @todo find out how the client calculates the maximal usage distance to spellless working
// gameobjects like guildbanks and mailboxes - 10.0 is a just an abitrary choosen number
case GAMEOBJECT_TYPE_GUILD_BANK:
case GAMEOBJECT_TYPE_MAILBOX:
case GAMEOBJECT_TYPE_AREADAMAGE:
return 0.0f;
case GAMEOBJECT_TYPE_QUESTGIVER:
case GAMEOBJECT_TYPE_TEXT:
case GAMEOBJECT_TYPE_FLAGSTAND:
case GAMEOBJECT_TYPE_FLAGDROP:
case GAMEOBJECT_TYPE_MINI_GAME:
return 5.5555553f;
case GAMEOBJECT_TYPE_BINDER:
return 10.0f;
case GAMEOBJECT_TYPE_FISHINGHOLE:
case GAMEOBJECT_TYPE_CHAIR:
case GAMEOBJECT_TYPE_BARBER_CHAIR:
return 3.0f;
case GAMEOBJECT_TYPE_FISHINGNODE:
return 100.0f;
case GAMEOBJECT_TYPE_FISHINGHOLE:
return 20.0f + CONTACT_DISTANCE; // max spell range
case GAMEOBJECT_TYPE_CAMERA:
case GAMEOBJECT_TYPE_MAP_OBJECT:
case GAMEOBJECT_TYPE_DUNGEON_DIFFICULTY:
case GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING:
case GAMEOBJECT_TYPE_DOOR:
return 5.0f;
// Following values are not blizzlike
case GAMEOBJECT_TYPE_GUILD_BANK:
case GAMEOBJECT_TYPE_MAILBOX:
// Successful mailbox interaction is rather critical to the client, failing it will start a minute-long cooldown until the next mail query may be executed.
// And since movement info update is not sent with mailbox interaction query, server may find the player outside of interaction range. Thus we increase it.
return 10.0f; // 5.0f is blizzlike
default:
return INTERACTION_DISTANCE;
}
Expand Down Expand Up @@ -2623,47 +2644,7 @@ bool GameObject::IsAtInteractDistance(Player const* player, SpellInfo const* spe
return IsAtInteractDistance(*player, maxRange);
}

float distance;
switch (GetGoType())
{
case GAMEOBJECT_TYPE_AREADAMAGE:
distance = 0.0f;
break;
case GAMEOBJECT_TYPE_QUESTGIVER:
case GAMEOBJECT_TYPE_TEXT:
case GAMEOBJECT_TYPE_FLAGSTAND:
case GAMEOBJECT_TYPE_FLAGDROP:
case GAMEOBJECT_TYPE_MINI_GAME:
distance = 5.5555553f;
break;
case GAMEOBJECT_TYPE_BINDER:
distance = 10.0f;
break;
case GAMEOBJECT_TYPE_CHAIR:
case GAMEOBJECT_TYPE_BARBER_CHAIR:
distance = 3.0f;
break;
case GAMEOBJECT_TYPE_FISHINGNODE:
distance = 100.0f;
break;
case GAMEOBJECT_TYPE_CAMERA:
case GAMEOBJECT_TYPE_MAP_OBJECT:
case GAMEOBJECT_TYPE_DUNGEON_DIFFICULTY:
case GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING:
case GAMEOBJECT_TYPE_DOOR:
default:
distance = 5.0f;
break;

// Following values are not blizzlike
case GAMEOBJECT_TYPE_MAILBOX:
// Successful mailbox interaction is rather critical to the client, failing it will start a minute-long cooldown until the next mail query may be executed.
// And since movement info update is not sent with mailbox interaction query, server may find the player outside of interaction range. Thus we increase it.
distance = 10.0f; // 5.0f is blizzlike
break;
}

return IsAtInteractDistance(*player, distance);
return IsAtInteractDistance(*player, GetInteractionDistance());
}

bool GameObject::IsAtInteractDistance(Position const& pos, float radius) const
Expand All @@ -2679,17 +2660,22 @@ bool GameObject::IsAtInteractDistance(Position const& pos, float radius) const
float maxY = displayInfo->maxY * scale + radius;
float maxZ = displayInfo->maxZ * scale + radius;

QuaternionData localRotation = GetLocalRotation();
G3D::Quat localRotationQuat(localRotation.x, localRotation.y, localRotation.z, localRotation.w);
QuaternionData worldRotation = GetWorldRotation();
G3D::Quat worldRotationQuat(worldRotation.x, worldRotation.y, worldRotation.z, worldRotation.w);

return G3D::CoordinateFrame { { localRotationQuat }, { GetPositionX(), GetPositionY(), GetPositionZ() } }
return G3D::CoordinateFrame { { worldRotationQuat }, { GetPositionX(), GetPositionY(), GetPositionZ() } }
.toWorldSpace(G3D::Box { { minX, minY, minZ }, { maxX, maxY, maxZ } })
.contains({ pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ() });
}

return GetExactDist(&pos) <= radius;
}

bool GameObject::IsWithinDistInMap(Player const* player) const
{
return IsInMap(this) && InSamePhase(this) && IsAtInteractDistance(player);
}

SpellInfo const* GameObject::GetSpellForLock(Player const* player) const
{
if (!player)
Expand All @@ -2708,7 +2694,7 @@ SpellInfo const* GameObject::GetSpellForLock(Player const* player) const
if (!lock->Type[i])
continue;

if (lock->Type[i] == LOCK_KEY_SKILL)
if (lock->Type[i] == LOCK_KEY_SPELL)
if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(lock->Index[i]))
return spell;

Expand Down
5 changes: 4 additions & 1 deletion src/server/game/Entities/GameObject/GameObject.h
Expand Up @@ -285,7 +285,10 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject>
void UpdateModelPosition();

bool IsAtInteractDistance(Position const& pos, float radius) const;
bool IsAtInteractDistance(Player const* player, SpellInfo const* spell) const;
bool IsAtInteractDistance(Player const* player, SpellInfo const* spell = nullptr) const;

bool IsWithinDistInMap(Player const* player) const;
using WorldObject::IsWithinDistInMap;

SpellInfo const* GetSpellForLock(Player const* player) const;

Expand Down
4 changes: 2 additions & 2 deletions src/server/game/Entities/Player/Player.cpp
Expand Up @@ -2298,7 +2298,7 @@ GameObject* Player::GetGameObjectIfCanInteractWith(ObjectGuid const& guid) const
if (!go)
return nullptr;

if (!go->IsWithinDistInMap(this, go->GetInteractionDistance()))
if (!go->IsWithinDistInMap(this))
return nullptr;

return go;
Expand Down Expand Up @@ -8377,7 +8377,7 @@ void Player::SendLoot(ObjectGuid guid, LootType loot_type)
}
else
{
if (lootType != LOOT_FISHINGHOLE && ((lootType != LOOT_FISHING && lootType != LOOT_FISHING_JUNK) || go->GetOwnerGUID() != GetGUID()) && !go->IsWithinDistInMap(this, INTERACTION_DISTANCE))
if (lootType != LOOT_FISHINGHOLE && ((lootType != LOOT_FISHING && lootType != LOOT_FISHING_JUNK) || go->GetOwnerGUID() != GetGUID()) && !go->IsWithinDistInMap(this))
return true;

if (lootType == LOOT_CORPSE && go->GetRespawnTime() && go->isSpawnedByDefault())
Expand Down
6 changes: 3 additions & 3 deletions src/server/game/Handlers/LootHandler.cpp
Expand Up @@ -47,7 +47,7 @@ void WorldSession::HandleAutostoreLootItemOpcode(WorldPacket& recvData)
GameObject* go = player->GetMap()->GetGameObject(lguid);

// not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO
if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player, INTERACTION_DISTANCE)))
if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player)))
{
player->SendLootRelease(lguid);
return;
Expand Down Expand Up @@ -118,7 +118,7 @@ void WorldSession::HandleLootMoneyOpcode(WorldPacket& /*recvData*/)
GameObject* go = GetPlayer()->GetMap()->GetGameObject(guid);

// do not check distance for GO if player is the owner of it (ex. fishing bobber)
if (go && ((go->GetOwnerGUID() == player->GetGUID() || go->IsWithinDistInMap(player, INTERACTION_DISTANCE))))
if (go && ((go->GetOwnerGUID() == player->GetGUID() || go->IsWithinDistInMap(player))))
loot = &go->loot;

break;
Expand Down Expand Up @@ -267,7 +267,7 @@ void WorldSession::DoLootRelease(ObjectGuid lguid)
GameObject* go = GetPlayer()->GetMap()->GetGameObject(lguid);

// not check distance for GO in case owned GO (fishing bobber case, for example) or Fishing hole GO
if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player, INTERACTION_DISTANCE)))
if (!go || ((go->GetOwnerGUID() != _player->GetGUID() && go->GetGoType() != GAMEOBJECT_TYPE_FISHINGHOLE) && !go->IsWithinDistInMap(_player)))
return;

loot = &go->loot;
Expand Down
39 changes: 27 additions & 12 deletions src/server/game/Handlers/SpellHandler.cpp
Expand Up @@ -330,6 +330,7 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
uint32 spellId;
uint8 castCount, castFlags;
recvPacket >> castCount >> spellId >> castFlags;
TriggerCastFlags triggerFlag = TRIGGERED_NONE;

TC_LOG_DEBUG("network", "WORLD: got cast spell packet, castCount: %u, spellId: %u, castFlags: %u, data length = %u", castCount, spellId, castFlags, (uint32)recvPacket.size());

Expand Down Expand Up @@ -369,24 +370,38 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
caster = _player;
}

// client provided targets
SpellCastTargets targets;
targets.Read(recvPacket, caster);
HandleClientCastFlags(recvPacket, castFlags, targets);

// not have spell in spellbook
if (caster->GetTypeId() == TYPEID_PLAYER && !caster->ToPlayer()->HasActiveSpell(spellId))
{
// not have spell in spellbook
recvPacket.rfinish(); // prevent spam at ignore packet
return;
bool allow = false;

// allow casting of unknown spells for special lock cases
if (GameObject *go = targets.GetGOTarget())
if (go->GetSpellForLock(caster->ToPlayer()) == spellInfo)
allow = true;

// TODO: Preparation for #23204
// allow casting of spells triggered by clientside periodic trigger auras
/*
if (caster->HasAuraTypeWithTriggerSpell(SPELL_AURA_PERIODIC_TRIGGER_SPELL_FROM_CLIENT, spellId))
{
allow = true;
triggerFlag = TRIGGERED_FULL_MASK;
}
*/

if (!allow)
return;
}

// can't use our own spells when we're in possession of another unit,
if (_player->isPossessing())
{
recvPacket.rfinish(); // prevent spam at ignore packet
return;
}

// client provided targets
SpellCastTargets targets;
targets.Read(recvPacket, caster);
HandleClientCastFlags(recvPacket, castFlags, targets);

// Client is resending autoshot cast opcode when other spell is cast during shoot rotation
// Skip it to prevent "interrupt" message
Expand Down Expand Up @@ -415,7 +430,7 @@ void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket)
spellInfo = actualSpellInfo;
}

Spell* spell = new Spell(caster, spellInfo, TRIGGERED_NONE);
Spell* spell = new Spell(caster, spellInfo, triggerFlag);
spell->m_cast_count = castCount; // set count of casts
spell->prepare(targets);
}
Expand Down
5 changes: 5 additions & 0 deletions src/server/game/Spells/Spell.cpp
Expand Up @@ -7593,6 +7593,11 @@ SpellCastResult Spell::CanOpenLock(uint32 effIndex, uint32 lockId, SkillType& sk

return SPELL_CAST_OK;
}
case LOCK_KEY_SPELL:
if (m_spellInfo->Id == lockInfo->Index[j])
return SPELL_CAST_OK;
reqKey = true;
break;
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/server/shared/SharedDefines.h
Expand Up @@ -2593,7 +2593,8 @@ enum LockKeyType
{
LOCK_KEY_NONE = 0,
LOCK_KEY_ITEM = 1,
LOCK_KEY_SKILL = 2
LOCK_KEY_SKILL = 2,
LOCK_KEY_SPELL = 3,
};

enum LockType
Expand Down

0 comments on commit 7807016

Please sign in to comment.