diff options
author | Jozef DĂșc <D0d0@users.noreply.github.com> | 2019-04-24 20:39:01 +0200 |
---|---|---|
committer | Giacomo Pozzoni <giacomopoz@gmail.com> | 2019-04-24 20:39:01 +0200 |
commit | 32e1de39a26628dcb64bc21ad415afb2ad938925 (patch) | |
tree | e5e18dc5bf3958fd241f4176b0be56696cd06bd8 /src | |
parent | 16a154c4e87ff1ff89323a8960bf601e6c18589b (diff) |
Core/Object: Range check (#23179)
* Should solve #23062. All credits to @xvwyh
* Remove unused variables
* Remove unused variable
* Cast int32 to uint32
* Remove G3D headers from core header file
* Change door distance
* Update GameObject.cpp
Add newline
* Update GameObject.h
Indentation
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Entities/GameObject/GameObject.cpp | 169 | ||||
-rw-r--r-- | src/server/game/Entities/GameObject/GameObject.h | 17 | ||||
-rw-r--r-- | src/server/game/Entities/Object/Object.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Entities/Transport/Transport.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 8 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_gobject.cpp | 2 |
6 files changed, 168 insertions, 32 deletions
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 6ad2416d24f..2453182784a 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -40,6 +40,8 @@ #include "Transport.h" #include "UpdateFieldFlags.h" #include "World.h" +#include <G3D/Box.h> +#include <G3D/CoordinateFrame.h> #include <G3D/Quat.h> void GameObjectTemplate::InitializeQueryData() @@ -299,7 +301,7 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u return false; } - SetWorldRotation(rotation.x, rotation.y, rotation.z, rotation.w); + SetLocalRotation(rotation.x, rotation.y, rotation.z, rotation.w); GameObjectAddon const* gameObjectAddon = sObjectMgr->GetGameObjectAddon(GetSpawnId()); // For most of gameobjects is (0, 0, 0, 1) quaternion, there are only some transports with not standard rotation @@ -977,7 +979,7 @@ void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask) data.id = GetEntry(); data.spawnPoint.WorldRelocate(this); data.phaseMask = phaseMask; - data.rotation = m_worldRotation; + data.rotation = m_localRotation; data.spawntimesecs = m_spawnedByDefault ? m_respawnDelayTime : -(int32)m_respawnDelayTime; data.animprogress = GetGoAnimProgress(); data.goState = GetGoState(); @@ -1005,10 +1007,10 @@ void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask) stmt->setFloat(index++, GetPositionY()); stmt->setFloat(index++, GetPositionZ()); stmt->setFloat(index++, GetOrientation()); - stmt->setFloat(index++, m_worldRotation.x); - stmt->setFloat(index++, m_worldRotation.y); - stmt->setFloat(index++, m_worldRotation.z); - stmt->setFloat(index++, m_worldRotation.w); + stmt->setFloat(index++, m_localRotation.x); + stmt->setFloat(index++, m_localRotation.y); + stmt->setFloat(index++, m_localRotation.z); + stmt->setFloat(index++, m_localRotation.w); stmt->setInt32(index++, int32(m_respawnDelayTime)); stmt->setUInt8(index++, GetGoAnimProgress()); stmt->setUInt8(index++, uint8(GetGoState())); @@ -2103,21 +2105,21 @@ void GameObject::UpdatePackedRotation() static const int32 PACK_YZ_MASK = (PACK_YZ << 1) - 1; static const int32 PACK_X_MASK = (PACK_X << 1) - 1; - int8 w_sign = (m_worldRotation.w >= 0.f ? 1 : -1); - int64 x = int32(m_worldRotation.x * PACK_X) * w_sign & PACK_X_MASK; - int64 y = int32(m_worldRotation.y * PACK_YZ) * w_sign & PACK_YZ_MASK; - int64 z = int32(m_worldRotation.z * PACK_YZ) * w_sign & PACK_YZ_MASK; + int8 w_sign = (m_localRotation.w >= 0.f ? 1 : -1); + int64 x = int32(m_localRotation.x * PACK_X) * w_sign & PACK_X_MASK; + int64 y = int32(m_localRotation.y * PACK_YZ) * w_sign & PACK_YZ_MASK; + int64 z = int32(m_localRotation.z * PACK_YZ) * w_sign & PACK_YZ_MASK; m_packedRotation = z | (y << 21) | (x << 42); } -void GameObject::SetWorldRotation(float qx, float qy, float qz, float qw) +void GameObject::SetLocalRotation(float qx, float qy, float qz, float qw) { G3D::Quat rotation(qx, qy, qz, qw); rotation.unitize(); - m_worldRotation.x = rotation.x; - m_worldRotation.y = rotation.y; - m_worldRotation.z = rotation.z; - m_worldRotation.w = rotation.w; + m_localRotation.x = rotation.x; + m_localRotation.y = rotation.y; + m_localRotation.z = rotation.z; + m_localRotation.w = rotation.w; UpdatePackedRotation(); } @@ -2129,10 +2131,27 @@ void GameObject::SetParentRotation(QuaternionData const& rotation) SetFloatValue(GAMEOBJECT_PARENTROTATION + 3, rotation.w); } -void GameObject::SetWorldRotationAngles(float z_rot, float y_rot, float x_rot) +void GameObject::SetLocalRotationAngles(float z_rot, float y_rot, float x_rot) { G3D::Quat quat(G3D::Matrix3::fromEulerAnglesZYX(z_rot, y_rot, x_rot)); - SetWorldRotation(quat.x, quat.y, quat.z, quat.w); + SetLocalRotation(quat.x, quat.y, quat.z, quat.w); +} + +QuaternionData GameObject::GetWorldRotation() const +{ + QuaternionData localRotation = GetLocalRotation(); + if (Transport* transport = GetTransport()) + { + QuaternionData worldRotation = transport->GetWorldRotation(); + + G3D::Quat worldRotationQuat(worldRotation.x, worldRotation.y, worldRotation.z, worldRotation.w); + G3D::Quat localRotationQuat(localRotation.x, localRotation.y, localRotation.z, localRotation.w); + + G3D::Quat resultRotation = localRotationQuat * worldRotationQuat; + + return QuaternionData(resultRotation.x, resultRotation.y, resultRotation.z, resultRotation.w); + } + return localRotation; } void GameObject::ModifyHealth(int32 change, WorldObject* attackerOrHealer /*= nullptr*/, uint32 spellId /*= 0*/) @@ -2590,3 +2609,119 @@ std::string GameObject::GetDebugInfo() const << "SpawnId: " << GetSpawnId() << " GoState: " << std::to_string(GetGoState()) << " ScriptId: " << GetScriptId() << " AIName: " << GetAIName(); return sstr.str(); } + +bool GameObject::IsAtInteractDistance(Player const* player, SpellInfo const* spell) const +{ + if (spell || (spell = GetSpellForLock(player))) + { + float maxRange = spell->GetMaxRange(spell->IsPositive()); + + if (GetGoType() == GAMEOBJECT_TYPE_SPELL_FOCUS) + return maxRange * maxRange >= GetExactDistSq(player); + + if (GameObjectDisplayInfoEntry const* displayInfo = sGameObjectDisplayInfoStore.LookupEntry(GetGOInfo()->displayId)) + 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); +} + +bool GameObject::IsAtInteractDistance(Position const& pos, float radius) const +{ + if (GameObjectDisplayInfoEntry const* displayInfo = sGameObjectDisplayInfoStore.LookupEntry(GetGOInfo()->displayId)) + { + float scale = GetObjectScale(); + + float minX = displayInfo->minX * scale - radius; + float minY = displayInfo->minY * scale - radius; + float minZ = displayInfo->minZ * scale - radius; + float maxX = displayInfo->maxX * scale + radius; + 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); + + return G3D::CoordinateFrame { { localRotationQuat }, { GetPositionX(), GetPositionY(), GetPositionZ() } } + .toWorldSpace(G3D::Box { { minX, minY, minZ }, { maxX, maxY, maxZ } }) + .contains({ pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ() }); + } + + return GetExactDist(&pos) <= radius; +} + +SpellInfo const* GameObject::GetSpellForLock(Player const* player) const +{ + if (!player) + return nullptr; + + uint32 lockId = GetGOInfo()->GetLockId(); + if (!lockId) + return nullptr; + + LockEntry const* lock = sLockStore.LookupEntry(lockId); + if (!lock) + return nullptr; + + for (uint8 i = 0; i < MAX_LOCK_CASE; ++i) + { + if (!lock->Type[i]) + continue; + + if (lock->Type[i] == LOCK_KEY_SKILL) + if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(lock->Index[i])) + return spell; + + if (lock->Type[i] != LOCK_KEY_SKILL) + break; + + for (auto&& playerSpell : player->GetSpellMap()) + if (SpellInfo const* spell = sSpellMgr->GetSpellInfo(playerSpell.first)) + for (auto&& effect : spell->Effects) + if (effect.Effect == SPELL_EFFECT_OPEN_LOCK && ((uint32) effect.MiscValue) == lock->Index[i]) + if (effect.CalcValue(player) >= int32(lock->Skill[i])) + return spell; + } + + return nullptr; +} diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index 10467d14b04..257e4ce99db 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -104,11 +104,13 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject> ObjectGuid::LowType GetSpawnId() const { return m_spawnId; } // z_rot, y_rot, x_rot - rotation angles around z, y and x axes - void SetWorldRotationAngles(float z_rot, float y_rot, float x_rot); - void SetWorldRotation(float qx, float qy, float qz, float qw); + void SetLocalRotationAngles(float z_rot, float y_rot, float x_rot); + void SetLocalRotation(float qx, float qy, float qz, float qw); void SetParentRotation(QuaternionData const& rotation); // transforms(rotates) transport's path - QuaternionData const& GetWorldRotation() const { return m_worldRotation; } - int64 GetPackedWorldRotation() const { return m_packedRotation; } + QuaternionData const& GetLocalRotation() const { return m_localRotation; } + int64 GetPackedLocalRotation() const { return m_packedRotation; } + + QuaternionData GetWorldRotation() const; // overwrite WorldObject function for proper name localization std::string const& GetNameForLocaleIdx(LocaleConstant locale_idx) const override; @@ -282,6 +284,11 @@ 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; + + SpellInfo const* GetSpellForLock(Player const* player) const; + void AIM_Destroy(); bool AIM_Initialize(); @@ -318,7 +325,7 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject<GameObject> GameObjectValue m_goValue; int64 m_packedRotation; - QuaternionData m_worldRotation; + QuaternionData m_localRotation; Position m_stationaryPosition; ObjectGuid m_lootRecipient; diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index bd3d20f9ff2..160469f5823 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -462,7 +462,7 @@ void Object::BuildMovementUpdate(ByteBuffer* data, uint16 flags) const // 0x200 if (flags & UPDATEFLAG_ROTATION) - *data << int64(ToGameObject()->GetPackedWorldRotation()); + *data << int64(ToGameObject()->GetPackedLocalRotation()); } void Object::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) const diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp index 69a76565b48..32b4a7c6de7 100644 --- a/src/server/game/Entities/Transport/Transport.cpp +++ b/src/server/game/Entities/Transport/Transport.cpp @@ -100,7 +100,7 @@ bool Transport::Create(ObjectGuid::LowType guidlow, uint32 entry, uint32 mapid, SetGoType(GAMEOBJECT_TYPE_MO_TRANSPORT); SetGoAnimProgress(animprogress); SetName(goinfo->name); - SetWorldRotation(0.0f, 0.0f, 0.0f, 1.0f); + SetLocalRotation(0.0f, 0.0f, 0.0f, 1.0f); SetParentRotation(QuaternionData()); m_model = CreateModel(); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index a0f35b48b29..d3ef850bd5d 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -6287,9 +6287,6 @@ SpellCastResult Spell::CheckRange(bool strict) const if (m_spellInfo->RangeEntry && m_spellInfo->RangeEntry->type != SPELL_RANGE_MELEE && !strict) maxRange += std::min(MAX_SPELL_RANGE_TOLERANCE, maxRange*0.1f); // 10% but no more than MAX_SPELL_RANGE_TOLERANCE - // save the original values before squaring them - float origMinRange = minRange, origMaxRange = maxRange; - // get square values for sqr distance checks minRange *= minRange; maxRange *= maxRange; @@ -6310,10 +6307,7 @@ SpellCastResult Spell::CheckRange(bool strict) const if (GameObject* goTarget = m_targets.GetGOTarget()) { - if (origMinRange > 0.0f && goTarget->IsInRange(m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), origMinRange)) - return SPELL_FAILED_OUT_OF_RANGE; - - if (!goTarget->IsInRange(m_caster->GetPositionX(), m_caster->GetPositionY(), m_caster->GetPositionZ(), origMaxRange)) + if (!goTarget->IsAtInteractDistance(m_caster->ToPlayer(), m_spellInfo)) return SPELL_FAILED_OUT_OF_RANGE; } diff --git a/src/server/scripts/Commands/cs_gobject.cpp b/src/server/scripts/Commands/cs_gobject.cpp index 0e65130fe61..5b1be208e06 100644 --- a/src/server/scripts/Commands/cs_gobject.cpp +++ b/src/server/scripts/Commands/cs_gobject.cpp @@ -433,7 +433,7 @@ public: Map* map = object->GetMap(); object->Relocate(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), oz); - object->SetWorldRotationAngles(oz, oy, ox); + object->SetLocalRotationAngles(oz, oy, ox); object->SaveToDB(); // Generate a completely new spawn with new guid |