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