aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Entities
diff options
context:
space:
mode:
authorMeji <alvaro.megias@outlook.com>2024-05-04 13:20:13 +0200
committerShauren <shauren.trinity@gmail.com>2024-05-27 18:53:47 +0200
commitb070e63fa867f7f25e73e9ef3aafbe18902a50e9 (patch)
treec3d0151e9b46d30ccb69d57983df431acfb673a3 /src/server/game/Entities
parent38e99e1569fcba821211fcd2d7c3a0b2bd00701c (diff)
Core/AreaTriggers: Fix triggering of client areatriggers for some shapes
Diffstat (limited to 'src/server/game/Entities')
-rw-r--r--src/server/game/Entities/AreaTrigger/AreaTrigger.cpp71
-rw-r--r--src/server/game/Entities/AreaTrigger/AreaTrigger.h1
-rw-r--r--src/server/game/Entities/Object/Position.cpp101
-rw-r--r--src/server/game/Entities/Object/Position.h9
-rw-r--r--src/server/game/Entities/Player/Player.cpp41
-rw-r--r--src/server/game/Entities/Player/Player.h2
6 files changed, 119 insertions, 106 deletions
diff --git a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp
index af7170cf345..85fbcc8f27a 100644
--- a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp
+++ b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp
@@ -705,7 +705,7 @@ void AreaTrigger::SearchUnitInPolygon(std::vector<Unit*>& targetList)
{
return unit->GetPositionZ() < minZ
|| unit->GetPositionZ() > maxZ
- || !CheckIsInPolygon2D(unit);
+ || !unit->IsInPolygon2D(*this, _polygonVertices);
});
}
@@ -919,75 +919,6 @@ void AreaTrigger::UpdatePolygonVertices()
_verticesUpdatePreviousOrientation = newOrientation;
}
-bool AreaTrigger::CheckIsInPolygon2D(Position const* pos) const
-{
- float testX = pos->GetPositionX();
- float testY = pos->GetPositionY();
-
- //this method uses the ray tracing algorithm to determine if the point is in the polygon
- bool locatedInPolygon = false;
-
- for (std::size_t vertex = 0; vertex < _polygonVertices.size(); ++vertex)
- {
- std::size_t nextVertex;
-
- //repeat loop for all sets of points
- if (vertex == (_polygonVertices.size() - 1))
- {
- //if i is the last vertex, let j be the first vertex
- nextVertex = 0;
- }
- else
- {
- //for all-else, let j=(i+1)th vertex
- nextVertex = vertex + 1;
- }
-
- float vertX_i = GetPositionX() + _polygonVertices[vertex].GetPositionX();
- float vertY_i = GetPositionY() + _polygonVertices[vertex].GetPositionY();
- float vertX_j = GetPositionX() + _polygonVertices[nextVertex].GetPositionX();
- float vertY_j = GetPositionY() + _polygonVertices[nextVertex].GetPositionY();
-
- // following statement checks if testPoint.Y is below Y-coord of i-th vertex
- bool belowLowY = vertY_i > testY;
- // following statement checks if testPoint.Y is below Y-coord of i+1-th vertex
- bool belowHighY = vertY_j > testY;
-
- /* following statement is true if testPoint.Y satisfies either (only one is possible)
- -->(i).Y < testPoint.Y < (i+1).Y OR
- -->(i).Y > testPoint.Y > (i+1).Y
-
- (Note)
- Both of the conditions indicate that a point is located within the edges of the Y-th coordinate
- of the (i)-th and the (i+1)- th vertices of the polygon. If neither of the above
- conditions is satisfied, then it is assured that a semi-infinite horizontal line draw
- to the right from the testpoint will NOT cross the line that connects vertices i and i+1
- of the polygon
- */
- bool withinYsEdges = belowLowY != belowHighY;
-
- if (withinYsEdges)
- {
- // this is the slope of the line that connects vertices i and i+1 of the polygon
- float slopeOfLine = (vertX_j - vertX_i) / (vertY_j - vertY_i);
-
- // this looks up the x-coord of a point lying on the above line, given its y-coord
- float pointOnLine = (slopeOfLine* (testY - vertY_i)) + vertX_i;
-
- //checks to see if x-coord of testPoint is smaller than the point on the line with the same y-coord
- bool isLeftToLine = testX < pointOnLine;
-
- if (isLeftToLine)
- {
- //this statement changes true to false (and vice-versa)
- locatedInPolygon = !locatedInPolygon;
- }//end if (isLeftToLine)
- }//end if (withinYsEdges
- }
-
- return locatedInPolygon;
-}
-
bool AreaTrigger::HasOverridePosition() const
{
return m_areaTriggerData->OverrideMoveCurveX->OverrideActive
diff --git a/src/server/game/Entities/AreaTrigger/AreaTrigger.h b/src/server/game/Entities/AreaTrigger/AreaTrigger.h
index 5eaa82e1a83..7d454298108 100644
--- a/src/server/game/Entities/AreaTrigger/AreaTrigger.h
+++ b/src/server/game/Entities/AreaTrigger/AreaTrigger.h
@@ -190,7 +190,6 @@ class TC_GAME_API AreaTrigger final : public WorldObject, public GridObject<Area
void SearchUnitInCylinder(std::vector<Unit*>& targetList);
void SearchUnitInDisk(std::vector<Unit*>& targetList);
void SearchUnitInBoundedPlane(std::vector<Unit*>& targetList);
- bool CheckIsInPolygon2D(Position const* pos) const;
void HandleUnitEnterExit(std::vector<Unit*> const& targetList);
void DoActions(Unit* unit);
diff --git a/src/server/game/Entities/Object/Position.cpp b/src/server/game/Entities/Object/Position.cpp
index d91c55eb84a..aa391a0d062 100644
--- a/src/server/game/Entities/Object/Position.cpp
+++ b/src/server/game/Entities/Object/Position.cpp
@@ -62,38 +62,109 @@ Position Position::GetPositionWithOffset(Position const& offset) const
return ret;
}
-bool Position::IsWithinBox(Position const& center, float xradius, float yradius, float zradius) const
+bool Position::IsWithinBox(Position const& boxOrigin, float length, float width, float height) const
{
// rotate the WorldObject position instead of rotating the whole cube, that way we can make a simplified
// is-in-cube check and we have to calculate only one point instead of 4
// 2PI = 360*, keep in mind that ingame orientation is counter-clockwise
- double rotation = 2 * M_PI - center.GetOrientation();
+ double rotation = 2 * M_PI - boxOrigin.GetOrientation();
double sinVal = std::sin(rotation);
double cosVal = std::cos(rotation);
- float BoxDistX = GetPositionX() - center.GetPositionX();
- float BoxDistY = GetPositionY() - center.GetPositionY();
+ float BoxDistX = GetPositionX() - boxOrigin.GetPositionX();
+ float BoxDistY = GetPositionY() - boxOrigin.GetPositionY();
- float rotX = float(center.GetPositionX() + BoxDistX * cosVal - BoxDistY*sinVal);
- float rotY = float(center.GetPositionY() + BoxDistY * cosVal + BoxDistX*sinVal);
+ float rotX = float(boxOrigin.GetPositionX() + BoxDistX * cosVal - BoxDistY * sinVal);
+ float rotY = float(boxOrigin.GetPositionY() + BoxDistY * cosVal + BoxDistX * sinVal);
// box edges are parallel to coordiante axis, so we can treat every dimension independently :D
- float dz = GetPositionZ() - center.GetPositionZ();
- float dx = rotX - center.GetPositionX();
- float dy = rotY - center.GetPositionY();
- if ((std::fabs(dx) > xradius) ||
- (std::fabs(dy) > yradius) ||
- (std::fabs(dz) > zradius))
+ float dz = GetPositionZ() - boxOrigin.GetPositionZ();
+ float dx = rotX - boxOrigin.GetPositionX();
+ float dy = rotY - boxOrigin.GetPositionY();
+ if ((std::fabs(dx) > length) ||
+ (std::fabs(dy) > width) ||
+ (std::fabs(dz) > height))
return false;
return true;
}
-bool Position::IsWithinDoubleVerticalCylinder(Position const* center, float radius, float height) const
+bool Position::IsWithinVerticalCylinder(Position const& cylinderOrigin, float radius, float height, bool isDoubleVertical) const
{
- float verticalDelta = GetPositionZ() - center->GetPositionZ();
- return IsInDist2d(center, radius) && std::abs(verticalDelta) <= height;
+ float verticalDelta = GetPositionZ() - cylinderOrigin.GetPositionZ();
+ bool isValidPositionZ = isDoubleVertical ? std::abs(verticalDelta) <= height : 0 <= verticalDelta && verticalDelta <= height;
+
+ return isValidPositionZ && IsInDist2d(cylinderOrigin, radius);
+}
+
+bool Position::IsInPolygon2D(Position const& polygonOrigin, std::span<Position const> vertices) const
+{
+ float testX = GetPositionX();
+ float testY = GetPositionY();
+
+ //this method uses the ray tracing algorithm to determine if the point is in the polygon
+ bool locatedInPolygon = false;
+
+ for (std::size_t vertex = 0; vertex < vertices.size(); ++vertex)
+ {
+ std::size_t nextVertex;
+
+ //repeat loop for all sets of points
+ if (vertex == (vertices.size() - 1))
+ {
+ //if i is the last vertex, let j be the first vertex
+ nextVertex = 0;
+ }
+ else
+ {
+ //for all-else, let j=(i+1)th vertex
+ nextVertex = vertex + 1;
+ }
+
+ float vertX_i = polygonOrigin.GetPositionX() + vertices[vertex].GetPositionX();
+ float vertY_i = polygonOrigin.GetPositionY() + vertices[vertex].GetPositionY();
+ float vertX_j = polygonOrigin.GetPositionX() + vertices[nextVertex].GetPositionX();
+ float vertY_j = polygonOrigin.GetPositionY() + vertices[nextVertex].GetPositionY();
+
+ // following statement checks if testPoint.Y is below Y-coord of i-th vertex
+ bool belowLowY = vertY_i > testY;
+ // following statement checks if testPoint.Y is below Y-coord of i+1-th vertex
+ bool belowHighY = vertY_j > testY;
+
+ /* following statement is true if testPoint.Y satisfies either (only one is possible)
+ -->(i).Y < testPoint.Y < (i+1).Y OR
+ -->(i).Y > testPoint.Y > (i+1).Y
+
+ (Note)
+ Both of the conditions indicate that a point is located within the edges of the Y-th coordinate
+ of the (i)-th and the (i+1)- th vertices of the polygon. If neither of the above
+ conditions is satisfied, then it is assured that a semi-infinite horizontal line draw
+ to the right from the testpoint will NOT cross the line that connects vertices i and i+1
+ of the polygon
+ */
+ bool withinYsEdges = belowLowY != belowHighY;
+
+ if (withinYsEdges)
+ {
+ // this is the slope of the line that connects vertices i and i+1 of the polygon
+ float slopeOfLine = (vertX_j - vertX_i) / (vertY_j - vertY_i);
+
+ // this looks up the x-coord of a point lying on the above line, given its y-coord
+ float pointOnLine = (slopeOfLine * (testY - vertY_i)) + vertX_i;
+
+ //checks to see if x-coord of testPoint is smaller than the point on the line with the same y-coord
+ bool isLeftToLine = testX < pointOnLine;
+
+ if (isLeftToLine)
+ {
+ //this statement changes true to false (and vice-versa)
+ locatedInPolygon = !locatedInPolygon;
+ }//end if (isLeftToLine)
+ }//end if (withinYsEdges
+ }
+
+ return locatedInPolygon;
}
bool Position::HasInArc(float arc, Position const* obj, float border) const
diff --git a/src/server/game/Entities/Object/Position.h b/src/server/game/Entities/Object/Position.h
index 1bd11b69c88..ed4709dadf3 100644
--- a/src/server/game/Entities/Object/Position.h
+++ b/src/server/game/Entities/Object/Position.h
@@ -19,6 +19,7 @@
#define Trinity_game_Position_h__
#include "Define.h"
+#include <span>
#include <string>
#include <cmath>
@@ -138,16 +139,18 @@ public:
float GetRelativeAngle(Position const* pos) const { return ToRelativeAngle(GetAbsoluteAngle(pos)); }
constexpr bool IsInDist2d(float x, float y, float dist) const { return GetExactDist2dSq(x, y) < dist * dist; }
+ constexpr bool IsInDist2d(Position const& pos, float dist) const { return GetExactDist2dSq(pos) < dist * dist; }
constexpr bool IsInDist2d(Position const* pos, float dist) const { return GetExactDist2dSq(pos) < dist * dist; }
constexpr bool IsInDist(float x, float y, float z, float dist) const { return GetExactDistSq(x, y, z) < dist * dist; }
constexpr bool IsInDist(Position const& pos, float dist) const { return GetExactDistSq(pos) < dist * dist; }
constexpr bool IsInDist(Position const* pos, float dist) const { return GetExactDistSq(pos) < dist * dist; }
- bool IsWithinBox(Position const& center, float xradius, float yradius, float zradius) const;
+ bool IsWithinBox(Position const& boxOrigin, float length, float width, float height) const;
- // dist2d < radius && abs(dz) < height
- bool IsWithinDoubleVerticalCylinder(Position const* center, float radius, float height) const;
+ bool IsWithinVerticalCylinder(Position const& cylinderOrigin, float radius, float height, bool isDoubleVertical = false) const;
+
+ bool IsInPolygon2D(Position const& polygonOrigin, std::span<Position const> vertices) const;
bool HasInArc(float arcangle, Position const* pos, float border = 2.0f) const;
bool HasInLine(Position const* pos, float objSize, float width) const;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index aad59f7930d..b06f41e0619 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -1029,7 +1029,7 @@ void Player::Update(uint32 p_time)
if (_restMgr->HasRestFlag(REST_FLAG_IN_TAVERN))
{
AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(_restMgr->GetInnTriggerID());
- if (!atEntry || !IsInAreaTriggerRadius(atEntry))
+ if (!atEntry || !IsInAreaTrigger(atEntry))
_restMgr->RemoveRestFlag(REST_FLAG_IN_TAVERN);
}
@@ -2015,29 +2015,38 @@ GameObject* Player::GetGameObjectIfCanInteractWith(ObjectGuid const& guid, Gameo
return go;
}
-bool Player::IsInAreaTriggerRadius(AreaTriggerEntry const* trigger) const
+bool Player::IsInAreaTrigger(AreaTriggerEntry const* areaTrigger) const
{
- if (!trigger)
+ if (!areaTrigger)
return false;
- if (int32(GetMapId()) != trigger->ContinentID && !GetPhaseShift().HasVisibleMapId(trigger->ContinentID))
+ if (int32(GetMapId()) != areaTrigger->ContinentID && !GetPhaseShift().HasVisibleMapId(areaTrigger->ContinentID))
return false;
- if (trigger->PhaseID || trigger->PhaseGroupID || trigger->PhaseUseFlags)
- if (!PhasingHandler::InDbPhaseShift(this, trigger->PhaseUseFlags, trigger->PhaseID, trigger->PhaseGroupID))
+ if (areaTrigger->PhaseID || areaTrigger->PhaseGroupID || areaTrigger->PhaseUseFlags)
+ if (!PhasingHandler::InDbPhaseShift(this, areaTrigger->PhaseUseFlags, areaTrigger->PhaseID, areaTrigger->PhaseGroupID))
return false;
- if (trigger->Radius > 0.f)
+ Position areaTriggerPos(areaTrigger->Pos.X, areaTrigger->Pos.Y, areaTrigger->Pos.Z, areaTrigger->BoxYaw);
+ switch (areaTrigger->ShapeType)
{
- // if we have radius check it
- float dist = GetDistance(trigger->Pos.X, trigger->Pos.Y, trigger->Pos.Z);
- if (dist > trigger->Radius)
- return false;
- }
- else
- {
- Position center(trigger->Pos.X, trigger->Pos.Y, trigger->Pos.Z, trigger->BoxYaw);
- if (!IsWithinBox(center, trigger->BoxLength / 2.f, trigger->BoxWidth / 2.f, trigger->BoxHeight / 2.f))
+ case 0: // Sphere
+ if (!IsInDist(&areaTriggerPos, areaTrigger->Radius))
+ return false;
+ break;
+ case 1: // Box
+ if (!IsWithinBox(areaTriggerPos, areaTrigger->BoxLength / 2.f, areaTrigger->BoxWidth / 2.f, areaTrigger->BoxHeight / 2.f))
+ return false;
+ break;
+ case 3: // Polygon
+ if (!IsInPolygon2D(areaTriggerPos, sObjectMgr->GetVerticesForAreaTrigger(areaTrigger)))
+ return false;
+ break;
+ case 4: // Cylinder
+ if (!IsWithinVerticalCylinder(areaTriggerPos, areaTrigger->Radius, areaTrigger->BoxHeight))
+ return false;
+ break;
+ default:
return false;
}
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 24bc8ae574b..e427a2639d4 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1178,7 +1178,7 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player>
bool IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* caster, bool requireImmunityPurgesEffectAttribute = false) const override;
- bool IsInAreaTriggerRadius(AreaTriggerEntry const* trigger) const;
+ bool IsInAreaTrigger(AreaTriggerEntry const* areaTrigger) const;
void SendInitialPacketsBeforeAddToMap();
void SendInitialPacketsAfterAddToMap();