1 package javabot;
2
3 import java.io.PrintWriter;
4 import java.io.StringWriter;
5 import java.util.ArrayList;
6 import java.util.HashMap;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.Map.Entry;
10 import java.util.concurrent.ConcurrentLinkedQueue;
11 import java.util.concurrent.LinkedBlockingQueue;
12 import java.util.concurrent.TimeUnit;
13 import java.util.logging.Level;
14
15 import javabot.JBot.EventData;
16 import javabot.JBot.FleetData;
17 import javabot.JBot.UnitData;
18 import javabot.events.DefConBasicUpdate;
19 import javabot.events.IDefConBasicEvent;
20 import cz.cuni.amis.pogamut.base.agent.state.impl.AgentState;
21 import cz.cuni.amis.pogamut.base.agent.state.impl.AgentStateStarted;
22 import cz.cuni.amis.pogamut.base.communication.translator.event.IWorldChangeEvent;
23 import cz.cuni.amis.pogamut.defcon.agent.DefConAgent;
24 import cz.cuni.amis.pogamut.defcon.agent.module.sensor.GameInfo;
25 import cz.cuni.amis.pogamut.defcon.agentmanager.DefConAgentManager;
26 import cz.cuni.amis.pogamut.defcon.agentmanager.exception.CantInstantiateAgentException;
27 import cz.cuni.amis.pogamut.defcon.agentmanager.exception.ModuleForAgentClassNotFoundException;
28 import cz.cuni.amis.pogamut.defcon.base3d.worldview.object.DefConLocation;
29 import cz.cuni.amis.pogamut.defcon.communication.messages.commands.DefConCommand;
30 import cz.cuni.amis.pogamut.defcon.communication.messages.infos.City;
31 import cz.cuni.amis.pogamut.defcon.communication.messages.infos.DefConEvent;
32 import cz.cuni.amis.pogamut.defcon.communication.messages.infos.DefConObject;
33 import cz.cuni.amis.pogamut.defcon.communication.messages.infos.DefConUnitObject;
34 import cz.cuni.amis.pogamut.defcon.communication.messages.infos.Fleet;
35 import cz.cuni.amis.pogamut.defcon.consts.Event;
36 import cz.cuni.amis.pogamut.defcon.consts.UnitType;
37 import cz.cuni.amis.pogamut.defcon.factory.DefConAgentModule;
38 import cz.cuni.amis.pogamut.defcon.utils.SyncMethodExecContainer;
39 import cz.cuni.amis.utils.ExceptionToString;
40 import cz.cuni.amis.utils.exception.PogamutInterruptedException;
41 import cz.cuni.amis.utils.flag.Flag;
42 import cz.cuni.amis.utils.flag.IFlag;
43 import cz.cuni.amis.utils.flag.WaitForFlagChange;
44 import cz.cuni.amis.utils.flag.WaitForFlagChange.IAccept;
45
46
47
48
49
50
51
52 public class PogamutJBotSupport {
53
54 private static final String NEW_LINE = System.getProperty("line.separator");
55
56 public static final String PROPERTY_CLASS = "module_class";
57 public static final String PROPERTY_START_TIMEOUT_SECS = "start_timeout";
58
59 private static final int DEFAULT_START_TIMEOUT_SECS = 10;
60 private static final long MAX_UPDATE_TIME = 75;
61
62 private static DefConAgent bot = null;
63
64 private static final ConcurrentLinkedQueue<SyncMethodExecContainer> queries =
65 new ConcurrentLinkedQueue<SyncMethodExecContainer>();
66
67 private static final LinkedBlockingQueue<IDefConBasicEvent> events = new LinkedBlockingQueue<IDefConBasicEvent>();
68
69 private static final LinkedBlockingQueue<IWorldChangeEvent> unitUpdates = new LinkedBlockingQueue<IWorldChangeEvent>();
70
71 private static final int COMMANDS_PER_TICK = 20;
72
73
74
75
76
77 public static Flag<Boolean> botIsRunning = new Flag<Boolean>(false);
78
79 private static ConcurrentLinkedQueue<DefConCommand> commands = new ConcurrentLinkedQueue<DefConCommand>();
80
81 private static ActExecutor actExecutor = new ActExecutor();
82
83 private static String mapToString(Map<?, ?> map) {
84 StringBuffer sb = new StringBuffer();
85 for (Entry<?, ?> entry : map.entrySet()) {
86 sb.append(entry.getKey() + " = " + entry.getValue());
87 sb.append(NEW_LINE);
88 }
89 return sb.toString();
90 }
91
92 private static boolean start(Map<String, String> options) {
93 logInit(Level.INFO, "Instantiating bot with options: " + NEW_LINE
94 + mapToString(options));
95
96 String clsStr = options.get(PROPERTY_CLASS);
97 Class<DefConAgentModule> cls = null;
98 if (clsStr != null) {
99 try {
100 cls = (Class<DefConAgentModule>) Class.forName(clsStr);
101 } catch (Exception e) {
102 logInit(
103 Level.SEVERE,
104 "Bot module class '"
105 + clsStr
106 + "' could not be found, did you put your jar into 'java' directory?");
107 logInit(Level.SEVERE, "BOT CAN NOT BE STARTED!");
108 logInit(Level.SEVERE, "RESTART DEFCON! " + e.toString() + " "
109 + System.getProperty("java.class.path"));
110 return false;
111 }
112 logInit(Level.INFO, "Bot module class '" + clsStr + "'.");
113 } else {
114 logInit(Level.INFO, "Bot module class ('" + PROPERTY_CLASS
115 + "' options) not specified.");
116 }
117
118 logInit(Level.INFO, "Instantiating bot.");
119
120 try {
121 bot = (DefConAgent<?>) DefConAgentManager.getInstance()
122 .getAgentInstance(cls);
123
124 } catch (CantInstantiateAgentException e) {
125 logInit(Level.SEVERE, ExceptionToString.process(e));
126 logInit(Level.SEVERE, "BOT CAN NOT BE STARTED!");
127 logInit(Level.SEVERE, "RESTART DEFCON!");
128 return false;
129 } catch (ModuleForAgentClassNotFoundException e) {
130 logInit(Level.SEVERE, ExceptionToString.process(e));
131 logInit(Level.SEVERE, "BOT CAN NOT BE STARTED!");
132 logInit(Level.SEVERE, "RESTART DEFCON!");
133 return false;
134 }
135
136 logInit(Level.INFO, "Bot was instantiated.");
137
138 String startTimeoutStr = options.get(PROPERTY_START_TIMEOUT_SECS);
139 int startTimeoutSecs = DEFAULT_START_TIMEOUT_SECS;
140 if (startTimeoutStr != null) {
141 try {
142 startTimeoutSecs = Integer.parseInt(startTimeoutStr);
143 } catch (Exception e) {
144 logInit(Level.WARNING, "Option '" + PROPERTY_START_TIMEOUT_SECS
145 + "' does not contain integer number.");
146 }
147 }
148
149 logInit(Level.INFO, "Starting bot (" + startTimeoutSecs
150 + " secs timeout).");
151
152 bot.setOptions(options);
153 try {
154 bot.start();
155 try {
156 new WaitForFlagChange<AgentState>((IFlag) bot.getState(),
157 new IAccept<AgentState>() {
158 @Override
159 public boolean accept(AgentState flagValue) {
160 return flagValue
161 .isState(AgentStateStarted.class);
162 }
163 }).await(startTimeoutSecs, TimeUnit.SECONDS);
164 } catch (PogamutInterruptedException e) {
165 logInit(Level.SEVERE, "Bot fails to start in "
166 + startTimeoutSecs + " secs, killing bot.");
167 bot.kill();
168 logInit(Level.SEVERE, "BOT CAN NOT BE STARTED!");
169 logInit(Level.SEVERE, "RESTART DEFCON!");
170 return false;
171 }
172 } catch (Exception e) {
173 logInit(Level.SEVERE, ExceptionToString.process(
174 "Bot fails to start.", e));
175 bot = null;
176 logInit(Level.SEVERE, "BOT CAN NOT BE STARTED!");
177 logInit(Level.SEVERE, "RESTART DEFCON!");
178 return false;
179 }
180 logInit(Level.INFO, "Bot running!");
181 botIsRunning.setFlag(true);
182 return true;
183 }
184
185 public static DefConAgent<?> getBot() {
186 return bot;
187 }
188
189 private static String[] split(String msg, int len) {
190 if (msg.length() < len)
191 return new String[] { msg };
192 String[] result = new String[msg.length() / len + 1];
193 for (int i = 0; i < msg.length() / len + 1; ++i) {
194 if ((i + 1) * len < msg.length()) {
195 result[i] = msg.substring(i * len, (i + 1) * len);
196 } else {
197 result[i] = msg.substring(i * len);
198 }
199 }
200 return result;
201 }
202
203 public static void logInitException(Throwable e) {
204 StringWriter writer = new StringWriter();
205 e.printStackTrace(new PrintWriter(writer));
206 writeToConsole(writer.toString());
207 }
208
209 public static void logGameException(Throwable e) {
210 StringWriter writer = new StringWriter();
211 e.printStackTrace(new PrintWriter(writer));
212 writeToConsole(writer.toString());
213 }
214
215
216
217
218
219
220
221 public static void logInit(Level level, String msg) {
222 if (botIsRunning.getFlag()) {
223 String[] msgs = split("[" + level + "] " + msg, 50);
224 for (String m : msgs) {
225 writeToConsole(m);
226 }
227 } else {
228 System.out.println("[" + level + "] " + msg);
229 }
230 }
231
232
233
234
235
236
237
238 public static void logGame(Level level, String msg) {
239 if (botIsRunning.getFlag()) {
240 JBot.DebugLog("[" + level + "] " + msg);
241 } else {
242 System.out.println("[" + level + "] " + msg);
243 }
244 }
245
246 public static GameInfo gameInfo = null;
247
248
249
250
251
252
253
254 public static boolean initialise(String[][] commandLineOptions) {
255 PogamutJBotSupport
256 .writeToConsole("Executing PogamutJBotSupport initialise");
257 logGame(Level.INFO, "Executing PogamutJBotSupport initialise");
258 StringBuffer sb = new StringBuffer();
259 sb.append("Command line options:");
260 Map<String, String> optionMap = new HashMap<String, String>();
261 for (String[] option : commandLineOptions) {
262 sb.append(NEW_LINE);
263 if (option.length > 0) {
264 logInit(Level.INFO, option[0]
265 + (option.length > 1 && option[1].length() > 0 ? " = "
266 + option[1] : ""));
267 optionMap.put(option[0], option.length > 1 ? option[1] : null);
268 }
269 }
270 logGame(Level.INFO, "Calling start");
271 boolean result = start(optionMap);
272 JBot.WriteToConsole("Finished start");
273
274 Thread.currentThread().setPriority(
275 (int) ((Thread.MAX_PRIORITY - Thread.NORM_PRIORITY) / 3d)
276 + Thread.NORM_PRIORITY);
277
278 return result;
279 }
280
281
282
283
284
285
286 public static void addEvent(EventData data) {
287 synchronized (events) {
288
289 if (data.m_eventType != JBot.EventDestroyed) {
290
291 DefConEvent event = Event.getInstanceOfUnitTypeFromEventType(
292 data,
293 bot
294 .getWorldView().getCurrentTime());
295
296 events.add(event);
297 } else {
298
299 UnitData unitdata = new UnitData();
300
301 unitdata.m_objectId = data.m_targetObjectId;
302 unitdata.m_teamId = JBot.GetTeamId(data.m_targetObjectId);
303 unitdata.m_type = JBot.GetType(data.m_targetObjectId);
304 unitdata.m_currentState = -1;
305 unitdata.m_visible = true;
306 unitdata.m_longitude = data.m_longitude;
307 unitdata.m_latitude = data.m_latitude;
308
309 if (UnitType.naval.contains(UnitType
310 .getEnum(unitdata.m_type))) {
311
312 int fleetId = JBot.GetFleetId(data.m_targetObjectId);
313
314 int[] fleetMembers = JBot.GetFleetMembers(fleetId);
315
316 if (fleetMembers.length == 1) {
317
318 Fleet fleet_object = new Fleet(fleetId,
319 unitdata.m_teamId,
320 new DefConLocation(data.m_longitude,
321 data.m_latitude),
322 false, fleetMembers, bot
323 .getWorldView().getCurrentTime());
324
325 unitUpdates.add(fleet_object.createDestroyedEvent());
326 }
327
328 }
329
330 DefConUnitObject<?> update_object = (DefConUnitObject<?>) UnitType
331 .getInstanceOfUnitTypeFromUnitData(unitdata, bot
332 .getWorldView().getCurrentTime());
333 unitUpdates.add(update_object.createDestroyedEvent());
334 }
335 }
336 }
337
338
339
340
341
342
343 public static boolean update() {
344
345
346 long current_time = System.currentTimeMillis();
347
348 if (JBot.IsVictoryTimerActive() && JBot.GetVictoryTimer() == 0) {
349 writeToConsole("Match result");
350 for (int teamId : JBot.GetTeamIds()) {
351 writeToConsole("TeamId: " + teamId);
352 writeToConsole("EnemyKills: " + JBot.GetEnemyKills(teamId));
353 writeToConsole("CollateralDamage: "
354 + JBot.GetCollateralDamage(teamId));
355 writeToConsole("Casualties: "
356 + JBot.GetFriendlyDeaths(teamId));
357 writeToConsole("RemainingPopulation: "
358 + JBot.GetRemainingPopulation(teamId));
359 }
360 try {
361 Thread.sleep(1000);
362 } catch (InterruptedException e) {
363 e.printStackTrace();
364 }
365 System.exit(0);
366 }
367
368 performCommands();
369
370 prepareUnitsUpdate();
371
372 synchronized (events) {
373
374 events.add(new DefConBasicUpdate((long) JBot.GetGameTime()));
375 }
376
377 while (System.currentTimeMillis() - current_time < MAX_UPDATE_TIME) {
378 checkQueries();
379 }
380
381 return true;
382 }
383
384
385
386
387
388
389 private static void prepareUnitsUpdate() {
390
391 synchronized (unitUpdates) {
392 List<UnitData> unit_data = JBot.GetAllUnitData();
393
394 float time = JBot.GetGameTime();
395 for (UnitData unit : unit_data) {
396 DefConObject object = UnitType
397 .getInstanceOfUnitTypeFromUnitData(
398 unit,
399 time);
400 unitUpdates.add(object.createUpdateEvent());
401 }
402
403
404 List<FleetData> fleet_data = JBot.GetAllFleetData();
405
406 for (FleetData fleet : fleet_data) {
407
408 Fleet object = new Fleet(fleet.m_fleetId,
409 fleet.m_teamId,
410 new DefConLocation(fleet.m_longitude, fleet.m_latitude),
411 fleet.m_visible, fleet.m_fleetMembers, time);
412
413 if (object.getFleetMembers().length > 0)
414 unitUpdates.add(object.createUpdateEvent());
415 }
416 for (int cityId : JBot.GetCityIds()) {
417 DefConLocation cityLocation = new DefConLocation(
418 JBot.GetLongitude(cityId),
419 JBot.GetLatitude(cityId));
420
421 int ownerId = JBot.GetTeamId(cityId);
422 City city = new City(cityId, ownerId, cityLocation, true,
423 JBot.GetCityPopulation(cityId), JBot.GetGameTime());
424
425 unitUpdates.add(city.createUpdateEvent());
426 }
427 }
428 }
429
430 public static List<IWorldChangeEvent> getUnitsUpdate() {
431 List<IWorldChangeEvent> update = new ArrayList<IWorldChangeEvent>();
432 unitUpdates.drainTo(update);
433
434 return update;
435 }
436
437 private static void checkQueries() {
438 SyncMethodExecContainer container = queries.poll();
439
440 if (container != null) {
441 container.execute();
442 }
443 }
444
445 public synchronized static void addQuery(SyncMethodExecContainer container) {
446 queries.add(container);
447 }
448
449 private static void performCommands() {
450 int counter = COMMANDS_PER_TICK;
451
452 while (--counter > 0 && !commands.isEmpty()) {
453 actExecutor.sendCommand(commands.poll());
454 }
455 }
456
457 public static void addCommand(DefConCommand command) {
458 synchronized (commands) {
459 commands.add(command);
460 }
461 }
462
463 public static List<IDefConBasicEvent> getEvents() {
464 List<IDefConBasicEvent> result = new ArrayList<IDefConBasicEvent>();
465
466 synchronized (events) {
467 events.drainTo(result);
468 }
469 return result;
470 }
471
472 public static void writeToConsole(String logLine) {
473 if (logLine != null) {
474 JBot.WriteToConsole(logLine);
475 } else {
476 JBot.WriteToConsole("NULL LOGLINE");
477 for (StackTraceElement element : Thread.currentThread()
478 .getStackTrace()) {
479 JBot.WriteToConsole(element.toString());
480 }
481 }
482 }
483
484 public static ActExecutor getDefConActExecutor() {
485 return actExecutor;
486 }
487
488 public static void setName(String name) {
489 JBot.SendChatMessage(String.format("/name [Bot]%s", name), 0);
490 }
491
492 }