View Javadoc

1   package cz.cuni.amis.pogamut.ut2004.tournament;
2   
3   import java.io.File;
4   import java.util.Iterator;
5   import java.util.logging.Level;
6   
7   import com.martiansoftware.jsap.FlaggedOption;
8   import com.martiansoftware.jsap.JSAP;
9   import com.martiansoftware.jsap.JSAPException;
10  import com.martiansoftware.jsap.JSAPResult;
11  import com.martiansoftware.jsap.Switch;
12  
13  import cz.cuni.amis.pogamut.base.utils.logging.LogCategory;
14  import cz.cuni.amis.pogamut.ut2004.tournament.capturetheflag.UT2004CaptureTheFlag;
15  import cz.cuni.amis.pogamut.ut2004.tournament.capturetheflag.UT2004CaptureTheFlagConfig;
16  import cz.cuni.amis.pogamut.ut2004.tournament.deathmatch.UT2004DeathMatch;
17  import cz.cuni.amis.pogamut.ut2004.tournament.deathmatch.UT2004DeathMatchConfig;
18  import cz.cuni.amis.pogamut.ut2004.tournament.match.UT2004BotConfig;
19  import cz.cuni.amis.pogamut.ut2004.tournament.match.UT2004HumanConfig;
20  import cz.cuni.amis.pogamut.ut2004.tournament.match.UT2004MatchConfig;
21  import cz.cuni.amis.pogamut.ut2004.tournament.match.UT2004NativeBotConfig;
22  import cz.cuni.amis.pogamut.ut2004.tournament.teamdeathmatch.UT2004TeamDeathMatch;
23  import cz.cuni.amis.pogamut.ut2004.tournament.teamdeathmatch.UT2004TeamDeathMatchConfig;
24  
25  public class UT2004MatchConsole {
26  	
27  	public enum MatchType {
28  		
29  		DM("DM", "Death Match", false, "BotDeathMatch"),
30  		TDM("TDM", "Team Death Match", true, "BotTeamGame"),
31  		CTF("CTF", "Capture the flag", true, "BotCTFGame"),
32  		DD("DD", "Double Domination", true, "BotDoubleDomination"),
33  		;
34  		
35  		String shortName;
36  		String name;
37  		boolean teamGame;
38  		String uccGameType;
39  		
40  		private MatchType(String shortName, String name, boolean teamGame, String uccGameType) {
41  			this.shortName = shortName;
42  			this.name = name;
43  			this.teamGame = teamGame;
44  			this.uccGameType = uccGameType;
45  		}
46  		
47  	}
48  	
49  	private static final char ARG_MATCH_TYPE_SHORT = 'y';
50  	
51  	private static final String ARG_MATCH_TYPE_LONG = "match-type";
52  	
53  	private static final char ARG_UT2004_HOME_DIR_SHORT = 'u';
54  	
55  	private static final String ARG_UT2004_HOME_DIR_LONG = "ut2004-home-dir";
56  	
57  	private static final char ARG_NATIVE_COUNT_SHORT = 'c';
58  	
59  	private static final String ARG_NATIVE_COUNT_LONG = "native-count";
60  	
61  	private static final char ARG_NATIVE_NAMES_SHORT = 'd';
62  	
63  	private static final String ARG_NATIVE_NAMES_LONG = "native-names";
64  	
65  	private static final char ARG_NATIVE_SKILLS_SHORT = 'e';
66  	
67  	private static final String ARG_NATIVE_SKILLS_LONG = "native-skills";
68  	
69  	private static final char ARG_NATIVE_TEAMS_SHORT = 'g';
70  	
71  	private static final String ARG_NATIVE_TEAMS_LONG = "native-teams";
72  	
73  	private static final char ARG_HUMAN_COUNT_SHORT = 'x';
74  	
75  	private static final String ARG_HUMAN_COUNT_LONG = "human-count";
76  	
77  	private static final char ARG_HUMAN_TEAMS_SHORT = 'z';
78  	
79  	private static final String ARG_HUMAN_TEAMS_LONG = "human-teams";
80  	
81  	private static final char ARG_BOT_JARs_SHORT = 'a';
82  	
83  	private static final String ARG_BOT_JARs_LONG = "bot-jars";
84  	
85  	private static final char ARG_BOT_NAMES_SHORT = 'b';
86  	
87  	private static final String ARG_BOT_NAMES_LONG = "bot-names";
88  	
89  	private static final char ARG_BOT_SKINS_SHORT = 'k';
90  	
91  	private static final String ARG_BOT_SKINS_LONG = "bot-skins";
92  	
93  	private static final char ARG_BOT_SKILLS_SHORT = 'l';
94  	
95  	private static final String ARG_BOT_SKILLS_LONG = "bot-skills";
96  	
97  	private static final char ARG_BOT_TEAMS_SHORT = 'i';
98  	
99  	private static final String ARG_BOT_TEAMS_LONG = "bot-teams";
100 	
101 	private static final char ARG_MAP_NAME_SHORT = 'm';
102 	
103 	private static final String ARG_MAP_NAME_LONG = "map-name";
104 	
105 	private static final char ARG_MATCH_NAME_SHORT = 'n';
106 	
107 	private static final String ARG_MATCH_NAME_LONG = "match-name";
108 	
109 	private static final char ARG_RESULT_DIR_SHORT = 'r';
110 	
111 	private static final String ARG_RESULT_DIR_LONG = "result-directory";
112 	
113 	private static final char ARG_SERVER_NAME_SHORT = 's';
114 	
115 	private static final String ARG_SERVER_NAME_LONG = "server-name";
116 	
117 	private static final char ARG_SCORE_LIMIT_SHORT = 'f';
118 	
119 	private static final String ARG_SCORE_LIMIT_LONG = "score-limit";
120 	
121 	private static final char ARG_TIMEOUT_MINUTES_SHORT = 't';
122 	
123 	private static final String ARG_TIMEOUT_MINUTES_LONG = "timeout-minutes";
124 	
125 	private static final char ARG_HUMAN_LIKE_LOG_SHORT = 'h';
126 	
127 	private static final String ARG_HUMAN_LIKE_LOG_LONG = "human-like-log";
128 	
129 	private static final char ARG_UT2004_PORT_SHORT = 'p';
130 	
131 	private static final String ARG_UT2004_PORT_LONG = "ut2004-port";
132 
133 	private static JSAP jsap;
134 
135 	private static boolean headerOutput = false;
136 
137 	private static String ut2004HomeDir;
138 	
139 	private static int nativeCount;
140 	
141 	private static String matchTypeName;
142 	
143 	private static MatchType matchType;
144 	
145 	private static String nativeNames;
146 	
147 	private static String[] nativeNamesSeparated;
148 	
149 	private static String nativeSkills;
150 	
151 	private static String[] nativeSkillsSeparated;
152 	
153 	private static Integer[] nativeSkillsNumbers;
154 	
155 	private static String nativeTeams;
156 	
157 	private static String[] nativeTeamsSeparated;
158 	
159 	private static Integer[] nativeTeamsNumbers;
160 	
161 	public static int humanCount;
162 	
163 	private static String humanTeams;
164 	
165 	private static String[] humanTeamsSeparated;
166 	
167 	private static Integer[] humanTeamsNumbers;
168 
169 	private static int botCount;
170 	
171 	private static String botJars;
172 	
173 	private static String[] botJarsSeparated;
174 
175 	private static String botNames;
176 	
177 	private static String[] botNamesSeparated;
178 	
179 	private static String botSkills;
180 	
181 	private static String[] botSkillsSeparated;
182 	
183 	private static Integer[] botSkillsNumbers;
184 	
185 	private static String botTeams;
186 	
187 	private static String[] botTeamsSeparated;
188 	
189 	private static Integer[] botTeamsNumbers;
190 	
191 	private static String botSkins;
192 	
193 	private static String[] botSkinsSeparated;
194 	
195 	private static File[] botJarFiles;
196 	
197 	private static String map;
198 
199 	private static String serverName;
200 
201 	private static String resultDir;
202 
203 	private static String matchName;
204 	
205 	private static int scoreLimit;
206 	
207 	private static int timeoutMinutes;
208 
209 	private static JSAPResult config;
210 
211 	private static File ut2004HomeDirFile;
212 
213 	private static File bot1JarFile;
214 
215 	private static File bot2JarFile;
216 
217 	private static File mapsDirFile;
218 
219 	private static File mapFile;
220 
221 	private static File ut2004SystemDirFile;
222 
223 	private static File ut2004IniFile;
224 
225 	private static boolean humanLikeLog;
226 
227 	private static int ut2004Port;	
228 	
229 	private static void fail(String errorMessage) {
230 		fail(errorMessage, null);
231 	}
232 
233 	private static void fail(String errorMessage, Throwable e) {
234 		header();
235 		System.out.println("ERROR: " + errorMessage);
236 		System.out.println();
237 		if (e != null) {
238 			e.printStackTrace();
239 			System.out.println("");
240 		}		
241         System.out.println("Usage: java -jar ut2004-tournament-1v1....jar ");
242         System.out.println("                " + jsap.getUsage());
243         System.out.println();
244         System.out.println(jsap.getHelp());
245         System.out.println();
246         throw new RuntimeException("FAILURE: " + errorMessage);
247 	}
248 
249 	private static void header() {
250 		if (headerOutput) return;
251 		System.out.println();
252 		System.out.println("=============================");
253 		System.out.println("Pogamut UT2004 Match Executor");
254 		System.out.println("=============================");
255 		System.out.println();
256 		headerOutput = true;
257 	}
258 	
259 	private static String getMatchTypes() {
260 		StringBuffer sb = new StringBuffer();
261 		boolean first = true;
262 		for (MatchType matchType : MatchType.values()) {
263 			if (first) first = false;
264 			else sb.append(", ");
265 			sb.append(matchType.shortName + " (" + matchType.name + ")");
266 		}
267 		return sb.toString();
268 	}
269 	
270 	private static void initJSAP() throws JSAPException {
271 		jsap = new JSAP();
272 		    	
273     	FlaggedOption opt1 = new FlaggedOption(ARG_UT2004_HOME_DIR_LONG)
274         	.setStringParser(JSAP.STRING_PARSER)
275         	.setRequired(true) 
276         	.setShortFlag(ARG_UT2004_HOME_DIR_SHORT)
277         	.setLongFlag(ARG_UT2004_HOME_DIR_LONG);    
278         opt1.setHelp("UT2004 home directory containing GameBots2004 (System/GameBots2004.u) present.");
279         
280         jsap.registerParameter(opt1);
281         
282         FlaggedOption opt111 = new FlaggedOption(ARG_MATCH_TYPE_LONG)
283 	    	.setStringParser(JSAP.STRING_PARSER)
284 	    	.setRequired(true) 
285 	    	.setShortFlag(ARG_MATCH_TYPE_SHORT)
286 	    	.setLongFlag(ARG_MATCH_TYPE_LONG);    
287 	    opt111.setHelp("Type of the match to execute. Valid values: " + getMatchTypes());
288 	    
289 	    jsap.registerParameter(opt111);
290         
291         FlaggedOption opt2 = new FlaggedOption(ARG_BOT_JARs_LONG)
292 	    	.setStringParser(JSAP.STRING_PARSER)
293 	    	.setRequired(false) 
294 	    	.setShortFlag(ARG_BOT_JARs_SHORT)
295 	    	.setLongFlag(ARG_BOT_JARs_LONG);    
296 	    opt2.setHelp("Semicolon separated PATH/TO/JAR/file1;PATH/TO/JAR/file2 containing executable jars of bots.");
297 	
298 	    jsap.registerParameter(opt2);
299 	    
300 	    FlaggedOption opt3 = new FlaggedOption(ARG_BOT_NAMES_LONG)
301 	    	.setStringParser(JSAP.STRING_PARSER)
302 	    	.setRequired(false) 
303 	    	.setShortFlag(ARG_BOT_NAMES_SHORT)
304 	    	.setLongFlag(ARG_BOT_NAMES_LONG);    
305 	    opt3.setHelp("Semicolon separated name1;name2;name3 (ids) that should be given to bots.");
306 	    
307 	    jsap.registerParameter(opt3);
308 	    
309 	    FlaggedOption opt31 = new FlaggedOption(ARG_BOT_SKILLS_LONG)
310 	    	.setStringParser(JSAP.STRING_PARSER)
311 	    	.setRequired(false) 
312 	    	.setShortFlag(ARG_BOT_SKILLS_SHORT)
313 	    	.setLongFlag(ARG_BOT_SKILLS_LONG);    
314 	    opt31.setHelp("Semicolon separated skill1;skill2;skill3 (desired skill levels) that should be given to bots. Can have 'empty space', e.g 1;;2, within to mark 'use bot supplied default value'.");
315 	
316 	    jsap.registerParameter(opt31);
317 	    
318 	    FlaggedOption opt32 = new FlaggedOption(ARG_BOT_SKINS_LONG)
319 	    	.setStringParser(JSAP.STRING_PARSER)
320 	    	.setRequired(false) 
321 	    	.setShortFlag(ARG_BOT_SKINS_SHORT)
322 	    	.setLongFlag(ARG_BOT_SKINS_LONG);    
323 	    opt32.setHelp("Semicolon separated skin1;skin2;skin3 (skins) that should be given to bots. Can have 'empty space', e.g skin1;;skin3, within to mark 'use bot supplied default value'.");
324 	    
325 	    jsap.registerParameter(opt32);
326 	    
327 	    FlaggedOption opt33 = new FlaggedOption(ARG_BOT_TEAMS_LONG)
328 	    	.setStringParser(JSAP.STRING_PARSER)
329 	    	.setRequired(false) 
330 	    	.setShortFlag(ARG_BOT_TEAMS_SHORT)
331 	    	.setLongFlag(ARG_BOT_TEAMS_LONG);    
332 	    opt33.setHelp("Semicolon separated team1;team2;team3 (desired teams) that should bots be in.");
333 	
334 	    jsap.registerParameter(opt33);
335     
336 	    FlaggedOption opt6 = new FlaggedOption(ARG_MAP_NAME_LONG)
337 	    	.setStringParser(JSAP.STRING_PARSER)
338 	    	.setRequired(false) 
339 	    	.setShortFlag(ARG_MAP_NAME_SHORT)
340 	    	.setLongFlag(ARG_MAP_NAME_LONG);    
341 	    opt6.setHelp("Map where the game should be played (e.g. DM-1on1-Albatross).");
342 	
343 	    jsap.registerParameter(opt6);
344         
345 	    FlaggedOption opt7 = new FlaggedOption(ARG_MATCH_NAME_LONG)
346 	    	.setStringParser(JSAP.STRING_PARSER)
347 	    	.setRequired(false) 
348 	    	.setShortFlag(ARG_MATCH_NAME_SHORT)
349 	    	.setLongFlag(ARG_MATCH_NAME_LONG)
350 	    	.setDefault("DMMatch1v1");    
351 	    opt7.setHelp("Name of the match == output folder for the results.");
352 	
353 	    jsap.registerParameter(opt7);
354 	    
355 	    FlaggedOption opt8 = new FlaggedOption(ARG_RESULT_DIR_LONG)
356 	    	.setStringParser(JSAP.STRING_PARSER)
357 	    	.setRequired(false) 
358 	    	.setShortFlag(ARG_RESULT_DIR_SHORT)
359 	    	.setLongFlag(ARG_RESULT_DIR_LONG)
360 	    	.setDefault(".");
361 	    opt8.setHelp("PATH/TO/directory where to output results (does not need to exist).");
362 	
363 	    jsap.registerParameter(opt8);
364 	    
365 	    FlaggedOption opt9 = new FlaggedOption(ARG_SERVER_NAME_LONG)
366 			.setStringParser(JSAP.STRING_PARSER)
367 			.setRequired(false) 
368 			.setShortFlag(ARG_SERVER_NAME_SHORT)
369 			.setLongFlag(ARG_SERVER_NAME_LONG)
370 			.setDefault("DMMatch1v1");
371 		opt9.setHelp("Server name that should be advertised via LAN.");
372 		
373 		jsap.registerParameter(opt9);
374 		
375 		FlaggedOption opt10 = new FlaggedOption(ARG_SCORE_LIMIT_LONG)
376 			.setStringParser(JSAP.INTEGER_PARSER)
377 			.setRequired(false) 
378 			.setShortFlag(ARG_SCORE_LIMIT_SHORT)
379 			.setLongFlag(ARG_SCORE_LIMIT_LONG)
380 			.setDefault("20");
381 		opt10.setHelp("DeathMatch - frag limit, Capture The Flag - team score limit");
382 		
383 		jsap.registerParameter(opt10);
384 		
385 		FlaggedOption opt11 = new FlaggedOption(ARG_TIMEOUT_MINUTES_LONG)
386 			.setStringParser(JSAP.INTEGER_PARSER)
387 			.setRequired(false) 
388 			.setShortFlag(ARG_TIMEOUT_MINUTES_SHORT)
389 			.setLongFlag(ARG_TIMEOUT_MINUTES_LONG)
390 			.setDefault("20");
391 		opt11.setHelp("Match timeout in minutes.");
392 		
393 		jsap.registerParameter(opt11);
394 		
395 		Switch opt12 = new Switch(ARG_HUMAN_LIKE_LOG_LONG)
396 			.setShortFlag(ARG_HUMAN_LIKE_LOG_SHORT)
397 			.setLongFlag(ARG_HUMAN_LIKE_LOG_LONG)
398 			.setDefault("false");
399 		opt12.setHelp("Whether to produce log for 'HumanLike Project' analysis.");
400 		
401 		jsap.registerParameter(opt12);
402 		
403 		FlaggedOption opt13 = new FlaggedOption(ARG_UT2004_PORT_LONG)
404 			.setStringParser(JSAP.INTEGER_PARSER)
405 			.setRequired(false) 
406 			.setShortFlag(ARG_UT2004_PORT_SHORT)
407 			.setLongFlag(ARG_UT2004_PORT_LONG)
408 			.setDefault("7777");
409 		opt13.setHelp("UT2004 port for the dedicated server (1-32000).");
410 		
411 		jsap.registerParameter(opt13);
412 		
413 		FlaggedOption opt14 = new FlaggedOption(ARG_NATIVE_COUNT_LONG)
414 			.setStringParser(JSAP.INTEGER_PARSER)
415 			.setRequired(false) 
416 			.setShortFlag(ARG_NATIVE_COUNT_SHORT)
417 			.setLongFlag(ARG_NATIVE_COUNT_LONG)
418 			.setDefault("0");
419 		opt14.setHelp("Number of native bots to participate within the match.");
420 		
421 		jsap.registerParameter(opt14);
422 		
423 		FlaggedOption opt15 = new FlaggedOption(ARG_NATIVE_NAMES_LONG)
424 			.setStringParser(JSAP.STRING_PARSER)
425 			.setRequired(false) 
426 			.setShortFlag(ARG_NATIVE_NAMES_SHORT)
427 			.setLongFlag(ARG_NATIVE_NAMES_LONG);
428 		opt15.setHelp("Semicolon separated name1;name2;... of names to be given to native bots.");
429 		
430 		jsap.registerParameter(opt15);
431 		
432 		FlaggedOption opt16 = new FlaggedOption(ARG_NATIVE_SKILLS_LONG)
433 			.setStringParser(JSAP.STRING_PARSER)
434 			.setRequired(false) 
435 			.setShortFlag(ARG_NATIVE_SKILLS_SHORT)
436 			.setLongFlag(ARG_NATIVE_SKILLS_LONG);
437 		opt16.setHelp("Semicolon separated skill1;skill2;... of skill levels of native bots.");
438 		
439 		jsap.registerParameter(opt16);
440 		
441 		FlaggedOption opt17 = new FlaggedOption(ARG_NATIVE_TEAMS_LONG)
442 			.setStringParser(JSAP.STRING_PARSER)
443 			.setRequired(false) 
444 			.setShortFlag(ARG_NATIVE_TEAMS_SHORT)
445 			.setLongFlag(ARG_NATIVE_TEAMS_LONG);
446 		opt17.setHelp("Semicolon separated team1;team2;... of teams the native bots should be in.");
447 		
448 		jsap.registerParameter(opt17);
449 		
450 		FlaggedOption opt20 = new FlaggedOption(ARG_HUMAN_COUNT_LONG)
451 			.setStringParser(JSAP.INTEGER_PARSER)
452 			.setRequired(false) 
453 			.setShortFlag(ARG_HUMAN_COUNT_SHORT)
454 			.setLongFlag(ARG_HUMAN_COUNT_LONG)
455 			.setDefault("0");
456 		opt20.setHelp("Number of humans that should participate in the match.");
457 		
458 		jsap.registerParameter(opt20);
459 		
460 		FlaggedOption opt21 = new FlaggedOption(ARG_HUMAN_TEAMS_LONG)
461 			.setStringParser(JSAP.STRING_PARSER)
462 			.setRequired(false) 
463 			.setShortFlag(ARG_HUMAN_TEAMS_SHORT)
464 			.setLongFlag(ARG_HUMAN_TEAMS_LONG);
465 		opt21.setHelp("Semicolon separated team1;team2;... of teams humans should be in.");
466 		
467 		jsap.registerParameter(opt21);
468 	}
469 
470 	private static void readConfig(String[] args) {
471 		System.out.println("Parsing command arguments.");
472 		
473 		try {
474 	    	config = jsap.parse(args);
475 	    } catch (Exception e) {
476 	    	fail(e.getMessage());
477 	    	System.out.println("");
478 	    	e.printStackTrace();
479 	    	throw new RuntimeException("FAILURE!");
480 	    }
481 		
482 		if (!config.success()) {
483 			String error = "Invalid arguments specified.";
484 			Iterator errorIter = config.getErrorMessageIterator();
485 			if (!errorIter.hasNext()) {
486 				error += "\n-- No details given.";
487 			} else {
488 				while (errorIter.hasNext()) {
489 					error += "\n-- " + errorIter.next();
490 				}
491 			}
492 			fail(error);
493     	}
494 		
495 		ut2004HomeDir = config.getString(ARG_UT2004_HOME_DIR_LONG);
496 		
497 		matchTypeName = config.getString(ARG_MATCH_TYPE_LONG);
498 		
499 		botJars = config.getString(ARG_BOT_JARs_LONG);
500 	    botJarsSeparated = botJars == null ? null : botJars.split(";");
501 	    botCount = botJarsSeparated == null ? 0 : botJarsSeparated.length;
502 	    botNames = config.getString(ARG_BOT_NAMES_LONG);
503 	    botNamesSeparated = botNames == null ? null : botNames.split(";");
504 	    botSkills = config.getString(ARG_BOT_SKILLS_LONG);
505 	    botSkillsSeparated = botSkills == null || botSkills.length() == 0 ? null : botSkills.split(";");
506 	    botSkins = config.getString(ARG_BOT_SKINS_LONG);
507 	    botSkinsSeparated = botSkins == null || botSkins.length() == 0 ? null : botSkins.split(";");
508 	    botTeams = config.getString(ARG_BOT_TEAMS_LONG);
509 	    botTeamsSeparated = botTeams == null || botTeams.length() == 0 ? null : botTeams.split(";");
510 	    
511 	    nativeCount = config.getInt(ARG_NATIVE_COUNT_LONG);
512 	    nativeNames = config.getString(ARG_NATIVE_NAMES_LONG);
513 	    nativeNamesSeparated = nativeNames == null ? null : nativeNames.split(";");
514 	    nativeSkills = config.getString(ARG_NATIVE_SKILLS_LONG);
515 	    nativeSkillsSeparated = nativeSkills == null ? null : nativeSkills.split(";");
516 	    nativeTeams = config.getString(ARG_NATIVE_TEAMS_LONG);
517 	    nativeTeamsSeparated = nativeTeams == null ? null : nativeTeams.split(";");
518 	    
519 	    humanCount = config.getInt(ARG_HUMAN_COUNT_LONG);
520 	    humanTeams = config.getString(ARG_HUMAN_TEAMS_LONG);
521 	    humanTeamsSeparated = humanTeams == null ? null : humanTeams.split(";");
522 	    
523 	    map = config.getString(ARG_MAP_NAME_LONG);
524 	    serverName = config.getString(ARG_SERVER_NAME_LONG);
525 	    resultDir = config.getString(ARG_RESULT_DIR_LONG);
526 	    matchName = config.getString(ARG_MATCH_NAME_LONG);
527 	    scoreLimit = config.getInt(ARG_SCORE_LIMIT_LONG);
528 	    timeoutMinutes = config.getInt(ARG_TIMEOUT_MINUTES_LONG);
529 	    humanLikeLog = config.getBoolean(ARG_HUMAN_LIKE_LOG_LONG);
530 	    ut2004Port = config.getInt(ARG_UT2004_PORT_LONG);
531 	}
532 	
533 	private static void sanityChecks() {
534 		System.out.println("Sanity checks...");
535 		
536 		// UT2004
537 		
538 	    ut2004HomeDirFile = new File(ut2004HomeDir);
539 	    if (!ut2004HomeDirFile.exists() || !ut2004HomeDirFile.isDirectory()) {
540 	    	fail("UT2004 directory was not found at '" + ut2004HomeDirFile.getAbsolutePath() + "', path resolved from configuration read as '" + ut2004HomeDir + "'.");
541 	    }
542 	    System.out.println("-- UT2004 directory found at '" + ut2004HomeDirFile.getAbsolutePath() + "'");
543 	    
544 	    ut2004SystemDirFile = new File(ut2004HomeDirFile, "System");
545 	    if (!ut2004SystemDirFile.exists() || !ut2004SystemDirFile.isDirectory()) {
546 	    	fail("UT2004/System directory was not found at '" + ut2004SystemDirFile.getAbsolutePath() + "', invalid UT2004 installation.");
547 	    }
548 	    System.out.println("-- UT2004/System directory found at '" + ut2004SystemDirFile.getAbsolutePath() + "'");
549 	    
550 	    ut2004IniFile = new File(ut2004SystemDirFile, "UT2004.ini");
551 	    if (!ut2004IniFile.exists() || !ut2004IniFile.isFile()) {
552 	    	fail("UT2004/System/UT2004.ini file was not found at '" + ut2004IniFile.getAbsolutePath() + "', invalid UT2004 installation.");
553 	    }
554 	    System.out.println("-- UT2004/System/UT2004.ini file found at '" + ut2004IniFile.getAbsolutePath() + "'");
555 	    
556 	    // MATCH TYPE
557 	    for (MatchType validMatchType : MatchType.values()) {
558 	    	if (validMatchType.shortName.equalsIgnoreCase(matchTypeName)) {
559 	    		matchType = validMatchType;
560 	    		break;
561 	    	}
562 	    }
563 	    if (matchType == null) {
564 	    	fail("Invalid match type specified '" + matchTypeName + "', valid values: " + getMatchTypes());
565 	    }
566 	    
567 	    System.out.println("-- Match type set as " + matchType.name + " (" + matchType.shortName + ")");
568 	    
569 	    // BOTS
570 	    
571 	    if (botCount > 0) {
572 	    	
573 	    	System.out.println("-- Adding " + botCount + " custom bots into the match");
574 	    	
575 		    if (botNamesSeparated == null) {
576 				fail("Bot name(s) was/were not specified correctly.");
577 			}
578 			
579 			if (botJarsSeparated.length != botNamesSeparated.length) {
580 				fail("Bot jar(s) and name(s) numbers mismatch. I've parsed " + botJarsSeparated.length + " bot jar files != " + botNamesSeparated.length + " of bot names.");
581 			}
582 			
583 			if (botSkillsSeparated != null && botSkillsSeparated.length != botJarsSeparated.length) {
584 				fail("Bot jar(s) and skills(s) numbers mismatch. I've parsed " + botJarsSeparated.length + " bot jar files != " + botSkillsSeparated.length + " of bot skill levels.");
585 			}
586 			
587 			if (botSkinsSeparated != null && botSkinsSeparated.length != botJarsSeparated.length) {
588 				fail("Bot jar(s) and skins(s) numbers mismatch. I've parsed " + botJarsSeparated.length + " bot jar files != " + botSkinsSeparated.length + " of bot skins.");
589 			}
590 			
591 			botJarFiles = new File[botJarsSeparated.length];
592 		    for (int i = 0; i < botJarsSeparated.length; ++i) {
593 		    	botJarFiles[i] = new File(botJarsSeparated[i]);
594 		    	if (!botJarFiles[i].exists() || !botJarFiles[i].isFile()) {
595 			    	fail("Bot" + (i+1) + " jar file was not found at '"+ botJarFiles[i].getAbsolutePath() + "', path resolved from configuration read as '" + botJarsSeparated[i] + "'.");
596 			    }
597 		    	System.out.println("-- Bot" + (i+1) + " jar file found at '" + botJarFiles[i].getAbsolutePath() + "'");
598 		    }
599 		    System.out.println("-- Bot jars ok");
600 		   	
601 		    for (int i = 0; i < botNamesSeparated.length; ++i) {
602 		    	if (botNamesSeparated[i] == null || botNamesSeparated[i].isEmpty()) {
603 		    		fail("Bot " + (i+1) + " invalid name '" + botNamesSeparated[i] +"' specified.");
604 		    	}
605 		    	System.out.println("-- Bot" + (i+1) + " name set as '" + botNamesSeparated[i] + "'");
606 		    }
607 		    System.out.println("-- Bot names ok");
608 		    
609 		    if (botSkillsSeparated != null) {
610 		    	botSkillsNumbers = new Integer[botSkillsSeparated.length];
611 		    	for (int i = 0; i < botSkillsSeparated.length; ++i) {
612 		    		if (botSkillsSeparated[i] == null || botSkillsSeparated[i].length() == 0) {
613 		    			botSkillsNumbers[i] = null;
614 		    			System.out.println("-- Bot" + (i+1) + " skill level will be set to default");
615 		    			continue;
616 		    		} 
617 		    		
618 		    		Integer number = null;
619 		    		try {
620 		    			number = Integer.parseInt(botSkillsSeparated[i]);
621 		    		} catch (Exception e) {
622 		    			fail("Bot " + (i+1) + " skill level specified as '" + botSkillsSeparated[i] + "', which is not a number!");
623 		    		}
624 		    		if (number < 0 || number > 7) {
625 		    			fail("Bot " + (i+1) + " skill level specified as '" + botSkillsSeparated[i] + "' and parsed as '" + number + "', which is of unsupported value, not from the range 0-7!");
626 		    		}
627 		    		
628 		    		botSkillsNumbers[i] = number;
629 		    		
630 		    		System.out.println("-- Bot" + (i+1) + " skill level set to " + number);
631 		    	}
632 		    	
633 		    	System.out.println("-- Bot skills ok");
634 		    }
635 		    
636 		    if (botSkinsSeparated != null) {
637 		    	for (int i = 0; i < botSkinsSeparated.length; ++i) {
638 		    		if (botSkinsSeparated[i] == null || botSkinsSeparated[i].length() == 0) {
639 		    			botSkinsSeparated[i] = null;
640 		    			System.out.println("-- Bot" + (i+1) + " skin will be supplied by the bot itself");
641 		    			continue;
642 		    		} 
643 		    		System.out.println("-- Bot" + (i+1) + " skin set to '" + botSkinsSeparated[i] + "'");
644 		    	}
645 		    	
646 		    	System.out.println("-- Bot skins ok");
647 		    }
648 	    
649 		    if (matchType.teamGame) {
650 		    	if (botTeamsSeparated == null) {
651 		    		fail("Bot teams not specified, but a team game specified (" + matchType.name + ").");
652 		    	}
653 		    	if (botTeamsSeparated.length != botJarsSeparated.length) {
654 					fail("Bot jar(s) and team(s) numbers mismatch. I've parsed " + botJarsSeparated.length + " bot jar files != " + botTeamsSeparated.length + " of bot teams.");
655 				}
656 	    		botTeamsNumbers = new Integer[botTeamsSeparated.length];
657 		    	for (int i = 0; i < botTeamsSeparated.length; ++i) {
658 		    		if (botTeamsSeparated[i] == null || botTeamsSeparated[i].length() == 0) {
659 		    			fail("Bot" + (i+1) + " does not have a team number specified.");
660 		    			continue;
661 		    		} 
662 		    		
663 		    		Integer number = null;
664 		    		try {
665 		    			number = Integer.parseInt(botTeamsSeparated[i]);
666 		    		} catch (Exception e) {
667 		    			fail("Bot " + (i+1) + " team number specified as '" + botTeamsSeparated[i] + "', which is not a number!");
668 		    		}
669 		    		if (number < 0 || number > 3) {
670 		    			fail("Bot " + (i+1) + " team number specified as '" + botTeamsSeparated[i] + "' and parsed as '" + number + "', which is of unsupported value, not from the range 0-3!");
671 		    		}
672 		    		
673 		    		botTeamsNumbers[i] = number;
674 		    		
675 		    		System.out.println("-- Bot" + (i+1) + " team number set to " + number);
676 		    	}
677 		    	
678 		    	System.out.println("-- Bot teams ok");
679 		    }
680 	    } 
681 	    
682 	    // NATIVES
683 	    
684 	    if (nativeCount > 0) {
685 	    	
686 	    	if (nativeCount < 1 || nativeCount > 16) {
687 	    		fail("Could start match with 1-16 native bots at max!");
688 	    	}
689 	    	
690 	    	System.out.println("-- Adding " + nativeCount + " native bots into the match");
691 	    
692 		    if (nativeNamesSeparated == null) {
693 				fail("Native bot name(s) was/were not specified correctly.");
694 			}
695 			
696 			if (nativeCount != nativeNamesSeparated.length) {
697 				fail("Native bot name(s) numbers invalid. I've parsed " + nativeNamesSeparated.length + " native bot name != " + nativeCount + " of native bot count.");
698 			}
699 			
700 			if (nativeSkillsSeparated == null) {
701 				fail("Native bot skill(s) not specified correctly.");
702 			}
703 			
704 			if (nativeSkillsSeparated.length != nativeCount) {
705 				fail("Native bot skills(s) numbers mismatch. I've parsed " + nativeSkillsSeparated.length + " native bot skills != " + nativeCount + " of native bot count.");
706 			}
707 			
708 		    for (int i = 0; i < nativeNamesSeparated.length; ++i) {
709 		    	if (nativeNamesSeparated[i] == null || nativeNamesSeparated[i].isEmpty()) {
710 		    		fail("Native bot " + (i+1) + " invalid name '" + nativeNamesSeparated[i] +"' specified.");
711 		    	}
712 		    	System.out.println("-- Native bot " + (i+1) + " name set as '" + nativeNamesSeparated[i] + "'");
713 		    }
714 		    System.out.println("-- Native names ok");
715 		    
716 		    nativeSkillsNumbers = new Integer[nativeSkillsSeparated.length];
717 	    	for (int i = 0; i < nativeSkillsSeparated.length; ++i) {
718 	    		if (nativeSkillsSeparated[i] == null || nativeSkillsSeparated[i].length() == 0) {
719 	    			fail("Native bot " + (i+1) + " invalid skill level '" + nativeNamesSeparated[i] +"' specified.");
720 	    		} 
721 	    		
722 	    		Integer number = null;
723 	    		try {
724 	    			number = Integer.parseInt(nativeSkillsSeparated[i]);
725 	    		} catch (Exception e) {
726 	    			fail("Native bot " + i + " skill level specified as '" + nativeSkillsSeparated[i] + "', which is not a number!");
727 	    		}
728 	    		if (number < 0 || number > 7) {
729 	    			fail("Native bot " + i + " skill level specified as '" + nativeSkillsSeparated[i] + "' and parsed as '" + number + "', which is of unsupported value, not from the range 0-7!");
730 	    		}
731 	    		
732 	    		nativeSkillsNumbers[i] = number;
733 	    		
734 	    		System.out.println("-- Native bot " + (i+1) + " skill level set to " + number);
735 	    	}
736 		    	
737 		    System.out.println("-- Native bot skills OK");
738 		    
739 		    if (matchType.teamGame) {
740 		    	if (nativeTeamsSeparated == null) {
741 		    		fail("Native bot teams not specified, but a team game specified (" + matchType.name + ").");
742 		    	}
743 		    	if (nativeTeamsSeparated.length != nativeCount) {
744 					fail("Native bot team(s) and native count numbers mismatch. I've parsed " + nativeCount + " native count != " + nativeTeamsSeparated.length + " of native bot teams.");
745 				}
746 		    	nativeTeamsNumbers = new Integer[nativeTeamsSeparated.length];
747 		    	for (int i = 0; i < nativeTeamsSeparated.length; ++i) {
748 		    		if (nativeTeamsSeparated[i] == null || nativeTeamsSeparated[i].length() == 0) {
749 		    			fail("Native bot " + (i+1) + " does not have team number specified.");
750 		    			continue;
751 		    		} 
752 		    		
753 		    		Integer number = null;
754 		    		try {
755 		    			number = Integer.parseInt(nativeTeamsSeparated[i]);
756 		    		} catch (Exception e) {
757 		    			fail("Native bot " + (i+1) + " team number specified as '" + nativeTeamsSeparated[i] + "', which is not a number!");
758 		    		}
759 		    		if (number < 0 || number > 3) {
760 		    			fail("Native bot " + (i+1) + " team number specified as '" + nativeTeamsSeparated[i] + "' and parsed as '" + number + "', which is of unsupported value, not from the range 0-3!");
761 		    		}
762 		    		
763 		    		nativeTeamsNumbers[i] = number;
764 		    		
765 		    		System.out.println("-- Native bot " + (i+1) + " team number set to " + number);
766 		    	}
767 		    	
768 		    	System.out.println("-- Native bot teams ok");
769 		    }
770 	    }
771 	    
772 	    // HUMANS
773 	    
774 	    if (humanCount > 0) {
775 	    	
776 	    	if (humanCount < 1 || humanCount > 16) {
777 	    		fail("Could start match with 1-16 humans at max!");
778 	    	}
779 	    	
780 	    	System.out.println("-- Expect " + humanCount + " humans to participate in the match");
781 	    
782 		    if (matchType.teamGame) {
783 		    	if (humanTeamsSeparated == null) {
784 		    		fail("Teams for humans not specified, but a team game specified (" + matchType.name + ").");
785 		    	}
786 		    	if (humanTeamsSeparated.length != humanCount) {
787 					fail("Human team(s) and human count numbers mismatch. I've parsed " + humanCount + " human count != " + humanTeamsSeparated.length + " of human bot teams.");
788 				}
789 		    	humanTeamsNumbers = new Integer[humanTeamsSeparated.length];
790 		    	for (int i = 0; i < humanTeamsSeparated.length; ++i) {
791 		    		if (humanTeamsSeparated[i] == null || humanTeamsSeparated[i].length() == 0) {
792 		    			fail("Human " + (i+1) + " does not have a team number specified.");
793 		    			continue;
794 		    		} 
795 		    		
796 		    		Integer number = null;
797 		    		try {
798 		    			number = Integer.parseInt(humanTeamsSeparated[i]);
799 		    		} catch (Exception e) {
800 		    			fail("Human " + (i+1) + " team number specified as '" + humanTeamsSeparated[i] + "', which is not a number!");
801 		    		}
802 		    		if (number < 0 || number > 3) {
803 		    			fail("Human " + (i+1) + " team number specified as '" + humanTeamsSeparated[i] + "' and parsed as '" + number + "', which is of unsupported value, not from the range 0-3!");
804 		    		}
805 		    		
806 		    		humanTeamsNumbers[i] = number;
807 		    		
808 		    		System.out.println("-- Human " + (i+1) + " is expected to belong to the team number" + number);
809 		    	}
810 		    	
811 		    	System.out.println("-- Human teams ok");
812 		    }
813 	    }
814 	    
815 	    // COUNT
816 	    
817 	    if (botCount + nativeCount + humanCount < 2) {
818 	    	fail("There must be at least 2 participants specified, custom + natives + humans = " + botCount + " + " + nativeCount + " + " + humanCount + " = " + (botCount + nativeCount + humanCount) + " < 2.");
819 	    }
820 	    
821 	    // MATCH CONFIG
822 	    
823 	    mapsDirFile = new File(ut2004HomeDirFile, "Maps");
824 	    if (!mapsDirFile.exists() || !mapsDirFile.isDirectory()) {
825 	    	fail("UT2004/Maps directory was not found at '" + mapsDirFile.getAbsolutePath() + "', invalid UT2004 installation.");
826 	    }
827 	    System.out.println("-- UT2004/Maps directory found at '" + mapsDirFile.getAbsolutePath() + "'");
828 	    
829 	    mapFile = new File(mapsDirFile, map + ".ut2");
830 	    if (!mapFile.exists() || !mapFile.isFile()) {
831 	    	fail("Specified map '" + map + "' was not found within UT2004/Maps dir at '" + mapFile.getAbsoluteFile() + "', could not execute the match.");
832 	    }
833 	    System.out.println("-- Map '" + map + "' found at '" + mapFile.getAbsolutePath() + "'");
834 	    
835 	    if (matchName == null || matchName.isEmpty()) {
836 	    	fail("Invalid match name '" + matchName + "' specified.");
837 	    }
838 	    System.out.println("-- Match name set as '" + matchName + "'");
839 	    
840 	    if (serverName == null || serverName.isEmpty()) {
841 	    	fail("Invalid server name '" + serverName + "' specified.");
842 	    }
843 	    System.out.println("-- Server name set as '" + serverName + "'");
844 	    
845 	    if (scoreLimit < 1) {
846 	    	fail("Invalid frag/score limit '" + scoreLimit +"' specified, must be >= 1.");
847 	    }
848 	    System.out.println("-- Frag limit set as '" + scoreLimit + "'");
849 	    
850 	    if (timeoutMinutes < 1) {
851 	    	fail("Invalid time limit '" + timeoutMinutes +"' specified, must be >= 1.");
852 	    }
853 	    System.out.println("-- Timeout set as '" + timeoutMinutes + "' minutes.");
854 	    
855 	    if (ut2004Port < 1 || ut2004Port > 32000) {
856 	    	fail("Invalid UT2004 port specified '" + ut2004Port + "', must be 1 <= port <= 32000.");
857 	    }
858 	    System.out.println("-- UT2004 port set as '" + ut2004Port + "'");
859 
860 	    System.out.println("Sanity checks OK!");
861 	}
862 	
863 	private static void setGenericMatchConfigs(UT2004MatchConfig config) {
864 		// UT2004 INI
865 		config.getUT2004Ini().setPort(ut2004Port);
866 		config.getUT2004Ini().setServerName(serverName, serverName);
867 		config.getUT2004Ini().setDemoSpectatorClass(UT2004Ini.Value_DemoSpectatorClass);
868 		
869 		// UCC
870 		config.getUccConf().setStartOnUnusedPort(true);
871 	    config.getUccConf().setUnrealHome(ut2004HomeDir);	
872 	    config.getUccConf().setGameType(matchType.uccGameType);
873 	    config.getUccConf().setMapName(map);
874 	    
875 	    // OTHERS
876 	    config.setOutputDirectory(new File(resultDir));
877 	    config.setMatchId(matchName);
878 	    config.setHumanLikeLogEnabled(humanLikeLog);
879 	}
880 	
881 	private static UT2004BotConfig[] createBotConfigs() {
882 		if (botCount <= 0) return null;
883 		UT2004BotConfig[] botConfigs = new UT2004BotConfig[botJarFiles.length];
884 		for (int i = 0; i < botJarFiles.length; ++i) {
885 			UT2004BotConfig botConfig = new UT2004BotConfig();
886 			botConfig.setBotId(botNamesSeparated[i]);
887 			botConfig.setPathToBotJar(botJarFiles[i].getAbsolutePath());
888 			if (botSkillsNumbers != null && botSkillsNumbers[i] != null) {
889 				botConfig.setDesiredSkill(botSkillsNumbers[i]);
890 			}
891 			if (botSkinsSeparated != null && botSkinsSeparated[i] != null) {
892 				botConfig.setSkin(botSkinsSeparated[i]);
893 			}
894 			if (matchType.teamGame) {
895 				botConfig.setTeamNumber(botTeamsNumbers[i]);
896 			}
897 			botConfig.setRedirectStdErr(true);
898 			botConfig.setRedirectStdOut(true);
899 			botConfigs[i] = botConfig;
900 		}
901 		return botConfigs;
902 	}
903 	
904 	private static UT2004NativeBotConfig[] createNativeBotConfig() {
905 		if (nativeCount <= 0) return null;
906 		UT2004NativeBotConfig[] nativeConfigs = new UT2004NativeBotConfig[nativeCount];
907 		for (int i = 0; i < nativeCount; ++i) {
908 			UT2004NativeBotConfig nativeConfig = new UT2004NativeBotConfig();
909 			nativeConfig.setBotId(nativeNamesSeparated[i]);
910 			nativeConfig.setDesiredSkill(nativeSkillsNumbers[i]);
911 			if (matchType.teamGame) {
912 				nativeConfig.setTeamNumber(nativeTeamsNumbers[i]);
913 			}
914 			nativeConfigs[i] = nativeConfig;
915 		}
916 		return nativeConfigs;
917 	}
918 	
919 	private static UT2004HumanConfig[] createHumanConfig() {
920 		if (humanCount <= 0) return null;
921 		UT2004HumanConfig[] humanConfigs = new UT2004HumanConfig[humanCount];
922 		for (int i = 0; i < humanCount; ++i) {
923 			UT2004HumanConfig humanConfig = new UT2004HumanConfig();
924 			humanConfig.setHumanId("Human" + i);
925 			if (matchType.teamGame) {
926 				humanConfig.setTeamNumber(humanTeamsNumbers[i]);
927 			}
928 			humanConfigs[i] = humanConfig;
929 		}
930 		return humanConfigs;
931 	}
932 	
933 	private static void executeDeathMatch() {
934 		UT2004DeathMatchConfig config = new UT2004DeathMatchConfig();
935 
936 		// GENERIC CONFIGS
937 		setGenericMatchConfigs(config);
938 		
939 		// CUSTOM BOTS
940 		if (botCount > 0) {
941 			config.setBot(createBotConfigs());
942 		}
943 		
944 		// NATIVE BOTS		
945 		if (nativeCount > 0) {			
946 			config.setNativeBot(createNativeBotConfig());
947 		}
948 		
949 		// HUMANS
950 		if (humanCount > 0) {
951 			config.setHuman(createHumanConfig());
952 		}
953 		
954 		// DEATH MATCH SPECIFIC CONFIGS		
955 	    config.setFragLimit(scoreLimit);
956 	    config.setTimeLimit(timeoutMinutes);
957 	     
958 	    // ------------
959 	    // START IT UP!
960 	    // ------------
961 	    
962 	    System.out.println("EXECUTING DEATH MATCH!");
963 
964 	    LogCategory log = new LogCategory(matchName);
965 	    UT2004DeathMatch match = new UT2004DeathMatch(config, log);
966 	    
967 	    match.getLog().setLevel(Level.INFO);
968 	    match.getLog().addConsoleHandler();
969 	    
970 	    match.run();
971 	}
972 	
973 	public static void executeTeamDeathMatch() { 
974 		UT2004TeamDeathMatchConfig config = new UT2004TeamDeathMatchConfig();
975 
976 		// GENERIC CONFIGS
977 		setGenericMatchConfigs(config);
978 		
979 		// CUSTOM BOTS
980 		if (botCount > 0) {
981 			config.setBot(createBotConfigs());
982 		}
983 		
984 		// NATIVE BOTS		
985 		if (nativeCount > 0) {			
986 			config.setNativeBot(createNativeBotConfig());
987 		}
988 		
989 		// HUMANS
990 		if (humanCount > 0) {
991 			config.setHuman(createHumanConfig());
992 		}
993 		
994 		// CAPTURE THE FLAG SPECIFIC CONFIGS		
995 	    config.setScoreLimit(scoreLimit);
996 	    config.setTimeLimit(timeoutMinutes);
997 	     
998 	    // ------------
999 	    // START IT UP!
1000 	    // ------------
1001 	    
1002 	    System.out.println("EXECUTING TEAM DEATH MATCH!");
1003 
1004 	    LogCategory log = new LogCategory(matchName);
1005 	    UT2004TeamDeathMatch match = new UT2004TeamDeathMatch(config, log);
1006 	    
1007 	    match.getLog().setLevel(Level.INFO);
1008 	    match.getLog().addConsoleHandler();
1009 	    
1010 	    match.run();	
1011 	}
1012 	
1013 	public static void executeCaptureTheFlag() { 
1014 		UT2004CaptureTheFlagConfig config = new UT2004CaptureTheFlagConfig();
1015 
1016 		// GENERIC CONFIGS
1017 		setGenericMatchConfigs(config);
1018 		
1019 		// CUSTOM BOTS
1020 		if (botCount > 0) {
1021 			config.setBot(createBotConfigs());
1022 		}
1023 		
1024 		// NATIVE BOTS		
1025 		if (nativeCount > 0) {			
1026 			config.setNativeBot(createNativeBotConfig());
1027 		}
1028 		
1029 		// HUMANS
1030 		if (humanCount > 0) {
1031 			config.setHuman(createHumanConfig());
1032 		}
1033 		
1034 		// CAPTURE THE FLAG SPECIFIC CONFIGS		
1035 	    config.setScoreLimit(scoreLimit);
1036 	    config.setTimeLimit(timeoutMinutes);
1037 	     
1038 	    // ------------
1039 	    // START IT UP!
1040 	    // ------------
1041 	    
1042 	    System.out.println("EXECUTING CAPTURE THE FLAG!");
1043 
1044 	    LogCategory log = new LogCategory(matchName);
1045 	    UT2004CaptureTheFlag match = new UT2004CaptureTheFlag(config, log);
1046 	    
1047 	    match.getLog().setLevel(Level.INFO);
1048 	    match.getLog().addConsoleHandler();
1049 	    
1050 	    match.run();
1051 	}
1052 	
1053 	public static void executeDoubleDomination() { 
1054 		fail("DOUBLE DOMINATION NOT SUPPORTED YET!");	
1055 	}
1056 	
1057 	
1058 	// ==============
1059 	// TEST ARGUMENTS
1060 	// ==============
1061 	public static String[] getArgs_DM_2v2v1() {
1062 		return new String[] {
1063 				"-y", // MATCH TYPE
1064 				"DM", // DEATH-MATCH
1065 				// GENERIC CONFIG
1066 				"-u",
1067 				"D:\\Games\\UT2004-Devel",
1068 				"-h", // human-like-log
1069 				"-r",
1070 				"./results",
1071 	            "-n",
1072 	            "Test-DM-2v2v1", // MATCH NAME
1073 				"-s",
1074 				"DMServer",				
1075 				// CUSTOM BOTS CONFIG
1076 				"-a",
1077 				"D:\\Workspaces\\Pogamut-Trunk\\Main\\PogamutUT2004Examples\\04-HunterBot\\target\\ut2004-04-hunter-bot-3.6.2-SNAPSHOT.one-jar.jar;D:\\Workspaces\\Pogamut-Trunk\\Main\\PogamutUT2004Examples\\04-HunterBot\\target\\ut2004-04-hunter-bot-3.6.2-SNAPSHOT.one-jar.jar",
1078 				"-b",
1079 				"HunterBot1;HunterBot2",
1080 	            "-l",
1081 	            "1;5",
1082 	            "-k",
1083 	            "HumanFemaleA.NightFemaleA;Aliens.AlienMaleB",
1084 				// NATIVE BOTS CONFIG
1085 	            "-c", // NATIVE BOT COUNT
1086 	            "2",
1087 	            "-d", // NATIVE BOT NAME
1088 	            "Native1;Native2",
1089 	            "-e", // NATIVE BOT SKILL
1090 	            "2;3",
1091 	            // HUMANS CONFIG
1092 	            "-x",
1093 	            "1", // HUMAN COUNT
1094 				// DEATH MATCH SPECIFIC CONFIG
1095 	            "-m",
1096 				"DM-TrainingDay",
1097 				"-f", // FRAG LIMIT
1098 				"5",
1099 				"-t", // TIME LIMIT IN MINS
1100 				"5",
1101 			};
1102 	}
1103 	
1104 	public static String[] getArgs_TDM_2v2v1() {
1105 		return new String[] {
1106 				"-y", // MATCH TYPE
1107 				"TDM", // CAPTURE THE FALG
1108 				// GENERIC CONFIG
1109 				"-u",
1110 				"D:\\Games\\UT2004-Devel",
1111 				"-h", // human-like-log
1112 				"-r",
1113 				"./results",
1114 	            "-n",
1115 	            "Test-CTF-2v2v1", // MATCH NAME
1116 				"-s",
1117 				"CTFServer",				
1118 				// CUSTOM BOTS CONFIG
1119 				"-a",
1120 				"D:\\Workspaces\\Pogamut-Trunk\\Main\\PogamutUT2004Examples\\04-HunterBot\\target\\ut2004-04-hunter-bot-3.6.2-SNAPSHOT.one-jar.jar;D:\\Workspaces\\Pogamut-Trunk\\Main\\PogamutUT2004Examples\\04-HunterBot\\target\\ut2004-04-hunter-bot-3.6.2-SNAPSHOT.one-jar.jar",
1121 				"-b",
1122 				"TDMBot1;TDMBot2",
1123 	            "-l",
1124 	            "3;4",
1125 	            "-k",
1126 	            "HumanFemaleA.NightFemaleA;HumanFemaleA.NightFemaleA",
1127 	            "-i",
1128 	            "0;1",
1129 				// NATIVE BOTS CONFIG
1130 	            "-c", // NATIVE BOT COUNT
1131 	            "2",
1132 	            "-d", // NATIVE BOT NAME
1133 	            "Native1;Native2",
1134 	            "-e", // NATIVE BOT SKILL
1135 	            "2;1",
1136 	            "-g", // NATIVE BOT TEAMS
1137 	            "0;1",
1138 	            // HUMANS CONFIG
1139 	            "-x",
1140 	            "1", // HUMAN COUNT
1141 	            "-z",
1142 	            "1",
1143 				// TEAM DEATH MATCH
1144 	            "-m",
1145 				"DM-Flux2",
1146 				"-f",
1147 				"5", // SCORE LIMIT
1148 				"-t",
1149 				"5", // TIME LIMIT
1150 			};
1151 	}
1152 	
1153 	public static String[] getArgs_CTF_2v2v1() {
1154 		return new String[] {
1155 				"-y", // MATCH TYPE
1156 				"CTF", // CAPTURE THE FALG
1157 				// GENERIC CONFIG
1158 				"-u",
1159 				"D:\\Games\\UT2004-Devel",
1160 				"-h", // human-like-log
1161 				"-r",
1162 				"./results",
1163 	            "-n",
1164 	            "Test-TDM-2v2v1", // MATCH NAME
1165 				"-s",
1166 				"TDMServer",				
1167 				// CUSTOM BOTS CONFIG
1168 				"-a",
1169 				"D:\\Workspaces\\Pogamut-Trunk\\Main\\PogamutUT2004Examples\\09-CTFBot\\target\\ut2004-09-ctf-bot-3.6.2-SNAPSHOT.one-jar.jar;D:\\Workspaces\\Pogamut-Trunk\\Main\\PogamutUT2004Examples\\09-CTFBot\\target\\ut2004-09-ctf-bot-3.6.2-SNAPSHOT.one-jar.jar",
1170 				"-b",
1171 				"CTFBot1;CTFBot2",
1172 	            "-l",
1173 	            "1;2",
1174 	            "-k",
1175 	            "HumanFemaleA.NightFemaleA;HumanFemaleA.NightFemaleA",
1176 	            "-i",
1177 	            "0;1",
1178 				// NATIVE BOTS CONFIG
1179 	            "-c", // NATIVE BOT COUNT
1180 	            "2",
1181 	            "-d", // NATIVE BOT NAME
1182 	            "Native1;Native2",
1183 	            "-e", // NATIVE BOT SKILL
1184 	            "5;6",
1185 	            "-g", // NATIVE BOT TEAMS
1186 	            "0;1",
1187 	            // HUMANS CONFIG
1188 	            "-x",
1189 	            "1", // HUMAN COUNT
1190 	            "-z",
1191 	            "1",
1192 				// CAPTURE THE FLAG SPECIFIC CONFIG
1193 	            "-m",
1194 				"CTF-LostFaith",
1195 				"-f",
1196 				"1", // SCORE LIMIT
1197 				"-t",
1198 				"5", // TIME LIMIT
1199 			};
1200 	}
1201 	
1202 	public static void main(String[] args) throws JSAPException {
1203 		// -----------
1204 		// FOR TESTING
1205 		// -----------
1206 		//args = getArgs_DM_2v2v1();		
1207 		//args = getArgs_TDM_2v2v1();
1208 		//args = getArgs_CTF_2v2v1();		
1209 		
1210 		// --------------
1211 		// IMPLEMENTATION
1212 		// --------------
1213 		
1214 		initJSAP();
1215 	    
1216 	    header();
1217 	    
1218 	    readConfig(args);
1219 	    
1220 	    sanityChecks();
1221 	    
1222 	    switch (matchType) {
1223 	    case DM:
1224 	    	executeDeathMatch();
1225 	    	break;
1226 	    case TDM:
1227 	    	executeTeamDeathMatch();
1228 	    	break;
1229 	    case CTF:
1230 	    	executeCaptureTheFlag();
1231 	    	break;
1232 	    case DD:
1233 	    	executeDoubleDomination();
1234 	    	break;
1235 	    default:
1236 	    	fail("Unsupported match type specified " + matchTypeName + " recognized as " + matchType.shortName + "[" + matchType.name + "].");
1237 	    }
1238 	}
1239 	
1240 }