1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package cz.cuni.amis.pogamut.ut2004.agent.navigation.navmesh.pathfollowing;
18
19 import cz.cuni.amis.pogamut.base.communication.worldview.IWorldView;
20 import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEventListener;
21 import cz.cuni.amis.pogamut.base.communication.worldview.object.event.WorldObjectUpdatedEvent;
22 import cz.cuni.amis.pogamut.base.utils.math.DistanceUtils;
23 import cz.cuni.amis.pogamut.base3d.worldview.object.ILocated;
24 import cz.cuni.amis.pogamut.base3d.worldview.object.Location;
25 import cz.cuni.amis.pogamut.ut2004.agent.module.sensor.AgentInfo;
26 import cz.cuni.amis.pogamut.ut2004.agent.module.sensor.NavPoints;
27 import cz.cuni.amis.pogamut.ut2004.agent.navigation.AbstractUT2004PathNavigator;
28 import cz.cuni.amis.pogamut.ut2004.agent.navigation.IUT2004PathRunner;
29 import cz.cuni.amis.pogamut.ut2004.agent.navigation.NavigationState;
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.gbinfomessages.Mover;
33 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.NavPoint;
34 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.NavPointNeighbourLink;
35 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Self;
36 import cz.cuni.amis.pogamut.ut2004.utils.UnrealUtils;
37 import cz.cuni.amis.utils.NullCheck;
38 import cz.cuni.amis.utils.SafeEquals;
39 import cz.cuni.amis.utils.exception.PogamutException;
40
41 import java.util.Iterator;
42 import java.util.List;
43 import java.util.logging.Level;
44 import java.util.logging.Logger;
45
46
47
48
49
50
51
52
53
54 public class NavMeshNavigator<PATH_ELEMENT extends ILocated> extends AbstractUT2004PathNavigator<PATH_ELEMENT> {
55
56
57
58
59 private Location navigDestination = null;
60
61
62
63
64 private Stage navigStage = Stage.COMPLETED;
65
66
67
68
69
70
71
72
73 private ILocated focus = null;
74
75
76
77
78 private class SelfListener implements IWorldObjectEventListener<Self, WorldObjectUpdatedEvent<Self>> {
79
80 private IWorldView worldView;
81
82
83
84
85
86
87 public SelfListener(IWorldView worldView) {
88 this.worldView = worldView;
89 worldView.addObjectListener(Self.class, WorldObjectUpdatedEvent.class, this);
90 }
91
92 @Override
93 public void notify(WorldObjectUpdatedEvent<Self> event) {
94 self = event.getObject();
95 }
96 }
97
98
99
100
101 private SelfListener selfListener;
102
103
104
105
106
107
108
109
110
111 public static final int CLOSE_ENOUGH = 40;
112
113
114 @Override
115 protected void navigate(ILocated focus, int pathElementIndex) {
116 if (log != null && log.isLoggable(Level.FINE)) {
117 log.log(Level.FINE, "Navigator.navigate(): Current stage {0}", navigStage);
118 }
119 this.focus = focus;
120 switch (navigStage = keepNavigating()) {
121 case AWAITING_MOVER:
122 case RIDING_MOVER:
123 setBotWaiting(true);
124 break;
125 case TELEPORT:
126 case NAVIGATING:
127 case REACHING:
128 setBotWaiting(false);
129 break;
130
131 case TIMEOUT:
132 case CRASHED:
133 case CANCELED:
134 if (log != null && log.isLoggable(Level.WARNING)) {
135 log.log(Level.WARNING, "Navigation {0}", navigStage);
136 }
137 executor.stuck();
138 return;
139
140 case COMPLETED:
141 executor.targetReached();
142 break;
143 }
144 if (log != null && log.isLoggable(Level.FINEST)) {
145 log.log(Level.FINEST, "Navigator.navigate(): Next stage {0}", navigStage);
146 }
147 }
148
149 @Override
150 public void reset() {
151
152
153 navigCurrentLocation = null;
154 navigCurrentNode = null;
155 navigCurrentLink = null;
156 navigDestination = null;
157 navigIterator = null;
158 navigLastLocation = null;
159 navigLastNode = null;
160 navigNextLocation = null;
161 navigNextNode = null;
162 navigNextLocationOffset = 0;
163 navigStage = Stage.COMPLETED;
164 setBotWaiting(false);
165
166 resetNavigMoverVariables();
167 }
168
169 @Override
170 public void newPath(List<PATH_ELEMENT> path, ILocated focus) {
171
172 reset();
173
174
175 Location dest = path.get(path.size() - 1).getLocation();
176
177
178 initPathNavigation(dest, path, focus);
179
180
181 navigate(focus);
182 }
183
184 @Override
185 public void pathExtended(List<PATH_ELEMENT> path, int currentPathIndex) {
186 if (path == null || path.isEmpty()) {
187 throw new RuntimeException("path is null or 0-sized!");
188 }
189 navigDestination = path.get(path.size() - 1).getLocation();
190 navigIterator = path.iterator();
191
192 int newOffset = -currentPathIndex;
193 for (int i = 0; i < path.size() && i < currentPathIndex + navigNextLocationOffset && navigIterator.hasNext(); ++i) {
194 ++newOffset;
195 navigIterator.next();
196 }
197 log.fine("PATH EXTEND ... curr index " + currentPathIndex + ", old offset " + navigNextLocationOffset + ", new offset " + newOffset + ", path size " + path.size());
198 navigNextLocationOffset = newOffset;
199 }
200
201 @Override
202 public NavPointNeighbourLink getCurrentLink() {
203 return navigCurrentLink;
204 }
205
206
207
208
209
210
211
212 protected void initDirectNavigation(Location dest) {
213
214 int distance = (int) memory.getLocation().getDistance(dest);
215
216 if (log != null && log.isLoggable(Level.FINE)) {
217 log.log(
218 Level.FINE,"Navigator.initDirectNavigation(): initializing direct navigation, distance {0}"
219 , distance);
220 }
221
222 initDirectly(dest);
223 }
224
225
226
227
228
229
230
231
232 protected void initPathNavigation(Location dest, List<PATH_ELEMENT> path, ILocated focus) {
233
234 if (log != null && log.isLoggable(Level.FINE)) {
235 log.log(
236 Level.FINE,"Navigator.initPathNavigation(): initializing path navigation, nodes {0}"
237 , path.size());
238 }
239
240 if (!initAlongPath(dest, path)) {
241
242 initDirectNavigation(dest);
243 }
244 }
245
246
247
248
249
250
251
252 protected Stage keepNavigating() {
253
254 if (navigStage.terminated) {
255 return navigStage;
256 }
257
258 if (log != null && log.isLoggable(Level.FINE)) {
259 if (navigLastNode != null) {
260 log.fine("Navigator.keepNavigating(): From " + NavPoints.describe(navigLastNode));
261 } else if (navigLastLocation != null) {
262 log.fine("Navigator.keepNavigating(): From " + navigLastLocation);
263 }
264 if (navigCurrentNode != null) {
265 log.fine("Navigator.keepNavigating(): To " + NavPoints.describe(navigCurrentNode));
266 } else if (navigCurrentLocation != null) {
267 log.fine("Navigator.keepNavigating(): To " + navigCurrentLocation);
268 }
269 }
270
271
272 switch (navigStage) {
273 case REACHING:
274 navigStage = navigDirectly();
275 break;
276 default:
277 navigStage = navigAlongPath();
278 break;
279 }
280
281
282 if (log != null && log.isLoggable(Level.FINEST)) {
283 log.finest("Navigator.keepNavigating(): In stage " + navigStage);
284 }
285 return navigStage;
286 }
287
288
289
290
291
292
293
294
295
296
297
298
299
300 private Stage initDirectly(Location dest) {
301
302 navigDestination = dest;
303
304 runner.reset();
305
306 return navigStage = Stage.REACHING;
307 }
308
309
310
311
312
313
314 private Stage navigDirectly() {
315
316 int distance = (int) memory.getLocation().getDistance(navigDestination);
317
318
319 if (distance <= CLOSE_ENOUGH) {
320 if (log != null && log.isLoggable(Level.FINE)) {
321 log.fine("Navigator.navigDirectly(): destination close enough: " + distance);
322 }
323 return Stage.COMPLETED;
324 }
325
326
327 if (!runner.runToLocation(navigLastLocation, navigDestination, null, (focus == null ? navigDestination : focus), null, true, false)) {
328 if (log != null && log.isLoggable(Level.FINE)) {
329 log.fine("Navigator.navigDirectly(): direct navigation failed");
330 }
331 return Stage.CRASHED;
332 }
333
334
335 if (log != null && log.isLoggable(Level.FINEST)) {
336 log.finer("Navigator.navigDirectly(): traveling directly, distance = " + distance);
337 }
338 return navigStage;
339 }
340
341
342
343
344
345
346
347
348
349
350 private Iterator<PATH_ELEMENT> navigIterator = null;
351
352
353
354
355
356 private int navigNextLocationOffset = 0;
357
358
359
360
361 private Location navigLastLocation = null;
362
363
364
365
366
367 private NavPoint navigLastNode = null;
368
369
370
371
372 private Location navigCurrentLocation = null;
373
374
375
376
377
378 private NavPoint navigCurrentNode = null;
379
380
381
382
383
384
385 private NavPointNeighbourLink navigCurrentLink = null;
386
387
388
389
390 private Location navigNextLocation = null;
391
392
393
394
395
396 private NavPoint navigNextNode = null;
397
398
399
400
401
402
403
404
405 private boolean initAlongPath(Location dest, List<PATH_ELEMENT> path) {
406
407 navigDestination = dest;
408 navigIterator = path.iterator();
409
410 navigCurrentLocation = bot.getLocation();
411 navigCurrentNode = DistanceUtils.getNearest(bot.getWorldView().getAll(NavPoint.class).values(), bot.getLocation(), 40);
412
413 prepareNextNode();
414
415 navigStage = Stage.NAVIGATING;
416
417 return switchToNextNode();
418 }
419
420
421
422
423
424
425 private Stage navigAlongPath() {
426
427 int totalDistance = (int) memory.getLocation().getDistance(navigDestination);
428
429
430 if (totalDistance <= CLOSE_ENOUGH) {
431 log.log(Level.FINEST, "Navigator.navigAlongPath(): destination close enough: {0}", totalDistance);
432 return Stage.COMPLETED;
433 }
434
435
436 if (navigStage.mover) {
437 log.fine("Navigator.navigAlongPath(): MOVER");
438 return navigMover();
439 } else if (navigStage.teleport) {
440 log.fine("Navigator.navigAlongPath(): TELEPORT");
441 return navigThroughTeleport();
442 } else {
443 log.fine("Navigator.navigAlongPath(): STANDARD");
444 return navigToCurrentNode(true, false);
445 }
446 }
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461 private void prepareNextNode() {
462 if (navigCurrentNode != null && navigCurrentNode.isTeleporter()) {
463
464 prepareNextNodeTeleporter();
465 return;
466 }
467
468
469
470 ILocated located = null;
471 navigNextLocation = null;
472 navigNextNode = null;
473 navigNextLocationOffset = 0;
474 while ((located == null) && navigIterator.hasNext()) {
475
476 located = navigIterator.next();
477 navigNextLocationOffset += 1;
478 }
479
480
481 if (located == null) {
482 navigNextLocationOffset = 0;
483 return;
484 }
485
486 if (executor.getPathElementIndex() + navigNextLocationOffset >= executor.getPath().size()) {
487 navigNextLocationOffset = 0;
488 }
489
490
491 navigNextLocation = located.getLocation();
492
493 navigNextNode = getNavPoint(located);
494 }
495
496
497
498
499
500 private void prepareNextNodeTeleporter() {
501
502
503 ILocated located = null;
504 navigNextLocation = null;
505 navigNextLocationOffset = 0;
506 boolean nextTeleporterFound = false;
507 while ((located == null) && navigIterator.hasNext()) {
508
509 located = navigIterator.next();
510 navigNextLocationOffset += 1;
511 if (located == null) {
512 continue;
513 }
514 navigNextNode = getNavPoint(located);
515 if (navigNextNode != null && navigNextNode.isTeleporter()) {
516
517 if (!nextTeleporterFound) {
518
519 located = null;
520 }
521 nextTeleporterFound = true;
522 } else {
523 break;
524 }
525 }
526
527
528 if (located == null) {
529 navigNextLocationOffset = 0;
530 return;
531 }
532
533 if (executor.getPathElementIndex() + navigNextLocationOffset >= executor.getPath().size()) {
534 navigNextLocationOffset = 0;
535 }
536
537
538 navigNextLocation = located.getLocation();
539
540 navigNextNode = getNavPoint(located);
541 }
542
543
544
545
546
547
548 private boolean switchToNextNode() {
549 if (log != null && log.isLoggable(Level.FINER)) {
550 log.finer("Navigator.switchToNextNode(): switching!");
551 }
552
553
554 navigLastLocation = navigCurrentLocation;
555 navigLastNode = navigCurrentNode;
556
557
558 if (null == (navigCurrentLocation = navigNextLocation)) {
559
560 if (log != null && log.isLoggable(Level.FINER)) {
561 log.finer("Navigator.switchToNextNode(): no nodes left");
562 }
563 navigCurrentNode = null;
564 return false;
565 }
566
567 navigCurrentNode = navigNextNode;
568
569
570 navigCurrentLink = getNavPointsLink(navigLastNode, navigCurrentNode);
571
572 if (navigCurrentLink == null) {
573 getNavPointsLink(navigLastNode, navigCurrentNode);
574 if (log.isLoggable(Level.INFO)) {
575 log.info("No link information...");
576 }
577 }
578
579
580 if (navigLastLocation == null) {
581 navigLastLocation = bot.getLocation();
582 navigLastNode = navigCurrentNode;
583 }
584
585
586 int localDistance = (int) memory.getLocation().getDistance(navigCurrentLocation.getLocation());
587
588
589 if (navigCurrentNode != null && navigCurrentNode.isTeleporter()) {
590 navigStage = Stage.TeleporterStage();
591 }
592 else if (navigCurrentNode != null && navigCurrentNode.isLiftCenter()) {
593
594 navigStage = Stage.FirstMoverStage();
595 resetNavigMoverVariables();
596 }
597 else if (navigStage.mover) {
598 navigStage = navigStage.next();
599
600 runner.reset();
601 } else if (navigStage.teleport) {
602 navigStage = navigStage.next();
603
604 runner.reset();
605 }
606 else {
607
608 runner.reset();
609 }
610
611
612 if (log != null && log.isLoggable(Level.FINE)) {
613 if (navigCurrentNode != null) {
614 log.fine(
615 "Navigator.switchToNextNode(): switch to next node " + navigCurrentNode.getId().getStringId()
616 + ", distance " + localDistance
617 + ", reachable true"
618 + ", mover " + navigStage.mover
619 );
620
621 } else {
622 log.log(Level.FINE, "Navigator.switchToNextNode(): switch to next location {0}, distance {1}, mover {2}", new Object[]{navigCurrentLocation, localDistance, navigStage.mover});
623 }
624 }
625
626
627 if (executor.getPathElementIndex() < 0) {
628 executor.switchToAnotherPathElement(0);
629 } else {
630 if (navigNextLocationOffset > 0) {
631 executor.switchToAnotherPathElement(executor.getPathElementIndex() + navigNextLocationOffset);
632 } else {
633 executor.switchToAnotherPathElement(executor.getPathElementIndex());
634 }
635 }
636 navigNextLocationOffset = 0;
637
638 prepareNextNode();
639
640 if (localDistance < 20) {
641 log.log(Level.FINER, "Navigator.switchToNextNode(): next location too near, switching again!");
642 return switchToNextNode();
643 }
644
645 return true;
646 }
647
648
649
650
651
652
653
654 private int navigMoverRideUpCount;
655
656 private int navigMoverRideDownCount;
657
658 private Boolean navigMoverIsRidingUp;
659
660 private Boolean navigMoverIsRidingDown;
661
662 private Boolean navigMoverGettingBackRunnerReset;
663
664 private Boolean navigMoverGettingToLiftCenterRunnerReset;
665
666 private void resetNavigMoverVariables() {
667 navigMoverIsRidingUp = null;
668 navigMoverIsRidingDown = null;
669 navigMoverRideUpCount = 0;
670 navigMoverRideDownCount = 0;
671 navigMoverGettingBackRunnerReset = false;
672 navigMoverGettingToLiftCenterRunnerReset = false;
673 }
674
675 private void checkMoverMovement(Mover mover) {
676
677 if (mover.getVelocity().z > 0) {
678
679 if (navigMoverIsRidingUp == null) {
680 navigMoverIsRidingUp = true;
681 navigMoverIsRidingDown = false;
682 navigMoverRideUpCount = 1;
683 navigMoverRideDownCount = 0;
684 log.fine("Navigator.checkMoverMovement(): MOVER RIDING UP (1)");
685 } else if (navigMoverIsRidingDown) {
686 navigMoverIsRidingUp = true;
687 navigMoverIsRidingDown = false;
688 ++navigMoverRideUpCount;
689 log.fine("Navigator.checkMoverMovement(): MOVER RIDING UP (" + navigMoverRideUpCount + ")");
690 }
691 } else if (mover.getVelocity().z < 0) {
692
693 if (navigMoverIsRidingDown == null) {
694 navigMoverIsRidingUp = false;
695 navigMoverIsRidingDown = true;
696 navigMoverRideUpCount = 0;
697 navigMoverRideDownCount = 1;
698 log.fine("Navigator.checkMoverMovement(): MOVER RIDING DOWN (1)");
699 } else if (navigMoverIsRidingUp) {
700 navigMoverIsRidingUp = false;
701 navigMoverIsRidingDown = true;
702 ++navigMoverRideDownCount;
703 log.fine("Navigator.checkMoverMovement(): MOVER RIDING DOWN (" + navigMoverRideDownCount + ")");
704 }
705 }
706 }
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725 private Stage navigMover() {
726 Stage stage = navigStage;
727
728 if (navigCurrentNode == null) {
729 if (log != null && log.isLoggable(Level.WARNING)) {
730 log.warning("Navigator.navigMover(" + stage + "): can't navigate through the mover without the navpoint instance (navigCurrentNode == null)");
731 }
732 return Stage.CRASHED;
733 }
734
735 Mover mover = (Mover) bot.getWorldView().get(navigCurrentNode.getMover());
736 if (mover == null) {
737 if (log != null && log.isLoggable(Level.WARNING)) {
738 log.warning("Navigator.navigMover(" + stage + "): can't navigate through the mover as current node does not represent a mover (moverId == null): " + navigCurrentNode);
739 }
740 return Stage.CRASHED;
741 }
742 checkMoverMovement(mover);
743
744
745 navigCurrentLocation = navigCurrentNode.getLocation();
746
747 if (navigNextNode != null) {
748
749 navigNextLocation = navigNextNode.getLocation();
750 }
751
752 log.fine("Navigator.navigMover(" + stage + "): SELF " + memory.getLocation());
753 log.fine("Navigator.navigMover(" + stage + "): CURR " + NavPoints.describe(navigCurrentNode));
754 log.fine("Navigator.navigMover(" + stage + "): NEXT " + NavPoints.describe(navigNextNode));
755 log.fine("Navigator.navigMover(" + stage + "): " + NavPoints.describe(mover));
756
757
758 int hDistance = (int) memory.getLocation().getDistance2D(navigCurrentLocation.getLocation());
759
760 int zDistance = (int) navigCurrentLocation.getLocation().getDistanceZ(memory.getLocation());
761
762 boolean moverRidingUp = mover.getVelocity().z > 0;
763
764 boolean moverRidingDown = mover.getVelocity().z < 0;
765
766 boolean moverStandingStill = Math.abs(mover.getVelocity().z) < Location.DISTANCE_ZERO;
767
768 int moverHDistance = (int) memory.getLocation().getDistance2D(mover.getLocation());
769 int moverZDistance = (int) mover.getLocation().getDistanceZ(memory.getLocation());
770
771 log.finer("Navigator.navigMover(" + stage + "): CURR hDist:" + hDistance + ", zDist:" + zDistance);
772 log.finer("Navigator.navigMover(" + stage + "): MOVER hDist:" + moverHDistance + ", zDist:" + moverZDistance + ", " + (moverRidingUp ? "riding UP" : (moverRidingDown ? "riding DOWN" : moverStandingStill ? "standing STILL" : " movement unknown")));
773
774
775
776
777
778
779
780 if (navigStage == Stage.AWAITING_MOVER) {
781
782 boolean waitForTheMover = false;
783
784 if (moverHDistance < 50 && moverZDistance > 100 && moverRidingUp) {
785 log.fine("Navigator.navigMover(" + stage + "): we are UNDER the mover and it is RIDING UP ... assuming waiting position");
786 waitForTheMover = true;
787 } else
788 if (moverZDistance > 10) {
789 log.fine("Navigator.navigMover(" + stage + "): mover is not in correct position ... assuming waiting position");
790 waitForTheMover = true;
791 } else
792 if (zDistance > 20 && moverRidingUp) {
793 log.fine("Navigator.navigMover(" + stage + "): mover is riding up, we won't make it to the center ... assuming waiting position");
794 waitForTheMover = true;
795 }
796
797 if (waitForTheMover) {
798
799 if (memory.atLocation(navigLastLocation, 50)) {
800
801 if (navigMoverGettingBackRunnerReset) {
802 navigMoverGettingBackRunnerReset = false;
803 runner.reset();
804 }
805 body.turnTo(navigCurrentLocation);
806 return navigStage;
807 }
808 if (!navigMoverGettingBackRunnerReset) {
809 runner.reset();
810 navigMoverGettingBackRunnerReset = true;
811 }
812 if (run(null, navigLastLocation, null, null, navigCurrentLocation, true) == NavigateResult.CRASHED) {
813 if (log != null && log.isLoggable(Level.FINE)) {
814 log.fine("Navigator.navigMover(" + stage + "): navigation to wait-for-mover node failed");
815 }
816 return Stage.CRASHED;
817 }
818 return navigStage;
819 }
820 if (navigMoverGettingBackRunnerReset) {
821 navigMoverGettingBackRunnerReset = false;
822 runner.reset();
823 }
824
825
826 if (log != null && log.isLoggable(Level.FINER)) {
827 log.finer("Navigator.navigMover(" + stage + "): mover arrived");
828 }
829
830
831 return navigToCurrentNode(false, true);
832 }
833 if (navigMoverGettingBackRunnerReset) {
834 navigMoverGettingBackRunnerReset = false;
835 runner.reset();
836 }
837
838
839
840
841
842
843
844 if (navigStage == Stage.RIDING_MOVER) {
845 if (navigMoverRideDownCount > 2 || navigMoverRideUpCount > 2) {
846
847 if (log != null && log.isLoggable(Level.FINE)) {
848 log.fine("Navigator.navigThroughMover(" + stage + "): navigation to mover exit node failed, we've rided twice up & down and there was no place suitable to exit the mover in order to get to get to " + navigCurrentNode);
849 }
850 return Stage.CRASHED;
851 }
852
853 if (hDistance > 600) {
854 if (log != null && log.isLoggable(Level.WARNING)) {
855 log.warning("Navigator.navigThroughMover(" + stage + "): navigation to mover exit node failed, the node is too far, hDistance " + hDistance + " > 600, unsupported (weird navigation graph link)");
856 }
857 return Stage.CRASHED;
858 }
859
860
861 if (Math.abs(zDistance) > 50) {
862
863 log.finer("Navigator.navigMover(" + stage + "): riding the mover");
864
865
866 if (moverHDistance < 35) {
867 log.finer("Navigator.navigMover(" + stage + "): at lift-center, looking towards exit");
868 if (navigMoverGettingToLiftCenterRunnerReset) {
869 navigMoverGettingToLiftCenterRunnerReset = false;
870 runner.reset();
871 }
872 body.turnTo(navigCurrentLocation);
873 } else {
874 log.finer("Navigator.navigMover(" + stage + "): reaching lift-center, looking towards exit");
875 if (!navigMoverGettingToLiftCenterRunnerReset) {
876 navigMoverGettingToLiftCenterRunnerReset = true;
877 runner.reset();
878 }
879
880 if (run(null, mover.getLocation(), null, null, navigCurrentLocation, true) == NavigateResult.CRASHED) {
881 log.fine("Navigator.navigMover(" + stage + "): navigation to last node failed");
882 return Stage.CRASHED;
883 }
884 }
885
886
887 return navigStage;
888 }
889 if (navigMoverGettingToLiftCenterRunnerReset) {
890 navigMoverGettingToLiftCenterRunnerReset = false;
891 runner.reset();
892 }
893
894
895 if (log != null && log.isLoggable(Level.FINER)) {
896 log.finer("Navigator.navigMover(" + stage + "): exiting the mover");
897 }
898
899
900 return navigToCurrentNode(false, false);
901 } else {
902 if (log != null && log.isLoggable(Level.WARNING)) {
903 log.warning("Navigator.navigThroughMover(" + stage + "): invalid stage, neither AWAITING_MOVER nor RIDING MOVER");
904 }
905 return Stage.CRASHED;
906 }
907
908 }
909
910
911
912
913
914
915
916
917
918
919
920
921 private Stage navigThroughTeleport() {
922 if (navigCurrentNode != null) {
923
924 navigCurrentLocation = navigCurrentNode.getLocation();
925 }
926
927 if (navigNextNode != null) {
928
929 navigNextLocation = navigNextNode.getLocation();
930 }
931
932
933 int localDistance2_1 = Integer.MAX_VALUE;
934 int localDistance2_2 = Integer.MAX_VALUE;
935 for (NavPointNeighbourLink link : navigCurrentNode.getOutgoingEdges().values()) {
936 if (link.getToNavPoint().isTeleporter()) {
937 localDistance2_1 = (int) memory.getLocation().getDistance(link.getToNavPoint().getLocation());
938 localDistance2_2 = (int) memory.getLocation().getDistance(Location.add(link.getToNavPoint().getLocation(), new Location(0, 0, 100)));
939
940
941 if ((localDistance2_1 < 200) || (localDistance2_2 < 200)) {
942
943 if (log != null && log.isLoggable(Level.FINE)) {
944 log.fine("Navigator.navigThroughTeleport(): at the other end of teleport, switching...");
945 }
946
947 if (!switchToNextNode()) {
948
949 if (log != null && log.isLoggable(Level.FINE)) {
950 log.fine("Navigator.navigThroughTeleport(): switch to direct navigation");
951 }
952 initDirectly(navigDestination);
953 }
954 return keepNavigating();
955 }
956 }
957 }
958
959
960 return navigToCurrentNode(true, false);
961 }
962
963
964
965
966
967
968
969
970
971
972 private Stage navigToCurrentNode(boolean useFocus, boolean forceNoJump) {
973 NavigateResult result = run(navigLastLocation, navigCurrentLocation, navigCurrentLink, navigNextLocation, useFocus ? focus : navigCurrentLocation, forceNoJump);
974 switch (result) {
975 case RUNNING:
976 return navigStage;
977 case CRASHED:
978 return Stage.CRASHED;
979 case REACHED:
980 if (!switchToNextNode()) {
981 initDirectly(navigDestination);
982 }
983 return keepNavigating();
984 }
985 throw new PogamutException("Unhandled NavigateResult." + result, this);
986 }
987
988 private enum NavigateResult {
989 REACHED,
990 RUNNING,
991 CRASHED
992 }
993
994
995
996
997 private NavigateResult run(ILocated ilocPrevious, ILocated ilocFirst, NavPointNeighbourLink linkFirst, ILocated ilocSecond, ILocated ilocFocus, boolean forceNoJump) {
998
999 NavPoint npFirst = getNavPoint(ilocFirst);
1000 NavPoint npSecond = getNavPoint(ilocSecond);
1001
1002
1003 Location locPrevious = ilocPrevious == null ? null : ilocPrevious.getLocation();
1004 Location locCurrent = memory.getLocation();
1005 Location locFirst = ilocFirst.getLocation();
1006 Location locSecond = ilocSecond == null ? null : ilocSecond.getLocation();
1007
1008
1009 if (npFirst != null) {
1010 if (npFirst.isLiftCenter() || npFirst.isTeleporter()) {
1011
1012 locSecond = null;
1013 if (npFirst.isLiftCenter()) {
1014 log.fine("Navigator.run(): Reaching LIFT-CENTER");
1015 }
1016 if (npFirst.isTeleporter()) {
1017 log.fine("Navigator.run(): Reaching TELEPORTER");
1018 }
1019 }
1020 }
1021 if (npSecond != null) {
1022 if (npSecond.isLiftCenter()) {
1023
1024 locSecond = null;
1025 log.fine("Navigator.run(): Will NOT continue to LIFT-CENTER");
1026 }
1027 if (npFirst != null && npFirst.isLiftExit() && npSecond.isLiftExit()) {
1028
1029 locSecond = null;
1030 log.fine("Navigator.run(): Will NOT continue to LIFT-EXIT");
1031 }
1032 }
1033
1034
1035 int distToFirst = (int) locCurrent.getDistance(locFirst);
1036 int dist2DToFirst = (int) locCurrent.getDistance2D(locFirst);
1037 int distZToFirst = (int) Math.abs(locCurrent.getDistanceZ(locFirst));
1038
1039
1040 double distTest = 50;
1041 double distTestZ = 115;
1042
1043 if (npFirst != null) {
1044
1045 if (npFirst.isJumpPad()) {
1046
1047 distTest = 70;
1048
1049 distZToFirst = 0;
1050 log.fine("Navigator.run(): Reaching JUMP-PAD");
1051 } else
1052
1053 if (npFirst.isLiftCenter()) {
1054
1055 distTest = 30;
1056 }
1057 }
1058
1059
1060 if (distToFirst < distTest) {
1061 log.fine("Navigator.run(): REACHED " + locFirst + ", dist == " + distToFirst + " < " + distTest + " == test-precision");
1062
1063 return NavigateResult.REACHED;
1064
1065 }
1066 if (distZToFirst < distTestZ && dist2DToFirst < distTest) {
1067 log.fine("Navigator.run(): REACHED " + locFirst + ", distZ == " + distZToFirst + " < " + distTestZ + " == test-z-precision, dist2D == " + dist2DToFirst + " < " + distTest + " == test-precision");
1068
1069 return NavigateResult.REACHED;
1070 }
1071
1072
1073 if (locPrevious != null && locSecond != null) {
1074 Location navigDirection = locFirst.sub(locPrevious).getNormalized();
1075 Location altDirection = locSecond.sub(locCurrent).getNormalized();
1076 double angle = Math.acos(navigDirection.dot(altDirection));
1077
1078 double correction = 50;
1079 double zMin = Math.min(locFirst.z, locSecond.z) - correction;
1080 double zMax = Math.max(locFirst.z, locSecond.z) + correction;
1081 boolean isZok = zMin < locCurrent.z && locCurrent.z < zMax;
1082
1083 double distToSecond = locCurrent.getDistance2D(locSecond);
1084
1085 if (angle < Math.PI / 3 && isZok) {
1086 if (distToSecond < distTest) {
1087 log.log(Level.FINE, "Navigator.run(): REACHED next " + locSecond + " reached, dist == " + distToSecond + " < " + distTest + " == test-precision");
1088 return NavigateResult.REACHED;
1089 }
1090 }
1091 }
1092
1093
1094 if (!runner.runToLocation(memory.getLocation(), locFirst, locSecond, ilocFocus, linkFirst, true, forceNoJump)) {
1095
1096 log.log(Level.INFO, "Navigator.run(): Runner CRASHED!");
1097 return NavigateResult.CRASHED;
1098 }
1099
1100 return NavigateResult.RUNNING;
1101 }
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117 protected NavPoint getNavPoint(ILocated location) {
1118 if (location == null) return null;
1119 if (location instanceof NavPoint) {
1120 return (NavPoint) location;
1121 }
1122 NavPoint np = DistanceUtils.getNearest(main.getWorldView().getAll(NavPoint.class).values(), location);
1123 if (np.getLocation().getDistance(location.getLocation()) < CLOSE_ENOUGH) {
1124 return np;
1125 }
1126 return null;
1127 }
1128
1129
1130
1131
1132
1133
1134
1135
1136 private NavPointNeighbourLink getNavPointsLink(NavPoint start, NavPoint end) {
1137 if (start == null) {
1138
1139 NavPoint tmp = getNavPoint(memory.getLocation());
1140 if (tmp != null) {
1141 start = tmp;
1142 } else {
1143 return null;
1144 }
1145 }
1146 if (end == null) {
1147 return null;
1148 }
1149
1150 if (end.getIncomingEdges().containsKey(start.getId())) {
1151 return end.getIncomingEdges().get(start.getId());
1152 }
1153
1154 return null;
1155 }
1156
1157
1158
1159
1160
1161
1162 private enum TerminatingStageType {
1163
1164
1165
1166
1167 SUCCESS(false),
1168
1169
1170
1171 FAILURE(true);
1172
1173
1174
1175
1176 public boolean failure;
1177
1178
1179
1180
1181
1182
1183 private TerminatingStageType(boolean failure) {
1184 this.failure = failure;
1185 }
1186 };
1187
1188
1189
1190
1191 private enum MoverStageType {
1192
1193
1194
1195
1196 WAITING,
1197
1198
1199
1200 RIDING;
1201 };
1202
1203
1204
1205
1206 private enum TeleportStageType {
1207
1208
1209
1210
1211 GOING_THROUGH;
1212 };
1213
1214
1215
1216
1217 public enum Stage {
1218
1219
1220
1221
1222 REACHING() {
1223 protected Stage next() {
1224 return this;
1225 }
1226 },
1227
1228
1229
1230 NAVIGATING() {
1231 protected Stage next() {
1232 return this;
1233 }
1234 },
1235
1236
1237
1238 AWAITING_MOVER(MoverStageType.WAITING) {
1239 protected Stage next() {
1240 return RIDING_MOVER;
1241 }
1242 },
1243
1244
1245
1246 RIDING_MOVER(MoverStageType.RIDING) {
1247 protected Stage next() {
1248 return NAVIGATING;
1249 }
1250 },
1251
1252
1253
1254 CANCELED(TerminatingStageType.FAILURE) {
1255 protected Stage next() {
1256 return this;
1257 }
1258 },
1259
1260
1261
1262 TIMEOUT(TerminatingStageType.FAILURE) {
1263 protected Stage next() {
1264 return this;
1265 }
1266 },
1267
1268
1269
1270 CRASHED(TerminatingStageType.FAILURE) {
1271 protected Stage next() {
1272 return this;
1273 }
1274 },
1275
1276
1277
1278 COMPLETED(TerminatingStageType.SUCCESS) {
1279 protected Stage next() {
1280 return this;
1281 }
1282 },
1283
1284
1285
1286 TELEPORT(TeleportStageType.GOING_THROUGH) {
1287 protected Stage next() {
1288 return NAVIGATING;
1289 }
1290 ;
1291 };
1292
1293
1294
1295
1296
1297
1298
1299 private boolean mover;
1300
1301
1302
1303 public boolean terminated;
1304
1305
1306
1307 public boolean failure;
1308
1309
1310
1311 public boolean teleport;
1312
1313
1314
1315
1316
1317 private Stage() {
1318 this.mover = false;
1319 this.teleport = false;
1320 this.terminated = false;
1321 this.failure = false;
1322 }
1323
1324 private Stage(TeleportStageType type) {
1325 this.mover = false;
1326 this.teleport = true;
1327 this.failure = false;
1328 this.terminated = false;
1329 }
1330
1331
1332
1333
1334
1335
1336 private Stage(MoverStageType type) {
1337 this.mover = true;
1338 this.teleport = false;
1339 this.terminated = false;
1340 this.failure = false;
1341 }
1342
1343
1344
1345
1346
1347
1348 private Stage(TerminatingStageType type) {
1349 this.mover = false;
1350 this.teleport = false;
1351 this.terminated = true;
1352 this.failure = type.failure;
1353 }
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363 protected abstract Stage next();
1364
1365
1366
1367
1368
1369
1370
1371 protected static Stage FirstMoverStage() {
1372 return AWAITING_MOVER;
1373 }
1374
1375
1376
1377
1378
1379
1380 protected static Stage TeleporterStage() {
1381 return Stage.TELEPORT;
1382 }
1383 }
1384
1385
1386
1387
1388
1389 private IUT2004PathRunner runner;
1390
1391
1392
1393
1394
1395 protected UT2004Bot main;
1396
1397
1398
1399 protected AgentInfo memory;
1400
1401
1402
1403 protected AdvancedLocomotion body;
1404
1405
1406
1407 protected Logger log;
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419 public NavMeshNavigator(UT2004Bot bot, AgentInfo info, AdvancedLocomotion move, IUT2004PathRunner runner, Logger log) {
1420
1421 this.main = bot;
1422 this.memory = info;
1423 this.body = move;
1424 this.log = log;
1425
1426 this.selfListener = new SelfListener(bot.getWorldView());
1427
1428
1429 this.runner = runner;
1430 NullCheck.check(this.runner, "runner");
1431 }
1432
1433 @Override
1434 public Logger getLog() {
1435 return log;
1436 }
1437
1438 }