View Javadoc

1   package cz.cuni.amis.pogamut.ut2004.agent.module.sensor;
2   
3   import java.util.Collection;
4   import java.util.Collections;
5   import java.util.HashMap;
6   import java.util.Map;
7   import java.util.logging.Logger;
8   
9   import cz.cuni.amis.pogamut.base.agent.module.SensorModule;
10  import cz.cuni.amis.pogamut.base.communication.worldview.IWorldView;
11  import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEvent;
12  import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEventListener;
13  import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectListener;
14  import cz.cuni.amis.pogamut.base.communication.worldview.object.event.WorldObjectUpdatedEvent;
15  import cz.cuni.amis.pogamut.base.utils.math.DistanceUtils;
16  import cz.cuni.amis.pogamut.base3d.worldview.object.ILocated;
17  import cz.cuni.amis.pogamut.unreal.communication.messages.UnrealId;
18  import cz.cuni.amis.pogamut.ut2004.bot.IUT2004BotController;
19  import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004Bot;
20  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.GameInfo;
21  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.NavPoint;
22  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Self;
23  import cz.cuni.amis.utils.collections.MyCollections;
24  
25  /**
26   * Memory module specialized on getting {@link NavPoint}s from the {@link IWorldView}.
27   * 
28   * <h2>Auto updating</h2>
29   *
30   * <p>All {@link NavPoint} objects returned by this memory module are always self-updating
31   * throughout the time, until the associated navPoint leaves the game. This means
32   * that once a valid NavPoint object is obtained, it is not necessary to call any
33   * methods of this memory module to get the object's info updated (e.g. navpoint's
34   * location, visibility, reachability, etc.). The object will autoupdate itself.
35   *
36   * <p>The same principle is applied to all Maps returned by this memory module.
37   * Each returned Map is self-updating throughout the time. Once a specific Map
38   * is obtained (e.g. a map of visible enemies) from this memory module, the Map
39   * will get updated based on actions of the navPoints (e.g. joining or leaving
40   * the game, changing their team, moving around the map, etc.) automatically.
41   *
42   * <p>Note: All Maps returned by this memory module are locked and can not be
43   * modified outside this memory module. If you need to modify a Map returned by
44   * this module (for your own specific purpose), create a duplicate first. Such
45   * duplicates, however and of course, will not get updated.
46   * 
47   * <p><b>WARNING:</b>It is totally unclear what UT2004 means by reachable!!!
48   * 
49   * <p><p>
50   * It is designed to be initialized inside {@link IUT2004BotController#prepareBot(UT2004Bot)} method call
51   * and may be used since {@link IUT2004BotController#botInitialized(cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.GameInfo, cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.ConfigChange, cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.InitedMessage)}
52   * is called.
53   * 
54   * @author Jimmy
55   */
56  public class NavPoints extends SensorModule<UT2004Bot> {
57  
58  	/**
59  	 * Retreives last known info about given navPoint.
60  	 *
61  	 * <p>Note: The returned NavPoint object is self updating throughout time.
62  	 * Once you have a valid NavPoint object, you do not have to call this
63  	 * method to get updated info about that navPoint.
64  	 * 
65  	 * <p>Note: If you have the string name only, you should use {@link #getNavPoint(String)} instead. 
66  	 *
67  	 * @param UnrealId NavPoint UnrealId to be retreived.
68  	 * @return Last known navPoint info; or null upon none.
69  	 *
70  	 * @see getNavPoint(nam)
71  	 * @see getVisibleNavPoint(UnrealId)
72  	 * @see getReachableNavPoint(UnrealId)
73  	 */
74  	public NavPoint getNavPoint(UnrealId UnrealId)
75  	{
76  		// retreive from map of all navPoints
77  		return navPoints.all.get(UnrealId);
78  	}
79  	
80  	/**
81  	 * Retreives last known info about given navPoint.
82  	 *
83  	 * <p>Note: The returned NavPoint object is self updating throughout time.
84  	 * Once you have a valid NavPoint object, you do not have to call this
85  	 * method to get updated info about that navPoint.
86  	 *
87  	 * @param String NavPoint name to be retreived, must not need to be prefixed with the map name
88  	 * @return Last known navPoint info; or null upon none.
89  	 *
90  	 * @see getVisibleNavPoint(UnrealId)
91  	 * @see getReachableNavPoint(UnrealId)
92  	 */
93  	public NavPoint getNavPoint(String name) {
94  		NavPoint result = navPoints.all.get(UnrealId.get(name));
95  		if (result != null) return result;
96  		GameInfo info = worldView.getSingle(GameInfo.class);
97  		if (info == null) return null;
98  		return navPoints.all.get(UnrealId.get(info.getLevel() + "." + name));
99  	}
100 	
101 	/**
102 	 * Returns {@link NavPoint} that is the nearest to the bot.
103 	 *
104 	 * @return
105 	 */
106 	public NavPoint getNearestNavPoint() {
107 		if (lastSelf == null) return null;
108 		return DistanceUtils.getNearest(navPoints.all.values(), lastSelf.getLocation());
109 	}
110 	
111 	
112 	/**
113 	 * Returns random navigation point.
114 	 * @return
115 	 */
116 	public NavPoint getRandomNavPoint() {
117 		return MyCollections.getRandom(navPoints.all.values());
118 	}
119 	
120 	/**
121 	 * Returns nearest {@link NavPoint} to the 'location'.
122 	 * @param location
123 	 * @return
124 	 */
125 	public NavPoint getNearestNavPoint(ILocated location) {
126 		if (location == null || location.getLocation() == null) return null;
127 		return DistanceUtils.getNearest(navPoints.all.values(), location);
128 	}
129 
130 	/**
131 	 * Retrieves info about given navPoint, but only it the navPoint is visible.
132 	 *
133 	 * <p>Note: The returned NavPoint object is self updating throughout time.
134 	 * Once you have a valid NavPoint object, you do not have to call this
135 	 * method to get updated info about visibility of that navPoint.
136 	 *
137 	 * @param UnrealId NavPoint UnrealId to be retrieved.
138 	 * @return NavPoint info; or null upon none or not visible.
139 	 *
140 	 * @see getNavPoint(UnrealId)
141 	 * @see getReachableNavPoint(UnrealId)
142 	 */
143 	public NavPoint getVisibleNavPoint(UnrealId UnrealId)
144 	{
145 		// retreive from map of all visible navPoints
146 		return navPoints.visible.get(UnrealId);
147 	}
148 
149 	/*========================================================================*/
150 
151 	/**
152 	 * Retreives a Map of all navPoints.
153 	 *
154 	 * <p>Note: The returned Map is unmodifiable and self updating throughout
155 	 * time. Once you obtain a specific Map of navPoints from this memory module,
156 	 * the Map will get updated based on actions of the navPoints (e.g. joining
157 	 * or leaving the game, changing their status, etc.).
158 	 *
159 	 * @return Map of all navPoints, using their UnrealIds as keys.
160 	 *
161 	 * @see getEnemies()
162 	 * @see getFriends()
163 	 * @see getVisibleNavPoints()
164 	 * @see getReachableNavPoints()
165 	 */
166 	public Map<UnrealId, NavPoint> getNavPoints()
167 	{
168 		// publish map of all navPoints
169 		return Collections.unmodifiableMap(navPoints.all);
170 	}
171 
172 	/*========================================================================*/
173 
174 	/**
175 	 * Retrieves a Map of all visible navPoints.
176 	 *
177 	 * <p>Note: The returned Map is unmodifiable and self updating throughout
178 	 * time. Once you obtain a specific Map of navPoints from this memory module,
179 	 * the Map will get updated based on actions of the navPoints (e.g. joining
180 	 * or leaving the game, or changing their visibility, etc.).
181 	 *
182 	 * @return Map of all visible navPoints, using their UnrealIds as keys.
183 	 *
184 	 * @see getNavPoints()
185 	 * @see getVisibleEnemies()
186 	 * @see getVisibleFriends()
187 	 * @see canSeeNavPoints()
188 	 */
189 	public Map<UnrealId, NavPoint> getVisibleNavPoints()
190 	{
191 		// publish map of all visible navPoints
192 		return Collections.unmodifiableMap(navPoints.visible);
193 	}
194 
195 	/*========================================================================*/
196 
197 	/**
198 	 * Returns nearest navPoint that is visible or that was 'recently' visible. If no such navPoint exists, returns null.
199 	 * 
200 	 * @param recently how long the navPoint may be non-visible. IN MILISECONDS!
201 	 * @return nearest visible or 'recentlyVisibleTime' visible navPoint
202 	 */
203 	public NavPoint getRecentlyVisibleNavPoint(double recently) {	
204 		NavPoint nearest = null;
205 		double distance = Double.MAX_VALUE;
206 		for (NavPoint plr : navPoints.all.values()) {
207 			if (plr.isVisible() || lastSelf.getSimTime() - plr.getSimTime() <= recently) {
208 				double d = lastSelf.getLocation().getDistance(plr.getLocation());
209 				if (d < distance) {
210 					distance = d;
211 					nearest = plr;
212 				}
213 			}
214 		}
215 		return nearest;
216 	}
217 	
218 	/**
219 	 * Returns nearest-visible navPoint - if no if no navPoint is visible returns null.
220 	 * 
221 	 * @return nearest visible navPoint
222 	 */
223 	public NavPoint getNearestVisibleNavPoint() {		
224         return DistanceUtils.getNearest(navPoints.visible.values(), lastSelf.getLocation());
225 	}
226 	
227 	/**
228 	 * Returns nearest-visible navPoint to the bot from the collection of 'navPoints' - if no navPoint
229 	 * is visible  returns null.
230 	 * 
231 	 * @param navPoints collection to go through
232 	 * @return nearest visible navPoint from the collection
233 	 */
234 	public NavPoint getNearestVisibleNavPoint(Collection<NavPoint> navPoints) {		
235         return DistanceUtils.getNearestVisible(navPoints, lastSelf.getLocation());
236 	}
237 	
238 	/**
239 	 * Returns random visible navPoint - if no if no navPoint is visible returns null.
240 	 * 
241 	 * @return random visible navPoint
242 	 */
243 	public NavPoint getRandomVisibleNavPoint() {		
244         return MyCollections.getRandom(navPoints.visible.values());
245 	}
246 	
247 	/*========================================================================*/
248 
249 	/**
250 	 * Tells, whether the agent sees any other navPoints.
251 	 *
252 	 * @return True, if at least one other navPoint is visible; false otherwise.
253 	 *
254 	 * @see getVisibleNavPoints()
255 	 */
256 	public boolean canSeeNavPoints()
257 	{
258 		// search map of all visible navPoints
259 		return (navPoints.visible.size() > 0);
260 	}
261 
262 	/*========================================================================*/
263 
264 	/**
265 	 * Maps of navPoints of specific type.
266 	 */
267 	private class NavPointMaps
268 	{
269 		/** Map of all navPoints of the specific type. */
270 		private HashMap<UnrealId, NavPoint> all = new HashMap<UnrealId, NavPoint> ();
271 		/** Map of visible navPoints of the specific type. */
272 		private HashMap<UnrealId, NavPoint> visible = new HashMap<UnrealId, NavPoint> ();
273 
274 		/**
275 		 * Processes events.
276 		 * @param navPoint NavPoint to process.
277 		 */
278 		private void notify(NavPoint navPoint)
279 		{
280 			UnrealId uid = navPoint.getId();
281 
282 			// be sure to be within all
283 			if (!all.containsKey(uid))
284 				all.put(uid, navPoint);
285 
286 			// previous visibility
287 			boolean wasVisible = visible.containsKey(uid);
288 			boolean isVisible = navPoint.isVisible();
289 
290 			// refresh visible
291 			if (isVisible && !wasVisible)
292 			{
293 				// add to visibles
294 				visible.put(uid, navPoint);
295 			}
296 			else if (!isVisible && wasVisible)
297 			{
298 				// remove from visibles
299 				visible.remove(uid);
300 			}
301 
302 		}
303 
304 		/**
305 		 * Removes navPoint from all maps.
306 		 * @param uid UnrealId of navPoint to be removed.
307 		 */
308 		private void remove(UnrealId uid)
309 		{
310 			// remove from all maps
311 			all.remove(uid);
312 			visible.remove(uid);
313 		}
314 
315 		private void clear() {
316 			all.clear();
317 			visible.clear();
318 		}
319 	}
320 
321 	/** Maps of all navPoints. */
322 	private NavPointMaps navPoints = new NavPointMaps ();
323 
324 	/*========================================================================*/
325 
326 	/**
327 	 * NavPoint listener.
328 	 */
329 	private class NavPointListener implements IWorldObjectEventListener<NavPoint, WorldObjectUpdatedEvent<NavPoint>>
330 	{
331 		@Override
332 		public void notify(WorldObjectUpdatedEvent<NavPoint> event)
333 		{
334             NavPoint navPoint = event.getObject();
335 			// do the job in map of navPoints
336 			navPoints.notify(navPoint);
337 		}
338 
339 		/**
340 		 * Constructor. Registers itself on the given WorldView object.
341 		 * @param worldView WorldView object to listent to.
342 		 */
343 		public NavPointListener(IWorldView worldView)
344 		{
345 			worldView.addObjectListener(NavPoint.class, WorldObjectUpdatedEvent.class, this);
346 		}
347 	}
348 
349 	/** NavPoint listener */
350 	NavPointListener navPointListener;
351 
352 	/*========================================================================*/
353 	
354 	/**
355 	 * Self listener.
356 	 */
357 	private class SelfListener implements IWorldObjectListener<Self>
358 	{
359 		@Override
360 		public void notify(IWorldObjectEvent<Self> event)
361 		{
362 			if (lastSelf == null || lastSelf.getTeam() != event.getObject().getTeam()) {
363 				lastSelf = event.getObject();				
364 			} else {
365 				lastSelf = event.getObject();
366 			}
367 		}
368 
369 		/**
370 		 * Constructor. Registers itself on the given WorldView object.
371 		 * @param worldView WorldView object to listent to.
372 		 */
373 		public SelfListener(IWorldView worldView)
374 		{
375 			worldView.addObjectListener(Self.class, this);
376 		}
377 	}
378 
379 	/** Self listener */
380 	SelfListener selfListener;
381 	
382 	Self lastSelf = null;
383 	
384 	/**
385 	 * Constructor. Setups the memory module based on bot's world view.
386 	 * @param bot owner of the module that is using it
387 	 */
388 	public NavPoints(UT2004Bot bot)
389 	{
390 		this(bot, null);
391 	}
392 	
393 	/**
394 	 * Constructor. Setups the memory module based on bot's world view.
395 	 * @param bot owner of the module that is using it
396 	 * @param log Logger to be used for logging runtime/debug info. If <i>null</i>, module creates its own logger.
397 	 */
398 	public NavPoints(UT2004Bot bot, Logger log)
399 	{
400 		super(bot, log);
401 		
402 		// create listeners
403 		navPointListener =     new NavPointListener(worldView);
404 		selfListener =       new SelfListener(worldView);
405 		
406 		cleanUp();
407 	}
408 	
409 	@Override
410 	protected void cleanUp() {
411 		super.cleanUp();
412 		lastSelf = null;
413 		navPoints.clear();		
414 	}
415 	
416 }