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