1 package cz.cuni.amis.pogamut.ut2004.tournament.capturetheflag;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.util.ArrayList;
6 import java.util.Collections;
7 import java.util.Comparator;
8 import java.util.Formatter;
9 import java.util.HashMap;
10 import java.util.List;
11 import java.util.Map;
12 import java.util.Map.Entry;
13 import java.util.concurrent.CountDownLatch;
14 import java.util.concurrent.TimeUnit;
15 import java.util.logging.Level;
16
17 import cz.cuni.amis.pogamut.base.agent.state.level0.IAgentState;
18 import cz.cuni.amis.pogamut.base.agent.state.level1.IAgentStateDown;
19 import cz.cuni.amis.pogamut.base.agent.state.level1.IAgentStateUp;
20 import cz.cuni.amis.pogamut.base.communication.worldview.event.IWorldEventListener;
21 import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEventListener;
22 import cz.cuni.amis.pogamut.base.communication.worldview.object.event.WorldObjectUpdatedEvent;
23 import cz.cuni.amis.pogamut.base.utils.guice.AdaptableProvider;
24 import cz.cuni.amis.pogamut.base.utils.logging.LogCategory;
25 import cz.cuni.amis.pogamut.unreal.communication.messages.UnrealId;
26 import cz.cuni.amis.pogamut.ut2004.agent.module.sensor.AgentStats;
27 import cz.cuni.amis.pogamut.ut2004.analyzer.IUT2004AnalyzerObserver;
28 import cz.cuni.amis.pogamut.ut2004.analyzer.UT2004Analyzer;
29 import cz.cuni.amis.pogamut.ut2004.analyzer.stats.UT2004AnalyzerObsStats;
30 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.StartPlayers;
31 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.MapFinished;
32 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.PlayerScore;
33 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.TeamScore;
34 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.TeamScoreMessage;
35 import cz.cuni.amis.pogamut.ut2004.server.impl.UT2004Server;
36 import cz.cuni.amis.pogamut.ut2004.tournament.botexecution.UT2004BotExecution;
37 import cz.cuni.amis.pogamut.ut2004.tournament.match.UT2004BotConfig;
38 import cz.cuni.amis.pogamut.ut2004.tournament.match.UT2004Match;
39 import cz.cuni.amis.pogamut.ut2004.tournament.match.UT2004MatchResult;
40 import cz.cuni.amis.pogamut.ut2004.utils.UCCWrapper;
41 import cz.cuni.amis.utils.ExceptionToString;
42 import cz.cuni.amis.utils.FilePath;
43 import cz.cuni.amis.utils.exception.PogamutException;
44 import cz.cuni.amis.utils.exception.PogamutIOException;
45 import cz.cuni.amis.utils.exception.PogamutInterruptedException;
46 import cz.cuni.amis.utils.flag.FlagListener;
47 import cz.cuni.amis.utils.token.IToken;
48
49 public class UT2004CaptureTheFlag extends UT2004Match<UT2004CaptureTheFlagConfig, UT2004CaptureTheFlagResult> {
50
51 public UT2004CaptureTheFlag(UT2004CaptureTheFlagConfig config, LogCategory log) {
52 super(false, config, log);
53 }
54
55 @Override
56 protected UT2004MatchResult waitMatchFinish(UCCWrapper ucc, UT2004Server server, UT2004Analyzer analyzer, Bots bots, long timeoutInMillis) {
57
58
59 if (log != null && log.isLoggable(Level.WARNING)) {
60 log.warning(config.getMatchId().getToken() + ": Waiting for the match to finish...");
61 }
62
63 if (config.getTimeLimit() * 60 * 1000 + 5 * 60 * 1000 > timeoutInMillis) {
64 timeoutInMillis = config.getTimeLimit() * 60 * 1000 + 5 * 60 * 1000;
65 }
66
67 Map<IToken, FlagListener<Boolean>> customBotObservers = new HashMap<IToken, FlagListener<Boolean>>(config.getBots().size());
68 FlagListener<IAgentState> serverObs = null;
69 FlagListener<Boolean> uccObs = null;
70 IWorldEventListener<PlayerScore> scoresListener = null;
71 IWorldObjectEventListener<TeamScore, WorldObjectUpdatedEvent<TeamScore>> teamScoresListener = null;
72 IWorldEventListener<MapFinished> mapFinishedListener = null;
73
74 final CountDownLatch waitLatch = new CountDownLatch(1);
75 final AdaptableProvider<Boolean> oneOfBotsDiedOut = new AdaptableProvider<Boolean>(false);
76 final AdaptableProvider<Boolean> serverDiedOut = new AdaptableProvider<Boolean>(false);
77 final Map<UnrealId, PlayerScore> scores = new HashMap<UnrealId, PlayerScore>();
78 final Map<Integer, TeamScore> teamScores = new HashMap<Integer, TeamScore>();
79
80 boolean exception = false;
81
82 try {
83 teamScores.put(0, new TeamScoreMessage(UnrealId.get("TEAM0"), 0, 0));
84 teamScores.put(1, new TeamScoreMessage(UnrealId.get("TEAM1"), 1, 0));
85 serverDiedOut.set(false);
86
87 scoresListener = new IWorldEventListener<PlayerScore>() {
88
89 @Override
90 public void notify(PlayerScore event) {
91 scores.put(event.getId(), event);
92 }
93
94 };
95 server.getWorldView().addEventListener(PlayerScore.class, scoresListener);
96
97 teamScoresListener = new IWorldObjectEventListener<TeamScore, WorldObjectUpdatedEvent<TeamScore>>() {
98
99 @Override
100 public void notify(WorldObjectUpdatedEvent<TeamScore> event) {
101 if (event.getObject() == null) return;
102 int team = event.getObject().getTeam();
103 teamScores.put(team, event.getObject());
104 }
105
106 };
107 server.getWorldView().addObjectListener(TeamScore.class, WorldObjectUpdatedEvent.class, teamScoresListener);
108
109
110 for (UT2004BotConfig botConfig : config.getBots().values()) {
111 FlagListener<Boolean> obs = new FlagListener<Boolean>() {
112 @Override
113 public void flagChanged(Boolean changedValue) {
114 if (!changedValue) {
115
116 oneOfBotsDiedOut.set(true);
117 waitLatch.countDown();
118 }
119 }
120 };
121
122 bots.bots.get(botConfig.getBotId()).getRunning().addListener(obs);
123 customBotObservers.put(botConfig.getBotId(), obs);
124 if (!bots.bots.get(botConfig.getBotId()).getRunning().getFlag()) {
125
126 oneOfBotsDiedOut.set(true);
127 waitLatch.countDown();
128 throw new PogamutException("One of custom bots died out from the start, failure!", log, this);
129 }
130 }
131
132 serverObs = new FlagListener<IAgentState>() {
133
134 @Override
135 public void flagChanged(IAgentState changedValue) {
136 if (changedValue instanceof IAgentStateDown) {
137
138 serverDiedOut.set(true);
139 waitLatch.countDown();
140 }
141 }
142
143 };
144
145 server.getState().addListener(serverObs);
146
147 mapFinishedListener = new IWorldEventListener<MapFinished>() {
148 @Override
149 public void notify(MapFinished event) {
150 log.info("MapFinished event received.");
151 waitLatch.countDown();
152 }
153 };
154
155 server.getWorldView().addEventListener(MapFinished.class, mapFinishedListener);
156
157 if (server.notInState(IAgentStateUp.class)) {
158
159 serverDiedOut.set(true);
160 waitLatch.countDown();
161 throw new PogamutException("Server is dead from the start, failure!", log, this);
162 }
163
164 uccObs = new FlagListener<Boolean>() {
165
166 @Override
167 public void flagChanged(Boolean changedValue) {
168 if (changedValue) {
169
170
171 serverDiedOut.set(true);
172 waitLatch.countDown();
173 }
174 }
175
176 };
177
178 ucc.getGameEnding().addListener(uccObs);
179
180 waitLatch.await(timeoutInMillis, TimeUnit.MILLISECONDS);
181 if (waitLatch.getCount() > 0) {
182
183 throw new PogamutException("TIMEOUT! The match did not end in " + (timeoutInMillis / 1000) + " secs.", log, this);
184 }
185
186 bots.matchEnd = System.currentTimeMillis();
187
188
189 if (oneOfBotsDiedOut.get()) {
190
191 try {
192 Thread.sleep(5000);
193 } catch (InterruptedException e) {
194 throw new PogamutInterruptedException("Interrupted while giving GB2004 time to tear down its connection.", log, this);
195 }
196 try {
197 server.getAct().act(new StartPlayers());
198 } catch (Exception e) {
199
200 serverDiedOut.set(true);
201 }
202 if (!serverDiedOut.get()) {
203
204 log.warning("ONE OF BOTS HAS DIED OUT, BUT SERVER IS STILL RUNNING ... POSSIBLE MATCH FAILURE!");
205 }
206 }
207 if (!serverDiedOut.get() && server.inState(IAgentStateUp.class)) {
208
209 server.kill();
210 }
211
212
213
214 if (ucc != null) {
215 try {
216 if (log != null && log.isLoggable(Level.INFO)) {
217 log.info(config.getMatchId().getToken() + ": Killing UCC...");
218 }
219 } catch (Exception e) {
220 }
221 try {
222 ucc.stop();
223 } catch (Exception e) {
224 }
225 }
226
227 List<Integer> winners = new ArrayList<Integer>(1);
228 int maxScore = 0;
229
230
231 for (Entry<Integer, TeamScore> entry : teamScores.entrySet()) {
232 if (entry.getValue() == null || entry.getValue().getScore() == null) {
233 throw new PogamutException("There is a team '" + entry.getKey() + "' that has NULL score!", this);
234 }
235 if (entry.getValue().getScore() == maxScore) {
236 winners.add(entry.getValue().getTeam());
237 } else
238 if (entry.getValue().getScore() > maxScore) {
239 winners.clear();
240 winners.add(entry.getValue().getTeam());
241 maxScore = entry.getValue().getScore();
242 }
243 }
244
245 if (winners.size() == 0) {
246
247 throw new PogamutException("There is no winner, impossible! **puzzled**", log, this);
248 }
249 if (winners.size() > 1) {
250 StringBuffer sb = new StringBuffer();
251 sb.append("There is more than one team with highest score == " + maxScore + ": ");
252 boolean first = true;
253 for (Integer id : winners) {
254 if (first) first = false;
255 else sb.append(", ");
256 sb.append("Team[" + id + "]");
257 }
258 sb.append(".");
259 if (log != null && log.isLoggable(Level.WARNING)) {
260 log.warning(sb.toString());
261 }
262 }
263
264 if (log != null && log.isLoggable(Level.WARNING)) {
265 log.warning(config.getMatchId().getToken() + ": MATCH FINISHED!");
266 }
267
268 return processResults(ucc, server, analyzer, bots, winners, scores, teamScores);
269
270 } catch (Exception e) {
271 exception = true;
272 throw new PogamutException("Failed to perform the match!", e, log, this);
273 } finally {
274 for (Entry<IToken, FlagListener<Boolean>> entry : customBotObservers.entrySet()) {
275 bots.bots.get(entry.getKey()).getRunning().removeListener(entry.getValue());
276 }
277 server.getState().removeListener(serverObs);
278 server.getWorldView().removeEventListener(PlayerScore.class, scoresListener);
279 }
280
281 }
282
283 protected UT2004CaptureTheFlagResult processResults(UCCWrapper ucc, UT2004Server server, UT2004Analyzer analyzer, Bots bots, List<Integer> winners, Map<UnrealId, PlayerScore> finalScores, Map<Integer, TeamScore> teamScores) {
284
285 if (log != null && log.isLoggable(Level.FINE)) {
286 log.fine(config.getMatchId().getToken() + ": Processing results...");
287 }
288
289 UT2004CaptureTheFlagResult result = new UT2004CaptureTheFlagResult();
290
291 result.setMatchTimeEnd(((double)bots.matchEnd - (double)bots.matchStart) / (1000));
292
293 for (Entry<Integer, TeamScore> entry : teamScores.entrySet()) {
294 result.getTeamScores().put(entry.getKey(), entry.getValue());
295 }
296
297 for (Entry<UnrealId, PlayerScore> entry : finalScores.entrySet()) {
298 result.getFinalScores().put(bots.getBotId(entry.getKey()), entry.getValue());
299 }
300
301 for (Entry<IToken, IUT2004AnalyzerObserver> entry : bots.botObservers.entrySet()) {
302 if (!(entry.getValue() instanceof UT2004AnalyzerObsStats)) {
303 throw new PogamutException("There is an observer of wrong class, expecting UT2004AnalyzerObsStats, got " + entry.getValue().getClass().getSimpleName() + "!", log, this);
304 }
305 result.getBotObservers().put(entry.getKey(), (UT2004AnalyzerObsStats)entry.getValue());
306 }
307
308 List<IToken> botIds = config.getAllBotIds();
309 for (IToken botId1 : botIds) {
310 result.getTotalKills().put(botId1, 0);
311 result.getWasKilled().put(botId1, 0);
312 result.getSuicides().put(botId1, 0);
313 for (IToken botId2 : botIds) {
314 result.getKillCounts().put(botId1, botId2, 0);
315 }
316 }
317
318 for (Entry<IToken, UT2004AnalyzerObsStats> entry : result.getBotObservers().entrySet()) {
319 IToken botId = entry.getKey();
320 UT2004AnalyzerObsStats obs = entry.getValue();
321 AgentStats stats = obs.getStats();
322 for (Entry<UnrealId, Integer> killed : stats.getKilled().entrySet()) {
323 result.getKillCounts().get(botId).put(bots.getBotId(killed.getKey()), killed.getValue());
324 }
325 for (Entry<UnrealId, Integer> killedBy : stats.getKilledBy().entrySet()) {
326 if (bots.isNativeBot(killedBy.getKey())) {
327 result.getKillCounts().get(bots.getBotId(killedBy.getKey())).put(botId, killedBy.getValue());
328 }
329 }
330 result.getSuicides().put(botId, stats.getSuicides());
331 result.getKillCounts().put(botId, botId, stats.getSuicides());
332 }
333
334 for (IToken nativeBotId1 : config.getNativeBots().keySet()) {
335 for (IToken nativeBotId2 : config.getNativeBots().keySet()) {
336 if (nativeBotId1 == nativeBotId2) continue;
337 result.getKillCounts().get(nativeBotId1).put(nativeBotId2, 0);
338 }
339 result.getSuicides().put(nativeBotId1, 0);
340 }
341
342 for (IToken botId : botIds) {
343 int totalKills = 0;
344 int totalKilled = 0;
345 for (IToken other : botIds) {
346 if (botId == other) continue;
347 totalKills += result.getKillCounts().get(botId, other);
348 totalKilled += result.getKillCounts().get(other, botId);
349 }
350 result.getTotalKills().put(botId, totalKills);
351 result.getWasKilled().put(botId, totalKilled);
352 if (config.isNativeBot(botId)) {
353 result.getSuicides().put(botId, result.getFinalScores().get(botId).getDeaths() - totalKilled);
354 }
355 }
356
357 if (winners.size() <= 0) {
358 throw new PogamutException("There is no winner, impossible! **puzzled**", log, this);
359 } else
360 if (winners.size() == 1) {
361 result.setWinnerTeam(winners.get(0));
362 } else {
363 result.setDraw(true);
364 }
365
366 if (log != null && log.isLoggable(Level.WARNING)) {
367 log.warning(config.getMatchId().getToken() + ": Results processed, " + (result.isDraw() ? "DRAW!" : "winner is Team[" + winners.get(0) + "]."));
368 }
369
370 return result;
371 }
372
373 protected void outputResults_step1(UT2004CaptureTheFlagResult result, File outputDirectory) {
374 if (log != null && log.isLoggable(Level.FINE)) {
375 log.fine(config.getMatchId().getToken() + ": Outputting match result into CSV file...");
376 }
377
378 File file = new File(outputDirectory.getAbsolutePath() + File.separator + "match-" + config.getMatchId().getToken() + "-result.csv");
379 FilePath.makeDirsToFile(file);
380 try {
381 Formatter writer = new Formatter(file);
382 writer.format("MatchId;ScoreLimit;TimeLimit;TimeEnd;Winner\n");
383 writer.format
384 (
385 "%s;%d;%d;%.3f;%s",
386 config.getMatchId().getToken(),
387 config.getScoreLimit(),
388 config.getTimeLimit(),
389 result.getMatchTimeEnd(),
390 result.isDraw() ? "DRAW" : "TEAM" + String.valueOf(result.getWinnerTeam())
391 );
392 try {
393 writer.close();
394 } catch (Exception e) {
395 }
396 } catch (IOException e) {
397 throw new PogamutIOException("Failed to write results!", e, log, this);
398 }
399
400 if (log != null && log.isLoggable(Level.INFO)) {
401 log.info(config.getMatchId().getToken() + ": Match result output into " + file.getAbsolutePath() + ".");
402 }
403
404 }
405
406 protected void outputResults_step2(UT2004CaptureTheFlagResult result, File outputDirectory) {
407 if (log != null && log.isLoggable(Level.FINE)) {
408 log.fine(config.getMatchId().getToken() + ": Outputting match scores into CSV file...");
409 }
410
411 File file = new File(outputDirectory.getAbsolutePath() + File.separator + "match-" + config.getMatchId().getToken() + "-team-scores.csv");
412 FilePath.makeDirsToFile(file);
413 try {
414 Formatter writer = new Formatter(file);
415
416 List<TeamScore> teams = new ArrayList<TeamScore>();
417 for (TeamScore score : result.getTeamScores().values()) {
418 teams.add(score);
419 }
420
421 Collections.sort(teams, new Comparator<TeamScore>() {
422 @Override
423 public int compare(TeamScore o1, TeamScore o2) {
424 return o1.getTeam().compareTo(o2.getTeam());
425 }
426 });
427
428 writer.format("teamId");
429 writer.format(";score");
430
431 for (TeamScore score : teams) {
432 writer.format("\n");
433 writer.format("%s", "TEAM" + score.getTeam());
434 writer.format(";%d", score.getScore());
435 }
436
437 try {
438 writer.close();
439 } catch (Exception e) {
440 }
441 } catch (IOException e) {
442 throw new PogamutIOException("Failed to write results!", e, log, this);
443 }
444
445 file = new File(outputDirectory.getAbsolutePath() + File.separator + "match-" + config.getMatchId().getToken() + "-bot-scores.csv");
446 FilePath.makeDirsToFile(file);
447 try {
448 Formatter writer = new Formatter(file);
449
450 List<IToken> bots = new ArrayList<IToken>(config.getBots().keySet());
451 List<IToken> nativeBots = new ArrayList<IToken>(config.getNativeBots().keySet());
452
453 Collections.sort(bots, new Comparator<IToken>() {
454 @Override
455 public int compare(IToken o1, IToken o2) {
456 return o1.getToken().compareTo(o2.getToken());
457 }
458 });
459 Collections.sort(nativeBots, new Comparator<IToken>() {
460 @Override
461 public int compare(IToken o1, IToken o2) {
462 return o1.getToken().compareTo(o2.getToken());
463 }
464 });
465 result.setBots(bots);
466 result.setNativeBots(nativeBots);
467
468 writer.format("botId");
469 writer.format(";score;kills;killedByOthers;deaths;suicides");
470 for (IToken token : config.getAllBotIds()) {
471 writer.format(";");
472 writer.format(token.getToken());
473 }
474
475 for (IToken token : config.getAllBotIds()) {
476 writer.format("\n");
477 writer.format(token.getToken());
478 writer.format(";%d", result.getFinalScores().get(token).getScore());
479 writer.format(";%d", result.getTotalKills().get(token));
480 writer.format(";%d", result.getWasKilled().get(token));
481 writer.format(";%d", result.getFinalScores().get(token).getDeaths());
482 writer.format(";%d", result.getSuicides().get(token));
483 for (IToken token2 : config.getAllBotIds()) {
484 writer.format(";%d", result.getKillCounts().get(token).get(token2));
485 }
486 }
487
488 try {
489 writer.close();
490 } catch (Exception e) {
491 }
492 } catch (IOException e) {
493 throw new PogamutIOException("Failed to write results!", e, log, this);
494 }
495
496 if (log != null && log.isLoggable(Level.INFO)) {
497 log.info(config.getMatchId().getToken() + ": Match scores output into " + file.getAbsolutePath() + ".");
498 }
499
500 }
501
502 @Override
503 protected void outputResults(UCCWrapper ucc, UT2004Server server, UT2004Analyzer analyzer, Bots bots, UT2004MatchResult result, File outputDirectory) {
504 if (!(result instanceof UT2004CaptureTheFlagResult)) {
505 throw new PogamutException("Can't out results! Expected results of class UT2004CaptureTheFlagResult and got " + result.getClass().getSimpleName() + "!", log, this);
506 }
507 outputResults_step1((UT2004CaptureTheFlagResult) result, outputDirectory);
508 outputResults_step2((UT2004CaptureTheFlagResult) result, outputDirectory);
509 }
510
511 @Override
512 public UT2004CaptureTheFlagResult execute() {
513 try {
514 if (log != null && log.isLoggable(Level.WARNING)) {
515 log.warning(config.getMatchId().getToken() + ": Executing!");
516 }
517 } catch (Exception e) {
518 }
519
520 UCCWrapper ucc = null;
521 UT2004Server server = null;
522 Bots bots = null;
523 UT2004Analyzer analyzer = null;
524 String recordFileName = config.getMatchId().getToken() + "-replay-" + UT2004Match.getCurrentDate();
525 boolean exception = false;
526
527 try {
528
529 setupLogger();
530
531
532 validate();
533
534
535 createGB2004Ini();
536
537
538 ucc = startUCC();
539
540
541 server = startControlServer(ucc);
542
543
544 bots = startBots(ucc, server);
545
546
547 analyzer = startAnalyzer(ucc, bots, getOutputPath("bots"));
548
549
550 matchIsAboutToBegin(ucc, server, analyzer, bots);
551
552
553 restartMatch(server, bots);
554
555
556 recordReplay(server, recordFileName);
557
558
559 UT2004CaptureTheFlagResult result = (UT2004CaptureTheFlagResult) waitMatchFinish(ucc, server, analyzer, bots, config.getTimeLimit() * 1000 + 60 * 1000);
560
561
562 copyReplay(ucc, recordFileName, getOutputPath());
563
564
565 outputResults(ucc, server, analyzer, bots, result, getOutputPath());
566
567
568 shutdownAll(ucc, server, analyzer, bots);
569
570 ucc = null;
571 server = null;
572 analyzer = null;
573 bots = null;
574
575
576 return result;
577
578 } catch (Exception e) {
579 if (log != null && log.isLoggable(Level.SEVERE)) {
580 log.severe(ExceptionToString.process(config.getMatchId().getToken() + ": EXCEPTION!", e));
581 }
582 exception = true;
583 if (e instanceof PogamutException) throw (PogamutException)e;
584 throw new PogamutException(e, log, this);
585 } finally {
586 try {
587 if (log != null && log.isLoggable(Level.INFO)) {
588 log.info(config.getMatchId().getToken() + ": Cleaning up...");
589 }
590 } catch (Exception e) {
591 }
592
593 if (ucc != null) {
594 try {
595 if (log != null && log.isLoggable(Level.INFO)) {
596 log.info(config.getMatchId().getToken() + ": Killing UCC...");
597 }
598 } catch (Exception e) {
599 }
600 try {
601 ucc.stop();
602 } catch (Exception e) {
603 }
604 }
605 if (server != null) {
606 try {
607 if (log != null && log.isLoggable(Level.INFO)) {
608 log.info(config.getMatchId().getToken() + ": Killing UT2004Server...");
609 }
610 } catch (Exception e) {
611 }
612 try {
613 server.kill();
614 } catch (Exception e) {
615 }
616 }
617 if (bots != null) {
618 try {
619 if (log != null && log.isLoggable(Level.INFO)) {
620 log.info(config.getMatchId().getToken() + ": Killing Custom bots...");
621 }
622 } catch (Exception e) {
623 }
624 for (UT2004BotExecution exec : bots.bots.values()) {
625 try {
626 exec.stop();
627 } catch (Exception e) {
628 }
629 }
630 try {
631 if (log != null && log.isLoggable(Level.INFO)) {
632 log.info(config.getMatchId().getToken() + ": Killing Custom bot observers...");
633 }
634 } catch (Exception e) {
635 }
636 for (IUT2004AnalyzerObserver obs : bots.botObservers.values()) {
637 try {
638 obs.kill();
639 } catch (Exception e) {
640 }
641 }
642 }
643 if (analyzer != null) {
644 try {
645 if (log != null && log.isLoggable(Level.INFO)) {
646 log.info(config.getMatchId().getToken() + ": Killing UT2004Analyzer...");
647 }
648 } catch (Exception e) {
649 }
650 try {
651 analyzer.kill();
652 } catch (Exception e) {
653 }
654 }
655
656 try {
657
658 restoreGB2004IniBackup();
659 } catch (Exception e) {
660 }
661
662 try {
663 if (log != null && log.isLoggable(Level.WARNING)) {
664 if (exception) {
665 log.warning(config.getMatchId().getToken() + ": Cleaned up, MATCH FAILED!");
666 } else {
667 log.warning(config.getMatchId().getToken() + ": Cleaned up, match finished successfully.");
668 }
669 }
670 } catch (Exception e) {
671 }
672 try {
673 closeLogger();
674 } catch (Exception e) {
675
676 }
677 }
678
679 }
680
681 }