1 package cz.cuni.amis.pogamut.ut2004.agent.navigation.navmesh.pathfollowing;
2
3 import java.util.ArrayList;
4 import java.util.List;
5 import java.util.logging.Level;
6 import java.util.logging.Logger;
7
8 import cz.cuni.amis.pogamut.base.agent.navigation.IPathExecutorState;
9 import cz.cuni.amis.pogamut.base.agent.navigation.IPathFuture;
10 import cz.cuni.amis.pogamut.base.agent.navigation.IPathPlanner;
11 import cz.cuni.amis.pogamut.base.communication.worldview.event.IWorldEventListener;
12 import cz.cuni.amis.pogamut.base.utils.logging.LogCategory;
13 import cz.cuni.amis.pogamut.base.utils.math.DistanceUtils;
14 import cz.cuni.amis.pogamut.base3d.worldview.object.ILocated;
15 import cz.cuni.amis.pogamut.base3d.worldview.object.Location;
16 import cz.cuni.amis.pogamut.ut2004.agent.module.sensor.AgentInfo;
17 import cz.cuni.amis.pogamut.ut2004.agent.navigation.IUT2004GetBackToNavGraph;
18 import cz.cuni.amis.pogamut.ut2004.agent.navigation.IUT2004Navigation;
19 import cz.cuni.amis.pogamut.ut2004.agent.navigation.IUT2004PathExecutor;
20 import cz.cuni.amis.pogamut.ut2004.agent.navigation.IUT2004RunStraight;
21 import cz.cuni.amis.pogamut.ut2004.agent.navigation.NavigationState;
22 import cz.cuni.amis.pogamut.ut2004.agent.navigation.UT2004GetBackToNavGraph;
23 import cz.cuni.amis.pogamut.ut2004.agent.navigation.UT2004Navigation;
24 import cz.cuni.amis.pogamut.ut2004.agent.navigation.UT2004RunStraight;
25 import cz.cuni.amis.pogamut.ut2004.agent.navigation.navmesh.NavMesh;
26 import cz.cuni.amis.pogamut.ut2004.agent.navigation.navmesh.NavMeshModule;
27 import cz.cuni.amis.pogamut.ut2004.agent.navigation.stuckdetector.AccUT2004DistanceStuckDetector;
28 import cz.cuni.amis.pogamut.ut2004.agent.navigation.stuckdetector.AccUT2004PositionStuckDetector;
29 import cz.cuni.amis.pogamut.ut2004.agent.navigation.stuckdetector.AccUT2004TimeStuckDetector;
30 import cz.cuni.amis.pogamut.ut2004.bot.command.AdvancedLocomotion;
31 import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004Bot;
32 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.Stop;
33 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.BotKilled;
34 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.EndMessage;
35 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Item;
36 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.NavPoint;
37 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Player;
38 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Self;
39 import cz.cuni.amis.utils.flag.Flag;
40 import cz.cuni.amis.utils.flag.FlagListener;
41
42
43
44
45
46
47
48
49
50
51
52
53 public class NavMeshNavigation implements IUT2004Navigation {
54
55 public static double EXTEND_PATH_THRESHOLD = 500;
56
57
58
59 protected LogCategory log;
60
61
62
63 protected IUT2004PathExecutor<ILocated> pathExecutor;
64
65
66
67 protected NavMeshModule navMeshModule;
68
69
70
71 protected NavMesh pathPlanner;
72
73
74
75 protected UT2004Bot bot;
76
77
78
79 protected IUT2004GetBackToNavGraph getBackToNavGraph;
80
81
82
83 protected IUT2004RunStraight runStraight;
84
85
86
87
88 protected double extendPathThreshold;
89
90
91
92 protected static final int NEW_PATH_DISTANCE_THRESHOLD = 40;
93
94
95
96
97 protected static final int ARRIVED_AT_LOCATION_XY_THRESHOLD = 50;
98
99
100
101
102 protected static final int ARRIVED_AT_LOCATION_Z_THRESHOLD = 100;
103
104
105
106
107 protected static final double PLAYER_DISTANCE_TRASHOLD = 600;
108
109
110
111 public static final double AT_PLAYER = 100;
112
113
114
115 protected Flag<NavigationState> state = new Flag<NavigationState>(NavigationState.STOPPED);
116
117
118
119
120 FlagListener<IPathExecutorState> myUT2004PathExecutorStateListener = new FlagListener<IPathExecutorState>() {
121
122 @Override
123 public void flagChanged(IPathExecutorState changedValue) {
124 switch (changedValue.getState()) {
125 case TARGET_REACHED:
126 targetReached();
127 break;
128 case PATH_COMPUTATION_FAILED:
129 noPath();
130 break;
131 case STUCK:
132 if (log != null && log.isLoggable(Level.WARNING)) {
133 log.warning("stuck() - Path executor reported stuck!");
134 }
135 stuck();
136 break;
137 }
138 }
139 };
140 protected IWorldEventListener<EndMessage> endMessageListener = new IWorldEventListener<EndMessage>() {
141 @Override
142 public void notify(EndMessage event) {
143 navigate();
144 }
145 };
146
147 protected IWorldEventListener<BotKilled> botKilledMessageListener = new IWorldEventListener<BotKilled>() {
148 @Override
149 public void notify(BotKilled event) {
150 reset(true, NavigationState.STOPPED);
151 }
152 };
153
154
155
156
157
158
159
160
161
162
163
164
165
166 public NavMeshNavigation(UT2004Bot bot, AgentInfo info, AdvancedLocomotion move, NavMeshModule navMeshModule) {
167 this.log = bot.getLogger().getCategory(this.getClass().getSimpleName());
168 this.bot = bot;
169 this.navMeshModule = navMeshModule;
170 this.pathPlanner = navMeshModule.getNavMesh();
171
172 this.pathExecutor = new UT2004AcceleratedPathExecutor<ILocated>(
173 bot, info, move,
174
175 new NavMeshNavigator<ILocated>(bot, info, move, new NavMeshRunner(bot, info, move, log, navMeshModule.getNavMesh()), log));
176
177 pathExecutor.addStuckDetector(new AccUT2004TimeStuckDetector(bot, 3000, 100000));
178
179
180 pathExecutor.addStuckDetector(new AccUT2004PositionStuckDetector(bot));
181
182
183
184 pathExecutor.addStuckDetector(new AccUT2004DistanceStuckDetector(bot));
185
186
187 this.getBackToNavGraph = new UT2004GetBackToNavGraph(bot, info, move);
188 this.runStraight = new UT2004RunStraight(bot, info, move);
189
190 initListeners();
191 }
192
193 @Override
194 public Logger getLog() {
195 return log;
196 }
197
198 public void setLogLevel(Level level) {
199 getLog().setLevel(level);
200 pathExecutor.getLog().setLevel(level);
201 getBackToNavGraph.getLog().setLevel(level);
202 runStraight.getLog().setLevel(level);
203 }
204
205 private void initListeners() {
206 this.pathExecutor.getState().addListener(myUT2004PathExecutorStateListener);
207 bot.getWorldView().addEventListener(EndMessage.class, endMessageListener);
208 bot.getWorldView().addEventListener(BotKilled.class, botKilledMessageListener);
209 }
210
211
212
213
214
215 @Override
216 public void addStrongNavigationListener(FlagListener<NavigationState> listener) {
217 state.addStrongListener(listener);
218 }
219
220 @Override
221 public void removeStrongNavigationListener(FlagListener<NavigationState> listener) {
222 state.removeListener(listener);
223 }
224
225 @Override
226 public IUT2004PathExecutor<ILocated> getPathExecutor() {
227 return pathExecutor;
228 }
229
230 @Override
231 public IPathPlanner<ILocated> getPathPlanner() {
232 return pathPlanner;
233 }
234
235 @Override
236 public IUT2004GetBackToNavGraph getBackToNavGraph() {
237 return getBackToNavGraph;
238 }
239
240 @Override
241 public IUT2004RunStraight getRunStraight() {
242 return runStraight;
243 }
244
245
246
247
248
249
250
251
252
253 public boolean isAvailable() {
254 return navMeshModule.isInitialized();
255 }
256
257 @Override
258 public boolean isNavigating() {
259 return navigating;
260 }
261
262 @Override
263 public boolean isNavigatingToNavPoint() {
264 return isNavigating() && getCurrentTarget() instanceof NavPoint;
265 }
266
267 @Override
268 public boolean isNavigatingToItem() {
269 return isNavigating() && getCurrentTarget() instanceof Item;
270 }
271
272 @Override
273 public boolean isNavigatingToPlayer() {
274 return isNavigating() && getCurrentTarget() instanceof Player;
275 }
276
277 @Override
278 public boolean isTryingToGetBackToNav() {
279 return getBackToNavGraph.isExecuting();
280 }
281
282 @Override
283 public boolean isPathExecuting() {
284 return pathExecutor.isExecuting();
285 }
286
287 @Override
288 public boolean isRunningStraight() {
289 return runStraight.isExecuting();
290 }
291
292 @Override
293 public ILocated getFocus() {
294 return pathExecutor.getFocus();
295 }
296
297 @Override
298 public void setFocus(ILocated located) {
299 pathExecutor.setFocus(located);
300 getBackToNavGraph.setFocus(located);
301 runStraight.setFocus(located);
302 }
303
304 @Override
305 public void stopNavigation() {
306 reset(true, NavigationState.STOPPED);
307 bot.getAct().act(new Stop());
308 }
309
310 @Override
311 public void navigate(ILocated target) {
312 if (!isAvailable()) {
313 log.severe("Cannot navigate as NavMesh was not successfully loaded! Check log during bot initialization to obtain more details.");
314 return;
315 }
316
317 if (target == null) {
318 if (log != null && log.isLoggable(Level.WARNING)) {
319 log.warning("Cannot navigate to NULL target!");
320 }
321 reset(true, NavigationState.STOPPED);
322 return;
323 }
324
325 if (target instanceof Player) {
326
327 navigate((Player) target);
328 return;
329 }
330
331 if (navigating) {
332 if (currentTarget == target || currentTarget.getLocation().equals(target.getLocation())) {
333
334 return;
335 }
336
337
338 reset(false, null);
339 }
340
341 if (log != null && log.isLoggable(Level.FINE)) {
342 log.fine("Start navigating to: " + target);
343 }
344
345 navigating = true;
346 switchState(NavigationState.NAVIGATING);
347
348 currentTarget = target;
349
350 navigate();
351 }
352
353 @Override
354 public void navigate(Player player) {
355 if (!isAvailable()) {
356 log.severe("Cannot navigate as NavMesh was not successfully loaded! Check log during bot initialization to obtain more details.");
357 return;
358 }
359
360 if (player == null) {
361 if (log != null && log.isLoggable(Level.WARNING)) {
362 log.warning("Cannot navigate to NULL player!");
363 }
364 return;
365 }
366
367 if (navigating) {
368 if (currentTarget == player) {
369
370 return;
371 }
372
373
374 reset(false, null);
375 }
376
377 if (log != null && log.isLoggable(Level.FINE)) {
378 log.fine("Start pursuing: " + player);
379 }
380
381 navigating = true;
382 switchState(NavigationState.NAVIGATING);
383
384
385
386
387 currentTarget = player;
388 currentTargetPlayer = player;
389
390 navigate();
391 }
392
393 @Override
394 public void navigate(IPathFuture<ILocated> pathHandle) {
395 if (!isAvailable()) {
396 log.severe("Cannot navigate as NavMesh was not successfully loaded! Check log during bot initialization to obtain more details.");
397 return;
398 }
399
400 if (pathHandle == null) {
401 if (log != null && log.isLoggable(Level.WARNING)) {
402 log.warning("Cannot navigate to NULL pathHandle!");
403 }
404 return;
405 }
406
407 if (navigating) {
408 if (currentPathFuture == pathHandle) {
409
410 return;
411 }
412
413
414 reset(false, null);
415 }
416
417 if (log != null && log.isLoggable(Level.FINE)) {
418 log.fine("Start running along the path to target: " + pathHandle.getPathTo());
419 }
420
421 navigating = true;
422 switchState(NavigationState.NAVIGATING);
423
424 currentTarget = pathHandle.getPathTo();
425 currentPathFuture = pathHandle;
426
427 navigate();
428 }
429
430
431 @Override
432 public NavPoint getNearestNavPoint(ILocated location) {
433 if (location == null) {
434 return null;
435 }
436 if (location instanceof NavPoint) {
437 return (NavPoint) location;
438 }
439 if (location instanceof Item) {
440 if (((Item) location).getNavPoint() != null) {
441 return ((Item) location).getNavPoint();
442 }
443 }
444 return DistanceUtils.getNearest(bot.getWorldView().getAll(NavPoint.class).values(), location);
445 }
446
447 public ILocated getContinueTo() {
448 return continueTo;
449 }
450
451 public void setContinueTo(ILocated continueTo) {
452 if (!isNavigating()) {
453 log.warning("Cannot continueTo(" + continueTo + ") as navigation is not navigating!");
454 return;
455 }
456 if (isNavigatingToPlayer()) {
457 log.warning("Cannot continueTo(" + continueTo + ") as we're navigating to player!");
458 return;
459 }
460 this.continueTo = continueTo;
461
462 NavPoint from = getNearestNavPoint(currentTarget);
463 NavPoint to = getNearestNavPoint(continueTo);
464
465 this.continueToPath = pathPlanner.computePath(from, to);
466
467 checkExtendPath();
468 }
469
470 @Override
471 public List<ILocated> getCurrentPathCopy() {
472 List<ILocated> result = new ArrayList();
473 if (currentPathFuture != null) {
474 result.addAll(currentPathFuture.get());
475 }
476 return result;
477 }
478
479 @Override
480 public List<ILocated> getCurrentPathDirect() {
481 if (currentPathFuture != null) {
482 return currentPathFuture.get();
483 }
484 return null;
485 }
486
487 @Override
488 public ILocated getCurrentTarget() {
489 return currentTarget;
490 }
491
492 @Override
493 public Player getCurrentTargetPlayer() {
494 return currentTargetPlayer;
495 }
496
497 @Override
498 public Item getCurrentTargetItem() {
499 if (currentTarget instanceof Item) {
500 return (Item) currentTarget;
501 }
502 return null;
503 }
504
505 @Override
506 public NavPoint getCurrentTargetNavPoint() {
507 if (currentTarget instanceof NavPoint) {
508 return (NavPoint) currentTarget;
509 }
510 return null;
511 }
512
513 @Override
514 public ILocated getLastTarget() {
515 return lastTarget;
516 }
517
518 @Override
519 public Player getLastTargetPlayer() {
520 return lastTargetPlayer;
521 }
522
523 @Override
524 public Item getLastTargetItem() {
525 if (lastTarget instanceof Item) {
526 return (Item) lastTarget;
527 }
528 return null;
529 }
530
531 @Override
532 public double getRemainingDistance() {
533 if (!isNavigating()) {
534 return 0;
535 }
536 if (isNavigatingToPlayer()) {
537 if (isPathExecuting()) {
538 return pathExecutor.getRemainingDistance() + pathExecutor.getPathTo().getLocation().getDistance(currentTargetPlayer.getLocation());
539 } else {
540
541 NavPoint from = getNearestNavPoint(bot.getLocation());
542 NavPoint to = getNearestNavPoint(currentTargetPlayer.getLocation());
543 IPathFuture<ILocated> pathFuture = pathPlanner.computePath(from, to);
544 if (pathFuture.isDone()) {
545 return bot.getLocation().getDistance(from.getLocation()) + getPathDistance(pathFuture.get()) + to.getLocation().getDistance(currentTargetPlayer.getLocation());
546 } else {
547
548 return -1;
549 }
550 }
551 } else {
552 if (isPathExecuting()) {
553 return pathExecutor.getRemainingDistance();
554 } else {
555
556 NavPoint from = getNearestNavPoint(bot.getLocation());
557 NavPoint to = getNearestNavPoint(currentTarget.getLocation());
558 IPathFuture<ILocated> pathFuture = pathPlanner.computePath(from, to);
559 if (pathFuture.isDone()) {
560 return bot.getLocation().getDistance(from.getLocation()) + getPathDistance(pathFuture.get()) + to.getLocation().getDistance(currentTarget.getLocation());
561 } else {
562
563 return -1;
564 }
565 }
566 }
567 }
568
569
570
571
572
573
574
575
576 private double getPathDistance(List list) {
577 if (list == null || list.size() <= 0) {
578 return 0;
579 }
580 double distance = 0;
581 ILocated curr = (ILocated) list.get(0);
582 for (int i = 1; i < list.size(); ++i) {
583 ILocated next = (ILocated) list.get(i);
584 distance += curr.getLocation().getDistance(next.getLocation());
585 curr = next;
586 }
587 return distance;
588 }
589
590
591
592
593
594
595
596
597 protected ILocated lastTarget = null;
598
599
600
601 protected Player lastTargetPlayer = null;
602
603
604
605 protected ILocated currentTarget = null;
606
607
608
609 protected Player currentTargetPlayer = null;
610
611
612
613
614 protected NavPoint fromNavPoint;
615
616
617
618 protected NavPoint toNavPoint;
619
620
621
622 protected IPathFuture currentPathFuture;
623
624
625
626 protected boolean navigating = false;
627
628
629
630 protected boolean runningStraightToPlayer = false;
631
632
633
634 protected Location runningStraightToPlayerFailedAt = null;
635
636
637
638 protected boolean usingGetBackToNavGraph = false;
639
640
641
642 protected ILocated continueTo;
643
644
645
646 protected IPathFuture<ILocated> continueToPath;
647
648
649
650
651
652 protected void navigate() {
653 if (!navigating) {
654 return;
655 }
656
657 if (log != null && log.isLoggable(Level.FINE)) {
658 log.fine("NAVIGATING");
659 }
660 if (currentTargetPlayer != null) {
661 if (log != null && log.isLoggable(Level.FINE)) {
662 log.log(Level.FINE, "Pursuing {0}", currentTargetPlayer);
663 }
664 navigatePlayer();
665 } else {
666 if (log != null && log.isLoggable(Level.FINE)) {
667 log.log(Level.FINE, "Navigating to {0}", currentTarget);
668 }
669 navigateLocation();
670 }
671 }
672
673 private void navigateLocation() {
674 if (isPathExecuting()) {
675
676
677 checkExtendPath();
678 if (log != null && log.isLoggable(Level.FINE)) {
679 log.fine("Path executor running");
680 }
681 return;
682 }
683
684
685
686
687
688 if (!usingGetBackToNavGraph && navMeshModule.getNavMesh().getPolygonId(bot.getSelf().getLocation()) >= 0) {
689
690 } else {
691
692 if (!getBackToNavGraph.isOnNavGraph()) {
693
694
695 if (log != null && log.isLoggable(Level.FINE)) {
696 log.fine("Getting back to navigation graph");
697 }
698 if (getBackToNavGraph.isExecuting()) {
699
700 return;
701 }
702 if (usingGetBackToNavGraph) {
703
704
705 if (log != null && log.isLoggable(Level.WARNING)) {
706 log.warning("stuck() - GetBackToNavGraph was already called && stopped && we're still not on nav graph.");
707 }
708 stuck();
709 return;
710 }
711 getBackToNavGraph.backToNavGraph();
712
713 usingGetBackToNavGraph = true;
714 return;
715 } else {
716 usingGetBackToNavGraph = false;
717 }
718
719
720 }
721
722 if (currentPathFuture == null) {
723 fromNavPoint = getNearestNavPoint(bot.getLocation());
724 toNavPoint = getNearestNavPoint(currentTarget);
725
726 if (log != null && log.isLoggable(Level.FINE)) {
727 log.fine("Computing path from " + fromNavPoint.getId().getStringId() + " to " + toNavPoint.getId().getStringId());
728 }
729
730 currentPathFuture = pathPlanner.computePath(fromNavPoint, toNavPoint);
731 }
732
733 switch (currentPathFuture.getStatus()) {
734 case FUTURE_IS_READY:
735
736 break;
737 case FUTURE_IS_BEING_COMPUTED:
738 if (log != null && log.isLoggable(Level.FINE)) {
739 log.fine("Waiting for the path to be computed...");
740 }
741 return;
742 case CANCELED:
743 if (log != null && log.isLoggable(Level.WARNING)) {
744 log.warning("Path computation has been canceled.");
745 }
746 noPath();
747 return;
748 case COMPUTATION_EXCEPTION:
749 if (log != null && log.isLoggable(Level.WARNING)) {
750 log.warning("Path computation has failed with an exception.");
751 }
752 noPath();
753 return;
754 }
755
756
757
758 if (!processPathFuture(currentPathFuture, currentTarget)) {
759 noPath();
760 return;
761 }
762
763 pathExecutor.followPath(currentPathFuture);
764 }
765
766 private void checkExtendPath() {
767 if (continueTo == null) {
768 return;
769 }
770 if (continueToPath == null) {
771 log.severe("continueTo specified, but continueToPath is NULL!");
772 return;
773 }
774 if (isNavigatingToPlayer()) {
775 log.warning("continueTo specified, but navigating to Player, INVALID!");
776 return;
777 }
778 if (isPathExecuting()) {
779 double remainingDistance = getRemainingDistance();
780 if (remainingDistance < extendPathThreshold) {
781 if (!continueToPath.isDone()) {
782 log.warning("Should extend path, remainingDistance = " + remainingDistance + " < " + extendPathThreshold + " = extendPathThreshold, but continueToPath.isDone() == false, cannot extend path!");
783 return;
784 }
785 log.info("Extending path to continue to " + continueTo);
786
787 pathExecutor.extendPath(((List) continueToPath.get()));
788
789
790 currentPathFuture = pathExecutor.getPathFuture();
791 lastTarget = currentTarget;
792 currentTarget = continueTo;
793 fromNavPoint = getNearestNavPoint(((IPathFuture<ILocated>) currentPathFuture).get().get(0).getLocation());
794 toNavPoint = getNearestNavPoint(((IPathFuture<ILocated>) currentPathFuture).get().get(currentPathFuture.get().size() - 1).getLocation());
795
796 continueTo = null;
797 continueToPath = null;
798 }
799 }
800
801 }
802
803
804 private void navigatePlayer() {
805 double vDistance = bot.getLocation().getDistanceZ(currentTargetPlayer.getLocation());
806 double hDistance = bot.getLocation().getDistance2D(currentTargetPlayer.getLocation());
807
808 if (hDistance < AT_PLAYER && vDistance < 50) {
809
810 if (log != null && log.isLoggable(Level.FINE)) {
811 log.fine("Player reached");
812 }
813 if (pathExecutor.isExecuting()) {
814 pathExecutor.getPath().set(pathExecutor.getPath().size() - 1, bot.getLocation());
815 } else {
816 targetReached();
817 }
818 return;
819 }
820
821 if (hDistance < 400 && Math.abs(vDistance) < 50) {
822
823 if (runningStraightToPlayer) {
824 if (runStraight.isFailed()) {
825 runningStraightToPlayer = false;
826 runningStraightToPlayerFailedAt = bot.getLocation();
827 }
828 } else {
829 if (runningStraightToPlayerFailedAt == null ||
830 bot.getLocation().getDistance(runningStraightToPlayerFailedAt) > 500
831 ) {
832 if (getBackToNavGraph.isExecuting()) {
833 getBackToNavGraph.stop();
834 usingGetBackToNavGraph = false;
835 }
836 if (pathExecutor.isExecuting()) {
837 pathExecutor.stop();
838 }
839 runningStraightToPlayer = true;
840 runningStraightToPlayerFailedAt = null;
841 runStraight.runStraight(currentTargetPlayer);
842 }
843 }
844 if (runningStraightToPlayer) {
845 if (log != null && log.isLoggable(Level.FINE)) {
846 log.fine("Running straight to player");
847 }
848 return;
849 }
850 } else {
851 if (runningStraightToPlayer) {
852 runningStraightToPlayer = false;
853 runStraight.stop(false);
854 }
855 }
856
857 if (pathExecutor.isExecuting()) {
858
859 if (log != null && log.isLoggable(Level.FINE)) {
860 log.fine("Path executor running");
861 }
862
863 double distance = currentTarget.getLocation().getDistance(currentTargetPlayer.getLocation());
864
865 if (distance < PLAYER_DISTANCE_TRASHOLD) {
866
867
868 return;
869 }
870
871 if (log != null && log.isLoggable(Level.FINE)) {
872 log.fine("Player moved " + distance + " from its original location, checking path...");
873 }
874
875 NavPoint newToNavPoint = getNearestNavPoint(currentTargetPlayer);
876 if (newToNavPoint != toNavPoint) {
877
878 if (log != null && log.isLoggable(Level.FINE)) {
879 log.fine("Replanning path to get to " + currentTargetPlayer);
880 }
881 pathExecutor.stop();
882 currentPathFuture = null;
883 } else {
884 if (log != null && log.isLoggable(Level.FINE)) {
885 log.fine("Path remains the same");
886 }
887 return;
888 }
889 }
890
891
892
893
894
895
896 if (!getBackToNavGraph.isOnNavGraph()) {
897
898
899 if (log != null && log.isLoggable(Level.FINE)) {
900 log.fine("Getting back to navigation graph");
901 }
902 if (getBackToNavGraph.isExecuting()) {
903
904 return;
905 }
906 if (usingGetBackToNavGraph) {
907
908
909 if (log != null && log.isLoggable(Level.WARNING)) {
910 log.warning("stuck() - GetBackToNavGraph was already called && stopped && we're still not on nav graph.");
911 }
912 stuck();
913 return;
914 }
915 getBackToNavGraph.backToNavGraph();
916
917 usingGetBackToNavGraph = true;
918 return;
919 } else {
920 usingGetBackToNavGraph = false;
921 }
922
923
924
925 if (currentPathFuture == null) {
926 fromNavPoint = getNearestNavPoint(bot.getLocation());
927 toNavPoint = getNearestNavPoint(currentTarget);
928
929 if (log != null && log.isLoggable(Level.FINE)) {
930 log.fine("Computing path from " + fromNavPoint.getId().getStringId() + " to " + toNavPoint.getId().getStringId());
931 }
932
933 currentPathFuture = pathPlanner.computePath(fromNavPoint, toNavPoint);
934 }
935
936 switch (currentPathFuture.getStatus()) {
937 case FUTURE_IS_READY:
938
939 break;
940 case FUTURE_IS_BEING_COMPUTED:
941 if (log != null && log.isLoggable(Level.FINE)) {
942 log.fine("Waiting for the path to be computed...");
943 }
944 return;
945 case CANCELED:
946 if (log != null && log.isLoggable(Level.WARNING)) {
947 log.warning("Path computation has been canceled.");
948 }
949 noPath();
950 return;
951 case COMPUTATION_EXCEPTION:
952 if (log != null && log.isLoggable(Level.WARNING)) {
953 log.warning("Path computation has failed with an exception.");
954 }
955 noPath();
956 return;
957 }
958
959
960
961 if (!processPathFuture(currentPathFuture, currentTarget)) {
962 noPath();
963 return;
964 }
965
966 pathExecutor.followPath(currentPathFuture);
967 }
968
969
970
971
972
973
974
975 protected boolean processPathFuture(IPathFuture futurePath, ILocated currentTarget) {
976 List<ILocated> pathList = futurePath.get();
977
978 if (pathList == null) {
979
980 return false;
981 }
982
983 if (currentTarget == null) {
984
985
986
987 if (pathList.size() == 0) {
988 return false;
989 }
990 currentTarget = pathList.get(pathList.size() - 1);
991 } else if (pathList.size() == 0) {
992 currentPathFuture.get().add(currentTarget);
993 } else {
994 ILocated lastPathElement = pathList.get(pathList.size() - 1);
995 if (lastPathElement.getLocation().getDistance(currentTarget.getLocation()) > NEW_PATH_DISTANCE_THRESHOLD) {
996 currentPathFuture.get().add(currentTarget);
997 }
998 }
999 return true;
1000 }
1001
1002 protected void switchState(NavigationState newState) {
1003 state.setFlag(newState);
1004 }
1005
1006 protected void noPath() {
1007
1008 reset(true, NavigationState.PATH_COMPUTATION_FAILED);
1009 }
1010
1011
1012 protected void stuck() {
1013
1014 reset(true, NavigationState.STUCK);
1015 }
1016
1017 protected void targetReached() {
1018
1019 reset(true, NavigationState.TARGET_REACHED);
1020 }
1021
1022 protected void reset(boolean stopGetBackToNavGraph, NavigationState resultState) {
1023 if (currentTarget != null) {
1024 lastTarget = currentTarget;
1025 lastTargetPlayer = currentTargetPlayer;
1026 }
1027
1028 navigating = false;
1029
1030 currentTarget = null;
1031 currentTargetPlayer = null;
1032
1033 fromNavPoint = null;
1034 toNavPoint = null;
1035
1036 currentPathFuture = null;
1037
1038 runningStraightToPlayer = false;
1039 runningStraightToPlayerFailedAt = null;
1040
1041 continueTo = null;
1042 continueToPath = null;
1043
1044 pathExecutor.stop();
1045 runStraight.stop(false);
1046 if (stopGetBackToNavGraph) {
1047 getBackToNavGraph.stop();
1048 usingGetBackToNavGraph = false;
1049 }
1050
1051
1052 if (resultState == null) {
1053 return;
1054 }
1055 switchState(resultState);
1056 }
1057
1058 @Override
1059 public Flag<NavigationState> getState() {
1060 return state.getImmutable();
1061 }
1062 }