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