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