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 will be thought to be spawned in "millis" 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 (bot has seen its spawning-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 (probably copy-paste) to suit your needs. 804 * 805 * <p><p>Note that this method is working correctly only if items are respawning. 806 * 807 * @param item Item, for which its pickup point is to be examined. 808 * @param long seconds, lookahead time, does not count with "picking up" 809 * @return True, if the item is spawned; false if the pickup is empty. 810 * 811 * @see getKnownPickups(boolean,boolean) 812 */ 813 public boolean willPickupBeSpawnedIn(Item item, double seconds) { 814 if (isPickupSpawned(item)) return true; 815 return !items.itemMissing.willBeTaboo(item, seconds); 816 } 817 818 /** 819 * Tells, whether the given pickup point contains a spawned item. 820 * 821 * <p><p>This implementation is guessing (optimistically) whether the item is spawned based on 822 * the last time we have seen it missing (saw its navpoint but the item was not laying there). 823 * 824 * <p><p>Note that the guessing is not perfect, experiment with it or check the source code 825 * and possibly reimplement to suit your needs. 826 * 827 * <p><p>Note that this method is working only if items are respawning. 828 * 829 * @param itemId Id of the item, for which its pickup point is to be examined. 830 * @return True, if the item is spawned; false if the pickup is empty. 831 * 832 * @see getKnownPickups(boolean,boolean) 833 */ 834 public boolean isPickupSpawned(UnrealId itemId) { 835 return isPickupSpawned(items.all.get(itemId)); 836 } 837 838 /*========================================================================*/ 839 840 /** 841 * Maps of items of specific type. 842 */ 843 private class ItemMaps 844 { 845 /** Map of all items (known and thrown). */ 846 private HashMap<UnrealId, Item> all = new HashMap<UnrealId, Item> (); 847 /** Map of visible items of the specific type. */ 848 private HashMap<UnrealId, Item> visible = new HashMap<UnrealId, Item> (); 849 /** Map of visible items of the specific type. */ 850 private HashMap<UnrealId, Item> reachable = new HashMap<UnrealId, Item> (); 851 /** Map of all known items of the specific type. */ 852 private HashMap<UnrealId, Item> known = new HashMap<UnrealId, Item> (); 853 /** Map of all items (known and thrown) of specific categories. */ 854 private HashMapMap<ItemType, UnrealId, Item> allCategories = new HashMapMap<ItemType, UnrealId, Item>(); 855 /** Map of visible items of the specific type. */ 856 private HashMapMap<ItemType, UnrealId, Item> visibleCategories = new HashMapMap<ItemType, UnrealId, Item> (); 857 /** Map of visible items of the specific type. */ 858 private HashMapMap<ItemType, UnrealId, Item> reachableCategories = new HashMapMap<ItemType, UnrealId, Item> (); 859 /** Map of all known items of the specific type. */ 860 private HashMapMap<ItemType, UnrealId, Item> knownCategories = new HashMapMap<ItemType, UnrealId, Item> (); 861 /**Map of all items and the time when they were last seen as 'missing' (== picked up == they were not on their navpoint). */ 862 private TabooSet<Item> itemMissing; 863 /** Set of items that were picked up in this sync-batch. */ 864 private Set<Item> justPickedUp = new HashSet<Item>(); 865 866 private HashMap<UnrealId, Boolean> itemSpawned = new HashMap<UnrealId, Boolean>(); 867 868 public ItemMaps(UT2004Bot bot) { 869 itemMissing = new TabooSet<Item>(bot); 870 } 871 872 private void notify(NavPoint navPoint) { 873 if (navPoint.getItem() == null) return; // NOT AN INVENTORY SPOT 874 Item item = getItem(navPoint.getItem()); 875 if (item == null) return; // MISSING ITEM? ... should not happen... 876 // we have an inventory spot 877 if (navPoint.isItemSpawned()) { 878 // item is spawned... 879 itemMissing.remove(item); 880 } else { 881 if (itemMissing.isTaboo(item)) { 882 // item is already a taboo 883 return; 884 } 885 itemMissing.add(item, getItemRespawnUT2004Time(item)); 886 } 887 } 888 889 /** 890 * Processes events. 891 * @param item Item to process. 892 */ 893 private void notify(Item item) 894 { 895 UnrealId uid = item.getId(); 896 897 // be sure to be within all 898 if (!all.containsKey(uid)) { 899 all.put(uid, item); 900 allCategories.put(item.getType(), item.getId(), item); 901 } 902 903 // previous visibility 904 boolean wasVisible = visible.containsKey(uid); 905 boolean isVisible = item.isVisible(); 906 907 // refresh visible 908 if (isVisible && !wasVisible) 909 { 910 // add to visible(s) 911 visible.put(uid, item); 912 visibleCategories.put(item.getType(), item.getId(), item); 913 } 914 else if (!isVisible && wasVisible) 915 { 916 // remove from visible(s) 917 visible.remove(uid); 918 visibleCategories.remove(item.getType(), item.getId()); 919 } 920 921 // remove non-visible thrown items 922 if (!isVisible && item.isDropped()) { 923 all.remove(uid); 924 allCategories.remove(item.getType(), item.getId()); 925 } 926 927 } 928 929 /** 930 * Processes events. 931 * @param items Map of known items to process. 932 */ 933 private void notify(Map<UnrealId, Item> items) 934 { 935 // register all known items 936 known.putAll(items); 937 for (Item item : items.values()) { 938 knownCategories.put(item.getType(), item.getId(), item); 939 notify(item); 940 } 941 } 942 943 /** 944 * Handles 'itemMissingTimes', called from the {@link EndMessageListener}. 945 * @param navPoints 946 */ 947 private void notifyBatchEnd(List<NavPoint> navPoints) { 948 justPickedUp.clear(); 949 } 950 951 /** 952 * Handles 'itemMissingTimes' for picked up item. 953 * @param event 954 */ 955 private void notify(ItemPickedUp event) { 956 Item item = all.get(event.getId()); 957 if (item == null) return; 958 justPickedUp.add(item); 959 itemMissing.add(item, getItemRespawnUT2004Time(item)); 960 } 961 962 private void clear() { 963 all.clear(); 964 allCategories.clear(); 965 itemMissing.clear(); 966 justPickedUp.clear(); 967 known.clear(); 968 knownCategories.clear(); 969 reachable.clear(); 970 reachableCategories.clear(); 971 visible.clear(); 972 visibleCategories.clear(); 973 } 974 } 975 976 /** Maps of all items. */ 977 private ItemMaps items; 978 979 /*========================================================================*/ 980 981 protected class ItemsListener implements IWorldObjectEventListener<Item, IWorldObjectEvent<Item>> { 982 983 public ItemsListener(IWorldView worldView) { 984 worldView.addObjectListener(Item.class, IWorldObjectEvent.class, this); 985 } 986 987 public void notify(IWorldObjectEvent<Item> event) { 988 items.notify(event.getObject()); 989 } 990 991 } 992 993 protected ItemsListener itemsListener; 994 995 /** 996 * This method is called from the constructor to hook a listener that updated the items field. 997 * <p><p> 998 * It must: 999 * <ol> 1000 * <li>initialize itemsListener field</li> 1001 * <li>hook the listener to the world view</li> 1002 * </ol> 1003 * <p><p> 1004 * By overriding this method you may provide your own listener that may wrap Items with your class 1005 * adding new fields into them. 1006 * 1007 * @param worldView 1008 **/ 1009 protected ItemsListener createItemsListener(IWorldView worldView) { 1010 return new ItemsListener(worldView); 1011 } 1012 1013 /*========================================================================*/ 1014 1015 /** 1016 * MapPointsListObtained listener. 1017 */ 1018 protected class MapPointsListener implements IWorldEventListener<MapPointListObtained> 1019 { 1020 /** 1021 * Constructor. Registers itself on the given WorldView object. 1022 * @param worldView WorldView object to listen to. 1023 */ 1024 public MapPointsListener(IWorldView worldView) 1025 { 1026 worldView.addEventListener(MapPointListObtained.class, this); 1027 } 1028 1029 @Override 1030 public void notify(MapPointListObtained event) 1031 { 1032 navPoints = event.getNavPoints(); 1033 items.notify(event.getItems()); 1034 } 1035 1036 } 1037 1038 /** MapPointsListObtained listener */ 1039 protected MapPointsListener mapPointsListener; 1040 protected Map<UnrealId, NavPoint> navPoints = new HashMap<UnrealId, NavPoint>(); 1041 1042 /** 1043 * This method is called from the constructor to create a listener that initialize items field from 1044 * the MapPointListObtained event. 1045 * <p><p> 1046 * By overriding this method you may provide your own listener that may wrap Items with your class 1047 * adding new fields into them. 1048 * 1049 * @param worldView 1050 * @return 1051 **/ 1052 protected MapPointsListener createMapPointsListener(IWorldView worldView) { 1053 return new MapPointsListener(worldView); 1054 } 1055 1056 /*========================================================================*/ 1057 1058 /** 1059 * MapPointsListObtained listener. 1060 */ 1061 protected class NavPointListener implements IWorldObjectEventListener<NavPoint, WorldObjectUpdatedEvent<NavPoint>> 1062 { 1063 /** 1064 * Constructor. Registers itself on the given WorldView object. 1065 * @param worldView WorldView object to listen to. 1066 */ 1067 public NavPointListener(IWorldView worldView) { 1068 worldView.addObjectListener(NavPoint.class, WorldObjectUpdatedEvent.class, this); 1069 } 1070 1071 @Override 1072 public void notify(WorldObjectUpdatedEvent<NavPoint> event) { 1073 items.notify(event.getObject()); 1074 if (event.getObject().isVisible()) { 1075 navPointsToProcess.add(event.getObject()); 1076 } else { 1077 navPointsToProcess.remove(event.getObject()); 1078 } 1079 } 1080 1081 } 1082 1083 /** 1084 * Contains only navpoints that are visible so we can check whether they are spawning-points, 1085 * if so - we may check whether the item is laying there or not to handle spawning times. 1086 */ 1087 protected List<NavPoint> navPointsToProcess = new ArrayList<NavPoint>(); 1088 1089 protected NavPointListener navPointListener; 1090 1091 /*========================================================================*/ 1092 1093 /** 1094 * {@link EndMessage} listener. 1095 */ 1096 protected class EndMessageListener implements IWorldEventListener<EndMessage> 1097 { 1098 /** 1099 * Constructor. Registers itself on the given WorldView object. 1100 * @param worldView WorldView object to listen to. 1101 */ 1102 public EndMessageListener(IWorldView worldView) 1103 { 1104 worldView.addEventListener(EndMessage.class, this); 1105 } 1106 1107 @Override 1108 public void notify(EndMessage event) 1109 { 1110 items.notifyBatchEnd(navPointsToProcess); 1111 } 1112 1113 } 1114 1115 protected EndMessageListener endMessageListener; 1116 1117 /*========================================================================*/ 1118 1119 /** 1120 * {@link ItemPickedUp} listener. 1121 */ 1122 protected class ItemPickedUpListener implements IWorldEventListener<ItemPickedUp> 1123 { 1124 /** 1125 * Constructor. Registers itself on the given WorldView object. 1126 * @param worldView WorldView object to listen to. 1127 */ 1128 public ItemPickedUpListener(IWorldView worldView) 1129 { 1130 worldView.addEventListener(ItemPickedUp.class, this); 1131 } 1132 1133 @Override 1134 public void notify(ItemPickedUp event) 1135 { 1136 items.notify(event); 1137 } 1138 1139 } 1140 1141 protected ItemPickedUpListener itemPickedUpListener; 1142 1143 /*========================================================================*/ 1144 1145 /** AgentInfo memory module. */ 1146 protected AgentInfo agentInfo; 1147 1148 /** Weaponry memory module. */ 1149 protected Weaponry weaponry; 1150 1151 /** Game memory module. */ 1152 protected Game game; 1153 1154 1155 /** 1156 * Constructor. Setups the memory module based on bot's world view. 1157 * @param bot owner of the module that is using it 1158 * @param agentInfo AgentInfo memory module 1159 * @param log Logger to be used for logging runtime/debug info, if null is provided the module creates its own logger 1160 */ 1161 public Items(UT2004Bot bot, AgentInfo agentInfo, Game game, Weaponry weaponry, Logger log) 1162 { 1163 super(bot, log); 1164 1165 // save reference 1166 this.agentInfo = agentInfo; 1167 NullCheck.check(this.agentInfo, "agentInfo"); 1168 1169 this.weaponry = weaponry; 1170 NullCheck.check(this.weaponry, "weaponry"); 1171 1172 this.game = game; 1173 NullCheck.check(this.game, "game"); 1174 1175 items = new ItemMaps(bot); 1176 1177 // create listeners 1178 itemsListener = createItemsListener(worldView); 1179 mapPointsListener = createMapPointsListener(worldView); 1180 navPointListener = new NavPointListener(worldView); 1181 endMessageListener = new EndMessageListener(worldView); 1182 itemPickedUpListener = new ItemPickedUpListener(worldView); 1183 1184 cleanUp(); 1185 } 1186 1187 @Override 1188 protected void cleanUp() { 1189 super.cleanUp(); 1190 navPoints.clear(); 1191 items.clear(); 1192 } 1193 1194 }