Cuberite
A lightweight, fast and extensible game server for Minecraft
Path.cpp
Go to the documentation of this file.
1 
2 #include "Globals.h"
3 
4 #include "Path.h"
5 #include "BlockType.h"
6 #include "../BlockInfo.h"
7 #include "../Chunk.h"
8 
9 #define JUMP_G_COST 20
10 #define NORMAL_G_COST 10
11 #define DIAGONAL_G_COST 14
12 
13 #define DISTANCE_MANHATTAN 0 // 1: More speed, a bit less accuracy 0: Max accuracy, less speed.
14 #define HEURISTICS_ONLY 0 // 1: Much more speed, much less accurate.
15 #define CALCULATIONS_PER_STEP 10 // Higher means more CPU load but faster path calculations.
16 // The only version which guarantees the shortest path is 0, 0.
17 
18 
19 
20 
21 
22 bool compareHeuristics::operator()(cPathCell * & a_Cell1, cPathCell * & a_Cell2)
23 {
24  return a_Cell1->m_F > a_Cell2->m_F;
25 }
26 
27 
28 
29 
30 
31 /* cPath implementation */
33  cChunk & a_Chunk,
34  const Vector3d & a_StartingPoint, const Vector3d & a_EndingPoint, int a_MaxSteps,
35  double a_BoundingBoxWidth, double a_BoundingBoxHeight
36 ) :
37  m_StepsLeft(a_MaxSteps),
38  m_IsValid(true),
39  m_CurrentPoint(0), // GetNextPoint increments this to 1, but that's fine, since the first cell is always a_StartingPoint
40  m_Chunk(&a_Chunk),
41  m_BadChunkFound(false)
42 {
43 
44  a_BoundingBoxWidth = 1; // Treat all mobs width as 1 until physics is improved.
45 
46  m_BoundingBoxWidth = CeilC(a_BoundingBoxWidth);
47  m_BoundingBoxHeight = CeilC(a_BoundingBoxHeight);
48  m_HalfWidth = a_BoundingBoxWidth / 2;
49 
50  int HalfWidthInt = FloorC(a_BoundingBoxWidth / 2);
51  m_Source.x = FloorC(a_StartingPoint.x - HalfWidthInt);
52  m_Source.y = FloorC(a_StartingPoint.y);
53  m_Source.z = FloorC(a_StartingPoint.z - HalfWidthInt);
54 
55  m_Destination.x = FloorC(a_EndingPoint.x - HalfWidthInt);
56  m_Destination.y = FloorC(a_EndingPoint.y);
57  m_Destination.z = FloorC(a_EndingPoint.z - HalfWidthInt);
58 
60  {
62  return;
63  }
64 
67 
68  ProcessCell(GetCell(m_Source), nullptr, 0);
69 }
70 
71 
72 
73 
74 
75 cPath::cPath() : m_IsValid(false)
76 {
77 
78 }
79 
80 
81 
82 
83 
85 {
86  m_Chunk = &a_Chunk;
88  {
89  return m_Status;
90  }
91 
92  if (m_BadChunkFound)
93  {
95  return m_Status;
96  }
97 
98  if (m_StepsLeft == 0)
99  {
101  }
102  else
103  {
104  --m_StepsLeft;
105  int i;
106  for (i = 0; i < CALCULATIONS_PER_STEP; ++i)
107  {
108  if (StepOnce()) // StepOnce returns true when no more calculation is needed.
109  {
110  break; // if we're here, m_Status must have changed either to PATH_FOUND or PATH_NOT_FOUND.
111  }
112  }
113 
114  m_Chunk = nullptr;
115  }
116  return m_Status;
117 }
118 
119 
120 
121 
122 
124 {
127  return m_Destination;
128 }
129 
130 
131 
132 
133 
135 {
136  cPathCell * CurrentCell = OpenListPop();
137 
138  // Path not reachable.
139  if (CurrentCell == nullptr)
140  {
142  return true;
143  }
144 
145  // Path found.
146  if (CurrentCell->m_Location == m_Destination)
147  {
148  BuildPath();
150  return true;
151  }
152 
153  // Calculation not finished yet
154  // Check if we have a new NearestPoint.
155  if ((m_Destination - CurrentCell->m_Location).Length() < 5)
156  {
157  if (GetRandomProvider().RandBool(0.25))
158  {
159  m_NearestPointToTarget = CurrentCell;
160  }
161  }
162  else if (CurrentCell->m_H < m_NearestPointToTarget->m_H)
163  {
164  m_NearestPointToTarget = CurrentCell;
165  }
166  // process a currentCell by inspecting all neighbors.
167 
168 
169  // Now we start checking adjacent cells.
170 
171 
172  // If true, no need to do more checks in that direction
173  bool DoneEast = false,
174  DoneWest = false,
175  DoneNorth = false,
176  DoneSouth = false;
177 
178  // If true, we can walk in that direction without changing height
179  // This is used for deciding if to calculate diagonals
180  bool WalkableEast = false,
181  WalkableWest = false,
182  WalkableNorth = false,
183  WalkableSouth = false;
184 
185  // If we can jump without hitting the ceiling
186  if (BodyFitsIn(CurrentCell->m_Location + Vector3i(0, 1, 0), CurrentCell->m_Location))
187  {
188  // For ladder climbing
189  ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, 1, 0), CurrentCell, JUMP_G_COST);
190 
191  // Check east-up
192  if (ProcessIfWalkable(CurrentCell->m_Location + Vector3i(1, 1, 0), CurrentCell, JUMP_G_COST))
193  {
194  DoneEast = true;
195  }
196 
197  // Check west-up
198  if (ProcessIfWalkable(CurrentCell->m_Location + Vector3i(-1, 1, 0), CurrentCell, JUMP_G_COST))
199  {
200  DoneWest = true;
201  }
202 
203  // Check north-up
204  if (ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, 1, -1), CurrentCell, JUMP_G_COST))
205  {
206  DoneNorth = true;
207  }
208 
209  // Check south-up
210  if (ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, 1, 1), CurrentCell, JUMP_G_COST))
211  {
212  DoneSouth = true;
213  }
214 
215  }
216 
217 
218  // Check North, South, East, West at our own height or below. We are willing to jump up to 3 blocks down.
219 
220 
221  if (!DoneEast)
222  {
223  for (int y = 0; y >= -3; --y)
224  {
225  if (ProcessIfWalkable(CurrentCell->m_Location + Vector3i(1, y, 0), CurrentCell, NORMAL_G_COST))
226  {
227  DoneEast = true;
228  if (y == 0)
229  {
230  WalkableEast = true;
231  }
232  break;
233  }
234  }
235  }
236 
237  if (!DoneWest)
238  {
239  for (int y = 0; y >= -3; --y)
240  {
241  if (ProcessIfWalkable(CurrentCell->m_Location + Vector3i(-1, y, 0), CurrentCell, NORMAL_G_COST))
242  {
243  DoneWest = true;
244  if (y == 0)
245  {
246  WalkableWest = true;
247  }
248  break;
249  }
250  }
251  }
252 
253  if (!DoneSouth)
254  {
255  for (int y = 0; y >= -3; --y)
256  {
257  if (ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, y, 1), CurrentCell, NORMAL_G_COST))
258  {
259  DoneSouth = true;
260  if (y == 0)
261  {
262  WalkableSouth = true;
263  }
264  break;
265  }
266  }
267  }
268 
269  if (!DoneNorth)
270  {
271  for (int y = 0; y >= -3; --y)
272  {
273  if (ProcessIfWalkable(CurrentCell->m_Location + Vector3i(0, y, -1), CurrentCell, NORMAL_G_COST))
274  {
275  DoneNorth = true;
276  if (y == 0)
277  {
278  WalkableNorth = true;
279  }
280  break;
281  }
282  }
283  }
284 
285  // Check diagonals
286 
287  if (WalkableNorth && WalkableEast)
288  {
289  ProcessIfWalkable(CurrentCell->m_Location + Vector3i(1, 0, -1), CurrentCell, DIAGONAL_G_COST);
290  }
291  if (WalkableNorth && WalkableWest)
292  {
293  ProcessIfWalkable(CurrentCell->m_Location + Vector3i(-1, 0, -1), CurrentCell, DIAGONAL_G_COST);
294  }
295  if (WalkableSouth && WalkableEast)
296  {
297  ProcessIfWalkable(CurrentCell->m_Location + Vector3i(1, 0, 1), CurrentCell, DIAGONAL_G_COST);
298  }
299  if (WalkableSouth && WalkableWest)
300  {
301  ProcessIfWalkable(CurrentCell->m_Location + Vector3i(-1, 0, 1), CurrentCell, DIAGONAL_G_COST);
302  }
303 
304  return false;
305 }
306 
307 
308 
309 
310 
312 {
314  {
316  }
317  else
318  {
320  BuildPath();
322  }
323 }
324 
325 
326 
327 
328 
330 {
331  cPathCell * CurrentCell = GetCell(m_Destination);
332  while (CurrentCell->m_Parent != nullptr)
333  {
334  // Waypoints are cylinders that start at some particular x, y, z and have infinite height.
335  // Submerging water waypoints allows swimming mobs to be able to touch them.
336  if (IsBlockWater(GetCell(CurrentCell->m_Location + Vector3i(0, -1, 0))->m_BlockType))
337  {
338  CurrentCell->m_Location.y -= 30;
339  }
340  m_PathPoints.push_back(CurrentCell->m_Location); // Populate the cPath with points. All midpoints are added. Destination is added. Source is excluded.
341  CurrentCell = CurrentCell->m_Parent;
342  }
343 
344 }
345 
346 
347 
348 
349 
351 {
352  m_Map.clear();
353  m_OpenList = std::priority_queue<cPathCell *, std::vector<cPathCell *>, compareHeuristics>{};
354 }
355 
356 
357 
358 
359 
361 {
362  if (m_BadChunkFound)
363  {
364  a_NewStatus = ePathFinderStatus::PATH_NOT_FOUND;
365  }
366  m_Status = a_NewStatus;
368 }
369 
370 
371 
372 
373 
375 {
377  m_OpenList.push(a_Cell);
378  #ifdef COMPILING_PATHFIND_DEBUGGER
379  si::setBlock(a_Cell->m_Location.x, a_Cell->m_Location.y, a_Cell->m_Location.z, debug_open, SetMini(a_Cell));
380  #endif
381 }
382 
383 
384 
385 
386 
387 cPathCell * cPath::OpenListPop() // Popping from the open list also means adding to the closed list.
388 {
389  if (m_OpenList.size() == 0)
390  {
391  return nullptr; // We've exhausted the search space and nothing was found, this will trigger a PATH_NOT_FOUND or NEARBY_FOUND status.
392  }
393 
394  cPathCell * Ret = m_OpenList.top();
395  m_OpenList.pop();
397  #ifdef COMPILING_PATHFIND_DEBUGGER
398  si::setBlock((Ret)->m_Location.x, (Ret)->m_Location.y, (Ret)->m_Location.z, debug_closed, SetMini(Ret));
399  #endif
400  return Ret;
401 }
402 
403 
404 
405 
406 
407 bool cPath::ProcessIfWalkable(const Vector3i & a_Location, cPathCell * a_Parent, int a_Cost)
408 {
409  if (IsWalkable(a_Location, a_Parent->m_Location))
410  {
411  ProcessCell(GetCell(a_Location), a_Parent, a_Cost);
412  return true;
413  }
414  return false;
415 }
416 
417 
418 
419 
420 
421 void cPath::ProcessCell(cPathCell * a_Cell, cPathCell * a_Caller, int a_GDelta)
422 {
423  // Case 1: Cell is in the closed list, ignore it.
424  if (a_Cell->m_Status == eCellStatus::CLOSEDLIST)
425  {
426  return;
427  }
428  if (a_Cell->m_Status == eCellStatus::NOLIST) // Case 2: The cell is not in any list.
429  {
430  // Cell is walkable, add it to the open list.
431  // Note that non-walkable cells are filtered out in Step_internal();
432  // Special case: Start cell goes here, gDelta is 0, caller is NULL.
433  a_Cell->m_Parent = a_Caller;
434  if (a_Caller != nullptr)
435  {
436  a_Cell->m_G = a_Caller->m_G + a_GDelta;
437  }
438  else
439  {
440  a_Cell->m_G = 0;
441  }
442 
443  // Calculate H. This is A*'s Heuristics value.
444  #if DISTANCE_MANHATTAN == 1
445  // Manhattan distance. DeltaX + DeltaY + DeltaZ.
446  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));
447  #else
448  // Euclidian distance. sqrt(DeltaX^2 + DeltaY^2 + DeltaZ^2), more precise.
449  a_Cell->m_H = static_cast<decltype(a_Cell->m_H)>((a_Cell->m_Location - m_Destination).Length() * 10);
450  #endif
451 
452  #if HEURISTICS_ONLY == 1
453  a_Cell->m_F = a_Cell->m_H; // Greedy search. https://en.wikipedia.org/wiki/Greedy_search
454  #else
455  a_Cell->m_F = a_Cell->m_H + a_Cell->m_G; // Regular A*.
456  #endif
457 
458  OpenListAdd(a_Cell);
459  return;
460  }
461 
462  // Case 3: Cell is in the open list, check if G and H need an update.
463  int NewG = a_Caller->m_G + a_GDelta;
464  if (NewG < a_Cell->m_G)
465  {
466  a_Cell->m_G = NewG;
467  a_Cell->m_H = a_Cell->m_F + a_Cell->m_G;
468  a_Cell->m_Parent = a_Caller;
469  }
470 
471 }
472 
473 
474 
475 
476 
478 {
479  const Vector3i & Location = a_Cell.m_Location;
480 
481  ASSERT(m_Chunk != nullptr);
482 
483  if (!cChunkDef::IsValidHeight(Location))
484  {
485  // Players can't build outside the game height, so it must be air
486  a_Cell.m_IsSolid = false;
487  a_Cell.m_IsSpecial = false;
488  a_Cell.m_BlockType = E_BLOCK_AIR;
489  return;
490  }
491  auto Chunk = m_Chunk->GetNeighborChunk(Location.x, Location.z);
492  if ((Chunk == nullptr) || !Chunk->IsValid())
493  {
494  m_BadChunkFound = true;
495  a_Cell.m_IsSolid = true;
496  a_Cell.m_IsSpecial = false;
497  a_Cell.m_BlockType = E_BLOCK_AIR; // m_BlockType is never used when m_IsSpecial is false, but it may be used if we implement dijkstra
498  return;
499  }
500  m_Chunk = Chunk;
501 
503  NIBBLETYPE BlockMeta;
504  int RelX = Location.x - m_Chunk->GetPosX() * cChunkDef::Width;
505  int RelZ = Location.z - m_Chunk->GetPosZ() * cChunkDef::Width;
506 
507  m_Chunk->GetBlockTypeMeta(RelX, Location.y, RelZ, BlockType, BlockMeta);
508  a_Cell.m_BlockType = BlockType;
509  a_Cell.m_BlockMeta = BlockMeta;
510 
511 
513  {
514  a_Cell.m_IsSpecial = true;
515  a_Cell.m_IsSolid = true; // Specials are solids only from a certain direction. But their m_IsSolid is always true
516  }
517  else if ((!cBlockInfo::IsSolid(a_Cell.m_BlockType)) && IsBlockFence(GetCell(Location + Vector3i(0, -1, 0))->m_BlockType))
518  {
519  // Nonsolid blocks with fences below them are consider Special Solids. That is, they sometimes behave as solids.
520  a_Cell.m_IsSpecial = true;
521  a_Cell.m_IsSolid = true;
522  }
523  else
524  {
525 
526  a_Cell.m_IsSpecial = false;
528  }
529 
530 }
531 
532 
533 
534 
535 
536 cPathCell * cPath::GetCell(const Vector3i & a_Location)
537 {
538  // Create the cell in the hash table if it's not already there.
539  if (m_Map.count(a_Location) == 0) // Case 1: Cell is not on any list. We've never checked this cell before.
540  {
541  m_Map[a_Location].m_Location = a_Location;
542  FillCellAttributes(m_Map[a_Location]);
543  m_Map[a_Location].m_Status = eCellStatus::NOLIST;
544  #ifdef COMPILING_PATHFIND_DEBUGGER
545  #ifdef COMPILING_PATHFIND_DEBUGGER_MARK_UNCHECKED
546  si::setBlock(a_Location.x, a_Location.y, a_Location.z, debug_unchecked, Cell->m_IsSolid ? NORMAL : MINI);
547  #endif
548  #endif
549  return &m_Map[a_Location];
550  }
551  else
552  {
553  return &m_Map[a_Location];
554  }
555 }
556 
557 
558 
559 
560 
561 bool cPath::IsWalkable(const Vector3i & a_Location, const Vector3i & a_Source)
562 {
563  return (HasSolidBelow(a_Location) && BodyFitsIn(a_Location, a_Source));
564 }
565 
566 
567 
568 
569 // We need the source because some special blocks are solid only from a certain direction e.g. doors
570 bool cPath::BodyFitsIn(const Vector3i & a_Location, const Vector3i & a_Source)
571 {
572  int x, y, z;
573  for (y = 0; y < m_BoundingBoxHeight; ++y)
574  {
575  for (x = 0; x < m_BoundingBoxWidth; ++x)
576  {
577  for (z = 0; z < m_BoundingBoxWidth; ++z)
578  {
579  cPathCell * CurrentCell = GetCell(a_Location + Vector3i(x, y, z));
580  if (CurrentCell->m_IsSolid)
581  {
582  if (CurrentCell->m_IsSpecial)
583  {
584  if (SpecialIsSolidFromThisDirection(CurrentCell->m_BlockType, CurrentCell->m_BlockMeta, a_Location - a_Source))
585  {
586  return false;
587  }
588  }
589  else
590  {
591  return false;
592  }
593  }
594  }
595  }
596  }
597  return true;
598 }
599 
600 
601 
602 
603 
605 {
606  if (IsBlockFence(a_Type))
607  {
608  return true;
609  }
610 
611  switch (a_Type)
612  {
613  case E_BLOCK_OAK_DOOR:
615  case E_BLOCK_TRAPDOOR:
616  case E_BLOCK_WATER:
618  {
619  return true;
620  }
621  default:
622  {
623  return false;
624  }
625  }
626 }
627 
628 
629 
630 
631 
632 bool cPath::SpecialIsSolidFromThisDirection(BLOCKTYPE a_Type, NIBBLETYPE a_Meta, const Vector3i & a_Direction)
633 {
634  if (a_Direction == Vector3i(0, 0, 0))
635  {
636  return false;
637  }
638 
639 
640  // If there is a nonsolid above a fence
641  if (!cBlockInfo::IsSolid(a_Type))
642  {
643  // Only treat as solid when we're coming from below
644  return (a_Direction.y > 0);
645  }
646 
647  /* switch (a_Type)
648  {
649  case E_BLOCK_ETC:
650  {
651  Decide if solid from this direction and return either true or false.
652  }
653 
654  // TODO Fill this with the other specials after physics is fixed
655  } */
656 
657 
658 
659  return true;
660 }
661 
662 
663 
664 
665 
666 bool cPath::HasSolidBelow(const Vector3i & a_Location)
667 {
668  int x, z;
669  for (x = 0; x < m_BoundingBoxWidth; ++x)
670  {
671  for (z = 0; z < m_BoundingBoxWidth; ++z)
672  {
673  if (GetCell(a_Location + Vector3i(x, -1, z))->m_IsSolid)
674  {
675  return true;
676  }
677  }
678  }
679  return false;
680 }
bool IsBlockWater(BLOCKTYPE a_BlockType)
Definition: BlockInfo.cpp:10
bool IsBlockFence(BLOCKTYPE a_BlockType)
Definition: BlockInfo.cpp:105
@ E_BLOCK_WATER
Definition: BlockType.h:18
@ E_BLOCK_TRAPDOOR
Definition: BlockType.h:111
@ E_BLOCK_AIR
Definition: BlockType.h:10
@ E_BLOCK_OAK_DOOR
Definition: BlockType.h:77
@ E_BLOCK_DARK_OAK_DOOR
Definition: BlockType.h:216
@ E_BLOCK_STATIONARY_WATER
Definition: BlockType.h:19
unsigned char NIBBLETYPE
The datatype used by nibbledata (meta, light, skylight)
Definition: ChunkDef.h:44
unsigned char BLOCKTYPE
The datatype used by blockdata.
Definition: ChunkDef.h:41
MTRand & GetRandomProvider()
Returns the current thread's random number source.
Definition: FastRandom.cpp:12
std::enable_if< std::is_arithmetic< T >::value, C >::type CeilC(T a_Value)
Ceils a value, then casts it to C (an int by default).
Definition: Globals.h:354
#define ASSERT(x)
Definition: Globals.h:276
std::enable_if< std::is_arithmetic< T >::value, C >::type FloorC(T a_Value)
Floors a value, then casts it to C (an int by default).
Definition: Globals.h:347
#define NORMAL_G_COST
Definition: Path.cpp:10
#define CALCULATIONS_PER_STEP
Definition: Path.cpp:15
#define DIAGONAL_G_COST
Definition: Path.cpp:11
#define JUMP_G_COST
Definition: Path.cpp:9
ePathFinderStatus
Definition: Path.h:26
BlockType
Definition: BlockTypes.h:4
Vector3< int > Vector3i
Definition: Vector3.h:487
static bool IsSolid(BLOCKTYPE Block)
Is this block solid (player cannot walk through)?
Definition: BlockInfo.cpp:892
Definition: Chunk.h:36
int GetPosX(void) const
Definition: Chunk.h:131
cChunk * GetNeighborChunk(int a_BlockX, int a_BlockZ)
Returns the chunk into which the specified block belongs, by walking the neighbors.
Definition: Chunk.cpp:1806
int GetPosZ(void) const
Definition: Chunk.h:132
void GetBlockTypeMeta(Vector3i a_RelPos, BLOCKTYPE &a_BlockType, NIBBLETYPE &a_BlockMeta) const
Definition: Chunk.cpp:1757
static bool IsValidHeight(Vector3i a_BlockPosition)
Validates a height-coordinate.
Definition: ChunkDef.h:185
static const int Width
Definition: ChunkDef.h:124
The pathfinder has 3 types of cells (cPathCell).
Definition: Path.h:44
bool m_IsSpecial
Definition: Path.h:50
int m_F
Definition: Path.h:46
NIBBLETYPE m_BlockMeta
Definition: Path.h:52
int m_G
Definition: Path.h:46
eCellStatus m_Status
Definition: Path.h:47
cPathCell * m_Parent
Definition: Path.h:48
int m_H
Definition: Path.h:46
BLOCKTYPE m_BlockType
Definition: Path.h:51
bool m_IsSolid
Definition: Path.h:49
Vector3i m_Location
Definition: Path.h:45
bool operator()(cPathCell *&a_V1, cPathCell *&a_V2)
Definition: Path.cpp:22
Vector3i m_Source
Definition: Path.h:176
cPathCell * m_NearestPointToTarget
Definition: Path.h:181
bool ProcessIfWalkable(const Vector3i &a_Location, cPathCell *a_Source, int a_Cost)
Definition: Path.cpp:407
bool BodyFitsIn(const Vector3i &a_Location, const Vector3i &a_Source)
Definition: Path.cpp:570
void FinishCalculation()
Definition: Path.cpp:350
void AttemptToFindAlternative()
Definition: Path.cpp:311
cPathCell * GetCell(const Vector3i &a_location)
Definition: Path.cpp:536
void ProcessCell(cPathCell *a_Cell, cPathCell *a_Caller, int a_GDelta)
Definition: Path.cpp:421
bool HasSolidBelow(const Vector3i &a_Location)
Definition: Path.cpp:666
std::unordered_map< Vector3i, cPathCell, VectorHasher< int > > m_Map
Definition: Path.h:174
bool IsWalkable(const Vector3i &a_Location, const Vector3i &a_Source)
Definition: Path.cpp:561
void OpenListAdd(cPathCell *a_Cell)
Definition: Path.cpp:374
ePathFinderStatus m_Status
Definition: Path.h:184
cPathCell * OpenListPop()
Definition: Path.cpp:387
int m_StepsLeft
Definition: Path.h:180
int m_BoundingBoxWidth
Definition: Path.h:177
void FillCellAttributes(cPathCell &a_Cell)
Definition: Path.cpp:477
Vector3i m_Destination
Definition: Path.h:175
bool BlockTypeIsSpecial(BLOCKTYPE a_Type)
Definition: Path.cpp:604
std::priority_queue< cPathCell *, std::vector< cPathCell * >, compareHeuristics > m_OpenList
Definition: Path.h:173
bool m_BadChunkFound
Definition: Path.h:194
int m_BoundingBoxHeight
Definition: Path.h:178
std::vector< Vector3i > m_PathPoints
Definition: Path.h:189
cPath()
Creates an invalid path which is not usable.
Definition: Path.cpp:75
double m_HalfWidth
Definition: Path.h:179
Vector3i AcceptNearbyPath()
Called after the PathFinder's step returns NEARBY_FOUND.
Definition: Path.cpp:123
ePathFinderStatus CalculationStep(cChunk &a_Chunk)
Performs part of the path calculation and returns the appropriate status.
Definition: Path.cpp:84
cChunk * m_Chunk
Definition: Path.h:193
void BuildPath()
Definition: Path.cpp:329
bool StepOnce()
Definition: Path.cpp:134
bool SpecialIsSolidFromThisDirection(BLOCKTYPE a_Type, NIBBLETYPE a_Meta, const Vector3i &a_Direction)
Definition: Path.cpp:632
T x
Definition: Vector3.h:17
T y
Definition: Vector3.h:17
T z
Definition: Vector3.h:17