1 package cz.cuni.amis.pogamut.ut2004.agent.module.sensor;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.Collections;
6 import java.util.HashMap;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.logging.Level;
10 import java.util.logging.Logger;
11
12 import cz.cuni.amis.pogamut.base.agent.module.SensorModule;
13 import cz.cuni.amis.pogamut.base.communication.worldview.IWorldView;
14 import cz.cuni.amis.pogamut.base.communication.worldview.event.IWorldEventListener;
15 import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEvent;
16 import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEventListener;
17 import cz.cuni.amis.pogamut.base.communication.worldview.object.event.WorldObjectUpdatedEvent;
18 import cz.cuni.amis.pogamut.base3d.worldview.object.Location;
19 import cz.cuni.amis.pogamut.unreal.communication.messages.UnrealId;
20 import cz.cuni.amis.pogamut.ut2004.bot.IUT2004BotController;
21 import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004Bot;
22 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.BeginMessage;
23 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.FlagInfo;
24 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.GameInfo;
25 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.InitedMessage;
26 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Mutator;
27 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.NavPoint;
28 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.PlayerScore;
29 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Self;
30 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.TeamScore;
31 import cz.cuni.amis.pogamut.ut2004.communication.translator.shared.events.MutatorListObtained;
32 import cz.cuni.amis.utils.exception.PogamutException;
33
34
35
36
37
38
39
40
41
42
43
44 public class Game extends SensorModule<UT2004Bot>
45 {
46
47
48
49
50
51 public enum GameType
52 {
53
54 BotDeathMatch,
55
56 BotTeamGame,
57
58 BotCTFGame,
59
60 BotBombingRun,
61
62 BotDoubleDomination,
63
64 Unknown;
65
66
67
68
69
70
71
72 public static GameType getType(String type)
73 {
74 if (type.equalsIgnoreCase("BotDeathMatch")) return BotDeathMatch;
75 if (type.equalsIgnoreCase("BotTeamGame")) return BotTeamGame;
76 if (type.equalsIgnoreCase("BotCTFGame")) return BotCTFGame;
77 if (type.equalsIgnoreCase("BotBombingRun")) return BotBombingRun;
78 if (type.equalsIgnoreCase("BotDoubleDomination")) return BotDoubleDomination;
79 return Unknown;
80 }
81 }
82
83
84
85
86
87
88 public GameInfo getGameInfo() {
89 return lastGameInfo;
90 }
91
92
93
94
95
96
97 public GameType getGameType()
98 {
99
100 if (lastGameInfo == null) return null;
101 return GameType.getType(lastGameInfo.getGametype());
102 }
103
104
105
106
107
108
109
110
111 public String getMapName()
112 {
113
114 if (lastGameInfo == null) return null;
115 return lastGameInfo.getLevel();
116 }
117
118
119
120
121
122
123 public boolean isMapName(String name) {
124 if (lastGameInfo == null) return false;
125 if (name == null) return false;
126 return lastGameInfo.getLevel().toLowerCase().equals(name.toLowerCase());
127 }
128
129
130
131
132
133
134
135
136
137
138
139 public String getPrefixed(String objectId) {
140
141 if (getMapName() == null) {
142 throw new PogamutException("GameInfo was not received yet, can't prefix '" + objectId + "'.", this);
143 }
144 if (objectId.toLowerCase().startsWith(mapNameLowerChar + ".")) {
145
146 if (!objectId.startsWith(getMapName())) {
147
148 objectId = getMapName() + objectId.substring(mapNameLowerChar.length());
149 }
150
151 return objectId;
152 } else {
153
154 if (objectId.contains(".")) {
155
156 throw new PogamutException("id '" + objectId + "' is already prefixed with '" + objectId.substring(0, objectId.indexOf(".")) + "' which is different from current map name '" + getMapName() + "', map name validation fails!", this);
157 }
158
159 return getMapName() + "." + objectId;
160 }
161 }
162
163
164
165
166
167
168
169
170
171
172
173 public UnrealId getPrefixedId(String objectId) {
174
175 if (getMapName() == null) {
176 throw new PogamutException("GameInfo was not received yet, can't prefix '" + objectId + "'.", this);
177 }
178 if (objectId.toLowerCase().startsWith(mapNameLowerChar + ".")) {
179
180 if (!objectId.startsWith(getMapName())) {
181
182 objectId = getMapName() + objectId.substring(mapNameLowerChar.length());
183 }
184
185 return UnrealId.get(objectId);
186 } else {
187
188 if (objectId.contains(".")) {
189
190 throw new PogamutException("id '" + objectId + "' is already prefixed with '" + objectId.substring(0, objectId.indexOf(".")) + "' which is different from current map name '" + getMapName() + "', map name validation fails!", this);
191 }
192
193 return UnrealId.get(getMapName() + "." + objectId);
194 }
195 }
196
197
198
199
200
201
202
203
204 public double getTime()
205 {
206
207 if (lastBeginMessage == null) return 0;
208 return lastBeginMessage.getTime();
209 }
210
211
212
213
214
215
216 public double getTimeDelta() {
217 return timeDelta;
218 }
219
220
221
222
223
224
225
226
227
228
229
230
231 public Double getTimeLimit()
232 {
233
234 if (lastGameInfo == null) return null;
235 return lastGameInfo.getTimeLimit();
236 }
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252 public Double getRemainingTime()
253 {
254
255 if (getTimeLimit() == null) return null;
256 return getTimeLimit() - getTime();
257 }
258
259
260
261
262
263
264
265
266
267
268
269 public Integer getFragLimit()
270 {
271
272 if (lastGameInfo == null) return null;
273 return lastGameInfo.getFragLimit();
274 }
275
276
277
278
279
280
281
282
283
284 public Integer getTeamScoreLimit()
285 {
286
287
288 if (lastGameInfo == null) return null;
289 return (int)lastGameInfo.getGoalTeamScore();
290 }
291
292
293
294
295
296
297
298
299
300
301 public FlagInfo getCTFFlag(int team) {
302 Collection<FlagInfo> flags = worldView.getAll(FlagInfo.class).values();
303 for (FlagInfo flag : flags) {
304 if (flag.getTeam() == team) {
305 return flag;
306 }
307 }
308 return null;
309 }
310
311
312
313
314
315
316
317 public Collection<FlagInfo> getCTFFlags() {
318 return worldView.getAll(FlagInfo.class).values();
319 }
320
321
322
323
324
325
326
327
328
329 public Collection<NavPoint> getDominationPoints() {
330 Collection<NavPoint> domPoints = new ArrayList();
331 Collection<NavPoint> navPoints = worldView.getAll(NavPoint.class).values();
332 for (NavPoint nav : navPoints) {
333 if (nav.isDomPoint()) {
334 domPoints.add(nav);
335 }
336 }
337 return domPoints;
338 }
339
340
341
342
343
344
345
346
347
348
349 public Map<Integer, TeamScore> getTeamScores() {
350 return Collections.unmodifiableMap(lastTeamScore);
351 }
352
353
354
355
356
357
358
359
360
361
362
363
364 public int getTeamScore(int team) {
365 TeamScore teamScore = lastTeamScore.get(team);
366 if (teamScore == null) {
367 return Integer.MIN_VALUE;
368 }
369
370 return teamScore.getScore();
371 }
372
373
374
375
376
377
378
379 public boolean isTeamScoreKnown(int team) {
380 return lastTeamScore.containsKey(team);
381 }
382
383
384
385
386
387
388
389
390 public Map<UnrealId, PlayerScore> getPlayerScores() {
391 return Collections.unmodifiableMap(lastPlayerScore);
392 }
393
394
395
396
397
398
399
400
401
402
403
404
405 public int getPlayerScore(UnrealId id) {
406 PlayerScore score = lastPlayerScore.get(id);
407 if (score != null) {
408 return score.getScore();
409 }
410 return Integer.MIN_VALUE;
411 }
412
413
414
415
416
417
418
419 public boolean isPlayerScoreKnown(UnrealId player) {
420 return lastPlayerScore.containsKey(player);
421 }
422
423
424
425
426
427
428
429
430
431
432
433
434 public int getPlayerDeaths(UnrealId id) {
435
436 PlayerScore score = lastPlayerScore.get(id);
437 if (score == null) {
438 return Integer.MIN_VALUE;
439 }
440 return score.getDeaths();
441 }
442
443
444
445
446
447
448
449 public boolean isPlayerDeathsKnown(UnrealId player) {
450 return lastPlayerScore.containsKey(player);
451 }
452
453
454
455
456
457
458
459
460
461
462
463 public Integer getMaxTeams()
464 {
465
466 if (lastGameInfo == null) return null;
467 return lastGameInfo.getMaxTeams();
468 }
469
470
471
472
473
474
475
476 public Integer getMaxTeamSize()
477 {
478
479 if (lastGameInfo == null) return null;
480 return lastGameInfo.getMaxTeamSize();
481 }
482
483
484
485
486
487
488
489
490
491
492
493
494 public Integer getStartHealth()
495 {
496
497 if (lastInitedMessage == null) return null;
498 return lastInitedMessage.getHealthStart();
499 }
500
501
502
503
504
505
506
507
508
509
510 public Integer getFullHealth()
511 {
512
513 if (lastInitedMessage == null) return null;
514 return lastInitedMessage.getHealthFull();
515 }
516
517
518
519
520
521
522
523
524
525
526
527 public Integer getMaxHealth()
528 {
529
530 if (lastInitedMessage == null) return null;
531 return lastInitedMessage.getHealthMax();
532 }
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547 public Integer getMaxArmor()
548 {
549
550 if (lastInitedMessage == null) return null;
551 return lastInitedMessage.getShieldStrengthMax();
552 }
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567 public int getMaxLowArmor()
568 {
569
570 return 50;
571 }
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586 public int getMaxHighArmor()
587 {
588
589 return 100;
590 }
591
592
593
594
595
596
597
598
599
600 public Integer getStartAdrenaline()
601 {
602
603
604 if (lastInitedMessage == null) return null;
605 return (int)lastInitedMessage.getAdrenalineStart();
606 }
607
608
609
610
611
612
613
614
615
616
617
618
619 public Integer getTargetAdrenaline()
620 {
621
622
623 if (lastInitedMessage == null) return null;
624 return (int)lastInitedMessage.getAdrenalineMax();
625 }
626
627
628
629
630
631
632 public Integer getMaxAdrenaline()
633 {
634
635
636 if (lastInitedMessage == null) return null;
637 return (int)lastInitedMessage.getAdrenalineMax();
638 }
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659 public Boolean getWeaponsStay()
660 {
661
662 if (lastGameInfo == null) return null;
663 return lastGameInfo.isWeaponStay();
664 }
665
666
667
668
669
670
671
672
673
674
675
676 public Integer getMaxMultiJump()
677 {
678
679 if (lastInitedMessage == null) return null;
680 return lastInitedMessage.getMaxMultiJump();
681 }
682
683
684
685
686
687
688
689
690 public List<Mutator> getMutators()
691 {
692 if (lastMutatorListObtained == null) return null;
693 return lastMutatorListObtained.getMutators();
694 }
695
696
697
698
699
700
701
702
703
704
705
706 public Boolean isPaused()
707 {
708
709 if (lastGameInfo == null) return null;
710 return lastGameInfo.isGamePaused();
711 }
712
713
714
715
716
717
718
719
720
721
722
723 public Boolean isBotsPaused()
724 {
725
726 if (lastGameInfo == null) return null;
727 return lastGameInfo.isBotsPaused();
728 }
729
730
731
732
733
734
735
736
737
738
739
740 public Map<Integer, FlagInfo> getAllCTFFlags()
741 {
742 return allCTFFlags;
743 }
744
745
746
747
748
749
750
751 public Collection<FlagInfo> getAllCTFFlagsCollection()
752 {
753 return allCTFFlags.values();
754 }
755
756
757
758
759
760
761 public FlagInfo getFlag(int team) {
762 return allCTFFlags.get(team);
763 }
764
765
766
767
768
769 public FlagInfo getMyFlag() {
770 if (self == null) return null;
771 return allCTFFlags.get(self.getTeam());
772 }
773
774
775
776
777
778 public FlagInfo getEnemyFlag() {
779 if (self == null) return null;
780 return getFlag(self.getTeam() == 0 ? 1 : 0);
781 }
782
783
784
785
786
787
788 public Location getFlagBase(int team) {
789 if (lastGameInfo == null) return null;
790 if (team == 0) return lastGameInfo.getRedBaseLocation();
791 else return lastGameInfo.getBlueBaseLocation();
792 }
793
794
795
796
797
798 public Location getMyFlagBase() {
799 if (self == null) return null;
800 return getFlagBase(self.getTeam());
801 }
802
803
804
805
806
807 public Location getEnemyFlagBase() {
808 if (self == null) return null;
809 return getFlagBase(self.getTeam() == 0 ? 1 : 0);
810 }
811
812
813
814
815 GameInfo lastGameInfo = null;
816
817
818 InitedMessage lastInitedMessage = null;
819
820
821 BeginMessage lastBeginMessage = null;
822
823
824 MutatorListObtained lastMutatorListObtained = null;
825
826
827 Map<Integer, FlagInfo> allCTFFlags = new HashMap();
828
829
830 Map<UnrealId, PlayerScore> lastPlayerScore = null;
831
832
833 Map<Integer, TeamScore> lastTeamScore = null;
834
835
836 Self self;
837
838
839
840
841
842
843 private class SelfListener implements IWorldObjectEventListener<Self, WorldObjectUpdatedEvent<Self>>
844 {
845 private IWorldView worldView;
846
847
848
849
850
851 public SelfListener(IWorldView worldView)
852 {
853 this.worldView = worldView;
854 worldView.addObjectListener(Self.class, WorldObjectUpdatedEvent.class, this);
855 }
856
857 @Override
858 public void notify(WorldObjectUpdatedEvent<Self> event) {
859 self = event.getObject();
860 }
861 }
862
863
864 private SelfListener selfListener;
865
866
867
868
869
870
871
872 private class GameInfoListener implements IWorldObjectEventListener<GameInfo, IWorldObjectEvent<GameInfo>>
873 {
874 @Override
875 public void notify(IWorldObjectEvent<GameInfo> event)
876 {
877 lastGameInfo = event.getObject();
878 mapNameLowerChar = lastGameInfo.getLevel().toLowerCase();
879 }
880
881
882
883
884
885 public GameInfoListener(IWorldView worldView)
886 {
887 worldView.addObjectListener(GameInfo.class, this);
888 }
889 }
890
891
892 GameInfoListener gameInfoListener;
893
894 String mapNameLowerChar = "";
895
896
897
898
899
900
901 private class InitedMessageListener implements IWorldObjectEventListener<InitedMessage, WorldObjectUpdatedEvent<InitedMessage>>
902 {
903 @Override
904 public void notify(WorldObjectUpdatedEvent<InitedMessage> event)
905 {
906 lastInitedMessage = event.getObject();
907 }
908
909
910
911
912
913 public InitedMessageListener(IWorldView worldView)
914 {
915 worldView.addObjectListener(InitedMessage.class, WorldObjectUpdatedEvent.class, this);
916 }
917 }
918
919
920 InitedMessageListener initedMessageListener;
921
922
923
924 private double timeDelta = -1;
925
926
927
928
929 private class BeginMessageListener implements IWorldEventListener<BeginMessage>
930 {
931 @Override
932 public void notify(BeginMessage event)
933 {
934 if (lastBeginMessage != null) {
935 timeDelta = lastBeginMessage.getTime() - event.getTime();
936 }
937 lastBeginMessage = event;
938 }
939
940
941
942
943
944 public BeginMessageListener(IWorldView worldView)
945 {
946 worldView.addEventListener(BeginMessage.class, this);
947 }
948 }
949
950
951 BeginMessageListener beginMessageListener;
952
953
954
955
956
957
958 private class MutatorListObtainedListener implements IWorldEventListener<MutatorListObtained>
959 {
960 @Override
961 public void notify(MutatorListObtained event)
962 {
963 lastMutatorListObtained = event;
964 }
965
966
967
968
969
970 public MutatorListObtainedListener(IWorldView worldView)
971 {
972 worldView.addEventListener(MutatorListObtained.class, this);
973 }
974 }
975
976
977 MutatorListObtainedListener mutatorListObtainedListener;
978
979
980
981
982
983
984 private class FlagInfoObjectListener implements IWorldObjectEventListener<FlagInfo,WorldObjectUpdatedEvent<FlagInfo>>
985 {
986
987
988
989
990
991 public void notify(WorldObjectUpdatedEvent<FlagInfo> event)
992 {
993 allCTFFlags.put(event.getObject().getTeam(), event.getObject());
994 }
995
996
997
998
999
1000 public FlagInfoObjectListener(IWorldView worldView)
1001 {
1002 worldView.addObjectListener(FlagInfo.class, WorldObjectUpdatedEvent.class, this);
1003 }
1004 }
1005
1006
1007 FlagInfoObjectListener flagInfoObjectListener;
1008
1009
1010
1011
1012
1013
1014 private class PlayerScoreListener implements IWorldEventListener<PlayerScore>
1015 {
1016 @Override
1017 public void notify(PlayerScore event)
1018 {
1019 synchronized(lastPlayerScore) {
1020 lastPlayerScore.put(event.getId(), event);
1021 }
1022 }
1023
1024
1025
1026
1027
1028 public PlayerScoreListener(IWorldView worldView)
1029 {
1030 worldView.addEventListener(PlayerScore.class, this);
1031 }
1032 }
1033
1034
1035 private PlayerScoreListener playerScoreListener;
1036
1037
1038
1039
1040
1041
1042 private class TeamScoreListener implements IWorldObjectEventListener<TeamScore, WorldObjectUpdatedEvent<TeamScore>>
1043 {
1044
1045
1046
1047
1048 public TeamScoreListener(IWorldView worldView)
1049 {
1050 worldView.addObjectListener(TeamScore.class, WorldObjectUpdatedEvent.class, this);
1051 }
1052
1053 @Override
1054 public void notify(WorldObjectUpdatedEvent<TeamScore> event) {
1055 synchronized(lastTeamScore) {
1056 lastTeamScore.put(event.getObject().getTeam(), event.getObject());
1057 }
1058 }
1059 }
1060
1061
1062 private TeamScoreListener teamScoreListener;
1063
1064
1065
1066
1067
1068
1069
1070 public Game(UT2004Bot bot) {
1071 this(bot, null);
1072 }
1073
1074
1075
1076
1077
1078
1079 public Game(UT2004Bot bot, Logger log)
1080 {
1081 super(bot, log);
1082
1083
1084 gameInfoListener = new GameInfoListener(worldView);
1085 beginMessageListener = new BeginMessageListener(worldView);
1086 initedMessageListener = new InitedMessageListener(worldView);
1087 mutatorListObtainedListener = new MutatorListObtainedListener(worldView);
1088 flagInfoObjectListener = new FlagInfoObjectListener(worldView);
1089 playerScoreListener = new PlayerScoreListener(worldView);
1090 teamScoreListener = new TeamScoreListener(worldView);
1091 lastPlayerScore = new HashMap<UnrealId, PlayerScore>();
1092 lastTeamScore = new HashMap<Integer, TeamScore>();
1093 selfListener = new SelfListener(worldView);
1094 mapNameLowerChar = "";
1095
1096 cleanUp();
1097 }
1098
1099 @Override
1100 protected void cleanUp() {
1101 super.cleanUp();
1102 lastGameInfo = null;
1103 lastInitedMessage = null;
1104 lastBeginMessage = null;
1105 lastMutatorListObtained = null;
1106 synchronized(lastPlayerScore) {
1107 lastPlayerScore.clear();
1108 }
1109 synchronized(lastTeamScore) {
1110 lastTeamScore.clear();
1111 }
1112 timeDelta = -1;
1113 }
1114
1115 }