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