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