Core/MMAPs: Adjust walkable climb and fix a lot of mmap raycast issues

Port From (https://github.com/TrinityCore/TrinityCore/commit/89afeed41b4f040e4852b35183f30291588662d7)
This commit is contained in:
hondacrx
2022-02-22 14:24:29 -05:00
parent 0600993129
commit c27475ae46
5 changed files with 99 additions and 119 deletions
+6 -5
View File
@@ -53,9 +53,9 @@ namespace Game.Chat
if (para.Equals("true"))
useStraightPath = true;
bool useStraightLine = false;
if (para.Equals("line"))
useStraightLine = true;
bool useRaycast = false;
if (para.Equals("line") || para.Equals("ray") || para.Equals("raycast"))
useRaycast = true;
// unit locations
float x, y, z;
@@ -64,11 +64,12 @@ namespace Game.Chat
// path
PathGenerator path = new(target);
path.SetUseStraightPath(useStraightPath);
bool result = path.CalculatePath(x, y, z, false, useStraightLine);
path.SetUseRaycast(useRaycast);
bool result = path.CalculatePath(x, y, z, false);
var pointPath = path.GetPath();
handler.SendSysMessage("{0}'s path to {1}:", target.GetName(), player.GetName());
handler.SendSysMessage("Building: {0}", useStraightPath ? "StraightPath" : useStraightLine ? "Raycast" : "SmoothPath");
handler.SendSysMessage("Building: {0}", useStraightPath ? "StraightPath" : useRaycast ? "Raycast" : "SmoothPath");
handler.SendSysMessage("Result: {0} - Length: {1} - Type: {2}", (result ? "true" : "false"), pointPath.Length, path.GetPathType());
var start = path.GetStartPosition();
+6 -4
View File
@@ -3424,10 +3424,11 @@ namespace Game.Entities
// Use a detour raycast to get our first collision point
PathGenerator path = new(this);
path.CalculatePath(destx, desty, destz, false, true);
path.SetUseRaycast(true);
path.CalculatePath(destx, desty, destz, false);
// We have a invalid path result. Skip further processing.
if ((path.GetPathType() & ~(PathType.Normal | PathType.Shortcut | PathType.Incomplete | PathType.FarFromPoly)) != 0)
if ((path.GetPathType() & ~(PathType.Normal | PathType.Shortcut | PathType.Incomplete | PathType.FarFromPoly | PathType.NotUsingPath)) != 0)
return;
Vector3 result = path.GetPath()[path.GetPath().Length - 1];
@@ -3437,7 +3438,8 @@ namespace Game.Entities
// check static LOS
float halfHeight = GetCollisionHeight() * 0.5f;
bool col = Global.VMapMgr.GetObjectHitPos(PhasingHandler.GetTerrainMapId(GetPhaseShift(), GetMap(), pos.posX, pos.posY),
bool col;
/*col = Global.VMapMgr.GetObjectHitPos(PhasingHandler.GetTerrainMapId(GetPhaseShift(), GetMap(), pos.posX, pos.posY),
pos.posX, pos.posY, pos.posZ + halfHeight,
destx, desty, destz + halfHeight,
out destx, out desty, out destz, -0.5f);
@@ -3450,7 +3452,7 @@ namespace Game.Entities
destx -= SharedConst.ContactDistance * MathF.Cos(angle);
desty -= SharedConst.ContactDistance * MathF.Sin(angle);
dist = MathF.Sqrt((pos.posX - destx) * (pos.posX - destx) + (pos.posY - desty) * (pos.posY - desty));
}
}*/
// check dynamic collision
col = GetMap().GetObjectHitPos(GetPhaseShift(), pos.posX, pos.posY, pos.posZ + halfHeight, destx, desty, destz + halfHeight, out destx, out desty, out destz, -0.5f);
@@ -47,7 +47,7 @@ namespace Game.Movement
CreateFilter();
}
public bool CalculatePath(float destX, float destY, float destZ, bool forceDest = false, bool straightLine = false)
public bool CalculatePath(float destX, float destY, float destZ, bool forceDest = false)
{
float x, y, z;
_source.GetPosition(out x, out y, out z);
@@ -62,7 +62,6 @@ namespace Game.Movement
SetStartPosition(start);
_forceDestination = forceDest;
_straightLine = straightLine;
Log.outDebug(LogFilter.Maps, "PathGenerator.CalculatePath() for {0} \n", _source.GetGUID().ToString());
@@ -145,6 +144,7 @@ namespace Game.Movement
return polyRef;
}
distance = float.MaxValue;
return 0;
}
@@ -160,6 +160,8 @@ namespace Game.Movement
ulong startPoly = GetPolyByLocation(startPoint, ref distToStartPoly);
ulong endPoly = GetPolyByLocation(endPoint, ref distToEndPoly);
pathType = PathType.Normal;
// we have a hole in our mesh
// make shortcut path and mark it as NOPATH ( with flying and swimming exception )
// its up to caller how he will use this info
@@ -185,8 +187,18 @@ namespace Game.Movement
}
}
pathType = (path || waterPath) ? (PathType.Normal | PathType.NotUsingPath) : PathType.NoPath;
return;
if (path || waterPath)
{
pathType = PathType.Normal | PathType.NotUsingPath;
return;
}
// raycast doesn't need endPoly to be valid
if (!_useRaycast)
{
pathType = PathType.NoPath;
return;
}
}
// we may need a better number here
@@ -225,10 +237,7 @@ namespace Game.Movement
BuildShortcut();
pathType = PathType.Normal | PathType.NotUsingPath;
if (startFarFromPoly)
pathType |= PathType.FarFromPolyStart;
if (endFarFromPoly)
pathType |= PathType.FarFromPolyEnd;
AddFarFromPolyFlags(startFarFromPoly, endFarFromPoly);
return;
}
@@ -245,10 +254,7 @@ namespace Game.Movement
pathType = PathType.Incomplete;
if (startFarFromPoly)
pathType |= PathType.FarFromPolyStart;
if (endFarFromPoly)
pathType |= PathType.FarFromPolyEnd;
AddFarFromPolyFlags(startFarFromPoly, endFarFromPoly);
}
}
@@ -256,7 +262,7 @@ namespace Game.Movement
// start and end are on same polygon
// handle this case as if they were 2 different polygons, building a line path split in some few points
if (startPoly == endPoly)
if (startPoly == endPoly && !_useRaycast)
{
Log.outDebug(LogFilter.Maps, "++ BuildPolyPath . (startPoly == endPoly)\n");
@@ -267,10 +273,7 @@ namespace Game.Movement
{
pathType = PathType.Incomplete;
if (startFarFromPoly)
pathType |= PathType.FarFromPolyStart;
if (endFarFromPoly)
pathType |= PathType.FarFromPolyEnd;
AddFarFromPolyFlags(startFarFromPoly, endFarFromPoly);
}
else
pathType = PathType.Normal;
@@ -368,38 +371,12 @@ namespace Game.Movement
ulong[] tempPolyRefs = new ulong[_pathPolyRefs.Length];
uint dtResult;
if (_straightLine)
if (_useRaycast)
{
float hit = 0;
float[] hitNormal = new float[3];
dtResult = _navMeshQuery.raycast(
suffixStartPoly,
suffixEndPoint,
endPoint,
_filter,
ref hit,
hitNormal,
tempPolyRefs,
ref suffixPolyLength,
74 - (int)prefixPolyLength);
// raycast() sets hit to FLT_MAX if there is a ray between start and end
if (hit != float.MaxValue)
{
// the ray hit something, return no path instead of the incomplete one
Clear();
_polyLength = 2;
Array.Resize(ref _pathPoints, 2);
_pathPoints[0] = GetStartPosition();
float[] hitPos = new float[3];
Detour.dtVlerp(hitPos, startPoint, endPoint, hit);
_pathPoints[1] = new Vector3(hitPos[2], hitPos[0], hitPos[1]);
NormalizePath();
pathType = PathType.Incomplete;
return;
}
Log.outError(LogFilter.Maps, $"PathGenerator::BuildPolyPath() called with _useRaycast with a previous path for unit {_source.GetGUID()}");
BuildShortcut();
pathType = PathType.NoPath;
return;
}
else
{
@@ -442,7 +419,7 @@ namespace Game.Movement
Clear();
uint dtResult;
if (_straightLine)
if (_useRaycast)
{
float hit = 0;
float[] hitNormal = new float[3];
@@ -458,24 +435,57 @@ namespace Game.Movement
ref _polyLength,
74);
if (_polyLength == 0 || Detour.dtStatusFailed(dtResult))
{
BuildShortcut();
pathType = PathType.NoPath;
AddFarFromPolyFlags(startFarFromPoly, endFarFromPoly);
return;
}
// raycast() sets hit to FLT_MAX if there is a ray between start and end
if (hit != float.MaxValue)
{
// the ray hit something, return no path instead of the incomplete one
Clear();
_polyLength = 2;
Array.Resize(ref _pathPoints, 2);
_pathPoints[0] = GetStartPosition();
float[] hitPos = new float[3];
// Walk back a bit from the hit point to make sure it's in the mesh (sometimes the point is actually outside of the polygons due to float precision issues)
hit *= 0.99f;
Detour.dtVlerp(hitPos, startPoint, endPoint, hit);
// if it fails again, clamp to poly boundary
if (Detour.dtStatusFailed(_navMeshQuery.getPolyHeight(_pathPolyRefs[_polyLength - 1], hitPos, ref hitPos[1])))
_navMeshQuery.closestPointOnPolyBoundary(_pathPolyRefs[_polyLength - 1], hitPos, hitPos);
_pathPoints = new Vector3[2];
_pathPoints[0] = GetStartPosition();
_pathPoints[1] = new Vector3(hitPos[2], hitPos[0], hitPos[1]);
NormalizePath();
pathType = PathType.Incomplete;
AddFarFromPolyFlags(startFarFromPoly, false);
return;
}
else
_navMeshQuery.getPolyHeight(_pathPolyRefs[_polyLength - 1], endPoint, ref endPoint[1]);
{
// clamp to poly boundary if we fail to get the height
if (Detour.dtStatusFailed(_navMeshQuery.getPolyHeight(_pathPolyRefs[_polyLength - 1], endPoint, ref endPoint[1])))
_navMeshQuery.closestPointOnPolyBoundary(_pathPolyRefs[_polyLength - 1], endPoint, endPoint);
_pathPoints = new Vector3[2];
_pathPoints[0] = GetStartPosition();
_pathPoints[1] = new Vector3(endPoint[2], endPoint[0], endPoint[1]);
NormalizePath();
if (startFarFromPoly || endFarFromPoly)
{
pathType = PathType.Incomplete;
AddFarFromPolyFlags(startFarFromPoly, endFarFromPoly);
}
else
pathType = PathType.Normal;
return;
}
}
else
{
@@ -506,10 +516,7 @@ namespace Game.Movement
else
pathType = PathType.Incomplete;
if (startFarFromPoly)
pathType |= PathType.FarFromPolyStart;
if (endFarFromPoly)
pathType |= PathType.FarFromPolyEnd;
AddFarFromPolyFlags(startFarFromPoly, endFarFromPoly);
// generate the point-path out of our up-to-date poly-path
BuildPointPath(startPoint, endPoint);
@@ -521,31 +528,13 @@ namespace Game.Movement
int pointCount = 0;
uint dtResult;
if (_straightLine)
if (_useRaycast)
{
dtResult = Detour.DT_SUCCESS;
pointCount = 1;
Array.Copy(startPoint, pathPoints, 3); // first point
// path has to be split into polygons with dist SMOOTH_PATH_STEP_SIZE between them
Vector3 startVec = new(startPoint[0], startPoint[1], startPoint[2]);
Vector3 endVec = new(endPoint[0], endPoint[1], endPoint[2]);
Vector3 diffVec = (endVec - startVec);
Vector3 prevVec = startVec;
float len = diffVec.Length();
diffVec *= 4.0f / len;
while (len > 4.0f)
{
len -= 4.0f;
prevVec += diffVec;
pathPoints[3 * pointCount + 0] = prevVec.X;
pathPoints[3 * pointCount + 1] = prevVec.Y;
pathPoints[3 * pointCount + 2] = prevVec.Z;
++pointCount;
}
Array.Copy(endPoint, 0, pathPoints, 3 * pointCount, 3); // last point
++pointCount;
// _straightLine uses raycast and it currently doesn't support building a point path, only a 2-point path with start and hitpoint/end is returned
Log.outError(LogFilter.Maps, $"PathGenerator::BuildPointPath() called with _useRaycast for unit {_source.GetGUID()}");
BuildShortcut();
pathType = PathType.NoPath;
return;
}
else if (_useStraightPath)
{
@@ -724,7 +713,7 @@ namespace Game.Movement
float[] targetPos = new float[3];
if (polyPathSize > 1)
{
// Pick the closest poitns on poly border
// Pick the closest points on poly border
if (Detour.dtStatusFailed(_navMeshQuery.closestPointOnPolyBoundary(polys[0], startPos, iterPos)))
return Detour.DT_FAILURE;
@@ -1008,6 +997,14 @@ namespace Game.Movement
return (target.GetPositionZ() - GetActualEndPosition().Z) > 5.0f;
}
void AddFarFromPolyFlags(bool startFarFromPoly, bool endFarFromPoly)
{
if (startFarFromPoly)
pathType |= PathType.FarFromPolyStart;
if (endFarFromPoly)
pathType |= PathType.FarFromPolyEnd;
}
void Clear()
{
_polyLength = 0;
@@ -1056,12 +1053,13 @@ namespace Game.Movement
public void SetUseStraightPath(bool useStraightPath) { _useStraightPath = useStraightPath; }
public void SetPathLengthLimit(float distance) { _pointPathLimit = Math.Min((uint)(distance / 4.0f), 74); }
public void SetUseRaycast(bool useRaycast) { _useRaycast = useRaycast; }
ulong[] _pathPolyRefs = new ulong[74];
uint _polyLength;
uint _pointPathLimit;
bool _straightLine; // use raycast if true for a straight line path
bool _useRaycast; // use raycast if true for a straight line path
WorldObject _source;
bool _forceDestination;
bool _useStraightPath;
+2 -17
View File
@@ -954,22 +954,7 @@ namespace Game.Spells
Position pos = new(dest.Position);
unitCaster.MovePositionToFirstCollision(pos, dist, angle);
// Generate path to that point.
if (m_preGeneratedPath == null)
m_preGeneratedPath = new(unitCaster);
m_preGeneratedPath.SetPathLengthLimit(dist);
// Should we use straightline here ? What do we do when we don't have a full path ?
bool pathResult = m_preGeneratedPath.CalculatePath(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), false, true);
if (pathResult && m_preGeneratedPath.GetPathType().HasAnyFlag(PathType.Normal | PathType.Shortcut))
{
pos.posX = m_preGeneratedPath.GetActualEndPosition().X;
pos.posY = m_preGeneratedPath.GetActualEndPosition().Y;
pos.posZ = m_preGeneratedPath.GetActualEndPosition().Z;
dest.Relocate(pos);
}
dest.Relocate(pos);
break;
}
case Targets.DestCasterGround:
@@ -4999,7 +4984,7 @@ namespace Game.Spells
m_preGeneratedPath.SetPathLengthLimit(range);
// first try with raycast, if it fails fall back to normal path
bool result = m_preGeneratedPath.CalculatePath(target.GetPositionX(), target.GetPositionY(), target.GetPositionZ(), false, false);
bool result = m_preGeneratedPath.CalculatePath(target.GetPositionX(), target.GetPositionY(), target.GetPositionZ(), false);
if (m_preGeneratedPath.GetPathType().HasAnyFlag(PathType.Short))
return SpellCastResult.NoPath;
else if (!result || m_preGeneratedPath.GetPathType().HasAnyFlag(PathType.NoPath | PathType.Incomplete))
+2 -8
View File
@@ -199,17 +199,11 @@ namespace Scripts.Spells.Warrior
PathGenerator generatedPath = new(GetCaster());
generatedPath.SetPathLengthLimit(range);
bool result = generatedPath.CalculatePath(dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ(), false, true);
bool result = generatedPath.CalculatePath(dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ(), false);
if (generatedPath.GetPathType().HasAnyFlag(PathType.Short))
return SpellCastResult.OutOfRange;
else if (!result || generatedPath.GetPathType().HasAnyFlag(PathType.NoPath))
{
result = generatedPath.CalculatePath(dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ(), false, false);
if (generatedPath.GetPathType().HasAnyFlag(PathType.Short))
return SpellCastResult.OutOfRange;
else if (!result || generatedPath.GetPathType().HasAnyFlag(PathType.NoPath))
return SpellCastResult.NoPath;
}
return SpellCastResult.NoPath;
}
else if (dest.GetPositionZ() > GetCaster().GetPositionZ() + 4.0f)
return SpellCastResult.NoPath;