View Javadoc

1   package cz.cuni.amis.pogamut.ut2004.agent.module.sensor;
2   
3   import java.util.ArrayList;
4   import java.util.Collections;
5   import java.util.HashMap;
6   import java.util.HashSet;
7   import java.util.Iterator;
8   import java.util.List;
9   import java.util.Map;
10  import java.util.Random;
11  import java.util.Set;
12  import java.util.logging.Logger;
13  
14  import cz.cuni.amis.pogamut.base.agent.module.SensorModule;
15  import cz.cuni.amis.pogamut.base.agent.navigation.IPathPlanner;
16  import cz.cuni.amis.pogamut.base.communication.worldview.IWorldView;
17  import cz.cuni.amis.pogamut.base.communication.worldview.event.IWorldEventListener;
18  import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEvent;
19  import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEventListener;
20  import cz.cuni.amis.pogamut.base.communication.worldview.object.event.WorldObjectUpdatedEvent;
21  import cz.cuni.amis.pogamut.base.utils.math.DistanceUtils;
22  import cz.cuni.amis.pogamut.base.utils.math.DistanceUtils.IGetDistance;
23  import cz.cuni.amis.pogamut.base3d.worldview.object.ILocated;
24  import cz.cuni.amis.pogamut.unreal.communication.messages.UnrealId;
25  import cz.cuni.amis.pogamut.ut2004.agent.module.sensomotoric.Weaponry;
26  import cz.cuni.amis.pogamut.ut2004.agent.module.utils.TabooSet;
27  import cz.cuni.amis.pogamut.ut2004.agent.navigation.floydwarshall.FloydWarshallMap;
28  import cz.cuni.amis.pogamut.ut2004.bot.IUT2004BotController;
29  import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004Bot;
30  import cz.cuni.amis.pogamut.ut2004.communication.messages.ItemType;
31  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.EndMessage;
32  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Item;
33  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.ItemPickedUp;
34  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.NavPoint;
35  import cz.cuni.amis.pogamut.ut2004.communication.translator.shared.events.MapPointListObtained;
36  import cz.cuni.amis.pogamut.ut2004.utils.UnrealUtils;
37  import cz.cuni.amis.utils.NullCheck;
38  import cz.cuni.amis.utils.collections.MyCollections;
39  import cz.cuni.amis.utils.maps.HashMapMap;
40  
41  /**
42   * Memory module specialized on items on the map.
43   * <p><p>
44   * Apart from providing useful getters based on {@link ItemType}, {@link ItemType.Group} and {@link ItemType.Category} it also
45   * provides an optimistic approach for guessing whether some item is spawned inside the map via getSpawnedXYZ methods
46   * such as {@link Items#getSpawnedItems()}.
47   * <p><p>
48   * <b>WARNING:</b>There are methods that contains "reachable" in its name but it is totally unclear what UT2004 means by reachable!!!
49   * These methods are for experimenting purposes only.
50   * <p><p>
51   * It is designed to be initialized inside {@link IUT2004BotController#prepareBot(UT2004Bot)} method call
52   * 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)}
53   * is called.
54   *
55   * @author Juraj 'Loque' Simlovic
56   * @author Jimmy
57   */
58  public abstract class Items extends SensorModule<UT2004Bot> {	
59  	
60  	private Random random = new Random(System.currentTimeMillis());
61  	
62  	private IPathPlanner<NavPoint> pathPlanner = null;
63  	
64  	private NavPoint obtainNavPoint(ILocated obj) {
65  		if (obj instanceof NavPoint) return (NavPoint)obj;
66  		if (obj instanceof Item) return ((Item)obj).getNavPoint();
67  		return null;
68  	}
69  	
70  	private IGetDistance<ILocated> pathPlannerGetDistance = new IGetDistance<ILocated>() {
71  
72  		@Override
73  		public double getDistance(ILocated object, ILocated target) {
74  			if (object == null || target == null) return Double.POSITIVE_INFINITY;
75  			if (pathPlanner == null) return target.getLocation().getDistance(object.getLocation());
76  			NavPoint objectNP = obtainNavPoint(object);
77  			NavPoint targetNP = obtainNavPoint(target);
78  			if (objectNP == null || targetNP == null) return Double.POSITIVE_INFINITY;
79  			return pathPlanner.getDistance(objectNP, targetNP);
80  		}
81  		
82  	};
83  	
84  	/**
85  	 * Sets {@link IPathPlanner} (typically {@link FloydWarshallMap}) to be used by the module in order to
86  	 * determine path-distance to items. 
87  	 * @param pathPlanner
88  	 */
89  	public void setPathPlanner(IPathPlanner<NavPoint> pathPlanner) {
90  		this.pathPlanner = pathPlanner;
91  	}
92  
93  	/**
94  	 * Method that determines whether 'item' is pickable in the current state of the bot.
95  	 * E.g., it asseses health for health items, ammo for weapons & ammo, etc.
96  	 * <p><p>
97  	 * Contributed by: David Holan
98  	 * 
99  	 * @param item
100 	 * @return
101 	 */
102 	public abstract boolean isPickable(Item item);
103 	
104 	/*========================================================================*/
105 	
106 	/**
107 	 * Retrieves list of all items, which includes all known pickups and all
108 	 * visible thrown items.
109 	 *
110 	 * <p>Note: The returned Map is unmodifiable and self updating throughout
111 	 * time. Once you obtain a specific Map of items from this module, the Map
112 	 * will get updated based on what happens within the map.
113 	 *
114 	 * @return List of all items. Note: Spawned items are included only.
115 	 */
116 	public Map<UnrealId, Item> getAllItems()
117 	{
118 		return Collections.unmodifiableMap(items.all);
119 	}
120 
121 	/**
122 	 * Retrieves list of all items <b>of specific type</b>.
123 	 *
124 	 * <p>Note: The returned Map is unmodifiable and self updating throughout
125 	 * time. Once you obtain a specific Map of items from this module, the Map
126 	 * will get updated based on what happens within the map.
127 	 *
128 	 * @return List of all items of specific type. Note: Spawned items are included only.
129 	 */
130 	public Map<UnrealId, Item> getAllItems(ItemType type)
131 	{
132 		return Collections.unmodifiableMap(items.allCategories.get(type));
133 	}
134 	
135 	/**
136 	 * Retrieves map of all items belonging to a <b>specific 'category'</b> of items, which
137 	 * includes all known pickups.
138 	 * 
139 	 * <p>Note: The returned Map is modifiable and is always constructed upon every
140 	 * invocation of this method.
141 	 * 
142 	 * <p><p>WARNING: O(n) complexity!
143 	 * 
144 	 * @param category
145 	 * @return Map of all items of a specific category.
146 	 */
147 	public Map<UnrealId, Item> getAllItems(ItemType.Category category) {
148 		Map<UnrealId, Item> result = new HashMap<UnrealId, Item>();
149 		for (ItemType type : category.getTypes()) {
150 			result.putAll(getAllItems(type));
151 		}
152 		return result;
153 	}
154 	
155 	/**
156 	 * Retrieves map of all items belonging to a <b>specific 'group'</b> of items, which
157 	 * includes all known pickups.
158 	 * 
159 	 * <p>Note: The returned Map is modifiable and is always constructed upon every
160 	 * invocation of this method.
161 	 * 
162 	 * <p><p>WARNING: O(n) complexity!
163 	 * 
164 	 * @param group
165 	 * @return Map of all items of a specific group.
166 	 */
167 	public Map<UnrealId, Item> getAllItems(ItemType.Group group) {
168 		Map<UnrealId, Item> result = new HashMap<UnrealId, Item>();
169 		for (ItemType type : group.getTypes()) {
170 			result.putAll(getAllItems(type));
171 		}
172 		return result;
173 	}
174 
175 	/**
176 	 * Retrieves a specific item from the all items in the map.
177 	 * <p><p>
178 	 * Once obtained it is self-updating based on what happens in the game.
179 	 *
180 	 * @param id
181 	 * @return A specific Item be it Spawned or Dropped (Dropped item must be visible though!).
182 	 */
183 	public Item getItem(UnrealId id) {
184 		Item item = items.all.get(id);
185 		if (item == null) item = items.visible.get(id);
186 		return item;
187 	}
188 
189 	/**
190 	 * Retrieves a specific item from the all items in the map.
191 	 * <p><p>
192 	 * Once obtained it is self-updating based on what happens in the game.
193 	 *
194 	 * @param stringUnrealId
195 	 * @return A specific Item be it Spawned or Dropped (Dropped item must be visible though!).
196 	 */
197 	public Item getItem(String stringUnrealId) {
198 		return getItem(UnrealId.get(stringUnrealId));
199 	}
200 	
201 	/**
202 	 * Returns random item from 'all' items.
203 	 * <p><p>
204 	 * Note that there is no need to provide all "getRandomXYZ(xyz)", just
205 	 * use {@link MyCollections#getRandom(java.util.Collection)}. 
206 	 * @return A specific Item be it Spawned or Dropped (Dropped item must be visible though!).
207 	 */
208 	public Item getRandomItem() {
209 		if (getAllItems().size() == 0) return null;
210 		int num = random.nextInt(getAllItems().size());
211 		Iterator<Item> iter = getAllItems().values().iterator();
212 		for (int i = 0; i < num-1; ++i) iter.next();
213 		return iter.next();
214 	}
215 	
216 	/**
217 	 * Returns nearest-by-air (Euclidean norm) item spawning point from 'all' items.
218 	 * Does not need to be necessarily spawned right now. 
219 	 * @return A nearest Item be it Spawned or Dropped (Dropped item must be visible though!).
220 	 */
221 	public Item getNearestItem() {
222 		return DistanceUtils.getNearest(getAllItems().values(), agentInfo.getLocation());
223 	}
224 	
225 	/**
226 	 * Returns nearest-by-path (using {@link #pathPlanner} previously injected via {@link #setPathPlanner(IPathPlanner)}) item spawning point from 'all' items EXCEPT DROPPED ONES!
227 	 * Does not need to be necessarily spawned right now. 
228 	 * @return A nearest Item be it Spawned.
229 	 */
230 	public Item getPathNearestItem() {
231 		return DistanceUtils.getNearest(getAllItems().values(), agentInfo.getNearestNavPoint(), pathPlannerGetDistance);
232 	}
233 	
234 	/**
235 	 * Returns nearest-by-air (Euclidean norm) item spawning point from 'all' items of specific category.
236 	 * Does not need to be necessarily spawned right now. 
237 	 * @param category 
238 	 * @return A nearest Item be it Spawned or Dropped (Dropped item must be visible though!) of specific category.
239 	 */
240 	public Item getNearestItem(ItemType.Category category) {
241 		return DistanceUtils.getNearest(getAllItems(category).values(), agentInfo.getLocation());
242 	}
243 	
244 	/**
245 	 * Returns nearest-by-path (using {@link #pathPlanner} previously injected via {@link #setPathPlanner(IPathPlanner)}) item spawning point from 'all' items EXCEPT DROPPED ONES!
246 	 * Does not need to be necessarily spawned right now. 
247 	 * @param category
248 	 * @return A nearest Item be it Spawned of specific category.
249 	 */
250 	public Item getPathNearestItem(ItemType.Category category) {
251 		return DistanceUtils.getNearest(getAllItems(category).values(), agentInfo.getNearestNavPoint(), pathPlannerGetDistance);
252 	}
253 	
254 	/**
255 	 * Returns nearest-by-air (Euclidean norm) item spawning point from 'all' items of specific group.
256 	 * Does not need to be necessarily spawned right now. 
257 	 * @param group 
258 	 * @return A nearest Item be it Spawned or Dropped (Dropped item must be visible though!) of specific group.
259 	 */
260 	public Item getNearestItem(ItemType.Group group) {
261 		return DistanceUtils.getNearest(getAllItems(group).values(), agentInfo.getLocation());
262 	}
263 	
264 	/**
265 	 * Returns nearest-by-path (using {@link #pathPlanner} previously injected via {@link #setPathPlanner(IPathPlanner)}) item spawning point from 'all' items EXCEPT DROPPED ONES!
266 	 * Does not need to be necessarily spawned right now. 
267 	 * @param group 
268 	 * @return A nearest Item be it Spawned of specific group.
269 	 */
270 	public Item getPathNearestItem(ItemType.Group group) {
271 		return DistanceUtils.getNearest(getAllItems(group).values(), agentInfo.getNearestNavPoint(), pathPlannerGetDistance);
272 	}
273 	
274 	/**
275 	 * Returns nearest-by-air (Euclidean norm) item spawning point from 'all' items of specific type.
276 	 * Does not need to be necessarily spawned right now. 
277 	 * @param group 
278 	 * @return A nearest Item be it Spawned or Dropped (Dropped item must be visible though!) of specific category.
279 	 */
280 	public Item getNearestItem(ItemType type) {
281 		return DistanceUtils.getNearest(getAllItems(type).values(), agentInfo.getLocation());
282 	}
283 	
284 	/**
285 	 * Returns nearest-by-path (using {@link #pathPlanner} previously injected via {@link #setPathPlanner(IPathPlanner)}) item spawning point from 'all' items EXCEPT DROPPED ONES!
286 	 * Does not need to be necessarily spawned right now. 
287 	 * @param type
288 	 * @return A nearest Item be it Spawned of specific type.
289 	 */
290 	public Item getPathNearestItem(ItemType type) {
291 		return DistanceUtils.getNearest(getAllItems(type).values(), agentInfo.getNearestNavPoint(), pathPlannerGetDistance);
292 	}
293 
294 	/*========================================================================*/
295 
296 	/**
297 	 * Retreives list of all visible items, which includes all visible known
298 	 * pickups and all visible thrown items.
299 	 *
300 	 * <p>Note: The returned Map is unmodifiable and self updating throughout
301 	 * time. Once you obtain a specific Map of items from this module, the Map
302 	 * will get updated based on what happens within the map.
303 	 *
304 	 * @return List of all visible items. Note: Spawned items are included only.
305 	 */
306 	public Map<UnrealId, Item> getVisibleItems()
307 	{
308 		return Collections.unmodifiableMap(items.visible);
309 	}
310 
311 	/**
312 	 * Retreives list of all visible items <b> of specific type</b>, which includes all visible known
313 	 * pickups and all visible thrown items.
314 	 *
315 	 * <p>Note: The returned Map is unmodifiable and self updating throughout
316 	 * time. Once you obtain a specific Map of items from this module, the Map
317 	 * will get updated based on what happens within the map.
318 	 *
319 	 * @return List of all visible items of specific type. Note: Spawned items are included only.
320 	 */
321 	public Map<UnrealId, Item> getVisibleItems(ItemType type)
322 	{
323 		return Collections.unmodifiableMap(items.visibleCategories.get(type));
324 	}
325 	
326 	/**
327 	 * Retrieves map of visible items belonging to a <b>specific 'category'</b> of items, which
328 	 * includes all known pickups.
329 	 * 
330 	 * <p>Note: The returned Map is modifiable and is always constructed upon every
331 	 * invocation of this method.
332 	 * 
333 	 * <p><p>WARNING: O(n) complexity!
334 	 * 
335 	 * @param category
336 	 * @return Map of visible items of a specific category.
337 	 */
338 	public Map<UnrealId, Item> getVisibleItems(ItemType.Category category) {
339 		Map<UnrealId, Item> result = new HashMap<UnrealId, Item>();
340 		for (ItemType type : category.getTypes()) {
341 			result.putAll(getVisibleItems(type));
342 		}
343 		return result;
344 	}
345 	
346 	/**
347 	 * Retrieves map of visible items belonging to a <b>specific 'group'</b> of items, which
348 	 * includes all known pickups.
349 	 * 
350 	 * <p>Note: The returned Map is modifiable and is always constructed upon every
351 	 * invocation of this method.
352 	 * 
353 	 * <p><p>WARNING: O(n) complexity!
354 	 * 
355 	 * @param group
356 	 * @return Map of visible items of a specific group.
357 	 */
358 	public Map<UnrealId, Item> getVisibleItems(ItemType.Group group) {
359 		Map<UnrealId, Item> result = new HashMap<UnrealId, Item>();
360 		for (ItemType type : group.getTypes()) {
361 			result.putAll(getVisibleItems(type));
362 		}
363 		return result;
364 	}
365 
366 	/**
367 	 * Retrieves a specific item from the visible items in the map. If item of specified
368 	 * id is not visible returns null.
369 	 * <p><p>
370 	 * Once obtained it is self-updating based on what happens in the game.
371 	 *
372 	 * @param id
373 	 * @return A specific Item be it Spawned or Dropped.
374 	 */
375 	public Item getVisibleItem(UnrealId id) {
376 		Item item = items.visible.get(id);
377 		return item;
378 	}
379 
380 	/**
381 	 * Retrieves a specific item from the visible items in the map. If item of specified
382 	 * id is not visible returns null.
383 	 * <p><p>
384 	 * Once obtained it is self-updating based on what happens in the game.
385 	 *
386 	 * @param stringUnrealId
387 	 * @return A specific Item be it Spawned or Dropped.
388 	 */
389 	public Item getVisibleItem(String stringUnrealId) {
390 		return getVisibleItem(UnrealId.get(stringUnrealId));
391 	}
392 	
393 	/**
394 	 * Returns nearest-by-air (Euclidean norm) item spawning point from visible items.
395 	 * Does not need to be necessarily spawned right now. 
396 	 * @return A nearest visible Item be it Spawned or Dropped (Dropped item must be visible though!).
397 	 */
398 	public Item getNearestVisibleItem() {
399 		return DistanceUtils.getNearest(getVisibleItems().values(), agentInfo.getLocation());
400 	}
401 	
402 	/**
403 	 * Returns nearest-by-path (using {@link #pathPlanner} previously injected via {@link #setPathPlanner(IPathPlanner)}) item spawning point from visible items EXCEPT DROPPED ONES!
404 	 * Does not need to be necessarily spawned right now. 
405 	 * @return A nearest visible Item be it Spawned.
406 	 */
407 	public Item getPathNearestVisibleItem() {
408 		return DistanceUtils.getNearest(getVisibleItems().values(), agentInfo.getNearestNavPoint(), pathPlannerGetDistance);
409 	}
410 	
411 	/**
412 	 * Returns nearest-by-air (Euclidean norm) item spawning point from visible items of specific category.
413 	 * Does not need to be necessarily spawned right now. 
414 	 * @param category 
415 	 * @return A nearest visible Item be it Spawned or Dropped (Dropped item must be visible though!) of specific category.
416 	 */
417 	public Item getNearestVisibleItem(ItemType.Category category) {
418 		return DistanceUtils.getNearest(getVisibleItems(category).values(), agentInfo.getLocation());
419 	}
420 	
421 	/**
422 	 * Returns nearest-by-path (using {@link #pathPlanner} previously injected via {@link #setPathPlanner(IPathPlanner)}) item spawning point from visible items EXCEPT DROPPED ONES!
423 	 * Does not need to be necessarily spawned right now. 
424 	 * @param category
425 	 * @return A nearest visible Item be it Spawned of specific category.
426 	 */
427 	public Item getPathNearestVisibleItem(ItemType.Category category) {
428 		return DistanceUtils.getNearest(getVisibleItems(category).values(), agentInfo.getNearestNavPoint(), pathPlannerGetDistance);
429 	}
430 	
431 	/**
432 	 * Returns nearest-by-air (Euclidean norm) item spawning point from visible items of specific group.
433 	 * Does not need to be necessarily spawned right now. 
434 	 * @param group 
435 	 * @return A nearest visible Item be it Spawned or Dropped (Dropped item must be visible though!) of specific group.
436 	 */
437 	public Item getNearestVisibleItem(ItemType.Group group) {
438 		return DistanceUtils.getNearest(getVisibleItems(group).values(), agentInfo.getLocation());
439 	}
440 	
441 	/**
442 	 * Returns nearest-by-path (using {@link #pathPlanner} previously injected via {@link #setPathPlanner(IPathPlanner)}) item spawning point from visible items EXCEPT DROPPED ONES!
443 	 * Does not need to be necessarily spawned right now. 
444 	 * @param group 
445 	 * @return A nearest visible Item be it Spawned of specific group.
446 	 */
447 	public Item getPathNearestVisibleItem(ItemType.Group group) {
448 		return DistanceUtils.getNearest(getVisibleItems(group).values(), agentInfo.getNearestNavPoint(), pathPlannerGetDistance);
449 	}
450 	
451 	/**
452 	 * Returns nearest-by-air (Euclidean norm) item spawning point from visible items of specific type.
453 	 * Does not need to be necessarily spawned right now. 
454 	 * @param group 
455 	 * @return A nearest visible Item be it Spawned or Dropped (Dropped item must be visible though!) of specific category.
456 	 */
457 	public Item getNearestVisibleItem(ItemType type) {
458 		return DistanceUtils.getNearest(getVisibleItems(type).values(), agentInfo.getLocation());
459 	}
460 	
461 	/**
462 	 * Returns nearest-by-path (using {@link #pathPlanner} previously injected via {@link #setPathPlanner(IPathPlanner)}) item spawning point from visible items EXCEPT DROPPED ONES!
463 	 * Does not need to be necessarily spawned right now. 
464 	 * @param type
465 	 * @return A nearest visible Item be it Spawned of specific type.
466 	 */
467 	public Item getPathNearestVisibleItem(ItemType type) {
468 		return DistanceUtils.getNearest(getVisibleItems(type).values(), agentInfo.getNearestNavPoint(), pathPlannerGetDistance);
469 	}
470 	
471 	/*========================================================================*/
472 
473 	/**
474 	 * Retrieves list of all known item pickup points.
475 	 *
476 	 * <p>Note: The returned Map is unmodifiable and self updating throughout
477 	 * time. Once you obtain a specific Map of items from this module, the Map
478 	 * will get updated based on what happens within the map.
479 	 *
480 	 * @return List of all items. Note: Empty pickups are included as well.
481 	 *
482 	 * @see isPickupSpawned(Item)
483 	 */
484 	public Map<UnrealId, Item> getKnownPickups()
485 	{
486 		return Collections.unmodifiableMap(items.known);
487 	}
488 
489 	/**
490 	 * Retrieves list of all known item pickup points <b>of specific type</b>.
491 	 *
492 	 * <p>Note: The returned Map is unmodifiable and self updating throughout
493 	 * time. Once you obtain a specific Map of items from this module, the Map
494 	 * will get updated based on what happens within the map.
495 	 *
496 	 * @return List of all items of specific type. Note: Empty pickups are included as well.
497 	 *
498 	 * @see isPickupSpawned(Item)
499 	 */
500 	public Map<UnrealId, Item> getKnownPickups(ItemType type)
501 	{
502 		return Collections.unmodifiableMap(items.knownCategories.get(type));
503 	}
504 	
505 	/**
506 	 * Retrieves map of all known pickups belonging to a <b>specific 'category'</b> of items, which
507 	 * includes all known pickups.
508 	 * 
509 	 * <p>Note: The returned Map is modifiable and is always constructed upon every
510 	 * invocation of this method.
511 	 * 
512 	 * <p><p>WARNING: O(n) complexity!
513 	 * 
514 	 * @param category
515 	 * @return Map of known pickups of a specific category.
516 	 */
517 	public Map<UnrealId, Item> getKnownPickups(ItemType.Category category) {
518 		Map<UnrealId, Item> result = new HashMap<UnrealId, Item>();
519 		for (ItemType type : category.getTypes()) {
520 			result.putAll(getKnownPickups(type));
521 		}
522 		return result;
523 	}
524 	
525 	/**
526 	 * Retrieves map of all known pickups belonging to a <b>specific 'group'</b> of items, which
527 	 * includes all known pickups.
528 	 * 
529 	 * <p>Note: The returned Map is modifiable and is always constructed upon every
530 	 * invocation of this method.
531 	 * 
532 	 * <p><p>WARNING: O(n) complexity!
533 	 * 
534 	 * @param group
535 	 * @return Map of known pickups of a specific group.
536 	 */
537 	public Map<UnrealId, Item> getKnownPickups(ItemType.Group group) {
538 		Map<UnrealId, Item> result = new HashMap<UnrealId, Item>();
539 		for (ItemType type : group.getTypes()) {
540 			result.putAll(getKnownPickups(type));
541 		}
542 		return result;
543 	}
544 
545 	/**
546 	 * Retrieves a specific pickup point.
547 	 * <p><p>
548 	 * Once obtained it is self-updating based on what happens in the game.
549 	 *
550 	 * @param id
551 	 * @return A specific Item be it Spawned or Dropped (Dropped item must be visible though!).
552 	 */
553 	public Item getKnownPickup(UnrealId id) {
554 		return items.known.get(id);
555 	}
556 
557 	/**
558 	 * Retrieves a specific pickup point.
559 	 * <p><p>
560 	 * Once obtained it is self-updating based on what happens in the game.
561 	 *
562 	 * @param stringUnrealId
563 	 * @return A specific Item be it Spawned or Dropped (Dropped item must be visible though!).
564 	 */
565 	public Item getKnownPickup(String stringUnrealId) {
566 		return getKnownPickup(UnrealId.get(stringUnrealId));
567 	}
568 
569 	/*========================================================================*/
570 	
571 	/**
572 	 * Uses {@link Items#isPickupSpawned(Item)} to return all items that are believed to 
573 	 * be currently spawned.
574 	 * 
575 	 * <p><p>WARNING: O(n) complexity!
576 	 * 
577 	 * @return collection of spawned items
578 	 */
579 	public Map<UnrealId, Item> getSpawnedItems() {
580 		Map<UnrealId, Item> result = new HashMap<UnrealId, Item>();
581 		for (Item item : getAllItems().values()) {
582 			if (isPickupSpawned(item)) result.put(item.getId(), item);
583 		}
584 		return result;
585 	}
586 	
587 	/**
588 	 * Uses {@link Items#isPickupSpawned(Item)} to return all items of 'type' that are believed to 
589 	 * be currently spawned.
590 	 * 
591 	 * <p><p>WARNING: O(n) complexity!
592 	 * 
593 	 * @return Map of spawned items of a specific type.
594 	 */
595 	public Map<UnrealId, Item> getSpawnedItems(ItemType type) {
596 		Map<UnrealId, Item> result = new HashMap<UnrealId, Item>();
597 		for (Item item : getAllItems(type).values()) {
598 			if (isPickupSpawned(item)) {
599 				result.put(item.getId(), item);
600 			}
601 		}
602 		return result;
603 	}
604 	
605 	/**
606 	 * Uses {@link Items#isPickupSpawned(Item)} to return all items belonging to a specific 'category' that are believed to 
607 	 * be currently spawned.
608 	 * 
609 	 * <p>Note: The returned Map is modifiable and is always constructed upon every
610 	 * invocation of this method.
611 	 * 
612 	 * <p><p>WARNING: O(n) complexity!
613 	 * 
614 	 * @param category
615 	 * @return Map of spawned items of a specific category.
616 	 */
617 	public Map<UnrealId, Item> getSpawnedItems(ItemType.Category category) {
618 		Map<UnrealId, Item> result = new HashMap<UnrealId, Item>();
619 		for (ItemType type : category.getTypes()) {
620 			result.putAll(getSpawnedItems(type));
621 		}
622 		return result;
623 	}
624 	
625 	/**
626 	 * Uses {@link Items#isPickupSpawned(Item)} to return all items belonging to a specific 'group' that are believed to 
627 	 * be currently spawned.
628 	 * 
629 	 * <p>Note: The returned Map is modifiable and is always constructed upon every
630 	 * invocation of this method.
631 	 * 
632 	 * <p><p>WARNING: O(n) complexity!
633 	 * 
634 	 * @param group
635 	 * @return Map of spawned items of a specific group.
636 	 */
637 	public Map<UnrealId, Item> getSpawnedItems(ItemType.Group group) {
638 		Map<UnrealId, Item> result = new HashMap<UnrealId, Item>();
639 		for (ItemType type : group.getTypes()) {
640 			result.putAll(getSpawnedItems(type));
641 		}
642 		return result;
643 	}
644 	
645 	/**
646 	 * Returns nearest-by-air (Euclidean norm) item spawning point from spawned items.
647 	 * Does not need to be necessarily spawned right now. 
648 	 * @return A nearest spawned Item be it Spawned or Dropped (Dropped item must be visible though!).
649 	 */
650 	public Item getNearestSpawnedItem() {
651 		return DistanceUtils.getNearest(getSpawnedItems().values(), agentInfo.getLocation());
652 	}
653 	
654 	/**
655 	 * Returns nearest-by-path (using {@link #pathPlanner} previously injected via {@link #setPathPlanner(IPathPlanner)}) item spawning point from spawned items EXCEPT DROPPED ONES!
656 	 * Does not need to be necessarily spawned right now. 
657 	 * @return A nearest spawned Item be it Spawned.
658 	 */
659 	public Item getPathNearestSpawnedItem() {
660 		return DistanceUtils.getNearest(getSpawnedItems().values(), agentInfo.getNearestNavPoint(), pathPlannerGetDistance);
661 	}
662 	
663 	/**
664 	 * Returns nearest-by-air (Euclidean norm) item spawning point from spawned items of specific category.
665 	 * Does not need to be necessarily spawned right now. 
666 	 * @param category 
667 	 * @return A nearest spawned Item be it Spawned or Dropped (Dropped item must be visible though!) of specific category.
668 	 */
669 	public Item getNearestSpawnedItem(ItemType.Category category) {
670 		return DistanceUtils.getNearest(getSpawnedItems(category).values(), agentInfo.getLocation());
671 	}
672 	
673 	/**
674 	 * Returns nearest-by-path (using {@link #pathPlanner} previously injected via {@link #setPathPlanner(IPathPlanner)}) item spawning point from spawned items EXCEPT DROPPED ONES!
675 	 * Does not need to be necessarily spawned right now. 
676 	 * @param category
677 	 * @return A nearest spawned Item be it Spawned of specific category.
678 	 */
679 	public Item getPathNearestSpawnedItem(ItemType.Category category) {
680 		return DistanceUtils.getNearest(getSpawnedItems(category).values(), agentInfo.getNearestNavPoint(), pathPlannerGetDistance);
681 	}
682 	
683 	/**
684 	 * Returns nearest-by-air (Euclidean norm) item spawning point from spawned items of specific group.
685 	 * Does not need to be necessarily spawned right now. 
686 	 * @param group 
687 	 * @return A nearest spawned Item be it Spawned or Dropped (Dropped item must be visible though!) of specific group.
688 	 */
689 	public Item getNearestSpawnedItem(ItemType.Group group) {
690 		return DistanceUtils.getNearest(getSpawnedItems(group).values(), agentInfo.getLocation());
691 	}
692 	
693 	/**
694 	 * Returns nearest-by-path (using {@link #pathPlanner} previously injected via {@link #setPathPlanner(IPathPlanner)}) item spawning point from spawned items EXCEPT DROPPED ONES!
695 	 * Does not need to be necessarily spawned right now. 
696 	 * @param group 
697 	 * @return A nearest spawned Item be it Spawned of specific group.
698 	 */
699 	public Item getPathNearestSpawnedItem(ItemType.Group group) {
700 		return DistanceUtils.getNearest(getSpawnedItems(group).values(), agentInfo.getNearestNavPoint(), pathPlannerGetDistance);
701 	}
702 	
703 	/**
704 	 * Returns nearest-by-air (Euclidean norm) item spawning point from spawned items of specific type.
705 	 * Does not need to be necessarily spawned right now. 
706 	 * @param group 
707 	 * @return A nearest spawned Item be it Spawned or Dropped (Dropped item must be visible though!) of specific category.
708 	 */
709 	public Item getNearestSpawnedItem(ItemType type) {
710 		return DistanceUtils.getNearest(getSpawnedItems(type).values(), agentInfo.getLocation());
711 	}
712 	
713 	/**
714 	 * Returns nearest-by-path (using {@link #pathPlanner} previously injected via {@link #setPathPlanner(IPathPlanner)}) item spawning point from spawned items EXCEPT DROPPED ONES!
715 	 * Does not need to be necessarily spawned right now. 
716 	 * @param type
717 	 * @return A nearest spawned Item be it Spawned of specific type.
718 	 */
719 	public Item getPathNearestSpawnedItem(ItemType type) {
720 		return DistanceUtils.getNearest(getSpawnedItems(type).values(), agentInfo.getNearestNavPoint(), pathPlannerGetDistance);
721 	}
722 	
723 	/**
724 	 * Returns how fast are the items respawning based on their item type (in UT Time == UT seconds == {@link UnrealUtils#UT2004_TIME_SPEED} * 1 seconds).
725 	 * @param item
726 	 * @return
727 	 */
728 	public double getItemRespawnUT2004Time(Item item) {
729 		return getItemRespawnTime(item.getType()) * UnrealUtils.UT2004_TIME_SPEED;
730 	}
731 	
732 	/**
733 	 * Returns how fast are the items respawning based on their item type (in UT Time == UT seconds == {@link UnrealUtils#UT2004_TIME_SPEED} * 1 seconds).
734 	 * @param itemType
735 	 * @return
736 	 */
737 	public double getItemRespawnUT2004Time(ItemType itemType) {
738 		return getItemRespawnTime(itemType) * UnrealUtils.UT2004_TIME_SPEED;
739 	}
740 	
741 	/**
742 	 * Returns how fast are the items respawning based on their item type (in real seconds according to {@link System#currentTimeMillis()}.
743 	 * @param item
744 	 * @return
745 	 */
746 	public double getItemRespawnTime(Item item) {
747 		return getItemRespawnTime(item.getType());
748 	}
749 	
750 	/**
751 	 * Returns how fast are the items respawning based on their item type (in real seconds according to {@link System#currentTimeMillis()}.
752 	 * @param itemType
753 	 * @return
754 	 */
755 	public abstract double getItemRespawnTime(ItemType itemType);
756 	
757 	/**
758 	 * Tells, whether the given pickup point contains a spawned item.
759 	 * 
760 	 * <p><p>This implementation is guessing (optimistically) whether the item is spawned based on
761 	 * the last time we have seen it missing (bot has seen its spawning-navpoint but the item was not laying there).
762 	 * 
763 	 * <p><p>Note that the guessing is not perfect, experiment with it or check the source code
764 	 * and possibly reimplement (probably copy-paste) to suit your needs.
765 	 * 
766 	 * <p><p>Note that this method is working correctly only if items are respawning.
767 	 *
768 	 * @param item Item, for which its pickup point is to be examined.
769 	 * @return True, if the item is spawned; false if the pickup is empty.
770 	 *
771 	 * @see getKnownPickups(boolean,boolean)
772 	 */
773 	public boolean isPickupSpawned(Item item) {
774 		if (item == null) return false;
775 		if (item.isVisible()) {
776 			// if the item is visible it is truly spawned
777 			return true;
778 		}
779 		NavPoint np = item.getNavPoint();
780 		if (np == null) {
781 			np = navPoints.get(item.getNavPointId());
782 		}		
783 		if (np != null) { 
784 			if (np.isVisible()) {
785 				// we can see the spawning-navpoint but the item is not visible!
786 				return np.isItemSpawned();
787 			} else {
788 				return !items.itemMissing.isTaboo(item);
789 			}			
790 		} else {
791 			// we do not have item's navpoint, just check times
792 			return !items.itemMissing.isTaboo(item);			
793 		}
794 	}
795 	
796 	/**
797 	 * Tells, whether the given pickup point contains a spawned item.
798 	 * 
799 	 * <p><p>This implementation is guessing (optimistically) whether the item is spawned based on
800 	 * the last time we have seen it missing (saw its navpoint but the item was not laying there).
801 	 * 
802 	 * <p><p>Note that the guessing is not perfect, experiment with it or check the source code
803 	 * and possibly reimplement to suit your needs.
804 	 * 
805 	 * <p><p>Note that this method is working only if items are respawning.
806 	 *
807 	 * @param itemId Id of the item, for which its pickup point is to be examined.
808 	 * @return True, if the item is spawned; false if the pickup is empty.
809 	 *
810 	 * @see getKnownPickups(boolean,boolean)
811 	 */
812 	public boolean isPickupSpawned(UnrealId itemId) {	
813 		return isPickupSpawned(items.all.get(itemId));
814 	}
815 
816 	/*========================================================================*/
817 
818 	/**
819 	 * Maps of items of specific type.
820 	 */
821 	private class ItemMaps
822 	{
823 		/** Map of all items (known and thrown). */
824 		private HashMap<UnrealId, Item> all = new HashMap<UnrealId, Item> ();
825 		/** Map of visible items of the specific type. */
826 		private HashMap<UnrealId, Item> visible = new HashMap<UnrealId, Item> ();
827 		/** Map of visible items of the specific type. */
828 		private HashMap<UnrealId, Item> reachable = new HashMap<UnrealId, Item> ();
829 		/** Map of all known items of the specific type. */
830 		private HashMap<UnrealId, Item> known = new HashMap<UnrealId, Item> ();
831 		/** Map of all items (known and thrown) of specific categories. */
832 		private HashMapMap<ItemType, UnrealId, Item> allCategories = new HashMapMap<ItemType, UnrealId, Item>();
833 		/** Map of visible items of the specific type. */
834 		private HashMapMap<ItemType, UnrealId, Item> visibleCategories = new HashMapMap<ItemType, UnrealId, Item> ();
835 		/** Map of visible items of the specific type. */
836 		private HashMapMap<ItemType, UnrealId, Item> reachableCategories = new HashMapMap<ItemType, UnrealId, Item> ();
837 		/** Map of all known items of the specific type. */
838 		private HashMapMap<ItemType, UnrealId, Item> knownCategories = new HashMapMap<ItemType, UnrealId, Item> ();
839 		/**Map of all items and the time when they were last seen as 'missing' (== picked up == they were not on their navpoint). */		
840 		private TabooSet<Item> itemMissing;	
841 		/** Set of items that were picked up in this sync-batch. */
842 		private Set<Item> justPickedUp = new HashSet<Item>();
843 		
844 		private HashMap<UnrealId, Boolean> itemSpawned = new HashMap<UnrealId, Boolean>();
845 		
846 		public ItemMaps(UT2004Bot bot) {
847 			itemMissing = new TabooSet<Item>(bot);		
848 		}
849 
850 		private void notify(NavPoint navPoint) {
851 			if (navPoint.getItem() == null) return; // NOT AN INVENTORY SPOT
852 			Item item = getItem(navPoint.getItem());
853 			if (item == null) return; // MISSING ITEM? ... should not happen...
854 			// we have an inventory spot
855 			if (navPoint.isItemSpawned()) {
856 				// item is spawned...
857 				itemMissing.remove(item);
858 			} else {
859 				if (itemMissing.isTaboo(item)) {
860 					// item is already a taboo
861 					return;
862 				}
863 				itemMissing.add(item, getItemRespawnUT2004Time(item));
864 			}
865 		}
866 		
867 		/**
868 		 * Processes events.
869 		 * @param item Item to process.
870 		 */
871 		private void notify(Item item)
872 		{
873 			UnrealId uid = item.getId();
874 
875 			// be sure to be within all
876 			if (!all.containsKey(uid)) {
877 				all.put(uid, item);
878 				allCategories.put(item.getType(), item.getId(), item);
879 			}
880 
881 			// previous visibility
882 			boolean wasVisible = visible.containsKey(uid);
883 			boolean isVisible = item.isVisible();
884 
885 			// refresh visible
886 			if (isVisible && !wasVisible)
887 			{
888 				// add to visible(s)
889 				visible.put(uid, item);
890 				visibleCategories.put(item.getType(), item.getId(), item);
891 			}
892 			else if (!isVisible && wasVisible)
893 			{
894 				// remove from visible(s)
895 				visible.remove(uid);
896 				visibleCategories.remove(item.getType(), item.getId());
897 			}
898 
899 			// remove non-visible thrown items
900 			if (!isVisible && item.isDropped()) {
901 				all.remove(uid);
902 				allCategories.remove(item.getType(), item.getId());
903 			}
904 	
905 		}
906 		
907 		/**
908 		 * Processes events.
909 		 * @param items Map of known items to process.
910 		 */
911 		private void notify(Map<UnrealId, Item> items)
912 		{
913 			// register all known items
914 			known.putAll(items);
915 			for (Item item : items.values()) {
916 				knownCategories.put(item.getType(), item.getId(), item);
917 				notify(item);
918 			}
919 		}
920 		
921 		/**
922 		 * Handles 'itemMissingTimes', called from the {@link EndMessageListener}.
923 		 * @param navPoints
924 		 */
925 		private void notifyBatchEnd(List<NavPoint> navPoints) {
926 			justPickedUp.clear();
927 		}
928 
929 		/**
930 		 * Handles 'itemMissingTimes' for picked up item.
931 		 * @param event
932 		 */
933 		private void notify(ItemPickedUp event) {
934 			Item item = all.get(event.getId());
935 			if (item == null) return;
936 			justPickedUp.add(item);
937 			itemMissing.add(item, getItemRespawnUT2004Time(item));
938 		}
939 
940 		private void clear() {
941 			all.clear();
942 			allCategories.clear();
943 			itemMissing.clear();
944 			justPickedUp.clear();
945 			known.clear();
946 			knownCategories.clear();
947 			reachable.clear();
948 			reachableCategories.clear();
949 			visible.clear();
950 			visibleCategories.clear();			
951 		}
952 	}
953 
954 	/** Maps of all items. */
955 	private ItemMaps items;
956 
957 	/*========================================================================*/
958 
959 	protected class ItemsListener implements IWorldObjectEventListener<Item, IWorldObjectEvent<Item>> {
960 
961 		public ItemsListener(IWorldView worldView) {
962 			worldView.addObjectListener(Item.class, IWorldObjectEvent.class, this);
963 		}
964 
965         public void notify(IWorldObjectEvent<Item> event) {
966             items.notify(event.getObject());
967         }
968 
969     }
970 
971 	protected ItemsListener itemsListener;
972 
973 	/**
974 	 *  This method is called from the constructor to hook a listener that updated the items field.
975 	 *  <p><p>
976 	 *  It must:
977 	 *  <ol>
978 	 *  <li>initialize itemsListener field</li>
979 	 *  <li>hook the listener to the world view</li>
980 	 *  </ol>
981 	 *  <p><p>
982 	 *  By overriding this method you may provide your own listener that may wrap Items with your class
983 	 *  adding new fields into them.
984 	 *
985 	 *  @param worldView
986 	 **/
987 	protected ItemsListener createItemsListener(IWorldView worldView) {
988 		return new ItemsListener(worldView);
989 	}
990 
991 	/*========================================================================*/
992 
993 	/**
994 	 * MapPointsListObtained listener.
995 	 */
996 	protected class MapPointsListener implements IWorldEventListener<MapPointListObtained>
997 	{
998 		/**
999 		 * Constructor. Registers itself on the given WorldView object.
1000 		 * @param worldView WorldView object to listen to.
1001 		 */
1002 		public MapPointsListener(IWorldView worldView)
1003 		{
1004 			worldView.addEventListener(MapPointListObtained.class, this);
1005 		}
1006 
1007 		@Override
1008 		public void notify(MapPointListObtained event)
1009 		{
1010 			navPoints = event.getNavPoints();
1011 			items.notify(event.getItems());			
1012 		}
1013 
1014 	}
1015 
1016 	/** MapPointsListObtained listener */
1017 	protected MapPointsListener mapPointsListener;
1018 	protected Map<UnrealId, NavPoint> navPoints = new HashMap<UnrealId, NavPoint>();
1019 
1020 	/**
1021 	 *  This method is called from the constructor to create a listener that initialize items field from
1022 	 *  the MapPointListObtained event.
1023 	 *  <p><p>
1024 	 *  By overriding this method you may provide your own listener that may wrap Items with your class
1025 	 *  adding new fields into them.
1026 	 *
1027 	 *  @param worldView
1028 	 * @return
1029 	 **/
1030 	protected MapPointsListener createMapPointsListener(IWorldView worldView) {
1031 		return new MapPointsListener(worldView);
1032 	}
1033 
1034 	/*========================================================================*/
1035 	
1036 	/**
1037 	 * MapPointsListObtained listener.
1038 	 */
1039 	protected class NavPointListener implements IWorldObjectEventListener<NavPoint, WorldObjectUpdatedEvent<NavPoint>>
1040 	{
1041 		/**
1042 		 * Constructor. Registers itself on the given WorldView object.
1043 		 * @param worldView WorldView object to listen to.
1044 		 */
1045 		public NavPointListener(IWorldView worldView) {
1046 			worldView.addObjectListener(NavPoint.class, WorldObjectUpdatedEvent.class, this);
1047 		}
1048 
1049 		@Override
1050 		public void notify(WorldObjectUpdatedEvent<NavPoint> event) {
1051 			items.notify(event.getObject());
1052 			if (event.getObject().isVisible()) {
1053 				navPointsToProcess.add(event.getObject());
1054 			} else {
1055 				navPointsToProcess.remove(event.getObject());
1056 			}
1057 		}
1058 
1059 	}
1060 	
1061 	/**
1062 	 * Contains only navpoints that are visible so we can check whether they are spawning-points,
1063 	 * if so - we may check whether the item is laying there or not to handle spawning times.
1064 	 */
1065 	protected List<NavPoint> navPointsToProcess = new ArrayList<NavPoint>();
1066 	
1067 	protected NavPointListener navPointListener;
1068 	
1069 	/*========================================================================*/
1070 	
1071 	/**
1072 	 * {@link EndMessage} listener.
1073 	 */
1074 	protected class EndMessageListener implements IWorldEventListener<EndMessage>
1075 	{
1076 		/**
1077 		 * Constructor. Registers itself on the given WorldView object.
1078 		 * @param worldView WorldView object to listen to.
1079 		 */
1080 		public EndMessageListener(IWorldView worldView)
1081 		{
1082 			worldView.addEventListener(EndMessage.class, this);
1083 		}
1084 
1085 		@Override
1086 		public void notify(EndMessage event)
1087 		{
1088 			items.notifyBatchEnd(navPointsToProcess);
1089 		}
1090 
1091 	}
1092 	
1093 	protected EndMessageListener endMessageListener;
1094 	
1095 	/*========================================================================*/
1096 	
1097 	/**
1098 	 * {@link ItemPickedUp} listener.
1099 	 */
1100 	protected class ItemPickedUpListener implements IWorldEventListener<ItemPickedUp>
1101 	{
1102 		/**
1103 		 * Constructor. Registers itself on the given WorldView object.
1104 		 * @param worldView WorldView object to listen to.
1105 		 */
1106 		public ItemPickedUpListener(IWorldView worldView)
1107 		{
1108 			worldView.addEventListener(ItemPickedUp.class, this);
1109 		}
1110 
1111 		@Override
1112 		public void notify(ItemPickedUp event)
1113 		{
1114 			items.notify(event);
1115 		}
1116 
1117 	}
1118 	
1119 	protected ItemPickedUpListener itemPickedUpListener;
1120 
1121 	/*========================================================================*/
1122 
1123 	/** AgentInfo memory module. */
1124 	protected AgentInfo agentInfo;
1125 	
1126 	/** Weaponry memory module. */
1127 	protected Weaponry weaponry;
1128 	
1129 	/** Game memory module. */
1130 	protected Game game;
1131 
1132 	
1133 	/**
1134 	 * Constructor. Setups the memory module based on bot's world view.
1135 	 * @param bot owner of the module that is using it
1136 	 * @param agentInfo AgentInfo memory module
1137 	 * @param log Logger to be used for logging runtime/debug info, if null is provided the module creates its own logger
1138 	 */
1139 	public Items(UT2004Bot bot, AgentInfo agentInfo, Game game, Weaponry weaponry, Logger log)
1140 	{
1141 		super(bot, log);
1142 
1143 		// save reference
1144 		this.agentInfo = agentInfo;
1145 		NullCheck.check(this.agentInfo, "agentInfo");
1146 		
1147 		this.weaponry = weaponry;
1148 		NullCheck.check(this.weaponry, "weaponry");
1149 		
1150 		this.game = game;
1151 		NullCheck.check(this.game, "game");
1152 
1153 		items = new ItemMaps(bot);
1154 		
1155 		// create listeners
1156 		itemsListener =        createItemsListener(worldView);
1157 		mapPointsListener =    createMapPointsListener(worldView);
1158 		navPointListener =     new NavPointListener(worldView);
1159 		endMessageListener =   new EndMessageListener(worldView);
1160 		itemPickedUpListener = new ItemPickedUpListener(worldView);
1161 		
1162 		cleanUp();
1163 	}
1164 
1165 	@Override
1166 	protected void cleanUp() {
1167 		super.cleanUp();
1168 		navPoints.clear();
1169 		items.clear();
1170 	}
1171 	
1172 }