diff options
Diffstat (limited to 'src/Mobs/Path.cpp')
-rw-r--r-- | src/Mobs/Path.cpp | 101 |
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; -} |