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