Fix a crash related to looting. (#142)

Also a WIP implementation of pathfinding Z-patch
This commit is contained in:
H0zen 2016-06-24 18:10:16 +03:00 committed by Antz
parent a7d914630a
commit 4811525de6
3 changed files with 69 additions and 31 deletions

View File

@ -36,9 +36,12 @@ PathFinder::PathFinder(const Unit* owner) :
m_useStraightPath(false), m_forceDestination(false), m_pointPathLimit(MAX_POINT_PATH_LENGTH),
m_sourceUnit(owner), m_navMesh(NULL), m_navMeshQuery(NULL)
{
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ PathFinder::PathInfo for %u \n", m_sourceUnit->GetGUIDLow());
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ PathFinder::PathFinder for %s \n", m_sourceUnit->GetGuidStr().c_str());
memset(m_pathPolyRefs, 0, sizeof(m_pathPolyRefs));
uint32 mapId = m_sourceUnit->GetMapId();
if (MMAP::MMapFactory::IsPathfindingEnabled(mapId, owner))
{
MMAP::MMapManager* mmap = MMAP::MMapFactory::createOrGetMMapManager();
@ -51,23 +54,26 @@ PathFinder::PathFinder(const Unit* owner) :
PathFinder::~PathFinder()
{
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ PathFinder::~PathInfo() for %u \n", m_sourceUnit->GetGUIDLow());
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ PathFinder::~PathFinder() for %s \n", m_sourceUnit->GetGuidStr().c_str());
}
bool PathFinder::calculate(float destX, float destY, float destZ, bool forceDest)
{
// Vector3 oldDest = getEndPosition();
Vector3 dest(destX, destY, destZ);
setEndPosition(dest);
float x, y, z;
m_sourceUnit->GetPosition(x, y, z);
if (!MaNGOS::IsValidMapCoord(x,y,z) || !MaNGOS::IsValidMapCoord(destX, destY, destZ))
{ return false; }
Vector3 start(x, y, z);
setStartPosition(start);
Vector3 dest(destX, destY, destZ);
setEndPosition(dest);
m_forceDestination = forceDest;
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ PathFinder::calculate() for %u \n", m_sourceUnit->GetGUIDLow());
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ PathFinder::calculate() for %s \n", m_sourceUnit->GetGuidStr().c_str());
// make sure navMesh works - we can run on map w/o mmap
// check if the start and end point have a .mmtile loaded (can we pass via not loaded tile on the way?)
@ -97,8 +103,8 @@ dtPolyRef PathFinder::getPathPolyByPosition(const dtPolyRef* polyPath, uint32 po
for (uint32 i = 0; i < polyPathSize; ++i)
{
float closestPoint[VERTEX_SIZE];
dtStatus dtResult = m_navMeshQuery->closestPointOnPoly(polyPath[i], point, closestPoint, NULL);
if (dtStatusFailed(dtResult))
if (dtStatusFailed(m_navMeshQuery->closestPointOnPoly(polyPath[i], point, closestPoint, NULL)))
continue;
float d = dtVdist2DSqr(point, closestPoint);
@ -133,8 +139,7 @@ dtPolyRef PathFinder::getPolyByLocation(const float* point, float* distance) con
// first try with low search box
float extents[VERTEX_SIZE] = {3.0f, 5.0f, 3.0f}; // bounds of poly search area
float closestPoint[VERTEX_SIZE] = {0.0f, 0.0f, 0.0f};
dtStatus dtResult = m_navMeshQuery->findNearestPoly(point, extents, &m_filter, &polyRef, closestPoint);
if (dtStatusSucceed(dtResult) && polyRef != INVALID_POLYREF)
if (dtStatusSucceed(m_navMeshQuery->findNearestPoly(point, extents, &m_filter, &polyRef, closestPoint)) && polyRef != INVALID_POLYREF)
{
*distance = dtVdist(closestPoint, point);
return polyRef;
@ -143,8 +148,7 @@ dtPolyRef PathFinder::getPolyByLocation(const float* point, float* distance) con
// still nothing ..
// try with bigger search box
extents[1] = 200.0f;
dtResult = m_navMeshQuery->findNearestPoly(point, extents, &m_filter, &polyRef, closestPoint);
if (dtStatusSucceed(dtResult) && polyRef != INVALID_POLYREF)
if (dtStatusSucceed(m_navMeshQuery->findNearestPoly(point, extents, &m_filter, &polyRef, closestPoint)) && polyRef != INVALID_POLYREF)
{
*distance = dtVdist(closestPoint, point);
return polyRef;
@ -171,7 +175,7 @@ void PathFinder::BuildPolyPath(const Vector3& startPos, const Vector3& endPos)
// its up to caller how he will use this info
if (startPoly == INVALID_POLYREF || endPoly == INVALID_POLYREF)
{
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: (startPoly == 0 || endPoly == 0)\n");
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: (startPoly == 0 || endPoly == 0) for %s\n", m_sourceUnit->GetGuidStr().c_str());
BuildShortcut();
if (m_sourceUnit->GetTypeId() == TYPEID_UNIT)
@ -179,9 +183,9 @@ void PathFinder::BuildPolyPath(const Vector3& startPos, const Vector3& endPos)
// Check for swimming or flying shortcut
if ((startPoly == INVALID_POLYREF && m_sourceUnit->GetTerrain()->IsUnderWater(startPos.x, startPos.y, startPos.z)) ||
(endPoly == INVALID_POLYREF && m_sourceUnit->GetTerrain()->IsUnderWater(endPos.x, endPos.y, endPos.z)))
{ m_type = ((Creature*)m_sourceUnit)->CanSwim() ? PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH) : PATHFIND_NOPATH; }
{ m_type = m_sourceUnit->ToCreature()->CanSwim() ? PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH) : PATHFIND_NOPATH; }
else
{ m_type = ((Creature*)m_sourceUnit)->CanFly() ? PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH) : PATHFIND_NOPATH; }
{ m_type = m_sourceUnit->ToCreature()->CanFly() ? PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH) : PATHFIND_NOPATH; }
}
else
{ m_type = PATHFIND_NOPATH; }
@ -193,23 +197,24 @@ void PathFinder::BuildPolyPath(const Vector3& startPos, const Vector3& endPos)
bool farFromPoly = (distToStartPoly > 7.0f || distToEndPoly > 7.0f);
if (farFromPoly)
{
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: farFromPoly distToStartPoly=%.3f distToEndPoly=%.3f\n", distToStartPoly, distToEndPoly);
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: farFromPoly distToStartPoly=%.3f distToEndPoly=%.3f for %s\n",
distToStartPoly, distToEndPoly, m_sourceUnit->GetGuidStr().c_str());
bool buildShotrcut = false;
if (m_sourceUnit->GetTypeId() == TYPEID_UNIT)
{
Creature* owner = (Creature*)m_sourceUnit;
const Creature* owner = m_sourceUnit->ToCreature();
Vector3 p = (distToStartPoly > 7.0f) ? startPos : endPos;
if (m_sourceUnit->GetTerrain()->IsUnderWater(p.x, p.y, p.z))
{
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: underWater case\n");
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: underWater case for %s\n", m_sourceUnit->GetGuidStr().c_str());
if (owner->CanSwim())
{ buildShotrcut = true; }
}
else
{
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: flying case\n");
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: flying case for %s\n", m_sourceUnit->GetGuidStr().c_str());
if (owner->CanFly())
{ buildShotrcut = true; }
}
@ -242,7 +247,7 @@ void PathFinder::BuildPolyPath(const Vector3& startPos, const Vector3& endPos)
// just need to move in straight line
if (startPoly == endPoly)
{
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: (startPoly == endPoly)\n");
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: (startPoly == endPoly) for %s\n", m_sourceUnit->GetGuidStr().c_str());
BuildShortcut();
@ -250,7 +255,7 @@ void PathFinder::BuildPolyPath(const Vector3& startPos, const Vector3& endPos)
m_polyLength = 1;
m_type = farFromPoly ? PATHFIND_INCOMPLETE : PATHFIND_NORMAL;
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: path type %d\n", m_type);
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: path type %d for %s\n", m_type, m_sourceUnit->GetGuidStr().c_str());
return;
}
@ -284,7 +289,7 @@ void PathFinder::BuildPolyPath(const Vector3& startPos, const Vector3& endPos)
if (startPolyFound && endPolyFound)
{
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: (startPolyFound && endPolyFound)\n");
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: (startPolyFound && endPolyFound) for %s\n", m_sourceUnit->GetGuidStr().c_str());
// we moved along the path and the target did not move out of our old poly-path
// our path is a simple subpath case, we have all the data we need
@ -295,7 +300,7 @@ void PathFinder::BuildPolyPath(const Vector3& startPos, const Vector3& endPos)
}
else if (startPolyFound && !endPolyFound)
{
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: (startPolyFound && !endPolyFound)\n");
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: (startPolyFound && !endPolyFound) for %s\n", m_sourceUnit->GetGuidStr().c_str());
// we are moving on the old path but target moved out
// so we have atleast part of poly-path ready
@ -353,14 +358,15 @@ void PathFinder::BuildPolyPath(const Vector3& startPos, const Vector3& endPos)
sLog.outError("%u's Path Build failed: 0 length path", m_sourceUnit->GetGUIDLow());
}
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ m_polyLength=%u prefixPolyLength=%u suffixPolyLength=%u \n", m_polyLength, prefixPolyLength, suffixPolyLength);
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ m_polyLength=%u prefixPolyLength=%u suffixPolyLength=%u for %s\n",
m_polyLength, prefixPolyLength, suffixPolyLength, m_sourceUnit->GetGuidStr().c_str());
// new path = prefix + suffix - overlap
m_polyLength = prefixPolyLength + suffixPolyLength - 1;
}
else
{
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: (!startPolyFound && !endPolyFound)\n");
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ BuildPolyPath :: (!startPolyFound && !endPolyFound) for %s\n", m_sourceUnit->GetGuidStr().c_str());
// either we have no path at all -> first run
// or something went really wrong -> we aren't moving along the path to the target
@ -382,7 +388,7 @@ void PathFinder::BuildPolyPath(const Vector3& startPos, const Vector3& endPos)
if (!m_polyLength || dtStatusFailed(dtResult))
{
// only happens if we passed bad data to findPath(), or navmesh is messed up
sLog.outError("%u's Path Build failed: 0 length path", m_sourceUnit->GetGUIDLow());
sLog.outError("Path Build failed: 0 length path for %s", m_sourceUnit->GetGuidStr().c_str());
BuildShortcut();
m_type = PATHFIND_NOPATH;
return;
@ -434,7 +440,7 @@ void PathFinder::BuildPointPath(const float* startPoint, const float* endPoint)
// only happens if pass bad data to findStraightPath or navmesh is broken
// single point paths can be generated here
// TODO : check the exact cases
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ PathFinder::BuildPointPath FAILED! path sized %d returned\n", pointCount);
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ PathFinder::BuildPointPath FAILED! path sized %d returned for %s\n", pointCount, m_sourceUnit->GetGuidStr().c_str());
BuildShortcut();
m_type = PATHFIND_NOPATH;
return;
@ -444,6 +450,8 @@ void PathFinder::BuildPointPath(const float* startPoint, const float* endPoint)
for (uint32 i = 0; i < pointCount; ++i)
{ m_pathPoints[i] = Vector3(pathPoints[i * VERTEX_SIZE + 2], pathPoints[i * VERTEX_SIZE], pathPoints[i * VERTEX_SIZE + 1]); }
//NormalizePath(pointCount);
// first point is always our current location - we need the next one
setActualEndPosition(m_pathPoints[pointCount - 1]);
@ -467,22 +475,26 @@ void PathFinder::BuildPointPath(const float* startPoint, const float* endPoint)
m_type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
}
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ PathFinder::BuildPointPath path type %d size %d poly-size %d\n", m_type, pointCount, m_polyLength);
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ PathFinder::BuildPointPath path type %d size %d poly-size %d for %s\n",
m_type, pointCount, m_polyLength, m_sourceUnit->GetGuidStr().c_str());
}
void PathFinder::BuildShortcut()
{
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ PathFinder::BuildShortcut :: making shortcut\n");
DEBUG_FILTER_LOG(LOG_FILTER_PATHFINDING, "++ PathFinder::BuildShortcut :: making shortcut for %s\n", m_sourceUnit->GetGuidStr().c_str());
clear();
// make two point path, our curr pos is the start, and dest is the end
m_pathPoints.resize(2);
uint32 size = 2;
m_pathPoints.resize(size);
// set start and a default next position
m_pathPoints[0] = getStartPosition();
m_pathPoints[1] = getActualEndPosition();
//NormalizePath(size);
m_type = PATHFIND_SHORTCUT;
}
@ -783,3 +795,23 @@ float PathFinder::dist3DSqr(const Vector3& p1, const Vector3& p2) const
{
return (p1 - p2).squaredLength();
}
void PathFinder::NormalizePath(uint32& size)
{
for (uint32 i = 0; i < m_pathPoints.size(); ++i)
{ m_sourceUnit->UpdateAllowedPositionZ(m_pathPoints[i].x, m_pathPoints[i].y, m_pathPoints[i].z); }
// check if the Z difference between each point is higher than SMOOTH_PATH_HEIGHT.
// add another point if that's the case and keep adding new midpoints till the Z difference is low enough
for (uint32 i = 1; i < m_pathPoints.size(); ++i)
{
if ((m_pathPoints[i - 1].z - m_pathPoints[i].z) > SMOOTH_PATH_HEIGHT)
{
auto midPoint = m_pathPoints[i - 1] + (m_pathPoints[i] - m_pathPoints[i - 1]) / 2.f;
m_sourceUnit->UpdateAllowedPositionZ(midPoint.x, midPoint.y, midPoint.z);
m_pathPoints.insert(m_pathPoints.begin() + i, midPoint);
--i;
}
}
size = m_pathPoints.size();
}

View File

@ -44,6 +44,7 @@ class Unit;
#define SMOOTH_PATH_STEP_SIZE 4.0f
#define SMOOTH_PATH_SLOP 0.3f
#define SMOOTH_PATH_HEIGHT 1.0f
#define VERTEX_SIZE 3
#define INVALID_POLYREF 0
@ -76,6 +77,7 @@ class PathFinder
Vector3 getStartPosition() const { return m_startPosition; }
Vector3 getEndPosition() const { return m_endPosition; }
Vector3 getActualEndPosition() const { return m_actualEndPosition; }
void NormalizePath(uint32& size);
PointsArray& getPath() { return m_pathPoints; }
PathType getPathType() const { return m_type; }

View File

@ -403,6 +403,10 @@ LootItem::LootItem(uint32 itemid_, uint32 count_, int32 randomPropertyId_)
// Basic checks for player/item compatibility - if false no chance to see the item in the loot
bool LootItem::AllowedForPlayer(Player const* player, WorldObject const* lootTarget) const
{
// player check
if (!player || !player->IsInWorld())
{ return false; }
// DB conditions check
if (conditionId && !sObjectMgr.IsPlayerMeetToCondition(conditionId, player, player->GetMap(), lootTarget, CONDITION_FROM_LOOT))
{ return false; }