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