View Javadoc

1   package cz.cuni.amis.pogamut.ut2004.bot.impl;
2   
3   import java.util.concurrent.TimeUnit;
4   import java.util.logging.Level;
5   import java.util.logging.Logger;
6   
7   import javax.management.InstanceAlreadyExistsException;
8   import javax.management.MBeanRegistrationException;
9   import javax.management.MBeanServer;
10  import javax.management.MalformedObjectNameException;
11  import javax.management.NotCompliantMBeanException;
12  import javax.management.ObjectName;
13  
14  import com.google.inject.Inject;
15  
16  import cz.cuni.amis.introspection.Folder;
17  import cz.cuni.amis.introspection.java.ReflectionObjectFolder;
18  import cz.cuni.amis.pogamut.base.agent.IAgentId;
19  import cz.cuni.amis.pogamut.base.agent.exceptions.AgentException;
20  import cz.cuni.amis.pogamut.base.agent.impl.AbstractAgent;
21  import cz.cuni.amis.pogamut.base.agent.jmx.AgentJMXComponents;
22  import cz.cuni.amis.pogamut.base.agent.jmx.adapter.AgentMBeanAdapter;
23  import cz.cuni.amis.pogamut.base.agent.state.level1.IAgentStateGoingUp;
24  import cz.cuni.amis.pogamut.base.agent.state.level1.IAgentStateUp;
25  import cz.cuni.amis.pogamut.base.communication.command.IAct;
26  import cz.cuni.amis.pogamut.base.communication.worldview.IWorldView;
27  import cz.cuni.amis.pogamut.base.communication.worldview.event.IWorldEventListener;
28  import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEventListener;
29  import cz.cuni.amis.pogamut.base.communication.worldview.object.event.WorldObjectUpdatedEvent;
30  import cz.cuni.amis.pogamut.base.communication.worldview.react.EventReact;
31  import cz.cuni.amis.pogamut.base.component.bus.IComponentBus;
32  import cz.cuni.amis.pogamut.base.component.bus.event.BusAwareCountDownLatch;
33  import cz.cuni.amis.pogamut.base.component.exception.ComponentCantStartException;
34  import cz.cuni.amis.pogamut.base.utils.guice.AgentScoped;
35  import cz.cuni.amis.pogamut.base.utils.logging.IAgentLogger;
36  import cz.cuni.amis.pogamut.base3d.agent.AbstractAgent3D;
37  import cz.cuni.amis.pogamut.base3d.worldview.IVisionWorldView;
38  import cz.cuni.amis.pogamut.base3d.worldview.object.Location;
39  import cz.cuni.amis.pogamut.base3d.worldview.object.Rotation;
40  import cz.cuni.amis.pogamut.base3d.worldview.object.Velocity;
41  import cz.cuni.amis.pogamut.ut2004.agent.module.utils.ProjectileCleanUp;
42  import cz.cuni.amis.pogamut.ut2004.agent.navigation.navmesh.NavMesh;
43  import cz.cuni.amis.pogamut.ut2004.bot.IUT2004Bot;
44  import cz.cuni.amis.pogamut.ut2004.bot.IUT2004BotController;
45  import cz.cuni.amis.pogamut.ut2004.bot.jmx.BotJMXMBeanAdapter;
46  import cz.cuni.amis.pogamut.ut2004.bot.params.UT2004BotParameters;
47  import cz.cuni.amis.pogamut.ut2004.bot.state.impl.BotStateHelloBotReceived;
48  import cz.cuni.amis.pogamut.ut2004.bot.state.impl.BotStateInited;
49  import cz.cuni.amis.pogamut.ut2004.bot.state.impl.BotStatePassword;
50  import cz.cuni.amis.pogamut.ut2004.bot.state.impl.BotStateSendingInit;
51  import cz.cuni.amis.pogamut.ut2004.bot.state.impl.BotStateSpawned;
52  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.Configuration;
53  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.DisconnectBot;
54  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.Initialize;
55  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.PasswordReply;
56  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.Ready;
57  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.Respawn;
58  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.BotKilled;
59  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.ConfigChange;
60  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.EndMessage;
61  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.GameInfo;
62  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.HelloBotHandshake;
63  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.IncomingProjectile;
64  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.InitedMessage;
65  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.LocationUpdate;
66  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Password;
67  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Self;
68  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.SelfMessage;
69  import cz.cuni.amis.pogamut.ut2004.communication.translator.shared.events.InitCommandRequest;
70  import cz.cuni.amis.pogamut.ut2004.communication.translator.shared.events.ReadyCommandRequest;
71  import cz.cuni.amis.pogamut.ut2004.utils.PogamutUT2004Property;
72  import cz.cuni.amis.utils.ExceptionToString;
73  import cz.cuni.amis.utils.NullCheck;
74  import cz.cuni.amis.utils.exception.PogamutException;
75  import cz.cuni.amis.utils.exception.PogamutJMXException;
76  import java.io.FileNotFoundException;
77  import java.io.IOException;
78  
79  /**
80   * Ancestor of all UT2004 bots.
81   * <p><p>
82   * Contains {@link #locationUpdateMessageListener} that auto-updates {@link Self} message with newer location/rotation/velocity info. This means, that {@link Self} updates
83   * comes more often then in &lt;3.7.0 versions of Pogamut.
84   * <p><p>
85   * TODO: [comment me!]
86   *
87   * @author Jimmy
88   */
89  @AgentScoped
90  public class UT2004Bot<WORLD_VIEW extends IVisionWorldView, ACT extends IAct, CONTROLLER extends IUT2004BotController> extends AbstractAgent3D<WORLD_VIEW, ACT> implements IUT2004Bot {
91  
92      /**
93       * If specified - used for the construction of the PasswordReply in createPasswordReply() method.
94       */
95  	private CONTROLLER controller;
96  	
97  	/**
98  	 * Latch that is raised when {@link InitedMessage} comes.
99  	 */
100 	private BusAwareCountDownLatch endMessageLatch;
101 
102 	/**
103 	 * Whether the {@link IUT2004BotController#botStopped()} was called during the running-phase of the agent.
104 	 */
105 	private boolean botStoppedCalled = false;
106 	
107 	private EventReact<HelloBotHandshake> helloBotReaction;
108 
109 	/**
110 	 * Parameters passed into the constructor/factory/runner (by whatever means the agent has been started).
111 	 */
112 	private UT2004BotParameters params;
113 	
114 	/**
115 	 * Abstraction over the UT2004 bot name within the game;
116 	 */
117 	private UT2004BotName botName;
118 	
119 	/**
120 	 * Provides clean-up behavior for {@link IncomingProjectile}. Whenever projectile disappears from the view, it is immediately destroyed
121 	 * as bot does not know what happens to it afterwards (whether it is still flying or already hit something). If we would not do this,
122 	 * world view would get littered with hanging {@link IncomingProjectile} instances leaking memory. 
123 	 */
124 	private ProjectileCleanUp projectileCleanUp;
125 	
126 	/**
127 	 * Auto-updates {@link Self} object within worldview based on {@link LocationUpdate} message. 
128 	 */
129 	private IWorldEventListener<LocationUpdate> locationUpdateMessageListener = new IWorldEventListener<LocationUpdate>() {
130         @Override
131         public void notify(LocationUpdate event) {
132             LocationUpdate locationUpdate = event;
133             Self self = getSelf();
134             if (self == null) {
135                 return;
136             }
137             Self newSelf = new SelfMessage(self.getId(), self.getBotId(), self.getName(), self.isVehicle(),
138                     locationUpdate.getLoc(), locationUpdate.getVel(), locationUpdate.getRot(), self.getTeam(),
139                     self.getWeapon(), self.isShooting(), self.getHealth(), self.getPrimaryAmmo(),
140                     self.getSecondaryAmmo(), self.getAdrenaline(), self.getArmor(), self.getSmallArmor(),
141                     self.isAltFiring(), self.isCrouched(), self.isWalking(), self.getFloorLocation(),
142                     self.getFloorNormal(), self.getCombo(), self.getUDamageTime(), self.getAction(),
143                     self.getEmotLeft(), self.getEmotCenter(), self.getEmotRight(), self.getBubble(),
144                     self.getAnim());
145             log.log(Level.FINEST, "LocationUpdate L:{0}, V:{1}, R:{2}", new Object[]{locationUpdate.getLoc(), locationUpdate.getVel(), locationUpdate.getRot()});
146             getWorldView().notifyImmediately(newSelf);
147         }
148     };
149         
150 	/**
151 	 * 
152 	 * @param agentId
153 	 * @param eventBus
154 	 * @param logger
155 	 * @param worldView due to Guice nature, this can't be templated with WORLD_VIEW - Guice can't use it as a key for the injection
156 	 * @param act due to Guice nature, this can't be templated with ACT - Guice can't use it as a key for the injection
157 	 * @param init due to Guice nature, this can't be templated with CONTROLLER - Guice can't use it as a key for the injection
158 	 */
159     @Inject
160     public UT2004Bot(UT2004BotParameters parameters, IComponentBus eventBus, IAgentLogger logger, IWorldView worldView, IAct act, IUT2004BotController init) {
161         super(parameters.getAgentId(), eventBus, logger, (WORLD_VIEW)worldView, (ACT)act);
162 
163         this.params = parameters;
164         this.controller = (CONTROLLER) init;
165         NullCheck.check(this.controller, "init");
166         if (log.isLoggable(Level.FINER)) log.finer("Initializing the controller...");
167         this.controller.initializeController(this);
168         if (log.isLoggable(Level.FINER)) log.finer("Preparing the controller...");
169         this.controller.prepareBot(this);
170         if (log.isLoggable(Level.FINE)) log.fine("Controller initialized.");
171         
172         helloBotReaction = new EventReact<HelloBotHandshake>(HelloBotHandshake.class, worldView) {
173 			@Override
174 			protected void react(HelloBotHandshake event) {
175 				if (event.isServerFull()) throw new ComponentCantStartException("Server is full.", UT2004Bot.this);
176 			}
177         };
178         
179         getWorldView().addEventListener(ReadyCommandRequest.class, readyCommandRequestListener);
180         getWorldView().addEventListener(InitCommandRequest.class, initCommandRequestListener);
181         getWorldView().addEventListener(Password.class, passwordRequestedListener);
182         getWorldView().addObjectListener(InitedMessage.class, WorldObjectUpdatedEvent.class, initedMessageListener);
183         getWorldView().addEventListener(BotKilled.class, killedListener);
184         getWorldView().addEventListener(LocationUpdate.class, locationUpdateMessageListener);
185         // endListener must be attached inside startAgent() as it is removed from the worldview in the end
186         // and we want the bot to be restartable
187         
188         endMessageLatch = new BusAwareCountDownLatch(1, getEventBus(), getWorldView());
189         
190         projectileCleanUp = new ProjectileCleanUp(this);
191         
192         botName = new UT2004BotName(this, "undefined");
193     }
194     
195     /**
196      * Returns the bot controller passed inside {@link UT2004Bot#AbstractUT2004Bot(IAgentId, IComponentBus, IAgentLogger, IVisionWorldView, IAct, IUT2004BotInitialization)}.
197      * @return
198      */
199     public CONTROLLER getController() {
200     	return controller;
201     }
202     
203     /**
204      * Returns parameters that were passed into the agent during the construction. 
205      * <p><p>
206      * This is a great place to parametrize your agent. Note that you may pass arbitrary subclass of {@link UT2004BotParameters}
207      * to the constructor/factory/runner and pick them up here.
208      * 
209      * @return parameters
210      */
211     public UT2004BotParameters getParams() {
212 		return params;
213 	}
214     
215     ////////  
216     //
217     // BOT CONTROL METHODS
218     //
219     ////////    
220 
221 	@Override
222 	protected void startAgent() {
223     	botStoppedCalled = false;
224     	super.startAgent();
225     	getWorldView().addEventListener(EndMessage.class, endListener);
226    		if (log.isLoggable(Level.INFO)) log.info("Waiting for the handshake to finish for 300s.");
227 		if (!endMessageLatch.await(300000, TimeUnit.MILLISECONDS)) {
228 			throw new ComponentCantStartException("The bot did not received first EndMessage in 300 seconds.", this);
229 		}
230 		if (log.isLoggable(Level.INFO)) log.info("Handshake finished.");
231     }
232 	
233 	@Override
234 	protected void startPausedAgent() {
235 		botStoppedCalled = false;
236 		super.startPausedAgent();
237 		getWorldView().addEventListener(EndMessage.class, endListener);
238    		if (log.isLoggable(Level.INFO)) log.info("Waiting for the handshake to finish for 300s.");
239 		if (!endMessageLatch.await(300000, TimeUnit.MILLISECONDS)) {
240 			throw new ComponentCantStartException("The bot did not received first EndMessage in 300 seconds.", this);
241 		}
242 		if (log.isLoggable(Level.INFO)) log.info("Handshake finished.");
243 	}
244     
245 	@Override
246 	protected void preStopAgent() {
247 		super.preStopAgent();
248 		try {
249 			tryDisconnect();
250     	} catch (Exception e) {
251 		}
252 	}
253 	
254     @Override
255     protected void stopAgent() {
256     	try {
257 	    	if (!botStoppedCalled) {
258 	    		botStoppedCalled = true;
259 	    		controller.botShutdown();	    		
260 	    	}	    	
261     	} finally {
262 			try {
263 				removeBotDisconnector();
264 			} finally {
265 				try {
266 					super.stopAgent();
267 				} finally {
268 					endMessageLatch = new BusAwareCountDownLatch(1, getEventBus(), getWorldView());
269 				}
270 			}
271     	}
272     }
273     
274     @Override
275     protected void preKillAgent() {
276     	super.preKillAgent();
277     	try {
278 			tryDisconnect();
279     	} catch (Exception e) {
280 		}
281     }
282     
283     @Override
284     protected void killAgent() {
285        	try {
286 	    	if (!botStoppedCalled) {
287 	    		botStoppedCalled = true;
288 	    		controller.botShutdown();	    		
289 	    	}
290     	} finally {
291 			try {
292 				removeBotDisconnector();
293 			} finally {
294 				try {
295 					super.killAgent();
296 				} finally {
297 					endMessageLatch = new BusAwareCountDownLatch(1, getEventBus(), getWorldView());
298 				}
299 			}
300     	}
301     }
302     
303     /**
304      * Disconnector thread serves as a last resort for shutting down the bot inside GB2004 in case of JVM failures.
305      */
306     protected Thread botDisconnectorThread;
307     
308     /**
309      * Sends {@link DisconnectBot} commands to GB2004, eats up all exceptions.
310      */
311     protected void tryDisconnect() {
312     	try {
313     		DisconnectBot cmd = new DisconnectBot();
314     		try {
315     			log.info("Sending " + cmd + " to destroy bot inside UT2004.");
316     		} finally {
317     			getAct().act(cmd);
318     			Thread.sleep(1000);    			
319     		}
320     	} catch (Exception e) {
321     		log.warning(ExceptionToString.process("Failed to disconnect the bot, we hope that GB2004 will remove it when the socket gets closed.", e));
322     	}
323     }
324     
325     /**
326      * Initializes & registers {@link UT2004Bot#botDisconnectorThread} as a {@link Runtime#addShutdownHook(Thread)}.
327      */
328     protected void addBotDisconnector() {
329     	if (botDisconnectorThread == null) {
330     		botDisconnectorThread = new Thread(
331     			new Runnable() {
332 					@Override
333 					public void run() {
334 						tryDisconnect();
335 					}    				
336     			},
337     			getName() + "-Disconnector"
338     		);
339     		try {
340     			Runtime.getRuntime().addShutdownHook(botDisconnectorThread);
341     		} catch (Exception e) {
342     			throw new PogamutException("Failed to add BotDisconnectorThread as a JVM shutdown hook.", e, this);
343     		}
344     	}
345     }
346     
347     /**
348      * Removes {@link UT2004Bot#botDisconnectorThread} as a {@link Runtime#removeShutdownHook(Thread)} and nullify the field.
349      */
350     protected void removeBotDisconnector() {
351     	if (botDisconnectorThread != null) {
352     		try {
353     			Runtime.getRuntime().removeShutdownHook(botDisconnectorThread);
354     		} catch (Exception e) {
355     			log.warning(ExceptionToString.process("Failed to remove BotDisconnectorThread as a JVM shutdown hook.", e));
356     		}
357     		botDisconnectorThread = null;
358     	}
359     }
360 
361     // --------------
362     // -=-=-=-=-=-=-=
363     // READY LISTENER
364     // -=-=-=-=-=-=-=
365     // --------------
366     
367     /**
368      * This method is called whenever HelloBot message is parsed - the GameBots2004 is awaiting
369      * the bot to reply with Ready command to begin the handshake.
370      */
371     protected void readyCommandRequested() {
372         getAct().act(new Ready());
373     }
374     
375     /**
376      * Listener that is hooked to WorldView awaiting event ReadyCommandRequest calling
377      * setupWorldViewListeners() and then readyCommandRequested() method upon receiving the event.
378      */
379     private IWorldEventListener<ReadyCommandRequest> readyCommandRequestListener =
380             new IWorldEventListener<ReadyCommandRequest>() {
381 
382                 @Override
383                 public void notify(ReadyCommandRequest event) {
384                 	controller.getLog().setLevel(Level.ALL);
385                 	setState(new BotStateHelloBotReceived("GameBots2004 greeted us, adding custom listeners onto the worldview."));
386                     readyCommandRequested();
387                     setState(new BotStateHelloBotReceived("READY sent, handshaking."));
388                 }
389             };
390             
391     // --------------------
392     // -=-=-=-=-=-=-=-=-=-=
393     // INITIALIZER LISTENER
394     // -=-=-=-=-=-=-=-=-=-=
395     // --------------------
396 
397     /**
398      * This method is called whenever handshake with GameBots2004 is over - the GameBots2004 is awaiting
399      * the bot to reply with Ready command to begin the handshake. It calls setUpInit() method
400      * to obtains Initialize message that is then sent to GameBots2004.
401      * <p><p>
402      * Left as protected if you need to override it - but you probably wouldn't.
403      */
404     protected void initCommandRequested() {
405     	// NOTIFY OTHERS
406     	getWorldView().notifyImmediately(new BotAboutToBeSpawnedForTheFirstTime());
407     	
408     	if (!inState(IAgentStateGoingUp.class, IAgentStateUp.class)) {
409     		// some exception happened
410     		log.warning("TERMINATING THE INITIALIZATION, bot in ivalid state: " + getState().getFlag().getClass().getSimpleName());
411     		return;
412     	}
413     	
414     	// CONTINUE WITH INITIALIZATION
415         Initialize initializeCommand = getController().getInitializeCommand();
416         if (initializeCommand == null) {
417         	throw new AgentException("getBotInit().getInitializeCommand() method returned null message, can't initialize the agent!", log, this);
418         }
419         if(initializeCommand.getName() == null) {
420             // set agent name shown in Unreal
421             initializeCommand.setName(getComponentId().getName().getFlag());
422         } else {
423             // override original name
424             getComponentId().getName().setFlag(initializeCommand.getName());
425         }
426         botName.setNameBase(initializeCommand.getName());
427         if (initializeCommand.getTeam() == null) {
428         	initializeCommand.setTeam(params.getTeam());
429         }
430         if (initializeCommand.getLocation() == null) {
431         	initializeCommand.setLocation(params.getInitialLocation());
432         }
433         if (initializeCommand.getRotation() == null) {
434         	initializeCommand.setRotation(params.getInitialRotation());
435         }
436         try {
437             // set the JMX name
438             initializeCommand.setJmx(getJMX().enableJMX());
439         } catch (Exception e) {
440             throw new PogamutJMXException("Error seting up JMX name of the agent.", e, log, this);
441         }
442         
443         String  defaultName  = (String) PogamutUT2004Property.POGAMUT_UT2004_BOT_INIT_NAME.getValue();
444         String  defaultSkin  = (String) PogamutUT2004Property.POGAMUT_UT2004_BOT_INIT_SKIN.getValue();
445         Integer defaultTeam  = (Integer)PogamutUT2004Property.POGAMUT_UT2004_BOT_INIT_TEAM.getValue();
446         Integer defaultSkill = (Integer)PogamutUT2004Property.POGAMUT_UT2004_BOT_INIT_SKILL.getValue();
447         
448         if ((Boolean)PogamutUT2004Property.POGAMUT_UT2004_BOT_INIT_OVERRIDE_PARAMS.getValue()) {
449         	if (defaultName != null) {
450         		initializeCommand.setName(defaultName);
451         		botName.setNameBase(defaultName);
452         	}
453         	if (defaultSkin != null) initializeCommand.setSkin(defaultSkin);
454         	if (defaultTeam != null) initializeCommand.setTeam(defaultTeam);
455         	if (defaultSkill != null) initializeCommand.setDesiredSkill(defaultSkill);
456         } else {
457         	if (defaultName != null  && initializeCommand.getName() == null) {
458         		initializeCommand.setName(defaultName);
459         		botName.setNameBase(defaultName);
460         	}
461         	if (defaultSkin != null  && initializeCommand.getSkin() == null) initializeCommand.setSkin(defaultSkin);
462         	if (defaultTeam != null  && initializeCommand.getTeam() == null) initializeCommand.setTeam(defaultTeam);
463         	if (defaultSkill != null && initializeCommand.getDesiredSkill() == null) initializeCommand.setDesiredSkill(defaultSkill);
464         }
465 
466         getAct().act(initializeCommand);
467     }
468     
469     /**
470      * Listener that is hooked to WorldView awaiting event InitCommandRequest calling
471      * initCommandRequested() method upon receiving the event.
472      */
473     private IWorldEventListener<InitCommandRequest> initCommandRequestListener =
474             new IWorldEventListener<InitCommandRequest>() {
475                 @Override
476                 public void notify(InitCommandRequest event) {
477                 	setState(new BotStateSendingInit("Handshake over, sending INIT."));
478                 	initCommandRequested();
479                 	setState(new BotStateSendingInit("Handshake over, INIT sent."));
480                 }
481             };
482             
483     // -----------------
484     // -=-=-=-=-=-=-=-=-
485     // PASSWORD LISTENER
486     // -=-=-=-=-=-=-=-=-
487     // -----------------
488     
489     /**
490      * Listener that is hooked to WorldView awaiting event InitCommandRequest calling
491      * initCommandRequested() method upon receiving the event.
492      */
493     private IWorldEventListener<Password> passwordRequestedListener =
494             new IWorldEventListener<Password>() {
495                 @Override
496                 public void notify(Password event) {
497                     setState(new BotStatePassword("Password requested by the world."));
498                     PasswordReply passwordReply = getController().getPassword();
499                     if (passwordReply == null) {
500                     	if (log.isLoggable(Level.WARNING)) log.warning("createPasswordReply() returned null");
501                         passwordReply = new PasswordReply("");
502                     }
503                     if (log.isLoggable(Level.INFO)) log.info("Password required for the world, replying with '" + passwordReply.getPassword() + "'.");
504                     getAct().act(passwordReply);
505                     setState(new BotStatePassword("Password sent."));
506                 }
507             };
508 
509     // -----------------------
510     // -=-=-=-=-=-=-=-=-=-=-=-
511     // INITED MESSAGE LISTENER
512     // -=-=-=-=-=-=-=-=-=-=-=-
513     // -----------------------
514     /**
515      * Listener that is hooked to WorldView awaiting event InitedMessage calling
516      * botInitialized method upon receiving the event.
517      */
518     private IWorldObjectEventListener<InitedMessage, WorldObjectUpdatedEvent<InitedMessage>> initedMessageListener =
519             new IWorldObjectEventListener<InitedMessage, WorldObjectUpdatedEvent<InitedMessage>>() {
520 
521                 @Override
522                 public void notify(WorldObjectUpdatedEvent<InitedMessage> event) {
523                 	setState(new BotStateInited("InitedMessage received, calling botInitialized()."));
524                 	controller.botInitialized(getWorldView().getSingle(GameInfo.class), getWorldView().getSingle(ConfigChange.class), event.getObject());
525                     setState(new BotStateInited("Bot initialized."));                    
526                 }
527             };
528             
529 	// ---------------------------
530 	// -=-=-=-=-=-=-=-=-=-=-=-=-=-
531 	// BOT KILLED MESSAGE LISTENER
532 	// -=-=-=-=-=-=-=-=-=-=-=-=-=-
533 	// ---------------------------
534 	/**
535 	 * Listener that is hooked to WorldView awaiting event {@link BotKilled} calling
536 	 * botKilled method upon receiving the event.
537 	 */
538 	private IWorldEventListener<BotKilled> killedListener =
539 	        new IWorldEventListener<BotKilled>() {
540 	            @Override
541 	            public void notify(BotKilled event) {
542 	                getController().botKilled(event);
543 	            }
544 	        };
545 	        
546     // ------------------
547 	// -=-=-=-=--=-=-=-=-
548 	// FIRST END LISTENER
549 	// -=-=-=-=--=-=-=-=-
550 	// ------------------
551 	private IWorldEventListener<EndMessage> endListener = 
552 			new IWorldEventListener<EndMessage>() {
553 
554 				@Override
555 				public void notify(EndMessage event) {
556 					setState(new BotStateSpawned("First batch of informations received - calling botSpawned()."));
557 					controller.botFirstSpawn(getWorldView().getSingle(GameInfo.class), getWorldView().getSingle(ConfigChange.class), getWorldView().getSingle(InitedMessage.class), getWorldView().getSingle(Self.class));
558 					setState(new BotStateSpawned("botSpawned() finished, finalizing controller initialization..."));					
559 					controller.finishControllerInitialization();
560 					setState(new BotStateSpawned("finishControllerInitialization() finished, UT2004Bot is running."));
561 					getWorldView().removeEventListener(EndMessage.class, this);
562 					endMessageLatch.countDown();
563 				}
564 		
565 	};
566 
567 	//
568 	// UTILITY METHODS
569 	//
570 	
571 	/**
572 	 * Return's bot's {@link Self} object.
573 	 * 
574 	 * WARNING: this returns NULL until the first sync-batch is sent by GB2004 (first logic() called).
575 	 */
576 	public Self getSelf() {
577 		return getWorldView().getSingle(Self.class);
578 	}
579 	
580     /**
581      * @return Location of the agent. Null if not set yet.
582      */
583     public Location getLocation() {
584         Self self = getWorldView().getSingle(Self.class);
585         if (self != null) {
586             return self.getLocation();
587         }
588         return null;
589     }
590 
591     /**
592      * @return Rotation of the agent. Null if not set yet.
593      */
594     public Rotation getRotation() {
595         Self self = getWorldView().getSingle(Self.class);
596         if (self != null) {
597             return self.getRotation();
598         }
599         return null;
600     }
601 
602     /**
603      * @return Velocity of the agent. Null if not set yet.
604      */
605     public Velocity getVelocity() {
606         Self self = getWorldView().getSingle(Self.class);
607         if (self != null) {
608             return self.getVelocity();
609         }
610         return null;
611     }
612 
613     public void respawn() throws PogamutException {
614         getAct().act(new Respawn());
615     }
616 
617     @Override
618     protected AgentJMXComponents createAgentJMX() {
619         return new AgentJMXComponents<IUT2004Bot>(this) {
620 
621             @Override
622             protected AgentMBeanAdapter createAgentMBean(ObjectName objectName, MBeanServer mbs) throws MalformedObjectNameException, InstanceAlreadyExistsException, InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException {
623                 return new BotJMXMBeanAdapter(UT2004Bot.this, objectName, mbs);
624             }
625         };
626     }
627 
628     public void setBoolConfigure(BoolBotParam param, boolean value) {
629         try {
630             Configuration configuration = new Configuration();
631             // uff, copy all values manually
632             ConfigChange confCh = getWorldView().getSingle(ConfigChange.class);
633             configuration.copy(confCh);
634 
635             param.set(configuration, value);
636             param.setField(confCh, value);
637             getAct().act(configuration);
638         } catch (Exception ex) {
639         	// TODO: jimmy - co to je za logging?! ... mame log.severe() ...
640         	//       a nemel by se volat FATAL ERROR?! ... nebo tu vyjimku propagovat?
641             Logger.getLogger(UT2004Bot.class.getName()).log(Level.SEVERE, null, ex);
642         }
643     }
644 
645     public boolean getBoolConfigure(BoolBotParam param) {
646         try {
647             return param.get(getWorldView().getSingle(ConfigChange.class));
648         } catch (Exception ex) {
649         	// TODO: jimmy - co to je za logging?! ... mame log.severe() ...
650         	//     	 a nemel by se volat FATAL ERROR?! ... nebo tu vyjimku propagovat?
651             Logger.getLogger(UT2004Bot.class.getName()).log(Level.SEVERE, null, ex);
652             return false; // TODO
653         }
654     }
655 
656     @Override
657     protected Folder createIntrospection() {
658         return new ReflectionObjectFolder(AbstractAgent.INTROSPECTION_ROOT_NAME, controller);
659     }
660     
661     @Override
662     public WORLD_VIEW getWorldView() {
663     	return super.getWorldView();
664     }
665 
666     public UT2004BotName getBotName() {
667             return botName;
668     }
669     
670 }