92 std::vector<std::pair<Position, float>>
FindPath(
const BehaviourClient& client,
const Position& start,
const Position& end,
const int dist_tolerance,
const int min_end_dist,
const int min_end_dist_xz,
const bool allow_jump)
96 std::pair<Position, float> pos;
99 PathNode(
const std::pair<Position, float>& p,
const float s)
105 bool operator>(
const PathNode& rhs)
const
107 return score > rhs.score;
112 return static_cast<float>(std::abs(a.
x - b.
x) + std::abs(a.
y - b.
y) + std::abs(a.
z - b.
z));
116 constexpr int budget_visit = 15000;
118 const std::array<Position, 4> neighbour_offsets = {
Position(1, 0, 0),
Position(-1, 0, 0),
Position(0, 0, 1),
Position(0, 0, -1) };
119 std::priority_queue<PathNode, std::vector<PathNode>, std::greater<PathNode> > nodes_to_explore;
120 std::unordered_map<std::pair<Position, float>, std::pair<Position, float>,
PosFloatPairHash> came_from;
121 std::unordered_map<std::pair<Position, float>, float,
PosFloatPairHash> cost;
123 const bool takes_damage = !client.
GetLocalPlayer()->GetInvulnerable();
124 std::shared_ptr<World> world = client.
GetWorld();
125 const Blockstate* block = world->GetBlock(start);
127 came_from[nodes_to_explore.top().pos] = nodes_to_explore.top().pos;
128 cost[nodes_to_explore.top().pos] = 0.0f;
133 bool suitable_location_found =
false;
135 bool end_reached =
false;
137 bool end_is_inside_solid =
false;
138 block = world->GetBlock(end);
139 end_is_inside_solid = block !=
nullptr && block->
IsSolid();
140#if PROTOCOL_VERSION > 765
141 const float step_height =
static_cast<float>(client.
GetLocalPlayer()->GetAttributeStepHeightValue());
143 const float step_height = 0.6f;
146 while (!nodes_to_explore.empty())
149 PathNode current_node = nodes_to_explore.top();
150 nodes_to_explore.pop();
152 end_reached |= current_node.pos.first == end;
153 suitable_location_found |=
154 std::abs(end.
x - current_node.pos.first.x) + std::abs(end.
y - current_node.pos.first.y) + std::abs(end.
z - current_node.pos.first.z) <= dist_tolerance &&
155 std::abs(end.
x - current_node.pos.first.x) + std::abs(end.
y - current_node.pos.first.y) + std::abs(end.
z - current_node.pos.first.z) >= min_end_dist &&
156 std::abs(end.
x - current_node.pos.first.x) + std::abs(end.
z - current_node.pos.first.z) >= min_end_dist_xz;
159 count_visit > budget_visit ||
161 (suitable_location_found && (end_reached || end_is_inside_solid)))
167 std::array<PathfindingBlockstate, 6> vertical_surroundings;
177 block = world->GetBlock(pos);
179 pos = current_node.pos.first +
Position(0, 1, 0);
180 block = world->GetBlock(pos);
183 pos = current_node.pos.first;
184 block = world->GetBlock(pos);
186 const bool can_jump =
187 vertical_surroundings[2].GetBlockstate() !=
nullptr &&
188 vertical_surroundings[2].GetBlockstate()->CanJumpWhenFeetInside();
192 if (!vertical_surroundings[2].IsSolid() && !vertical_surroundings[2].IsHazardous())
196 pos = current_node.pos.first +
Position(0, -1, 0);
197 block = world->GetBlock(pos);
201 if (!vertical_surroundings[3].IsSolid() && !vertical_surroundings[3].IsHazardous())
203 pos = current_node.pos.first +
Position(0, -2, 0);
204 block = world->GetBlock(pos);
206 pos = current_node.pos.first +
Position(0, -3, 0);
207 block = world->GetBlock(pos);
220 if (vertical_surroundings[2].IsClimbable()
221 && !vertical_surroundings[1].IsSolid()
222 && !vertical_surroundings[1].IsHazardous()
223 && !vertical_surroundings[0].IsSolid()
224 && !vertical_surroundings[0].IsHazardous()
227 const float new_cost = cost[current_node.pos] + 1.0f;
228 const std::pair<Position, float> new_pos = {
229 current_node.pos.first +
Position(0, 1, 0),
230 current_node.pos.first.y + 1.0f
232 auto it = cost.find(new_pos);
234 if (it == cost.end() ||
235 new_cost < it->second)
237 cost[new_pos] = new_cost;
238 nodes_to_explore.emplace(PathNode(
240 new_cost + PathNode::Heuristic(new_pos.first, end))
242 came_from[new_pos] = current_node.pos;
253 && vertical_surroundings[1].IsClimbable()
254 && !vertical_surroundings[0].IsSolid()
255 && !vertical_surroundings[0].IsHazardous()
256 && (vertical_surroundings[2].IsSolid() ||
257 vertical_surroundings[3].IsSolid())
260 const float new_cost = cost[current_node.pos] + 1.5f;
261 const std::pair<Position, float> new_pos = {
262 current_node.pos.first +
Position(0, 1, 0),
263 current_node.pos.first.y + 1.0f
265 auto it = cost.find(new_pos);
267 if (it == cost.end() ||
268 new_cost < it->second)
270 cost[new_pos] = new_cost;
271 nodes_to_explore.emplace(PathNode(
273 new_cost + PathNode::Heuristic(new_pos.first, end))
275 came_from[new_pos] = current_node.pos;
285 if (!vertical_surroundings[2].IsSolid() &&
286 vertical_surroundings[3].IsClimbable()
289 const float new_cost = cost[current_node.pos] + 1.0f;
290 const std::pair<Position, float> new_pos = {
291 current_node.pos.first +
Position(0, -1, 0),
292 current_node.pos.first.y - 1.0f
294 auto it = cost.find(new_pos);
296 if (it == cost.end() ||
297 new_cost < it->second)
299 cost[new_pos] = new_cost;
300 nodes_to_explore.emplace(PathNode(new_pos, new_cost + PathNode::Heuristic(new_pos.first, end)));
301 came_from[new_pos] = current_node.pos;
311 if (!vertical_surroundings[2].IsSolid() &&
312 vertical_surroundings[3].IsClimbable()
313 && vertical_surroundings[4].IsEmpty()
314 && !vertical_surroundings[5].IsEmpty()
315 && !vertical_surroundings[5].IsHazardous()
318 const bool above_block = vertical_surroundings[5].IsClimbable() || vertical_surroundings[5].GetHeight() + 1e-3f > current_node.pos.first.y - 2;
319 const float new_cost = cost[current_node.pos] + 3.0f - 1.0f * above_block;
320 const std::pair<Position, float> new_pos = {
321 current_node.pos.first +
Position(0, -3 + 1 * above_block, 0),
322 above_block ? std::max(current_node.pos.first.y - 2.0f, vertical_surroundings[5].GetHeight()) : vertical_surroundings[5].GetHeight()
324 auto it = cost.find(new_pos);
326 if (it == cost.end() ||
327 new_cost < it->second)
329 cost[new_pos] = new_cost;
330 nodes_to_explore.emplace(PathNode(
332 new_cost + PathNode::Heuristic(new_pos.first, end))
334 came_from[new_pos] = current_node.pos;
346 if (vertical_surroundings[2].IsClimbable()
347 && vertical_surroundings[3].IsEmpty()
348 && vertical_surroundings[4].IsEmpty()
349 && !vertical_surroundings[5].IsEmpty()
350 && !vertical_surroundings[5].IsHazardous()
353 const bool above_block = vertical_surroundings[5].IsClimbable() || vertical_surroundings[5].GetHeight() + 1e-3f > current_node.pos.first.y - 2;
354 const float new_cost = cost[current_node.pos] + 3.0f - 1.0f * above_block;
355 const std::pair<Position, float> new_pos = {
356 current_node.pos.first +
Position(0, -3 + 1 * above_block, 0),
357 above_block ? std::max(current_node.pos.first.y - 2.0f, vertical_surroundings[5].GetHeight()) : vertical_surroundings[5].GetHeight()
359 auto it = cost.find(new_pos);
361 if (it == cost.end() ||
362 new_cost < it->second)
364 cost[new_pos] = new_cost;
365 nodes_to_explore.emplace(PathNode(
367 new_cost + PathNode::Heuristic(new_pos.first, end))
369 came_from[new_pos] = current_node.pos;
382 if (!vertical_surroundings[2].IsSolid() &&
383 vertical_surroundings[3].IsClimbable()
384 && vertical_surroundings[4].IsEmpty()
385 && vertical_surroundings[5].IsEmpty()
388 for (
int y = -4; current_node.pos.first.y + y >= world->GetMinY(); --y)
390 pos = current_node.pos.first +
Position(0, y, 0);
391 block = world->GetBlock(pos);
401 const float new_cost = cost[current_node.pos] + std::abs(y);
402 const std::pair<Position, float> new_pos = {
403 current_node.pos.first +
Position(0, y + 1, 0),
404 current_node.pos.first.y + y + 1.0f
406 auto it = cost.find(new_pos);
408 if (it == cost.end() ||
409 new_cost < it->second)
411 cost[new_pos] = new_cost;
412 nodes_to_explore.emplace(PathNode(
414 new_cost + PathNode::Heuristic(new_pos.first, end))
416 came_from[new_pos] = current_node.pos;
427 for (
int i = 0; i < neighbour_offsets.size(); ++i)
429 const Position next_location = current_node.pos.first + neighbour_offsets[i];
430 const Position next_next_location = next_location + neighbour_offsets[i];
433 std::array<PathfindingBlockstate, 12> horizontal_surroundings;
445 pos = next_location +
Position(0, 2, 0);
446 block = world->GetBlock(pos);
448 pos = next_location +
Position(0, 1, 0);
449 block = world->GetBlock(pos);
451 const bool horizontal_movement =
452 (!horizontal_surroundings[1].IsSolid() ||
453 (horizontal_surroundings[1].GetHeight() - current_node.pos.second < 1.25f &&
454 !horizontal_surroundings[0].IsSolid() && !horizontal_surroundings[0].IsHazardous())
455 ) && !horizontal_surroundings[1].IsHazardous();
458 if (horizontal_movement)
461 block = world->GetBlock(pos);
463 pos = next_location +
Position(0, -1, 0);
464 block = world->GetBlock(pos);
466 pos = next_location +
Position(0, -2, 0);
467 block = world->GetBlock(pos);
469 pos = next_location +
Position(0, -3, 0);
470 block = world->GetBlock(pos);
476 if (allow_jump && can_jump)
478 pos = next_next_location +
Position(0, 2, 0);
479 block = world->GetBlock(pos);
481 pos = next_next_location +
Position(0, 1, 0);
482 block = world->GetBlock(pos);
484 pos = next_next_location;
485 block = world->GetBlock(pos);
487 pos = next_next_location +
Position(0, -1, 0);
488 block = world->GetBlock(pos);
490 pos = next_next_location +
Position(0, -2, 0);
491 block = world->GetBlock(pos);
493 pos = next_next_location +
Position(0, -3, 0);
494 block = world->GetBlock(pos);
509 if (!horizontal_surroundings[1].IsSolid()
510 && !horizontal_surroundings[1].IsHazardous()
511 && !horizontal_surroundings[2].IsSolid()
512 && !horizontal_surroundings[2].IsHazardous()
513 && !horizontal_surroundings[3].IsEmpty()
514 && !horizontal_surroundings[3].IsHazardous()
515 && (!horizontal_surroundings[3].IsFluid()
516 || !vertical_surroundings[3].IsFluid()
517 || horizontal_surroundings[2].IsFluid()
518 || vertical_surroundings[2].IsFluid())
521 const bool above_block = horizontal_surroundings[2].IsClimbable() || horizontal_surroundings[3].IsClimbable() || horizontal_surroundings[3].GetHeight() + 1e-3f > current_node.pos.first.y;
522 const float new_cost = cost[current_node.pos] + 2.0f - 1.0f * above_block;
523 const std::pair<Position, float> new_pos = {
524 next_location +
Position(0, 1 - 1 * above_block, 0),
525 above_block ? std::max(
static_cast<float>(next_location.
y), horizontal_surroundings[3].GetHeight()) : std::max(horizontal_surroundings[3].GetHeight(), horizontal_surroundings[4].GetHeight())
527 auto it = cost.find(new_pos);
529 if (it == cost.end() ||
530 new_cost < it->second)
532 cost[new_pos] = new_cost;
533 nodes_to_explore.emplace(PathNode(
535 new_cost + PathNode::Heuristic(new_pos.first, end))
537 came_from[new_pos] = current_node.pos;
549 && !vertical_surroundings[0].IsSolid()
550 && !vertical_surroundings[0].IsHazardous()
551 && vertical_surroundings[1].IsEmpty()
552 && (vertical_surroundings[2].IsSolid() || !vertical_surroundings[3].IsClimbable())
553 && !horizontal_surroundings[0].IsSolid()
554 && !horizontal_surroundings[0].IsHazardous()
555 && !horizontal_surroundings[1].IsEmpty()
556 && !horizontal_surroundings[1].IsHazardous()
557 && horizontal_surroundings[1].GetHeight() - current_node.pos.second < 1.25f
560 const float new_cost = cost[current_node.pos] + 2.5f;
561 const std::pair<Position, float> new_pos = {
563 std::max(horizontal_surroundings[1].GetHeight(), horizontal_surroundings[2].GetHeight())
565 auto it = cost.find(new_pos);
567 if (it == cost.end() ||
568 new_cost < it->second)
570 cost[new_pos] = new_cost;
571 nodes_to_explore.emplace(PathNode(
573 new_cost + PathNode::Heuristic(new_pos.first, end))
575 came_from[new_pos] = current_node.pos;
585 if ((can_jump || horizontal_surroundings[2].GetHeight() - current_node.pos.second < step_height)
586 && !vertical_surroundings[0].IsSolid()
587 && !vertical_surroundings[0].IsHazardous()
588 && vertical_surroundings[1].IsEmpty()
589 && (vertical_surroundings[2].IsSolid() || (vertical_surroundings[2].IsEmpty() && vertical_surroundings[3].IsSolid()))
590 && !horizontal_surroundings[0].IsSolid()
591 && !horizontal_surroundings[0].IsHazardous()
592 && !horizontal_surroundings[1].IsSolid()
593 && !horizontal_surroundings[1].IsHazardous()
594 && !horizontal_surroundings[2].IsEmpty()
595 && !horizontal_surroundings[2].IsHazardous()
596 && horizontal_surroundings[2].GetHeight() - current_node.pos.second < 1.25f
599 const bool above_block = horizontal_surroundings[1].IsClimbable() || horizontal_surroundings[2].IsClimbable() || horizontal_surroundings[2].GetHeight() + 1e-3f > current_node.pos.first.y + 1;
600 const float new_cost = cost[current_node.pos] + 1.0f + 1.0f * above_block + 0.5f * (horizontal_surroundings[1].IsClimbable() || horizontal_surroundings[2].GetHeight() - vertical_surroundings[2].GetHeight() > 0.5);
601 const std::pair<Position, float> new_pos = {
602 next_location +
Position(0, 1 * above_block, 0),
603 above_block ? std::max(current_node.pos.first.y + 1.0f, horizontal_surroundings[2].GetHeight()) : std::max(horizontal_surroundings[2].GetHeight(), horizontal_surroundings[3].GetHeight())
605 auto it = cost.find(new_pos);
607 if (it == cost.end() ||
608 new_cost < it->second)
610 cost[new_pos] = new_cost;
611 nodes_to_explore.emplace(PathNode(
613 new_cost + PathNode::Heuristic(new_pos.first, end))
615 came_from[new_pos] = current_node.pos;
625 if (!horizontal_surroundings[1].IsSolid()
626 && !horizontal_surroundings[1].IsHazardous()
627 && horizontal_surroundings[2].IsEmpty()
628 && horizontal_surroundings[3].IsEmpty()
629 && !horizontal_surroundings[4].IsEmpty()
630 && !horizontal_surroundings[4].IsHazardous()
633 const bool above_block = horizontal_surroundings[4].IsClimbable() || horizontal_surroundings[4].GetHeight() + 1e-3f > current_node.pos.first.y - 1;
634 const float new_cost = cost[current_node.pos] + 3.5f - 1.0f * above_block;
635 const std::pair<Position, float> new_pos = {
636 next_location +
Position(0, -2 + 1 * above_block, 0),
637 above_block ? std::max(current_node.pos.first.y - 1.0f, horizontal_surroundings[4].GetHeight()) : std::max(horizontal_surroundings[4].GetHeight(), horizontal_surroundings[5].GetHeight())
639 auto it = cost.find(new_pos);
641 if (it == cost.end() ||
642 new_cost < it->second)
644 cost[new_pos] = new_cost;
645 nodes_to_explore.emplace(PathNode(
647 new_cost + PathNode::Heuristic(new_pos.first, end))
649 came_from[new_pos] = current_node.pos;
659 if (!horizontal_surroundings[1].IsSolid()
660 && !horizontal_surroundings[1].IsHazardous()
661 && horizontal_surroundings[2].IsEmpty()
662 && horizontal_surroundings[3].IsEmpty()
663 && horizontal_surroundings[4].IsEmpty()
664 && !horizontal_surroundings[5].IsEmpty()
665 && !horizontal_surroundings[5].IsHazardous()
668 const bool above_block = horizontal_surroundings[5].IsClimbable() || horizontal_surroundings[5].GetHeight() + 1e-3f > current_node.pos.first.y - 2;
669 const float new_cost = cost[current_node.pos] + 4.5f - 1.0f * above_block;
670 const std::pair<Position, float> new_pos = {
671 next_location +
Position(0, -3 + 1 * above_block, 0),
672 above_block ? std::max(current_node.pos.first.y - 2.0f, horizontal_surroundings[5].GetHeight()) : horizontal_surroundings[5].GetHeight()
674 auto it = cost.find(new_pos);
676 if (it == cost.end() ||
677 new_cost < it->second)
679 cost[new_pos] = new_cost;
680 nodes_to_explore.emplace(PathNode(
682 new_cost + PathNode::Heuristic(new_pos.first, end))
684 came_from[new_pos] = current_node.pos;
696 if (!horizontal_surroundings[1].IsSolid()
697 && !horizontal_surroundings[1].IsHazardous()
698 && horizontal_surroundings[2].IsEmpty()
699 && horizontal_surroundings[3].IsEmpty()
700 && horizontal_surroundings[4].IsEmpty()
701 && horizontal_surroundings[5].IsEmpty()
704 for (
int y = -4; next_location.
y + y >= world->GetMinY(); --y)
706 pos = next_location +
Position(0, y, 0);
707 block = world->GetBlock(pos);
717 const float new_cost = cost[current_node.pos] + std::abs(y) + 1.5f;
718 const std::pair<Position, float> new_pos = {
719 next_location +
Position(0, y + 1, 0),
720 next_location.
y + y + 1.0f
722 auto it = cost.find(new_pos);
724 if (it == cost.end() ||
725 new_cost < it->second)
727 cost[new_pos] = new_cost;
728 nodes_to_explore.emplace(PathNode(
730 new_cost + PathNode::Heuristic(new_pos.first, end))
732 came_from[new_pos] = current_node.pos;
744 || vertical_surroundings[0].IsSolid()
745 || vertical_surroundings[0].IsHazardous()
746 || !vertical_surroundings[1].IsEmpty()
747 || vertical_surroundings[3].IsFluid()
748 || vertical_surroundings[3].IsEmpty()
749 || horizontal_surroundings[0].IsSolid()
750 || horizontal_surroundings[0].IsHazardous()
751 || !horizontal_surroundings[1].IsEmpty()
752 || !horizontal_surroundings[2].IsEmpty()
753 || horizontal_surroundings[6].IsSolid()
754 || horizontal_surroundings[6].IsHazardous()
767 if (!horizontal_surroundings[7].IsEmpty()
768 && !horizontal_surroundings[7].IsHazardous()
769 && horizontal_surroundings[7].GetHeight() - current_node.pos.second < 1.25f
774 const float new_cost = cost[current_node.pos] + 5.0f;
775 const std::pair<Position, float> new_pos = {
776 next_next_location +
Position(0, 1, 0),
777 std::max(horizontal_surroundings[7].GetHeight(), horizontal_surroundings[8].GetHeight()),
779 auto it = cost.find(new_pos);
781 if (it == cost.end() ||
782 new_cost < it->second)
784 cost[new_pos] = new_cost;
785 nodes_to_explore.emplace(PathNode(
787 new_cost + PathNode::Heuristic(new_pos.first, end))
789 came_from[new_pos] = current_node.pos;
799 if (horizontal_surroundings[7].IsEmpty()
800 && !horizontal_surroundings[8].IsEmpty()
801 && !horizontal_surroundings[8].IsHazardous()
802 && horizontal_surroundings[8].GetHeight() - current_node.pos.second < 1.25f
805 const bool above_block = horizontal_surroundings[8].IsClimbable() || horizontal_surroundings[8].GetHeight() + 1e-3f > current_node.pos.first.y + 1;
808 const float new_cost = cost[current_node.pos] + 3.0f + 1.0f * above_block;
809 const std::pair<Position, float> new_pos = {
810 next_next_location +
Position(0, above_block * 1, 0),
811 above_block ? std::max(current_node.pos.first.y + 1.0f, horizontal_surroundings[8].GetHeight()) : std::max(horizontal_surroundings[8].GetHeight(), horizontal_surroundings[9].GetHeight())
813 auto it = cost.find(new_pos);
815 if (it == cost.end() ||
816 new_cost < it->second)
818 cost[new_pos] = new_cost;
819 nodes_to_explore.emplace(PathNode(
821 new_cost + PathNode::Heuristic(new_pos.first, end))
823 came_from[new_pos] = current_node.pos;
833 if (horizontal_surroundings[7].IsEmpty()
834 && horizontal_surroundings[8].IsEmpty()
835 && !horizontal_surroundings[9].IsEmpty()
836 && !horizontal_surroundings[9].IsHazardous()
839 const bool above_block = horizontal_surroundings[9].IsClimbable() || horizontal_surroundings[9].GetHeight() + 1e-3f > current_node.pos.first.y;
840 const float new_cost = cost[current_node.pos] + 3.5f - 1.0f * above_block;
841 const std::pair<Position, float> new_pos = {
842 next_next_location +
Position(0, -1 + 1 * above_block, 0),
843 above_block ? std::max(
static_cast<float>(current_node.pos.first.y), horizontal_surroundings[9].GetHeight()) : std::max(horizontal_surroundings[9].GetHeight(), horizontal_surroundings[10].GetHeight())
845 auto it = cost.find(new_pos);
847 if (it == cost.end() ||
848 new_cost < it->second)
850 cost[new_pos] = new_cost;
851 nodes_to_explore.emplace(PathNode(
853 new_cost + PathNode::Heuristic(new_pos.first, end))
855 came_from[new_pos] = current_node.pos;
865 if (horizontal_surroundings[7].IsEmpty()
866 && horizontal_surroundings[8].IsEmpty()
867 && horizontal_surroundings[9].IsEmpty()
868 && !horizontal_surroundings[10].IsEmpty()
869 && !horizontal_surroundings[10].IsHazardous()
872 const bool above_block = horizontal_surroundings[10].IsClimbable() || horizontal_surroundings[10].GetHeight() + 1e-3f > current_node.pos.first.y - 1;
873 const float new_cost = cost[current_node.pos] + 4.5f - 1.0f * above_block;
874 const std::pair<Position, float> new_pos = {
875 next_next_location +
Position(0, -2 + 1 * above_block, 0),
876 above_block ? std::max(current_node.pos.first.y - 1.0f, horizontal_surroundings[10].GetHeight()) : std::max(horizontal_surroundings[10].GetHeight(), horizontal_surroundings[11].GetHeight())
878 auto it = cost.find(new_pos);
880 if (it == cost.end() ||
881 new_cost < it->second)
883 cost[new_pos] = new_cost;
884 nodes_to_explore.emplace(PathNode(
886 new_cost + PathNode::Heuristic(new_pos.first, end))
888 came_from[new_pos] = current_node.pos;
898 if (horizontal_surroundings[7].IsEmpty()
899 && horizontal_surroundings[8].IsEmpty()
900 && horizontal_surroundings[9].IsEmpty()
901 && horizontal_surroundings[10].IsEmpty()
902 && !horizontal_surroundings[11].IsEmpty()
903 && !horizontal_surroundings[11].IsHazardous()
906 const bool above_block = horizontal_surroundings[11].IsClimbable() || horizontal_surroundings[11].GetHeight() + 1e-3f > current_node.pos.first.y - 2;
907 const float new_cost = cost[current_node.pos] + 6.5f - 1.0f * above_block;
908 const std::pair<Position, float> new_pos = {
909 next_next_location +
Position(0, -3 + 1 * above_block, 0),
910 above_block ? std::max(current_node.pos.first.y - 2.0f, horizontal_surroundings[11].GetHeight()) : horizontal_surroundings[1].GetHeight()
912 auto it = cost.find(new_pos);
914 if (it == cost.end() ||
915 new_cost < it->second)
917 cost[new_pos] = new_cost;
918 nodes_to_explore.emplace(PathNode(
920 new_cost + PathNode::Heuristic(new_pos.first, end))
922 came_from[new_pos] = current_node.pos;
928 auto it_end_path = came_from.begin();
935 int best_dist = std::numeric_limits<int>::max();
936 int best_dist_start = std::numeric_limits<int>::max();
937 for (
auto it = came_from.begin(); it != came_from.end(); ++it)
939 const Position diff = it->first.first - end;
940 const int d_xz = std::abs(diff.
x) + std::abs(diff.
z);
941 const int d = d_xz + std::abs(diff.
y);
942 const Position diff_start = it->first.first - start;
943 const int d_start = std::abs(diff_start.
x) + std::abs(diff_start.
y) + std::abs(diff_start.
z);
944 if (d <= dist_tolerance && d >= min_end_dist && d_xz >= min_end_dist_xz &&
945 (d_start < best_dist_start || (d_start == best_dist_start && d < best_dist))
949 best_dist_start = d_start;
957 if (best_dist == std::numeric_limits<int>::max())
959 for (
auto it = came_from.begin(); it != came_from.end(); ++it)
961 const Position diff = it->first.first - end;
962 const int d_xz = std::abs(diff.
x) + std::abs(diff.
z);
963 const int d = d_xz + std::abs(diff.
y);
964 const Position diff_start = it->first.first - start;
965 const int d_start = std::abs(diff_start.
x) + std::abs(diff_start.
y) + std::abs(diff_start.
z);
966 if (d < best_dist || (d == best_dist && d_start < best_dist_start))
969 best_dist_start = d_start;
975 std::deque<std::pair<Position, float>> output_deque;
976 output_deque.push_front(it_end_path->first);
977 while (it_end_path->second.first != start)
979 it_end_path = came_from.find(it_end_path->second);
980 output_deque.push_front(it_end_path->first);
983 return std::vector<std::pair<Position, float>>(output_deque.begin(), output_deque.end());
996 static_cast<int>(std::floor(target_position.
x)),
997 static_cast<int>(std::floor(target_position.
y)),
998 static_cast<int>(std::floor(target_position.
z))
1001 const Vector3<double> motion_vector = target_position - local_player->GetPosition();
1002 const double half_player_width = 0.5 * local_player->GetWidth();
1003 const Vector3<double> horizontal_target_position(target_position.
x, 0.0, target_position.
z);
1006 std::shared_ptr<World> world = client.
GetWorld();
1008 if (speed_factor != 1.0f)
1010 local_player->SetAttributeModifier(
1014 speed_factor - 1.0f,
1022 local_player->LookAt(look_at_target,
true);
1025 if (std::abs(motion_vector.
x) > 0.5 || std::abs(motion_vector.
z) > 0.5)
1028 if (motion_vector.
y > 0.5 || std::abs(motion_vector.
x) > 1.5 || std::abs(motion_vector.
z) > 1.5)
1031 if (std::abs(motion_vector.
x) < 1.5 && std::abs(motion_vector.
z) < 1.5)
1033 local_player->SetInputsJump(
true);
1037 return local_player->GetY() >= target_block.
y;
1038 }, client, 40.0 * ms_per_tick))
1047 std::floor(local_player->GetX()) + 0.5,
1049 std::floor(local_player->GetZ()) + 0.5
1054 if (local_player->GetDirtyInputs())
1060 local_player->LookAt(look_at_target,
false);
1061 local_player->SetInputsForward(1.0);
1062 local_player->SetInputsSprint(sprint);
1064 if (
Vector3<double>(local_player->GetX(), 0.0, local_player->GetZ()).
SqrDist(current_block_center_xz) > half_player_width * half_player_width)
1067 local_player->SetInputsJump(
true);
1072 }, client, 20.0 * ms_per_tick))
1081 if (local_player->GetDirtyInputs())
1087 const Vector3<double> current_motion_vector = target_position - current_pos;
1089 if ((current_motion_vector.
x * motion_vector.
x + current_motion_vector.
z * motion_vector.
z) < 0.0 ||
1090 Vector3<double>(current_pos.
x, 0.0, current_pos.
z).
SqrDist(horizontal_target_position) < (0.5 - half_player_width) * (0.5 - half_player_width))
1095 local_player->LookAt(look_at_target,
false);
1097 double forward = 1.0;
1100 if (motion_vector.
y < -0.5 &&
1101 static_cast<int>(std::floor(current_pos.
x)) == target_block.
x &&
1102 static_cast<int>(std::floor(current_pos.
z)) == target_block.
z)
1104 if (std::max(std::abs(speed.
x), std::abs(speed.
z)) > 0.12)
1108 else if (std::max(std::abs(speed.
x), std::abs(speed.
z)) > 0.06)
1113 local_player->SetInputsForward(forward);
1114 local_player->SetInputsSprint(sprint && (forward == 1.0));
1117 }, client, (std::abs(motion_vector.
x) + std::abs(motion_vector.
z) + (motion_vector.
y < -0.5)) * 20.0 * ms_per_tick))
1129 if (local_player->GetDirtyInputs())
1134 if (
static_cast<int>(std::floor(local_player->GetY())) <= target_block.
y &&
1135 (local_player->GetOnGround() || local_player->IsClimbing() || local_player->IsInFluid()))
1142 static_cast<int>(std::floor(current_pos.x)),
1143 static_cast<int>(std::floor(current_pos.y)),
1144 static_cast<int>(std::floor(current_pos.z))
1146 local_player->SetInputsSneak(feet_block !=
nullptr &&
1148 local_player->SetInputsJump(local_player->GetFlying());
1151 if (
Vector3<double>(current_pos.x, 0.0, current_pos.z).
SqrDist(horizontal_target_position) > (0.5 - half_player_width) * (0.5 - half_player_width))
1153 local_player->LookAt(look_at_target,
false);
1154 local_player->SetInputsForward(1.0);
1158 }, client, 20.0 * ms_per_tick + (1 + std::abs(motion_vector.
y))))
1167 if (local_player->GetDirtyInputs())
1173 if (
static_cast<int>(std::floor(current_pos.y)) >= target_block.
y)
1178 local_player->SetInputsJump(
true);
1181 if (
Vector3<double>(current_pos.x, 0.0, current_pos.z).
SqrDist(horizontal_target_position) > (0.5 - half_player_width) * (0.5 - half_player_width))
1183 local_player->LookAt(look_at_target,
false);
1184 local_player->SetInputsForward(1.0);
1188 }, client, 20.0 * ms_per_tick * (1 + std::abs(motion_vector.
y))))
1196 if (local_player->GetDirtyInputs())
1202 if (local_player->GetY() >= target_position.
y && local_player->GetY() - target_position.
y < 0.2)
1209 static_cast<int>(std::floor(current_pos.x)),
1210 static_cast<int>(std::floor(current_pos.y)),
1211 static_cast<int>(std::floor(current_pos.z))
1213 local_player->SetInputsSneak(feet_block !=
nullptr &&
1215 local_player->SetInputsJump(local_player->GetFlying());
1218 if (
Vector3<double>(current_pos.x, 0.0, current_pos.z).
SqrDist(horizontal_target_position) > (0.5 - half_player_width) * (0.5 - half_player_width))
1220 local_player->LookAt(look_at_target,
false);
1221 local_player->SetInputsForward(1.0);
1225 }, client, 20.0 * ms_per_tick);