1 package cz.cuni.amis.pogamut.ut2004.agent.module.sensor;
2
3 import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEvent;
4
5 import java.io.File;
6 import java.io.FileNotFoundException;
7 import java.util.Formatter;
8 import java.util.Map;
9 import java.util.logging.Logger;
10
11 import cz.cuni.amis.pogamut.base.agent.IObservingAgent;
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.IWorldObjectEventListener;
16 import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectListener;
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.analyzer.UT2004AnalyzerObserver;
21 import cz.cuni.amis.pogamut.ut2004.analyzer.stats.UT2004AnalyzerObsStats;
22 import cz.cuni.amis.pogamut.ut2004.bot.IUT2004BotController;
23 import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004Bot;
24 import cz.cuni.amis.pogamut.ut2004.communication.messages.ItemType;
25 import cz.cuni.amis.pogamut.ut2004.communication.messages.ItemType.Category;
26 import cz.cuni.amis.pogamut.ut2004.communication.messages.UT2004ItemType;
27 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.Shoot;
28 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.BeginMessage;
29 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.BotKilled;
30 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.ControlMessage;
31 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.EndMessage;
32 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.FlagInfo;
33 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.GameRestarted;
34 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.ItemPickedUp;
35 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.PlayerKilled;
36 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.PlayerScore;
37 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Self;
38 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.TeamScore;
39 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.TeamScoreMessage;
40 import cz.cuni.amis.utils.FilePath;
41 import cz.cuni.amis.utils.NullCheck;
42 import cz.cuni.amis.utils.exception.PogamutException;
43 import cz.cuni.amis.utils.exception.PogamutIOException;
44 import cz.cuni.amis.utils.maps.LazyMap;
45
46
47
48
49
50
51
52
53
54
55 public class AgentStats extends SensorModule<IObservingAgent> {
56
57 protected boolean observer = false;
58
59
60
61
62
63 public boolean isObserver() {
64 return observer;
65 }
66
67
68
69
70
71 public void setObserver(boolean observer) {
72 this.observer = observer;
73 }
74
75
76
77
78
79 public UnrealId getBotId() {
80 if (self == null) return null;
81 return self.getBotId();
82 }
83
84
85
86
87 protected Map<UnrealId, Integer> killed = new LazyMap<UnrealId, Integer>() {
88
89 @Override
90 protected Integer create(UnrealId key) {
91 return 0;
92 }
93
94 };
95
96
97
98
99
100 protected Map<UnrealId, Integer> killedBy = new LazyMap<UnrealId, Integer>() {
101
102 @Override
103 protected Integer create(UnrealId key) {
104 return 0;
105 }
106
107 };
108
109
110
111
112 protected Map<UnrealId, PlayerScore> playerScores = new LazyMap<UnrealId, PlayerScore>() {
113
114 @Override
115 protected PlayerScore create(UnrealId key) {
116 return new PlayerScore(currentUT2004Time, key, 0, 0);
117 }
118
119 };
120
121
122
123
124 protected Map<Integer, TeamScore> teamScores = new LazyMap<Integer, TeamScore>() {
125
126 @Override
127 protected TeamScore create(Integer key) {
128 return new TeamScoreMessage();
129 }
130
131 };
132
133
134
135
136
137 protected int deaths = 0;
138
139
140
141
142 protected int suicides = 0;
143
144
145
146
147 protected int killedByOthers = 0;
148
149
150
151
152 protected int killedOthers = 0;
153
154
155
156
157 protected double travelledDistance = 0.0;
158
159
160
161
162 protected boolean shooting = false;
163
164
165
166
167 protected double timeShooting = 0;
168
169
170
171
172 protected double timeMoving = 0;
173
174
175
176
177
178 protected Map<ItemType, Double> weaponsUsedTime = new LazyMap<ItemType, Double>() {
179
180 @Override
181 protected Double create(ItemType key) {
182 return (double)0;
183 }
184
185 };
186
187
188
189
190 protected Map<ItemType, Integer> itemsCollected = new LazyMap<ItemType, Integer>() {
191
192 @Override
193 protected Integer create(ItemType key) {
194 return 0;
195 }
196
197 };
198
199
200
201
202 protected Map<ItemType.Category, Integer> itemsByCategoryCollected = new LazyMap<ItemType.Category, Integer>() {
203
204 @Override
205 protected Integer create(ItemType.Category key) {
206 return 0;
207 }
208
209 };
210
211
212
213
214 protected int totalItemsCollected = 0;
215
216
217
218
219 protected int numberOfPlayersKilledWithoutDeath = 0;
220
221
222
223
224 protected int doubleDamageCount = 0;
225
226
227
228
229 protected double doubleDamageTime = 0;
230
231
232
233
234
235
236
237
238
239
240
241
242 public void outputHeader(Formatter output) {
243 if (output == null) return;
244 synchronized(output) {
245 output.format("MatchTime;UT2004Time;Health;Armor;Adrenaline;Score;Deaths;Suicides;Killed;WasKilled;NumKillsWithoutDeath;"
246
247 +"Team;TeamScore;"
248
249 +"ItemsCollect;WeaponsCollect;AmmoCollect;HealthCollect;ArmorCollect;ShieldCollect;AdrenalineCollect;OtherCollect;"
250
251 +"TimeMoving;TimeShooting;DoubleDamageCount;DoubleDamageTime;TraveledDistance;"
252
253 +"Combo;HasDoubleDamage;IsShooting;Velocity;Location_x;Location_y;Location_z");
254
255
256 for (ItemType weapon : ItemType.Category.WEAPON.getTypes()) {
257 output.format(";" + fixSemicolon(weapon.getName()).replace(".", "_") + "_TimeUsed");
258 }
259
260 output.format(";Event;EventParams...\n");
261 output.flush();
262 }
263 }
264
265
266
267
268
269
270
271 public void outputStatLine(Formatter output, double time, String... eventOutput) {
272 if (output == null) return;
273 synchronized(output) {
274 output.format("%.3f;%.3f;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%.3f;%.3f;%d;%.3f;%.3f;%s;%d;%d;%.3f;%.3f;%.3f;%.3f",
275
276 time,
277 getCurrentUT2004Time(),
278 (self == null ? 0 : self.getHealth()),
279 (self == null ? 0 : self.getArmor()),
280 (self == null ? 0 : self.getAdrenaline()),
281 getScore(),
282 deaths,
283 suicides,
284 killedOthers,
285 killedByOthers,
286 numberOfPlayersKilledWithoutDeath,
287 (self == null ? 255 : self.getTeam()),
288 getTeamScore(),
289 totalItemsCollected,
290 itemsByCategoryCollected.get(ItemType.Category.WEAPON),
291 itemsByCategoryCollected.get(ItemType.Category.AMMO),
292 itemsByCategoryCollected.get(ItemType.Category.HEALTH),
293 itemsByCategoryCollected.get(ItemType.Category.ARMOR),
294 itemsByCategoryCollected.get(ItemType.Category.SHIELD),
295 itemsByCategoryCollected.get(ItemType.Category.ADRENALINE),
296 itemsByCategoryCollected.get(ItemType.Category.OTHER),
297 timeMoving,
298 timeShooting,
299 doubleDamageCount,
300 doubleDamageTime,
301 travelledDistance,
302 (self == null ? "" : fixSemicolon(self.getCombo())),
303 (self == null ? 0 : self.getUDamageTime() > 0 ? 1 : 0),
304 (self == null ? 0 : (self.isShooting() || self.isAltFiring()) ? 1 : 0),
305 (self == null ? (double)0 : self.getVelocity().size()),
306 (self == null ? (double)0 : self.getLocation().x),
307 (self == null ? (double)0 : self.getLocation().y),
308 (self == null ? (double)0 : self.getLocation().z)
309 );
310
311 for (ItemType weapon : ItemType.Category.WEAPON.getTypes()) {
312 output.format(";%.3f", weaponsUsedTime.get(weapon));
313 }
314
315 for (String event : eventOutput) {
316 output.format(";%s", fixSemicolon(event));
317 }
318 output.format("\n");
319 output.flush();
320 }
321 }
322
323
324
325
326
327 protected void outputStatLine(double time, String... eventOutput) {
328 if (!isLogging()) return;
329 if (outputFile == null) return;
330 outputStatLine(outputFile, time, eventOutput);
331 }
332
333 protected String fixSemicolon(String text) {
334 if (text == null) return "";
335 return text.replace(";", "_");
336 }
337
338
339
340
341
342
343
344 protected Object statsMutex = new Object();
345
346
347
348
349 public void resetStats() {
350 synchronized (statsMutex) {
351 self = null;
352 deaths = 0;
353 suicides = 0;
354 killedOthers = 0;
355 killedByOthers = 0;
356 numberOfPlayersKilledWithoutDeath = 0;
357 totalItemsCollected = 0;
358 synchronized (itemsByCategoryCollected) {
359 itemsByCategoryCollected.clear();
360 }
361 timeMoving = 0;
362 timeShooting = 0;
363 doubleDamageCount = 0;
364 doubleDamageTime = 0;
365 travelledDistance = 0;
366 synchronized (itemsCollected) {
367 itemsCollected.clear();
368 }
369 synchronized (weaponsUsedTime) {
370 weaponsUsedTime.clear();
371 }
372 synchronized (playerScores) {
373 playerScores.clear();
374 }
375
376
377 playerKilledInRow = 0;
378 lastLocation = null;
379 }
380 }
381
382
383
384
385 public void resetMatchTime() {
386 synchronized(statsMutex) {
387 if (getCurrentMatchTime() > 0) {
388 matchStartTime = getCurrentMatchTime();
389 }
390 }
391 }
392
393
394
395
396
397
398
399
400
401
402 protected String pathToOutput = null;
403
404
405
406
407 protected File fileToOutput = null;
408
409
410
411
412 protected Formatter outputFile = null;
413
414
415
416
417
418 public boolean isOutputting() {
419 return isLogging() && outputFile != null;
420 }
421
422
423
424
425
426
427
428 public String getOutputPath() {
429 return pathToOutput;
430 }
431
432
433
434
435
436 public File getOutputFile() {
437 return fileToOutput;
438 }
439
440
441
442
443
444
445
446
447 public void startOutput(String pathToFile) {
448 startOutput(pathToFile, false);
449 }
450
451
452
453
454
455
456
457
458
459
460
461 public void stopOutput() {
462 if (outputFile == null) return;
463 synchronized(outputFile) {
464 try {
465 outputFile.close();
466 } catch (Exception e) {
467 }
468 outputFile = null;
469 fileToOutput = null;
470 }
471 }
472
473
474
475
476
477
478
479
480
481
482
483 protected File getOutputFile(String pathToFile, boolean seekAlternatives) {
484 NullCheck.check(pathToFile, "pathToFile");
485
486 if (!seekAlternatives) {
487 File file = new File(pathToFile);
488 if (!file.exists() || file.isFile()) {
489 return file;
490 }
491 throw new PogamutException("Can't output stats into " + file.getAbsolutePath() + ", invalid location.", this);
492 }
493
494 String fragment;
495 String rest;
496 if (pathToFile.contains(".")) {
497 fragment = pathToFile.substring(0, pathToFile.lastIndexOf("."));
498 rest = pathToFile.substring(pathToFile.lastIndexOf("."));
499 } else {
500 fragment = pathToFile;
501 rest = ".csv";
502 }
503 for (int i = 0; i < 1000; ++i) {
504 String num = String.valueOf(i);
505 while (num.length() < 3) {
506 num = "0" + num;
507 }
508 String fileName = fragment + "_" + num + rest;
509 File file = new File(fileName);
510 if (file.exists()) continue;
511 return file;
512 }
513 throw new PogamutException("No suitable filename for stats to the: " + pathToFile + "...", this);
514 }
515
516
517
518
519
520
521
522
523
524
525 public void startOutput(String pathToFile, boolean seekAlternatives) {
526 stopOutput();
527 this.pathToOutput = pathToFile;
528 fileToOutput = getOutputFile(pathToFile, seekAlternatives);
529 FilePath.makeDirsToFile(fileToOutput);
530 try {
531 outputFile = new Formatter(fileToOutput);
532 } catch (FileNotFoundException e) {
533 throw new PogamutIOException("Could not start logging into '" + fileToOutput.getAbsolutePath() + "' due to: " + e.getMessage(), e, this);
534 }
535 outputHeader(outputFile);
536 }
537
538
539
540
541
542
543
544
545
546
547
548 public Map<UnrealId, Integer> getKilled() {
549 return killed;
550 }
551
552
553
554
555
556 public Map<UnrealId, PlayerScore> getPlayerScores() {
557 return playerScores;
558 }
559
560
561
562
563
564 public Map<Integer, TeamScore> getTeamScores() {
565 return teamScores;
566 }
567
568
569
570
571
572
573
574
575
576
577 public double getCurrentMatchTime() {
578 if (isLogging() && currentUT2004Time > 0) {
579
580 return currentUT2004Time - matchStartTime + ((System.currentTimeMillis() - currentSystemTime) / 1000);
581 } else {
582 return -1;
583 }
584 }
585
586
587
588
589
590
591
592
593 public double getCurrentUT2004Time() {
594 return currentUT2004Time;
595 }
596
597
598
599
600
601 public int getKilledOthers() {
602 return killedOthers;
603 }
604
605
606
607
608
609 public boolean isShooting() {
610 return shooting;
611 }
612
613
614
615
616
617 public double getTimeShooting() {
618 return timeShooting;
619 }
620
621
622
623
624
625 public double getTimeMoving() {
626 return timeMoving;
627 }
628
629
630
631
632
633 public Map<ItemType, Double> getWeaponsUsedTime() {
634 return weaponsUsedTime;
635 }
636
637
638
639
640
641 public Map<ItemType, Integer> getItemsCollected() {
642 return itemsCollected;
643 }
644
645
646
647
648
649 public Map<ItemType.Category, Integer> getItemsByCategoryCollected() {
650 return itemsByCategoryCollected;
651 }
652
653
654
655
656
657 public int getTotalItemsCollected() {
658 return totalItemsCollected;
659 }
660
661
662
663
664
665 public int getNumberOfPlayersKilledWithoutDeath() {
666 return numberOfPlayersKilledWithoutDeath;
667 }
668
669
670
671
672
673 public int getDoubleDamageCount() {
674 return doubleDamageCount;
675 }
676
677
678
679
680
681 public double getDoubleDamageTime() {
682 return doubleDamageTime;
683 }
684
685
686
687
688
689 public Map<UnrealId, Integer> getKilledBy() {
690 return killedBy;
691 }
692
693
694
695
696
697 public int getDeaths() {
698 return deaths;
699 }
700
701
702
703
704
705 public double getTravelledDistance() {
706 return travelledDistance;
707 }
708
709
710
711
712
713 public int getSuicides() {
714 return suicides;
715 }
716
717
718
719
720
721 public int getScore() {
722 return self == null ? 0 : playerScores.get(getBotId()).getScore();
723 }
724
725
726
727
728
729 public int getTeamScore() {
730 return self == null ? 0 : teamScores.get(self.getTeam()).getScore();
731 }
732
733
734
735
736
737 public int getKilledByOthers() {
738 return killedByOthers;
739 }
740
741
742
743
744
745
746
747
748
749
750
751 public boolean isTimeInitialized() {
752 return previousUT2004Time > 0 && currentUT2004Time > 0;
753 }
754
755
756
757
758
759 public double getMatchStartTime() {
760 return matchStartTime;
761 }
762
763
764
765
766
767
768
769
770
771
772
773
774 private class ControlMessageListener implements IWorldEventListener<ControlMessage>
775 {
776 @Override
777 public void notify(ControlMessage event)
778 {
779 synchronized(statsMutex) {
780 outputStatLine(getCurrentMatchTime(), event.getType(), String.valueOf(event.getPF1()), String.valueOf(event.getPF2()), String.valueOf(event.getPF3()), String.valueOf(event.getPI1()), String.valueOf(event.getPI2()), String.valueOf(event.getPI3()), String.valueOf(event.getPS1()), String.valueOf(event.getPS2()), String.valueOf(event.getPS3()));
781 }
782 }
783
784
785
786
787
788 public ControlMessageListener(IWorldView worldView)
789 {
790 worldView.addEventListener(ControlMessage.class, this);
791 }
792 }
793
794
795 private ControlMessageListener controlMessageListener;
796
797
798
799
800
801
802
803 private class BeginMessageListener implements IWorldEventListener<BeginMessage>
804 {
805 @Override
806 public void notify(BeginMessage event)
807 {
808 synchronized(statsMutex) {
809 lastBeginMessage = event;
810
811 if (currentUT2004Time <= 0) {
812 if (isLogBeforeMatchRestart()) {
813 matchStartTime = event.getTime();
814 }
815 }
816
817 previousUT2004Time = currentUT2004Time;
818 currentUT2004Time = event.getTime();
819 ut2004TimeDelta = currentUT2004Time - previousUT2004Time;
820
821 previousSystemTime = currentSystemTime;
822 currentSystemTime = System.currentTimeMillis();
823 systemTimeDelta = currentSystemTime - previousSystemTime;
824 }
825 }
826
827
828
829
830
831 public BeginMessageListener(IWorldView worldView)
832 {
833 worldView.addEventListener(BeginMessage.class, this);
834 }
835 }
836
837
838 private BeginMessageListener beginMessageListener;
839
840
841 private BeginMessage lastBeginMessage = null;
842
843
844 private double previousUT2004Time = -1;
845
846
847 private long previousSystemTime = -1;
848
849
850 private double currentUT2004Time = -1;
851
852
853 private long currentSystemTime = -1;
854
855
856
857
858 private double ut2004TimeDelta = -1;
859
860
861
862
863 private long systemTimeDelta = -1;
864
865
866
867
868
869
870 private class EndMessageListener implements IWorldEventListener<EndMessage>
871 {
872 @Override
873 public void notify(EndMessage event)
874 {
875 synchronized(statsMutex) {
876 lastEndMessage = event;
877 updateStats(event);
878 }
879 }
880
881
882
883
884
885 public EndMessageListener(IWorldView worldView)
886 {
887 worldView.addEventListener(EndMessage.class, this);
888 }
889 }
890
891
892 EndMessageListener endMessageListener;
893
894
895 EndMessage lastEndMessage = null;
896
897
898
899
900
901
902 private class PlayerScoreListener implements IWorldEventListener<PlayerScore>
903 {
904 @Override
905 public void notify(PlayerScore event)
906 {
907 synchronized(statsMutex) {
908 synchronized(playerScores) {
909 playerScores.put(event.getId(), event);
910 }
911 }
912 }
913
914
915
916
917
918 public PlayerScoreListener(IWorldView worldView)
919 {
920 worldView.addEventListener(PlayerScore.class, this);
921 }
922 }
923
924
925 private PlayerScoreListener playerScoreListener;
926
927
928
929
930
931
932 private class TeamScoreListener implements IWorldObjectEventListener<TeamScore, WorldObjectUpdatedEvent<TeamScore>>
933 {
934
935
936
937
938 public TeamScoreListener(IWorldView worldView)
939 {
940 worldView.addObjectListener(TeamScore.class, WorldObjectUpdatedEvent.class, this);
941 }
942
943 @Override
944 public void notify(WorldObjectUpdatedEvent<TeamScore> event) {
945 synchronized(statsMutex) {
946 synchronized(teamScores) {
947 teamScores.put(event.getObject().getTeam(), event.getObject());
948 }
949 }
950 }
951 }
952
953
954 private TeamScoreListener teamScoreListener;
955
956
957
958
959
960
961 private class SelfListener implements IWorldObjectEventListener<Self, WorldObjectUpdatedEvent<Self>>
962 {
963
964
965
966
967 public SelfListener(IWorldView worldView)
968 {
969 worldView.addObjectListener(Self.class, WorldObjectUpdatedEvent.class, this);
970 }
971
972 @Override
973 public void notify(WorldObjectUpdatedEvent<Self> event) {
974 synchronized(statsMutex) {
975 self = event.getObject();
976 }
977 }
978 }
979
980
981 private SelfListener selfListener;
982
983
984 private Self self = null;
985
986
987
988
989
990
991 private class BotKilledListener implements IWorldEventListener<BotKilled>
992 {
993
994
995
996
997 public BotKilledListener(IWorldView worldView)
998 {
999 worldView.addEventListener(BotKilled.class, this);
1000 }
1001
1002 @Override
1003 public void notify(BotKilled event) {
1004 botKilled(event);
1005 }
1006 }
1007
1008
1009 private BotKilledListener botKilledListener;
1010
1011
1012
1013
1014
1015
1016 private class PlayerKilledListener implements IWorldEventListener<PlayerKilled>
1017 {
1018
1019
1020
1021
1022 public PlayerKilledListener(IWorldView worldView)
1023 {
1024 worldView.addEventListener(PlayerKilled.class, this);
1025 }
1026
1027 @Override
1028 public void notify(PlayerKilled event) {
1029 playerKilled(event);
1030 }
1031 }
1032
1033
1034 private PlayerKilledListener playerKilledListener;
1035
1036
1037
1038
1039
1040
1041 private class GameRestartedListener implements IWorldEventListener<GameRestarted>
1042 {
1043
1044
1045
1046
1047 public GameRestartedListener(IWorldView worldView)
1048 {
1049 worldView.addEventListener(GameRestarted.class, this);
1050 }
1051
1052 @Override
1053 public void notify(GameRestarted event) {
1054 gameRestarted(event);
1055 }
1056 }
1057
1058
1059 private GameRestartedListener gameRestartedListener;
1060
1061
1062
1063
1064
1065
1066 private class ItemPickedUpListener implements IWorldEventListener<ItemPickedUp>
1067 {
1068
1069
1070
1071
1072 public ItemPickedUpListener(IWorldView worldView)
1073 {
1074 worldView.addEventListener(ItemPickedUp.class, this);
1075 }
1076
1077 @Override
1078 public void notify(ItemPickedUp event) {
1079 itemPickedUp(event);
1080 }
1081 }
1082
1083
1084 private ItemPickedUpListener itemPickedUpListener;
1085
1086
1087
1088
1089
1090
1091 private class FlagListener implements IWorldObjectListener<FlagInfo>
1092 {
1093
1094
1095
1096
1097 public FlagListener(IWorldView worldView)
1098 {
1099 worldView.addObjectListener(FlagInfo.class, this);
1100 }
1101
1102 @Override
1103 public void notify(IWorldObjectEvent<FlagInfo> event) {
1104 FlagInfo t = event.getObject();
1105 flagInfo(t);
1106 }
1107 }
1108
1109
1110 private FlagListener flagListener;
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123 private double matchStartTime = 0;
1124
1125
1126
1127
1128
1129
1130 private boolean shouldLog = true;
1131
1132
1133
1134
1135 private boolean logBeforeMatchRestart = true;
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149 public boolean isLogging() {
1150 return isTimeInitialized() && shouldLog && self != null;
1151 }
1152
1153
1154
1155
1156
1157 public boolean isLogBeforeMatchRestart() {
1158 return logBeforeMatchRestart;
1159 }
1160
1161
1162
1163
1164
1165
1166
1167
1168 public void setLogBeforeMatchRestart(boolean logBeforeMatchRestart) {
1169 this.logBeforeMatchRestart = logBeforeMatchRestart;
1170 if (this.logBeforeMatchRestart) {
1171 shouldLog = true;
1172 } else {
1173 shouldLog = false;
1174 }
1175 }
1176
1177 protected void gameRestarted(GameRestarted event) {
1178 synchronized(statsMutex) {
1179 if (event.isFinished()) {
1180 shouldLog = true;
1181 resetStats();
1182 matchStartTime = currentUT2004Time;
1183 outputStatLine(0, "GAME_RESTARTED");
1184 }
1185 }
1186 }
1187
1188
1189
1190
1191
1192
1193
1194 protected int playerKilledInRow = 0;
1195
1196 protected void botKilled(BotKilled event) {
1197 synchronized(statsMutex) {
1198 if (!isLogging()) return;
1199 ++deaths;
1200 if (event.getKiller() == null || (event.getKiller().equals(getBotId())) || (self != null && event.getKiller().equals(self.getBotId()))) {
1201 ++suicides;
1202 } else {
1203 ++killedByOthers;
1204 synchronized(killedBy) {
1205 killedBy.put(event.getKiller(), killedBy.get(event.getKiller())+1);
1206 }
1207 }
1208
1209
1210 playerKilledInRow = 0;
1211 lastLocation = null;
1212
1213
1214 if (event.getKiller() == null || (self != null && event.getKiller().equals(getBotId()))) {
1215 outputStatLine(getCurrentMatchTime(), "BOT_KILLED", "SUICIDE", event.getDamageType());
1216 } else {
1217 outputStatLine(getCurrentMatchTime(), "BOT_KILLED", event.getKiller().getStringId(), event.getDamageType());
1218 }
1219 }
1220 }
1221
1222 protected void playerKilled(PlayerKilled event) {
1223 synchronized(statsMutex) {
1224 if (!isLogging()) return;
1225 UnrealId killer = event.getKiller();
1226 UnrealId me = getBotId();
1227 if (event.getId().equals(me)) {
1228
1229 return;
1230 }
1231 if (killer == null || (!killer.equals(me))) {
1232
1233 } else {
1234
1235 ++killedOthers;
1236 ++playerKilledInRow;
1237 if (playerKilledInRow > numberOfPlayersKilledWithoutDeath) {
1238 numberOfPlayersKilledWithoutDeath = playerKilledInRow;
1239 }
1240 synchronized(killed) {
1241 killed.put(event.getId(), killed.get(event.getId())+1);
1242 }
1243 outputStatLine(getCurrentMatchTime(), "PLAYER_KILLED", event.getId().getStringId(), event.getDamageType());
1244 }
1245 }
1246 }
1247
1248 private String team0FlagState;
1249 private String team1FlagState;
1250
1251 protected void flagInfo(FlagInfo event) {
1252 synchronized(statsMutex) {
1253 if (!isLogging()) return;
1254 String flagState;
1255 if(event.getTeam() == 0 )
1256 flagState = team0FlagState;
1257 else
1258 flagState = team1FlagState;
1259
1260
1261 if(flagState != null && !flagState.equals(event.getState())){
1262 if(event.getState().toLowerCase().equals("home"))
1263 {
1264 if(flagState.toLowerCase().equals("held"))
1265 outputStatLine(getCurrentMatchTime(), "FLAG_CAPTURED", event.getTeam().toString(), event.getHolder()!=null?event.getHolder().getStringId():"");
1266 else if(flagState.toLowerCase().equals("dropped"))
1267 outputStatLine(getCurrentMatchTime(), "FLAG_RETURNED", event.getTeam().toString(), event.getHolder()!=null?event.getHolder().getStringId():"");
1268 }else if(event.getState().toLowerCase().equals("held"))
1269 outputStatLine(getCurrentMatchTime(), "FLAG_PICKEDUP".toUpperCase(), event.getTeam().toString(), event.getHolder()!=null?event.getHolder().getStringId():"");
1270 else
1271 outputStatLine(getCurrentMatchTime(), "FLAG_"+event.getState().toUpperCase(), event.getTeam().toString(), event.getHolder()!=null?event.getHolder().getStringId():"");
1272 }
1273
1274 if(event.getTeam() == 0 )
1275 team0FlagState = event.getState();
1276 else
1277 team1FlagState = event.getState();
1278 }
1279 }
1280
1281 protected void itemPickedUp(ItemPickedUp event) {
1282 synchronized(statsMutex) {
1283 if (!isLogging()) return;
1284 if (event.getType() == UT2004ItemType.U_DAMAGE_PACK) {
1285 ++doubleDamageCount;
1286 }
1287 synchronized(itemsCollected) {
1288 itemsCollected.put(event.getType(), itemsCollected.get(event.getType()) + 1);
1289 }
1290 synchronized(itemsByCategoryCollected) {
1291 itemsByCategoryCollected.put(event.getType().getCategory(), itemsByCategoryCollected.get(event.getType().getCategory())+1);
1292 }
1293 outputStatLine(getCurrentMatchTime(), "ITEM_PICKEDUP", event.getType().getName(), event.getType().getCategory().name);
1294 }
1295 }
1296
1297
1298
1299
1300
1301
1302
1303 protected Location lastLocation;
1304
1305
1306
1307
1308 protected void updateStats(EndMessage event) {
1309 synchronized(statsMutex) {
1310 if (self == null) {
1311 log.warning("EndMessage received but no SELF was received.");
1312 return;
1313 }
1314 if (!isLogging()) return;
1315
1316 if (self.getVelocity().size() > 1) {
1317 timeMoving += ut2004TimeDelta;
1318 }
1319 if (self.isShooting()) {
1320 timeShooting += ut2004TimeDelta;
1321 ItemType weapon = UT2004ItemType.getWeapon(UnrealId.get(self.getWeapon()));
1322 if (weapon == null) {
1323 log.warning("Unrecognized weapon of id: " + self.getWeapon());
1324 } else {
1325 synchronized(weaponsUsedTime) {
1326 weaponsUsedTime.put(weapon, weaponsUsedTime.get(weapon) + ut2004TimeDelta);
1327 }
1328 }
1329 }
1330 if (self.getUDamageTime() > 0) {
1331 doubleDamageTime += ut2004TimeDelta;
1332 }
1333 if (lastLocation != null) {
1334 travelledDistance += lastLocation.getDistance(self.getLocation());
1335 }
1336 lastLocation = self.getLocation();
1337
1338 outputStatLine(getCurrentMatchTime());
1339 }
1340 }
1341
1342
1343
1344
1345
1346
1347
1348 @Override
1349 protected void start(boolean startToPaused) {
1350 super.start(startToPaused);
1351 resetStats();
1352 resetMatchTime();
1353 }
1354
1355 @Override
1356 protected void stop() {
1357 super.stop();
1358 synchronized(statsMutex) {
1359 stopOutput();
1360 }
1361 }
1362
1363 @Override
1364 protected void kill() {
1365 super.kill();
1366 synchronized(statsMutex) {
1367 stopOutput();
1368 }
1369 }
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381 public AgentStats(IObservingAgent bot) {
1382 this(bot, null);
1383 }
1384
1385
1386
1387
1388
1389
1390 public AgentStats(IObservingAgent bot, Logger log)
1391 {
1392 super(bot, log);
1393
1394
1395 controlMessageListener = new ControlMessageListener(worldView);
1396 beginMessageListener = new BeginMessageListener(worldView);
1397 endMessageListener = new EndMessageListener(worldView);
1398 selfListener = new SelfListener(worldView);
1399 botKilledListener = new BotKilledListener(worldView);
1400 playerKilledListener = new PlayerKilledListener(worldView);
1401 itemPickedUpListener = new ItemPickedUpListener(worldView);
1402 flagListener = new FlagListener(worldView);
1403 gameRestartedListener = new GameRestartedListener(worldView);
1404 playerScoreListener = new PlayerScoreListener(worldView);
1405 teamScoreListener = new TeamScoreListener(worldView);
1406 cleanUp();
1407 }
1408
1409 }