summaryrefslogtreecommitdiffstats
path: root/src/Mobs/Path.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Mobs/Path.cpp')
-rw-r--r--src/Mobs/Path.cpp101
1 files changed, 61 insertions, 40 deletions
diff --git a/src/Mobs/Path.cpp b/src/Mobs/Path.cpp
index 2dd2a3c99..8701dad10 100644
--- a/src/Mobs/Path.cpp
+++ b/src/Mobs/Path.cpp
@@ -7,13 +7,13 @@
#define DISTANCE_MANHATTAN 0 // 1: More speed, a bit less accuracy 0: Max accuracy, less speed.
#define HEURISTICS_ONLY 0 // 1: Much more speed, much less accurate.
-#define CALCULATIONS_PER_STEP 5 // Higher means more CPU load but faster path calculations.
+#define CALCULATIONS_PER_STEP 60 // Higher means more CPU load but faster path calculations.
// The only version which guarantees the shortest path is 0, 0.
enum class eCellStatus {OPENLIST, CLOSEDLIST, NOLIST};
struct cPathCell
{
- Vector3d m_Location; // Location of the cell in the world.
+ Vector3i m_Location; // Location of the cell in the world.
int m_F, m_G, m_H; // F, G, H as defined in regular A*.
eCellStatus m_Status; // Which list is the cell in? Either non, open, or closed.
cPathCell * m_Parent; // Cell's parent, as defined in regular A*.
@@ -36,28 +36,51 @@ bool compareHeuristics::operator()(cPathCell * & a_Cell1, cPathCell * & a_Cell2)
/* cPath implementation */
cPath::cPath(
cChunk & a_Chunk,
- const Vector3d & a_StartingPoint, const Vector3d & a_EndingPoint, int a_MaxSteps,
+ const Vector3i & a_StartingPoint, const Vector3i & a_EndingPoint, int a_MaxSteps,
double a_BoundingBoxWidth, double a_BoundingBoxHeight,
int a_MaxUp, int a_MaxDown
-)
+) :
+ m_Destination(a_EndingPoint.Floor()),
+ m_Source(a_StartingPoint.Floor()),
+ m_CurrentPoint(0), // GetNextPoint increments this to 1, but that's fine, since the first cell is always a_StartingPoint
+ m_Chunk(&a_Chunk)
{
// TODO: if src not walkable OR dest not walkable, then abort.
// Borrow a new "isWalkable" from ProcessIfWalkable, make ProcessIfWalkable also call isWalkable
- m_Chunk = &a_Chunk;
- m_Source = a_StartingPoint.Floor();
- m_Destination = a_EndingPoint.Floor();
-
if (GetCell(m_Source)->m_IsSolid || GetCell(m_Destination)->m_IsSolid)
{
m_Status = ePathFinderStatus::PATH_NOT_FOUND;
return;
}
- m_Status = ePathFinderStatus::CALCULATING;
+ // If destination in water, set water surface as destination.
+ cChunk * Chunk = m_Chunk->GetNeighborChunk(m_Destination.x, m_Destination.z);
+ if ((Chunk != nullptr) && Chunk->IsValid())
+ {
+ BLOCKTYPE BlockType;
+ NIBBLETYPE BlockMeta;
+ int RelX = m_Destination.x - m_Chunk->GetPosX() * cChunkDef::Width;
+ int RelZ = m_Destination.z - m_Chunk->GetPosZ() * cChunkDef::Width;
+ bool inwater = false;
+ for (;;)
+ {
+ m_Chunk->GetBlockTypeMeta(RelX, m_Destination.y, RelZ, BlockType, BlockMeta);
+ if (BlockType != E_BLOCK_STATIONARY_WATER)
+ {
+ break;
+ }
+ inwater = true;
+ m_Destination+=Vector3d(0, 1, 0);
+ }
+ if (inwater)
+ {
+ m_Destination+=Vector3d(0, -1, 0);
+ }
+ }
+ m_Status = ePathFinderStatus::CALCULATING;
m_StepsLeft = a_MaxSteps;
- m_PointCount = 0;
ProcessCell(GetCell(a_StartingPoint), nullptr, 0);
m_Chunk = nullptr;
@@ -82,6 +105,7 @@ cPath::~cPath()
ePathFinderStatus cPath::Step(cChunk & a_Chunk)
{
m_Chunk = &a_Chunk;
+
if (m_Status != ePathFinderStatus::CALCULATING)
{
return m_Status;
@@ -103,6 +127,7 @@ ePathFinderStatus cPath::Step(cChunk & a_Chunk)
}
}
}
+
m_Chunk = nullptr;
return m_Status;
}
@@ -111,23 +136,32 @@ ePathFinderStatus cPath::Step(cChunk & a_Chunk)
-bool cPath::IsSolid(const Vector3d & a_Location)
+bool cPath::IsSolid(const Vector3i & a_Location)
{
ASSERT(m_Chunk != nullptr);
- m_Chunk = m_Chunk->GetNeighborChunk(a_Location.x, a_Location.z);
- if ((m_Chunk == nullptr) || (!m_Chunk->IsValid()))
+
+ auto Chunk = m_Chunk->GetNeighborChunk(a_Location.x, a_Location.z);
+ if ((Chunk == nullptr) || !Chunk->IsValid())
{
return true;
}
+ m_Chunk = Chunk;
+
BLOCKTYPE BlockType;
NIBBLETYPE BlockMeta;
int RelX = a_Location.x - m_Chunk->GetPosX() * cChunkDef::Width;
int RelZ = a_Location.z - m_Chunk->GetPosZ() * cChunkDef::Width;
+
m_Chunk->GetBlockTypeMeta(RelX, a_Location.y, RelZ, BlockType, BlockMeta);
if ((BlockType == E_BLOCK_FENCE) || (BlockType == E_BLOCK_FENCE_GATE))
{
- GetCell(a_Location + Vector3d(0, 1, 0))->m_IsSolid = true; // Mobs will always think that the fence is 2 blocks high and therefore won't jump over.
+ GetCell(a_Location + Vector3i(0, 1, 0))->m_IsSolid = true; // Mobs will always think that the fence is 2 blocks high and therefore won't jump over.
}
+ if (BlockType == E_BLOCK_STATIONARY_WATER)
+ {
+ GetCell(a_Location + Vector3i(0, -1, 0))->m_IsSolid = true; // Mobs will always think that the fence is 2 blocks high and therefore won't jump over.
+ }
+
return cBlockInfo::IsSolid(BlockType);
}
@@ -152,11 +186,10 @@ bool cPath::Step_Internal()
{
do
{
- AddPoint(CurrentCell->m_Location + Vector3d(0.5, 0, 0.5)); // Populate the cPath with points.
+ m_PathPoints.push_back(CurrentCell->m_Location); // Populate the cPath with points.
CurrentCell = CurrentCell->m_Parent;
} while (CurrentCell != nullptr);
- m_CurrentPoint = -1;
FinishCalculation(ePathFinderStatus::PATH_FOUND);
return true;
}
@@ -167,10 +200,10 @@ bool cPath::Step_Internal()
int i;
for (i = -1; i <= 1; ++i)
{
- ProcessIfWalkable(CurrentCell->m_Location + Vector3d(1, i, 0), CurrentCell, 10);
- ProcessIfWalkable(CurrentCell->m_Location + Vector3d(-1, i, 0), CurrentCell, 10);
- ProcessIfWalkable(CurrentCell->m_Location + Vector3d(0, i, 1), CurrentCell, 10);
- ProcessIfWalkable(CurrentCell->m_Location + Vector3d(0, i, -1), CurrentCell, 10);
+ ProcessIfWalkable(CurrentCell->m_Location + Vector3i(1, i, 0), CurrentCell, 10);
+ ProcessIfWalkable(CurrentCell->m_Location + Vector3i(-1, i, 0), CurrentCell, 10);
+ ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, i, 1), CurrentCell, 10);
+ ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, i, -1), CurrentCell, 10);
}
// Check diagonals on mob's height only.
@@ -180,18 +213,17 @@ bool cPath::Step_Internal()
for (z = -1; z <= 1; z += 2)
{
// This condition prevents diagonal corner cutting.
- if (!GetCell(CurrentCell->m_Location + Vector3d(x, 0, 0))->m_IsSolid && !GetCell(CurrentCell->m_Location + Vector3d(0, 0, z))->m_IsSolid)
+ if (!GetCell(CurrentCell->m_Location + Vector3i(x, 0, 0))->m_IsSolid && !GetCell(CurrentCell->m_Location + Vector3i(0, 0, z))->m_IsSolid)
{
// This prevents falling of "sharp turns" e.g. a 1x1x20 rectangle in the air which breaks in a right angle suddenly.
- if (GetCell(CurrentCell->m_Location + Vector3d(x, -1, 0))->m_IsSolid && GetCell(CurrentCell->m_Location + Vector3d(0, -1, z))->m_IsSolid)
+ if (GetCell(CurrentCell->m_Location + Vector3i(x, -1, 0))->m_IsSolid && GetCell(CurrentCell->m_Location + Vector3i(0, -1, z))->m_IsSolid)
{
- ProcessIfWalkable(CurrentCell->m_Location + Vector3d(x, 0, z), CurrentCell, 14); // 14 is a good enough approximation of sqrt(10 + 10).
+ ProcessIfWalkable(CurrentCell->m_Location + Vector3i(x, 0, z), CurrentCell, 14); // 14 is a good enough approximation of sqrt(10 + 10).
}
}
}
}
-
return false;
}
@@ -257,10 +289,10 @@ si::setBlock((Ret)->m_Location.x, (Ret)->m_Location.y, (Ret)->m_Location.z, debu
-void cPath::ProcessIfWalkable(const Vector3d & a_Location, cPathCell * a_Parent, int a_Cost)
+void cPath::ProcessIfWalkable(const Vector3i & a_Location, cPathCell * a_Parent, int a_Cost)
{
- cPathCell * cell = GetCell(a_Location);
- if (!cell->m_IsSolid && GetCell(a_Location + Vector3d(0, -1, 0))->m_IsSolid && !GetCell(a_Location + Vector3d(0, 1, 0))->m_IsSolid)
+ cPathCell * cell = GetCell(a_Location);
+ if (!cell->m_IsSolid && GetCell(a_Location + Vector3i(0, -1, 0))->m_IsSolid && !GetCell(a_Location + Vector3i(0, 1, 0))->m_IsSolid)
{
ProcessCell(cell, a_Parent, a_Cost);
}
@@ -298,7 +330,7 @@ void cPath::ProcessCell(cPathCell * a_Cell, cPathCell * a_Caller, int a_GDelta)
a_Cell->m_H = 10 * (abs(a_Cell->m_Location.x-m_Destination.x) + abs(a_Cell->m_Location.y-m_Destination.y) + abs(a_Cell->m_Location.z-m_Destination.z));
#else
// Euclidian distance. sqrt(DeltaX^2 + DeltaY^2 + DeltaZ^2), more precise.
- a_Cell->m_H = std::sqrt((a_Cell->m_Location.x - m_Destination.x) * (a_Cell->m_Location.x - m_Destination.x) * 100 + (a_Cell->m_Location.y - m_Destination.y) * (a_Cell->m_Location.y - m_Destination.y) * 100 + (a_Cell->m_Location.z - m_Destination.z) * (a_Cell->m_Location.z - m_Destination.z) * 100);
+ a_Cell->m_H = static_cast<decltype(a_Cell->m_H)>((a_Cell->m_Location - m_Destination).Length() * 10);
#endif
#if HEURISTICS_ONLY == 1
@@ -326,7 +358,7 @@ void cPath::ProcessCell(cPathCell * a_Cell, cPathCell * a_Caller, int a_GDelta)
-cPathCell * cPath::GetCell(const Vector3d & a_Location)
+cPathCell * cPath::GetCell(const Vector3i & a_Location)
{
// Create the cell in the hash table if it's not already there.
cPathCell * Cell;
@@ -349,14 +381,3 @@ cPathCell * cPath::GetCell(const Vector3d & a_Location)
return m_Map[a_Location];
}
}
-
-
-
-
-
-// Add the next point in the final path.
-void cPath::AddPoint(Vector3d a_Vector)
-{
- m_PathPoints.push_back(a_Vector);
- ++m_PointCount;
-}