diff options
Diffstat (limited to '')
-rw-r--r-- | src/Mobs/Path.cpp | 2 | ||||
-rw-r--r-- | src/Mobs/PathFinder.cpp | 74 |
2 files changed, 40 insertions, 36 deletions
diff --git a/src/Mobs/Path.cpp b/src/Mobs/Path.cpp index e9c4e6ca7..05ccd6c39 100644 --- a/src/Mobs/Path.cpp +++ b/src/Mobs/Path.cpp @@ -480,7 +480,7 @@ void cPath::FillCellAttributes(cPathCell & a_Cell) ASSERT(m_Chunk != nullptr); - if (!cChunkDef::IsValidHeight(Location.y)) + if (!cChunkDef::IsValidHeight(Location)) { // Players can't build outside the game height, so it must be air a_Cell.m_IsSolid = false; diff --git a/src/Mobs/PathFinder.cpp b/src/Mobs/PathFinder.cpp index bcc48d80e..260044f3b 100644 --- a/src/Mobs/PathFinder.cpp +++ b/src/Mobs/PathFinder.cpp @@ -185,74 +185,78 @@ bool cPathFinder::EnsureProperPoint(Vector3d & a_Vector, cChunk & a_Chunk) return false; } - int RelX = FloorC(a_Vector.x) - Chunk->GetPosX() * cChunkDef::Width; - int RelZ = FloorC(a_Vector.z) - Chunk->GetPosZ() * cChunkDef::Width; - // If destination in the air, first try to go 1 block north, or east, or west. // This fixes the player leaning issue. // If that failed, we instead go down to the lowest air block. - int YBelowUs = FloorC(a_Vector.y) - 1; - if (!cChunkDef::IsValidHeight(YBelowUs)) + auto Below = a_Vector.Floor().addedY(-1); + if (!cChunkDef::IsValidHeight(Below)) { return false; } - Chunk->GetBlockTypeMeta(RelX, YBelowUs, RelZ, BlockType, BlockMeta); + auto BelowRel = cChunkDef::AbsoluteToRelative(Below); + + Chunk->GetBlockTypeMeta(BelowRel, BlockType, BlockMeta); if (!(IsWaterOrSolid(BlockType))) { + constexpr std::array<Vector3i, 8> Offsets = + { + { + {-1, 0, 0}, + {1, 0, 0}, + {0, 0, -1}, + {0, 0, 1}, + {-1, 0, -1}, + {-1, 0, 1}, + {1, 0, -1}, + {1, 0, 1}, + } + }; + + // Looks for a neighbouring block one block in x or z direction that is water or solid. bool InTheAir = true; - int x, z; - for (z = -1; z <= 1; ++z) + for (const auto & Offset : Offsets) { - for (x = -1; x <= 1; ++x) + auto InspectPos = Below + Offset; + Chunk = a_Chunk.GetNeighborChunk(InspectPos.x, InspectPos.z); + if ((Chunk == nullptr) || !Chunk->IsValid()) { - if ((x == 0) && (z == 0)) - { - continue; - } - Chunk = a_Chunk.GetNeighborChunk(FloorC(a_Vector.x+x), FloorC(a_Vector.z+z)); - if ((Chunk == nullptr) || !Chunk->IsValid()) - { - return false; - } - RelX = FloorC(a_Vector.x+x) - Chunk->GetPosX() * cChunkDef::Width; - RelZ = FloorC(a_Vector.z+z) - Chunk->GetPosZ() * cChunkDef::Width; - Chunk->GetBlockTypeMeta(RelX, YBelowUs, RelZ, BlockType, BlockMeta); - if (IsWaterOrSolid((BlockType))) - { - a_Vector.x += x; - a_Vector.z += z; - InTheAir = false; - goto breakBothLoops; - } + return false; + } + auto InspectRel = cChunkDef::AbsoluteToRelative(InspectPos); + Chunk->GetBlockTypeMeta(InspectRel, BlockType, BlockMeta); + if (IsWaterOrSolid((BlockType))) + { + BelowRel = InspectRel; + InTheAir = false; + break; } } - breakBothLoops: // Go down to the lowest air block. if (InTheAir) { - while (a_Vector.y > 0) + while (cChunkDef::IsValidHeight(a_Vector.addedY(-1))) { - Chunk->GetBlockTypeMeta(RelX, FloorC(a_Vector.y) - 1, RelZ, BlockType, BlockMeta); + Chunk->GetBlockTypeMeta(BelowRel.addedY(-1), BlockType, BlockMeta); if (IsWaterOrSolid(BlockType)) { break; } - a_Vector.y -= 1; + BelowRel.y -= 1; } } } // If destination in water or solid, go up to the first air block. - while (a_Vector.y < cChunkDef::Height) + while (BelowRel.y < cChunkDef::Height) { - Chunk->GetBlockTypeMeta(RelX, FloorC(a_Vector.y), RelZ, BlockType, BlockMeta); + Chunk->GetBlockTypeMeta(BelowRel, BlockType, BlockMeta); if (!IsWaterOrSolid(BlockType)) { break; } - a_Vector.y += 1; + BelowRel.y += 1; } return true; |