View Javadoc

1   package cz.cuni.amis.pogamut.udk.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.event.IWorldEventListener;
12  import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEvent;
13  import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEventListener;
14  import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectListener;
15  import cz.cuni.amis.pogamut.base.communication.worldview.object.event.WorldObjectUpdatedEvent;
16  import cz.cuni.amis.pogamut.base.utils.math.DistanceUtils;
17  import cz.cuni.amis.pogamut.udk.bot.IUDKBotController;
18  import cz.cuni.amis.pogamut.udk.bot.impl.UDKBot;
19  import cz.cuni.amis.pogamut.unreal.communication.messages.UnrealId;
20  import cz.cuni.amis.pogamut.udk.communication.messages.gbinfomessages.Player;
21  import cz.cuni.amis.pogamut.udk.communication.messages.gbinfomessages.PlayerLeft;
22  import cz.cuni.amis.pogamut.udk.communication.messages.gbinfomessages.Self;
23  import cz.cuni.amis.utils.collections.MyCollections;
24  
25  /**
26   * Memory module specialized on whereabouts of other players.
27   *
28   * <h2>Auto updating</h2>
29   *
30   * <p>All Player objects returned by this memory module are always self-updating
31   * throughout the time, until the associated player leaves the game. This means
32   * that once a valid Player object is obtained, it is not necessary to call any
33   * methods of this memory module to get the object's info updated (e.g. player's
34   * location, visibility, reachability, etc.). The object will autoupdate itself.
35   *
36   * <p>The same principle is applied to all Maps returned by this memory module.
37   * Each returned Map is self-updating throughout the time. Once a specific Map
38   * is obtained (e.g. a map of visible enemies) from this memory module, the Map
39   * will get updated based on actions of the players (e.g. joining or leaving
40   * the game, changing their team, moving around the map, etc.) automatically.
41   *
42   * <p>Note: All Maps returned by this memory module are locked and can not be
43   * modified outside this memory module. If you need to modify a Map returned by
44   * this module (for your own specific purpose), create a duplicate first. Such
45   * duplicates, however and of course, will not get updated.
46   * 
47   * <p>If you need to get info about players' deaths use {@link Senses} module.
48   * 
49   * <p><b>WARNING:</b>It is totally unclear what UT2004 means by reachable!!!
50   * 
51   * <p><p>
52   * It is designed to be initialized inside {@link IUDKBotController#prepareBot(UDKBot)} method call
53   * and may be used since {@link IUDKBotController#botInitialized(cz.cuni.amis.pogamut.udk.communication.messages.gbinfomessages.GameInfo, cz.cuni.amis.pogamut.udk.communication.messages.gbinfomessages.ConfigChange, cz.cuni.amis.pogamut.udk.communication.messages.gbinfomessages.InitedMessage)}
54   * is called.
55   *
56   *
57   * @author Juraj 'Loque' Simlovic
58   * @author Jimmy
59   */
60  public class Players extends SensorModule<UDKBot>
61  {
62  	/**
63  	 * Retreives last known info about given player.
64  	 *
65  	 * <p>Note: The returned Player object is self updating throughout time.
66  	 * Once you have a valid Player object, you do not have to call this
67  	 * method to get updated info about that player.
68  	 *
69  	 * @param UnrealId Player UnrealId to be retreived.
70  	 * @return Last known player info; or null upon none.
71  	 *
72  	 * @see getVisiblePlayer(UnrealId)
73  	 * @see getReachablePlayer(UnrealId)
74  	 */
75  	public Player getPlayer(UnrealId UnrealId)
76  	{
77  		// retreive from map of all players
78  		return players.all.get(UnrealId);
79  	}
80  
81  	/**
82  	 * Retreives info about given player, but only it the player is visible.
83  	 *
84  	 * <p>Note: The returned Player object is self updating throughout time.
85  	 * Once you have a valid Player object, you do not have to call this
86  	 * method to get updated info about visibility of that player.
87  	 *
88  	 * @param UnrealId Player UnrealId to be retrieved.
89  	 * @return Player info; or null upon none or not visible.
90  	 *
91  	 * @see getPlayer(UnrealId)
92  	 * @see getReachablePlayer(UnrealId)
93  	 */
94  	public Player getVisiblePlayer(UnrealId UnrealId)
95  	{
96  		// retreive from map of all visible players
97  		return players.visible.get(UnrealId);
98  	}
99  
100 	/**
101 	 * Retreives info about given player, but only it the player is reachable.
102 	 * <p><b>WARNING:</b>It is totally unclear what UT2004 means by reachable!!!
103 	 *
104 	 * <p>Note: The returned Player object is self updating throughout time.
105 	 * Once you have a valid Player object, you do not have to call this
106 	 * method to get updated info about reachability of that player.
107 	 *
108 	 * @param UnrealId Player UnrealId to be retreived.
109 	 * @return Player info; or null upon none or not reachable.
110 	 *
111 	 * @see getPlayer(UnrealId)
112 	 * @see getVisiblePlayer(UnrealId)
113 	 */
114 	public Player getReachablePlayer(UnrealId UnrealId)
115 	{
116 		// retreive from map of all reachable players
117 		return players.reachable.get(UnrealId);
118 	}
119 
120 	/*========================================================================*/
121 
122 	/**
123 	 * Retreives a Map of all players.
124 	 *
125 	 * <p>Note: The returned Map is unmodifiable and self updating throughout
126 	 * time. Once you obtain a specific Map of players from this memory module,
127 	 * the Map will get updated based on actions of the players (e.g. joining
128 	 * or leaving the game, changing their status, etc.).
129 	 *
130 	 * @return Map of all players, using their UnrealIds as keys.
131 	 *
132 	 * @see getEnemies()
133 	 * @see getFriends()
134 	 * @see getVisiblePlayers()
135 	 * @see getReachablePlayers()
136 	 */
137 	public Map<UnrealId, Player> getPlayers()
138 	{
139 		// publish map of all players
140 		return Collections.unmodifiableMap(players.all);
141 	}
142 
143 	/**
144 	 * Retreives a Map of all enemies.
145 	 *
146 	 * <p>Note: The returned Map is unmodifiable and self updating throughout
147 	 * time. Once you obtain a specific Map of enemies from this memory module,
148 	 * the Map will get updated based on actions of the players (e.g. joining
149 	 * or leaving the game, changing their team or status, etc.).
150 	 *
151 	 * @return Map of all enemies, using their UnrealIds as keys.
152 	 *
153 	 * @see getPlayers()
154 	 * @see getFriends()
155 	 * @see getVisibleEnemies()
156 	 * @see getReachableEnemies()
157 	 */
158 	public Map<UnrealId, Player> getEnemies()
159 	{
160 		// publish map of all enemies
161 		return Collections.unmodifiableMap(enemies.all);
162 	}
163 
164 	/**
165 	 * Retreives a Map of all friends.
166 	 *
167 	 * <p>Note: The returned Map is unmodifiable and self updating throughout
168 	 * time. Once you obtain a specific Map of friends from this memory module,
169 	 * the Map will get updated based on actions of the players (e.g. joining
170 	 * or leaving the game, changing their team or status, etc.).
171 	 *
172 	 * @return Map of all friends, using their UnrealIds as keys.
173 	 *
174 	 * @see getPlayers()
175 	 * @see getEnemies()
176 	 * @see getVisibleFriends()
177 	 * @see getReachableFriends()
178 	 */
179 	public Map<UnrealId, Player> getFriends()
180 	{
181 		// publish map of all friends
182 		return Collections.unmodifiableMap(friends.all);
183 	}
184 
185 	/*========================================================================*/
186 
187 	/**
188 	 * Retreives a Map of all visible players.
189 	 *
190 	 * <p>Note: The returned Map is unmodifiable and self updating throughout
191 	 * time. Once you obtain a specific Map of players from this memory module,
192 	 * the Map will get updated based on actions of the players (e.g. joining
193 	 * or leaving the game, or changing their visibility, etc.).
194 	 *
195 	 * @return Map of all visible players, using their UnrealIds as keys.
196 	 *
197 	 * @see getPlayers()
198 	 * @see getVisibleEnemies()
199 	 * @see getVisibleFriends()
200 	 * @see canSeePlayers()
201 	 */
202 	public Map<UnrealId, Player> getVisiblePlayers()
203 	{
204 		// publish map of all visible players
205 		return Collections.unmodifiableMap(players.visible);
206 	}
207 
208 	/**
209 	 * Retreives a Map of all visible enemies.
210 	 *
211 	 * <p>Note: The returned Map is unmodifiable and self updating throughout
212 	 * time. Once you obtain a specific Map of enemies from this memory module,
213 	 * the Map will get updated based on actions of the players (e.g. joining
214 	 * or leaving the game, changing their team, status or visibility, etc.).
215 	 *
216 	 * @return Map of all visible enemies, using their UnrealIds as keys.
217 	 *
218 	 * @see getEnemies()
219 	 * @see getVisiblePlayers()
220 	 * @see getVisibleFriends()
221 	 * @see canSeeEnemies()
222 	 */
223 	public Map<UnrealId, Player> getVisibleEnemies()
224 	{
225 		// publish map of all visible enemies
226 		return Collections.unmodifiableMap(enemies.visible);
227 	}
228 
229 	/**
230 	 * Retreives a Map of all visible friends.
231 	 *
232 	 * <p>Note: The returned Map is unmodifiable and self updating throughout
233 	 * time. Once you obtain a specific Map of friends from this memory module,
234 	 * the Map will get updated based on actions of the players (e.g. joining
235 	 * or leaving the game, changing their team, status or visibility, etc.).
236 	 *
237 	 * @return Map of all visible friends, using their UnrealIds as keys.
238 	 *
239 	 * @see getFriends()
240 	 * @see getVisiblePlayers()
241 	 * @see getVisibleEnemies()
242 	 * @see canSeeFriends()
243 	 */
244 	public Map<UnrealId, Player> getVisibleFriends()
245 	{
246 		// publish map of all visible friends
247 		return Collections.unmodifiableMap(friends.visible);
248 	}
249 
250 	/*========================================================================*/
251 
252 	/**
253 	 * Retreives a Map of all reachable players.
254 	 * <p><b>WARNING:</b>It is totally unclear what UT2004 means by reachable!!!
255 	 *
256 	 * <p>Note: The returned Map is unmodifiable and self updating throughout
257 	 * time. Once you obtain a specific Map of players from this memory module,
258 	 * the Map will get updated based on actions of the players (e.g. joining
259 	 * or leaving the game, or changing their visibility, etc.).
260 	 *
261 	 * @return Map of all reachable players, using their UnrealIds as keys.
262 	 *
263 	 * @see getPlayers()
264 	 * @see getReachableEnemies()
265 	 * @see getReachableFriends()
266 	 * @see canReachPlayers()
267 	 */
268 	public Map<UnrealId, Player> getReachablePlayers()
269 	{
270 		// publish map of all reachable players
271 		return Collections.unmodifiableMap(players.reachable);
272 	}
273 
274 	/**
275 	 * Retreives a Map of all reachable enemies.
276 	 * <p><b>WARNING:</b>It is totally unclear what UT2004 means by reachable!!!
277 	 *
278 	 * <p>Note: The returned Map is unmodifiable and self updating throughout
279 	 * time. Once you obtain a specific Map of enemies from this memory module,
280 	 * the Map will get updated based on actions of the players (e.g. joining
281 	 * or leaving the game, changing their team, status or visibility, etc.).
282 	 *
283 	 * @return Map of all reachable enemies, using their UnrealIds as keys.
284 	 *
285 	 * @see getEnemies()
286 	 * @see getReachablePlayers()
287 	 * @see getReachableFriends()
288 	 * @see canReachEnemies()
289 	 */
290 	public Map<UnrealId, Player> getReachableEnemies()
291 	{
292 		// publish map of all reachable enemies
293 		return Collections.unmodifiableMap(enemies.reachable);
294 	}
295 
296 	/**
297 	 * Retreives a Map of all reachable friends.
298 	 * <p><b>WARNING:</b>It is totally unclear what UT2004 means by reachable!!!
299 	 *
300 	 * <p>Note: The returned Map is unmodifiable and self updating throughout
301 	 * time. Once you obtain a specific Map of friends from this memory module,
302 	 * the Map will get updated based on actions of the players (e.g. joining
303 	 * or leaving the game, changing their team, status or visibility, etc.).
304 	 *
305 	 * @return Map of all reachable friends, using their UnrealIds as keys.
306 	 *
307 	 * @see getFriends()
308 	 * @see getReachablePlayers()
309 	 * @see getReachableEnemies()
310 	 * @see canReachFriends()
311 	 */
312 	public Map<UnrealId, Player> getReachableFriends()
313 	{
314 		// publish map of all reachable friends
315 		return Collections.unmodifiableMap(friends.reachable);
316 	}
317 
318 	/*========================================================================*/
319 
320 	/**
321 	 * Returns nearest player that is visible or that was 'recently' visible. If no such player exists, returns null.
322 	 * 
323 	 * @param recentlyVisibleTime how long the player may be non-visible
324 	 * @return nearest visible or 'recentlyVisibleTime' visible player
325 	 */
326 	public Player getNearestPlayer(double recently) {	
327 		Player nearest = null;
328 		double distance = Double.MAX_VALUE;
329 		for (Player plr : players.all.values()) {
330 			if (plr.isVisible() || lastSelf.getLastSeenTime() - plr.getLastSeenTime() <= recently) {
331 				double d = lastSelf.getLocation().getDistance(plr.getLocation());
332 				if (d < distance) {
333 					distance = d;
334 					nearest = plr;
335 				}
336 			}
337 		}
338 		return nearest;
339 	}
340 	
341 	/**
342 	 * Returns nearest enemy that is visible or that was 'recently' visible. If no such enemy exists, returns null.
343 	 * 
344 	 * @param recentlyVisibleTime how long the player may be non-visible
345 	 * @return nearest visible or 'recently' visible enemy
346 	 */
347 	public Player getNearestEnemy(double recentlyVisibleTime) {	
348 		Player nearest = null;
349 		double distance = Double.MAX_VALUE;
350 		for (Player plr : enemies.all.values()) {
351 			if (plr.isVisible() || lastSelf.getLastSeenTime() - plr.getLastSeenTime() <= recentlyVisibleTime) {
352 				double d = lastSelf.getLocation().getDistance(plr.getLocation());
353 				if (d < distance) {
354 					distance = d;
355 					nearest = plr;
356 				}
357 			}
358 		}
359 		return nearest;
360 	}
361 	
362 	/**
363 	 * Returns nearest friend that is visible or that was 'recently' visible. If no such friend exists, returns null.
364 	 * 
365 	 * @param recentlyVisibleTime how long the player may be non-visible
366 	 * @return nearest visible or 'recently' visible friend
367 	 */
368 	public Player getNearestFriend(double recentlyVisibleTime) {	
369 		Player nearest = null;
370 		double distance = Double.MAX_VALUE;
371 		for (Player plr : friends.all.values()) {
372 			if (plr.isVisible() || lastSelf.getLastSeenTime() - plr.getLastSeenTime() <= recentlyVisibleTime) {
373 				double d = lastSelf.getLocation().getDistance(plr.getLocation());
374 				if (d < distance) {
375 					distance = d;
376 					nearest = plr;
377 				}
378 			}
379 		}
380 		return nearest;
381 	}
382 	
383 	/**
384 	 * Returns nearest-visible player - if no if no player is visible returns null.
385 	 * 
386 	 * @return nearest visible player
387 	 */
388 	public Player getNearestVisiblePlayer() {		
389         return DistanceUtils.getNearest(players.visible.values(), lastSelf.getLocation());
390 	}
391 	
392 	/**
393 	 * Returns nearest-visible enemy - if no enemy is visible returns null.
394 	 * 
395 	 * @return nearest visible enemy
396 	 */
397 	public Player getNearestVisibleEnemy() {		
398         return DistanceUtils.getNearest(enemies.visible.values(), lastSelf.getLocation());
399 	}
400 	
401 	/**
402 	 * Returns nearest-visible friend - if no friend is visible returns null.
403 	 * 
404 	 * @return nearest visible friend
405 	 */
406 	public Player getNearestVisibleFriend() {		
407         return DistanceUtils.getNearest(friends.visible.values(), lastSelf.getLocation());
408 	}
409 	
410 	/**
411 	 * Returns nearest-visible player to the bot from the collection of 'players' - if no player
412 	 * is visible  returns null.
413 	 * 
414 	 * @param players collection to go through
415 	 * @return nearest visible player from the collection
416 	 */
417 	public Player getNearestVisiblePlayer(Collection<Player> players) {		
418         return DistanceUtils.getNearestVisible(players, lastSelf.getLocation());
419 	}
420 	
421 	/**
422 	 * Returns random visible player - if no if no player is visible returns null.
423 	 * 
424 	 * @return random visible player
425 	 */
426 	public Player getRandomVisiblePlayer() {		
427         return MyCollections.getRandom(players.visible.values());
428 	}
429 	
430 	/**
431 	 * Returns random visible enemy - if no enemy is visible returns null.
432 	 * 
433 	 * @return random visible enemy
434 	 */
435 	public Player getRandomVisibleEnemy() {		
436         return MyCollections.getRandom(enemies.visible.values());
437 	}
438 	
439 	/**
440 	 * Returns random friend - if no friend is visible returns null.
441 	 * 
442 	 * @return random visible friend
443 	 */
444 	public Player getRandomVisibleFriend() {		
445         return MyCollections.getRandom(friends.visible.values());
446 	}
447 
448 	/*========================================================================*/
449 
450 	/**
451 	 * Tells, whether the agent sees any other players.
452 	 *
453 	 * @return True, if at least one other player is visible; false otherwise.
454 	 *
455 	 * @see getVisiblePlayers()
456 	 */
457 	public boolean canSeePlayers()
458 	{
459 		// search map of all visible players
460 		return (players.visible.size() > 0);
461 	}
462 
463 	/**
464 	 * Tells, whether the agent sees any other enemies.
465 	 *
466 	 * @return True, if at least one other enemy is visible; false otherwise.
467 	 *
468 	 * @see getVisibleEnemies()
469 	 */
470 	public boolean canSeeEnemies()
471 	{
472 		// search map of all visible enemies
473 		return (enemies.visible.size() > 0);
474 	}
475 
476 	/**
477 	 * Tells, whether the agent sees any other friends.
478 	 *
479 	 * @return True, if at least one other friend is visible; false otherwise.
480 	 *
481 	 * @see getVisibleFriends()
482 	 */
483 	public boolean canSeeFriends()
484 	{
485 		// search map of all visible friends
486 		return (friends.visible.size() > 0);
487 	}
488 
489 	/*========================================================================*/
490 
491 	/**
492 	 * Tells, whether the agent can reach any other players.
493 	 * <p><b>WARNING:</b>It is totally unclear what UT2004 means by reachable!!!
494 	 *
495 	 * @return True, if at least one other player is reachable; false otherwise.
496 	 *
497 	 * @see getReachablePlayers()
498 	 */
499 	public boolean canReachPlayers()
500 	{
501 		// search map of all reachable players
502 		return (players.reachable.size() > 0);
503 	}
504 
505 	/**
506 	 * Tells, whether the agent can reach any other enemies.
507 	 * <p><b>WARNING:</b>It is totally unclear what UT2004 means by reachable!!!
508 	 *
509 	 * @return True, if at least one other enemy is reachable; false otherwise.
510 	 *
511 	 * @see getReachableEnemies()
512 	 */
513 	public boolean canReachEnemies()
514 	{
515 		// search map of all reachable enemies
516 		return (enemies.reachable.size() > 0);
517 	}
518 
519 	/**
520 	 * Tells, whether the agent can reach any other friends.
521 	 * <p><b>WARNING:</b>It is totally unclear what UT2004 means by reachable!!!
522 	 *
523 	 * @return True, if at least one other friend is reachable; false otherwise.
524 	 *
525 	 * @see getReachableFriends()
526 	 */
527 	public boolean canReachFriends()
528 	{
529 		// search map of all reachable friends
530 		return (friends.reachable.size() > 0);
531 	}
532 	
533 	/**
534 	 * Tells, whether a given team is an enemy team to the agent.
535 	 *
536 	 * @param team Team number to be tested.
537 	 * @return True, if the given team is an enemy team.
538 	 *
539 	 * @see getTeam()
540 	 * @see isFriend(int)
541 	 */
542 	public boolean isEnemy(int team)
543 	{
544 		// freelancers' team or different team
545 		return (team == AgentInfo.TEAM_NONE) || (team != lastSelf.getTeam());
546 	}
547 
548 	/**
549 	 * Tells, whether a given player is an enemy to the agent.
550 	 *
551 	 * @param player Player to be tested.
552 	 * @return True, if the given player is an enemy.
553 	 *
554 	 * @see getTeam()
555 	 * @see isFriend(Player)
556 	 */
557 	public boolean isEnemy(Player player)
558 	{
559 		// test the enemy team number
560 		return isEnemy(player.getTeam());
561 	}
562 
563 	/**
564 	 * Tells, whether a given team is a friend team to the agent.
565 	 *
566 	 * @param team Team number to be tested.
567 	 * @return True, if the given team is a friend team.
568 	 *
569 	 * @see getTeam()
570 	 * @see isEnemy(int)
571 	 */
572 	public boolean isFriend(int team)
573 	{
574 		// same team only
575 		return team != AgentInfo.TEAM_NONE && (team == lastSelf.getTeam());
576 	}
577 
578 	/**
579 	 * Tells, whether a given player is a friend to the agent.
580 	 *
581 	 * @param player Player to be tested.
582 	 * @return True, if the given player is a friend.
583 	 *
584 	 * @see getTeam()
585 	 * @see isEnemy(Player)
586 	 */
587 	public boolean isFriend(Player player)
588 	{
589 		// test the friend team number
590 		return isFriend(player.getTeam());
591 	}
592 
593 	/*========================================================================*/
594 
595 	/**
596 	 * Maps of players of specific type.
597 	 */
598 	private class PlayerMaps
599 	{
600 		/** Map of all players of the specific type. */
601 		private HashMap<UnrealId, Player> all = new HashMap<UnrealId, Player> ();
602 		/** Map of visible players of the specific type. */
603 		private HashMap<UnrealId, Player> visible = new HashMap<UnrealId, Player> ();
604 		/** Map of reachable players of the specific type. */
605 		private HashMap<UnrealId, Player> reachable = new HashMap<UnrealId, Player> ();
606 
607 		/**
608 		 * Processes events.
609 		 * @param player Player to process.
610 		 */
611 		private void notify(Player player)
612 		{
613 			UnrealId uid = player.getId();
614 
615 			// be sure to be within all
616 			if (!all.containsKey(uid))
617 				all.put(uid, player);
618 
619 			// previous visibility
620 			boolean wasVisible = visible.containsKey(uid);
621 			boolean isVisible = player.isVisible();
622 
623 			// refresh visible
624 			if (isVisible && !wasVisible)
625 			{
626 				// add to visibles
627 				visible.put(uid, player);
628 			}
629 			else if (!isVisible && wasVisible)
630 			{
631 				// remove from visibles
632 				visible.remove(uid);
633 			}
634 
635 			// previous reachability
636 			boolean wasReachable = reachable.containsKey(uid);
637 			boolean isReachable = player.isReachable();
638 
639 			// refresh reachable
640 			if (isReachable && !wasReachable)
641 			{
642 				// add to reachables
643 				reachable.put(uid, player);
644 			}
645 			else if (!isReachable && wasReachable)
646 			{
647 				// remove from reachables
648 				reachable.remove(uid);
649 			}
650 		}
651 
652 		/**
653 		 * Removes player from all maps.
654 		 * @param uid UnrealId of player to be removed.
655 		 */
656 		private void remove(UnrealId uid)
657 		{
658 			// remove from all maps
659 			all.remove(uid);
660 			visible.remove(uid);
661 			reachable.remove(uid);
662 		}
663 
664 		private void clear() {
665 			all.clear();
666 			visible.clear();
667 			reachable.clear();
668 		}
669 	}
670 
671 	/** Maps of all players. */
672 	private PlayerMaps players = new PlayerMaps ();
673 	/** Maps of all enemies. */
674 	private PlayerMaps enemies = new PlayerMaps ();
675 	/** Maps of all friends. */
676 	private PlayerMaps friends = new PlayerMaps ();
677 
678 	/*========================================================================*/
679 
680 	/**
681 	 * Player listener.
682 	 */
683 	private class PlayerListener implements IWorldObjectEventListener<Player, WorldObjectUpdatedEvent<Player>>
684 	{
685 		@Override
686 		public void notify(WorldObjectUpdatedEvent<Player> event)
687 		{
688             Player player = event.getObject();
689 			// do the job in map of players
690 			players.notify(player);
691 			if (lastSelf == null) return; // we do not have self yet ... we do not know which team are we in
692 			// do the job in map of enemies
693 			if (isEnemy(player))
694 				enemies.notify(player);
695 			// do the job in map of friends
696 			if (isFriend(player))
697 				friends.notify(player);
698 		}
699 
700 		/**
701 		 * Constructor. Registers itself on the given WorldView object.
702 		 * @param worldView WorldView object to listent to.
703 		 */
704 		public PlayerListener(IWorldView worldView)
705 		{
706 			worldView.addObjectListener(Player.class, WorldObjectUpdatedEvent.class, this);
707 		}
708 	}
709 
710 	/** Player listener */
711 	PlayerListener playerListener;
712 
713 	/*========================================================================*/
714 
715 	/**
716 	 * PlayerLeft listener.
717 	 */
718 	private class PlayerLeftListener implements IWorldEventListener<PlayerLeft>
719 	{
720 		@Override
721 		public void notify(PlayerLeft event)
722 		{
723 			UnrealId uid = event.getId();
724 
725 			// remove from all maps
726 			players.remove(uid);
727 			enemies.remove(uid);
728 			friends.remove(uid);
729 		}
730 
731 		/**
732 		 * Constructor. Registers itself on the given WorldView object.
733 		 * @param worldView WorldView object to listent to.
734 		 */
735 		public PlayerLeftListener(IWorldView worldView)
736 		{
737 			worldView.addEventListener(PlayerLeft.class, this);
738 		}
739 	}
740 
741 	/** PlayerLeft listener */
742 	PlayerLeftListener playerLeftListener;
743 
744 	/*========================================================================*/
745 	
746 	/**
747 	 * Self listener.
748 	 */
749 	private class SelfListener implements IWorldObjectListener<Self>
750 	{
751 		@Override
752 		public void notify(IWorldObjectEvent<Self> event)
753 		{
754 			if (lastSelf == null) {
755 				lastSelf = event.getObject();
756 				for (Player plr : players.all.values()) {
757 					if (isFriend(plr)) friends.notify(plr);
758 					if (isEnemy(plr)) enemies.notify(plr);
759 				}
760 			} else {
761 				lastSelf = event.getObject();
762 			}
763 		}
764 
765 		/**
766 		 * Constructor. Registers itself on the given WorldView object.
767 		 * @param worldView WorldView object to listent to.
768 		 */
769 		public SelfListener(IWorldView worldView)
770 		{
771 			worldView.addObjectListener(Self.class, this);
772 		}
773 	}
774 
775 	/** Self listener */
776 	SelfListener selfListener;
777 	
778 	Self lastSelf = null;
779 	
780 	/**
781 	 * Constructor. Setups the memory module based on bot's world view.
782 	 * @param bot owner of the module that is using it
783 	 */
784 	public Players(UDKBot bot)
785 	{
786 		this(bot, null);
787 	}
788 	
789 	/**
790 	 * Constructor. Setups the memory module based on bot's world view.
791 	 * @param bot owner of the module that is using it
792 	 * @param log Logger to be used for logging runtime/debug info. If <i>null</i>, module creates its own logger.
793 	 */
794 	public Players(UDKBot bot, Logger log)
795 	{
796 		super(bot, log);
797 		
798 
799 		// create listeners
800 		playerListener = new PlayerListener(worldView);
801 		playerLeftListener = new PlayerLeftListener(worldView);
802 		selfListener = new SelfListener(worldView);
803 	}
804 	
805 	/**
806 	 * Provides initialization of the module (clearing internal data structures). Called automatically
807 	 * during the agent starting sequence.
808 	 */
809 	@Override
810 	protected void start(boolean startPaused) {
811 		super.start(startPaused);
812 		lastSelf = null;
813 		players.clear();
814 		friends.clear();
815 		enemies.clear();
816 	}
817 }