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