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
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
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
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
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
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
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
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
865 config.getUT2004Ini().setPort(ut2004Port);
866 config.getUT2004Ini().setServerName(serverName, serverName);
867 config.getUT2004Ini().setDemoSpectatorClass(UT2004Ini.Value_DemoSpectatorClass);
868
869
870 config.getUccConf().setStartOnUnusedPort(true);
871 config.getUccConf().setUnrealHome(ut2004HomeDir);
872 config.getUccConf().setGameType(matchType.uccGameType);
873 config.getUccConf().setMapName(map);
874
875
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
937 setGenericMatchConfigs(config);
938
939
940 if (botCount > 0) {
941 config.setBot(createBotConfigs());
942 }
943
944
945 if (nativeCount > 0) {
946 config.setNativeBot(createNativeBotConfig());
947 }
948
949
950 if (humanCount > 0) {
951 config.setHuman(createHumanConfig());
952 }
953
954
955 config.setFragLimit(scoreLimit);
956 config.setTimeLimit(timeoutMinutes);
957
958
959
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
977 setGenericMatchConfigs(config);
978
979
980 if (botCount > 0) {
981 config.setBot(createBotConfigs());
982 }
983
984
985 if (nativeCount > 0) {
986 config.setNativeBot(createNativeBotConfig());
987 }
988
989
990 if (humanCount > 0) {
991 config.setHuman(createHumanConfig());
992 }
993
994
995 config.setScoreLimit(scoreLimit);
996 config.setTimeLimit(timeoutMinutes);
997
998
999
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
1017 setGenericMatchConfigs(config);
1018
1019
1020 if (botCount > 0) {
1021 config.setBot(createBotConfigs());
1022 }
1023
1024
1025 if (nativeCount > 0) {
1026 config.setNativeBot(createNativeBotConfig());
1027 }
1028
1029
1030 if (humanCount > 0) {
1031 config.setHuman(createHumanConfig());
1032 }
1033
1034
1035 config.setScoreLimit(scoreLimit);
1036 config.setTimeLimit(timeoutMinutes);
1037
1038
1039
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
1060
1061 public static String[] getArgs_DM_2v2v1() {
1062 return new String[] {
1063 "-y",
1064 "DM",
1065
1066 "-u",
1067 "D:\\Games\\UT2004-Devel",
1068 "-h",
1069 "-r",
1070 "./results",
1071 "-n",
1072 "Test-DM-2v2v1",
1073 "-s",
1074 "DMServer",
1075
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
1085 "-c",
1086 "2",
1087 "-d",
1088 "Native1;Native2",
1089 "-e",
1090 "2;3",
1091
1092 "-x",
1093 "1",
1094
1095 "-m",
1096 "DM-TrainingDay",
1097 "-f",
1098 "5",
1099 "-t",
1100 "5",
1101 };
1102 }
1103
1104 public static String[] getArgs_TDM_2v2v1() {
1105 return new String[] {
1106 "-y",
1107 "TDM",
1108
1109 "-u",
1110 "D:\\Games\\UT2004-Devel",
1111 "-h",
1112 "-r",
1113 "./results",
1114 "-n",
1115 "Test-CTF-2v2v1",
1116 "-s",
1117 "CTFServer",
1118
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
1130 "-c",
1131 "2",
1132 "-d",
1133 "Native1;Native2",
1134 "-e",
1135 "2;1",
1136 "-g",
1137 "0;1",
1138
1139 "-x",
1140 "1",
1141 "-z",
1142 "1",
1143
1144 "-m",
1145 "DM-Flux2",
1146 "-f",
1147 "5",
1148 "-t",
1149 "5",
1150 };
1151 }
1152
1153 public static String[] getArgs_CTF_2v2v1() {
1154 return new String[] {
1155 "-y",
1156 "CTF",
1157
1158 "-u",
1159 "D:\\Games\\UT2004-Devel",
1160 "-h",
1161 "-r",
1162 "./results",
1163 "-n",
1164 "Test-TDM-2v2v1",
1165 "-s",
1166 "TDMServer",
1167
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
1179 "-c",
1180 "2",
1181 "-d",
1182 "Native1;Native2",
1183 "-e",
1184 "5;6",
1185 "-g",
1186 "0;1",
1187
1188 "-x",
1189 "1",
1190 "-z",
1191 "1",
1192
1193 "-m",
1194 "CTF-LostFaith",
1195 "-f",
1196 "1",
1197 "-t",
1198 "5",
1199 };
1200 }
1201
1202 public static void main(String[] args) throws JSAPException {
1203
1204
1205
1206
1207
1208
1209
1210
1211
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 }