From 6612a8fc14e9e2cda772e4551f0a24687c879e62 Mon Sep 17 00:00:00 2001 From: Major- Date: Fri, 27 Jun 2014 13:05:04 +0100 Subject: [PATCH] Move sector-related items, correct a bug in MobRepository and NpcActionVerificationHandler. --- .../impl/NpcActionVerificationHandler.java | 25 ++- src/org/apollo/game/model/area/Sector.java | 160 ++++++++++++++++++ .../game/model/area/SectorCoordinates.java | 79 +++++++++ .../game/model/area/SectorListener.java | 20 +++ .../game/model/area/SectorRepository.java | 111 ++++++++++++ .../apollo/game/model/area/package-info.java | 5 + src/org/apollo/util/MobRepository.java | 25 +-- 7 files changed, 400 insertions(+), 25 deletions(-) create mode 100644 src/org/apollo/game/model/area/Sector.java create mode 100644 src/org/apollo/game/model/area/SectorCoordinates.java create mode 100644 src/org/apollo/game/model/area/SectorListener.java create mode 100644 src/org/apollo/game/model/area/SectorRepository.java create mode 100644 src/org/apollo/game/model/area/package-info.java diff --git a/src/org/apollo/game/event/handler/impl/NpcActionVerificationHandler.java b/src/org/apollo/game/event/handler/impl/NpcActionVerificationHandler.java index f6a9972b..7e504321 100644 --- a/src/org/apollo/game/event/handler/impl/NpcActionVerificationHandler.java +++ b/src/org/apollo/game/event/handler/impl/NpcActionVerificationHandler.java @@ -13,21 +13,20 @@ import org.apollo.game.model.WorldConstants; * * @author Stuart */ -public class NpcActionVerificationHandler extends EventHandler { +public final class NpcActionVerificationHandler extends EventHandler { - @Override - public void handle(EventHandlerContext ctx, Player player, NpcActionEvent event) { - if(event.getIndex() < 0 || event.getIndex() > WorldConstants.MAXIMUM_NPCS) { - ctx.breakHandlerChain(); - return; - } + @Override + public void handle(EventHandlerContext ctx, Player player, NpcActionEvent event) { + if (event.getIndex() < 0 || event.getIndex() >= WorldConstants.MAXIMUM_NPCS) { + ctx.breakHandlerChain(); + return; + } - Npc npc = (Npc)World.getWorld().getNpcRepository().get(event.getIndex()); + Npc npc = World.getWorld().getNpcRepository().get(event.getIndex()); - if(npc == null || !player.getPosition().isWithinDistance(npc.getPosition(), 15)) { - ctx.breakHandlerChain(); - return; - } - } + if (npc == null || !player.getPosition().isWithinDistance(npc.getPosition(), 15)) { + ctx.breakHandlerChain(); + } + } } \ No newline at end of file diff --git a/src/org/apollo/game/model/area/Sector.java b/src/org/apollo/game/model/area/Sector.java new file mode 100644 index 00000000..6d646583 --- /dev/null +++ b/src/org/apollo/game/model/area/Sector.java @@ -0,0 +1,160 @@ +package org.apollo.game.model.area; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apollo.game.model.Entity; +import org.apollo.game.model.Entity.EntityType; +import org.apollo.game.model.Position; + +/** + * Represents an 8x8 area of the map. + * + * @author Major + */ +public final class Sector { + + /** + * The width and height of a sector, in tiles. + */ + public static final int SECTOR_SIZE = 8; + + /** + * The sector coordinates of this sector. + */ + private final SectorCoordinates coordinates; + + /** + * A map of positions to entities in that position. + */ + private final Map> entities = new HashMap<>(); + + /** + * A list of listeners registered to this sector. + */ + private final List listeners = new ArrayList<>(); + + /** + * Creates a new sector. + * + * @param x The x coordinate of the sector. + * @param y The y coordinate of the sector. + */ + public Sector(int x, int y) { + this(new SectorCoordinates(x, y)); + } + + /** + * Creates a new sector with the specified {@link SectorCoordinates}. + * + * @param coordinates The coordinates. + */ + public Sector(SectorCoordinates coordinates) { + this.coordinates = coordinates; + } + + /** + * Adds a {@link Entity} from to sector. Note that this does not spawn the entity, or do any other action other than + * register it to this sector. + * + * @param entity The entity. + * @return {@code true} if the entity was added successfully, otherwise {@code false}. + */ + public boolean addEntity(Entity entity) { + Position position = entity.getPosition(); + List entities = this.entities.get(position); + if (entities == null) { + entities = new ArrayList<>(); + } + + if (entities.add(entity)) { + this.entities.put(position, entities); + notifyListeners(entity); + return true; + } + return false; + } + + /** + * Checks if this sector contains the specified entity. + * + * @param entity The entity. + * @return {@code true} if this sector contains the entity, otherwise {@code false}. + */ + public boolean contains(Entity entity) { + List entities = this.entities.get(entity.getPosition()); + return entities.contains(entity); + } + + /** + * Gets this sector's {@link SectorCoordinates}. + * + * @return The sector coordinates. + */ + public SectorCoordinates getCoordinates() { + return coordinates; + } + + /** + * Gets a copy of the {@link List} of {@link Entity}s. + * + * @param position The position containing the entities. + * @return The list. + */ + public List getEntities(Position position) { + return new ArrayList<>(entities.get(position)); + } + + /** + * Gets a copy of the {@link List} of {@link Entity}s with the specified {@link EntityType}. + * + * @param position The {@link Position} containing the entities. + * @param type The {@link EntityType}. + * @return The list of entities. + */ + @SuppressWarnings("unchecked") + public List getEntities(Position position, EntityType type) { + List entities = getEntities(position); + List filtered = new ArrayList<>(); + for (Entity entity : entities) { + if (entity.getEntityType() == type) { + filtered.add((T) entity); + } + } + return filtered; + } + + /** + * Notifies the listeners registered to this sector that an update has occurred. + * + * @param entity The entity that was updated. + */ + public void notifyListeners(Entity entity) { + for (SectorListener listener : listeners) { + listener.execute(this, entity); + } + } + + /** + * Removes a {@link Entity} from this sector. + * + * @param entity The entity. + * @return {@code true} if the entity was removed, otherwise {@code false}. + */ + public boolean removeEntity(Entity entity) { + List entities = this.entities.get(entity.getPosition()); + if (entities == null) { + this.entities.put(entity.getPosition(), new ArrayList()); + return false; + } + + if (entities.remove(entity)) { + notifyListeners(entity); + return true; + } + return false; + } + +} \ No newline at end of file diff --git a/src/org/apollo/game/model/area/SectorCoordinates.java b/src/org/apollo/game/model/area/SectorCoordinates.java new file mode 100644 index 00000000..ca5203dd --- /dev/null +++ b/src/org/apollo/game/model/area/SectorCoordinates.java @@ -0,0 +1,79 @@ +package org.apollo.game.model.area; + +import org.apollo.game.model.Position; + +/** + * An immutable class representing the coordinates of a sector, where the coordinates ({@code x, y}) are the top-left of + * the sector. + * + * @author Graham + */ +public final class SectorCoordinates { + + /** + * Gets a pair of sector coordinates from a {@link Position}. + * + * @param position The position. + * @return The sector coordinates. + */ + public static SectorCoordinates fromPosition(Position position) { + return new SectorCoordinates(position.getTopLeftSectorX(), position.getTopLeftSectorY()); + } + + /** + * The x coordinate of this sector. + */ + private final int x; + + /** + * The y coordinate of this sector. + */ + private final int y; + + /** + * Creates the sector coordinates. + * + * @param x The x coordinate. + * @param y The y coordinate. + */ + public SectorCoordinates(int x, int y) { + this.x = x; + this.y = y; + } + + @Override + public boolean equals(Object obj) { + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final SectorCoordinates other = (SectorCoordinates) obj; + if (x != other.x || y != other.y) { + return false; + } + return true; + } + + /** + * Gets the x coordinate (equivalent to the {@link Position#getTopLeftSectorX()} of a position within this sector). + * + * @return The x coordinate. + */ + public int getX() { + return x; + } + + /** + * Gets the y coordinate (equivalent to the {@link Position#getTopLeftSectorY()} of a position within this sector). + * + * @return The y coordinate. + */ + public int getY() { + return y; + } + + @Override + public int hashCode() { + return 61 * (427 + x) + y; + } + +} \ No newline at end of file diff --git a/src/org/apollo/game/model/area/SectorListener.java b/src/org/apollo/game/model/area/SectorListener.java new file mode 100644 index 00000000..62d4d3c1 --- /dev/null +++ b/src/org/apollo/game/model/area/SectorListener.java @@ -0,0 +1,20 @@ +package org.apollo.game.model.area; + +import org.apollo.game.model.Entity; + +/** + * A class that should be extended by listeners that execute actions when an entity is added or removed from the sector. + * + * @author Major + */ +public abstract class SectorListener { + + /** + * Executes the action for this listener. + * + * @param The sector that was updated. + * @param entity The affected entity. + */ + public abstract void execute(Sector sector, Entity entity); + +} \ No newline at end of file diff --git a/src/org/apollo/game/model/area/SectorRepository.java b/src/org/apollo/game/model/area/SectorRepository.java new file mode 100644 index 00000000..dc46c99a --- /dev/null +++ b/src/org/apollo/game/model/area/SectorRepository.java @@ -0,0 +1,111 @@ +package org.apollo.game.model.area; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * A repository of sectors, backed by a {@link HashMap} of {@link SectorCoordinates} that correspond to their + * appropriate {@link Sector}s. + * + * @author Major + */ +public final class SectorRepository { + + /** + * Indicates whether sectors can be removed from this repository. + */ + private final boolean permitRemoval; + + /** + * A {@link Map} of {@link SectorCoordinates} that correspond to the appropriate {@link Sector}s.. + */ + private final Map sectors = new HashMap<>(); + + /** + * Creates a new sector repository. + * + * @param permitRemoval If removal (of {@link Sector}s) from this repository should be permitted. + */ + public SectorRepository(boolean permitRemoval) { + this.permitRemoval = permitRemoval; + } + + /** + * Adds a {@link Sector} to the repository. + * + * @param sector The sector. + * @throws IllegalArgumentException If the provided sector is null. + * @throws UnsupportedOperationException If the coordinates of the provided sector are already mapped (and hence the + * existing sector would be replaced), and removal of sectors is not permitted. + */ + public void add(Sector sector) { + if (sector == null) { + throw new IllegalArgumentException("Sector cannot be null."); + } else if (sectors.containsKey(sector.getCoordinates()) && !permitRemoval) { + throw new UnsupportedOperationException( + "Cannot add a sector with the same coordinates as an existing sector."); + } + sectors.put(sector.getCoordinates(), sector); + } + + /** + * Indicates whether the supplied value (i.e. the {@link Sector}) has a mapping. + * + * @param sector The sector. + * @return {@code true} if the value is mapped by a key (i.e. {@link SectorCoordinates}), otherwise {@code false}. + */ + public boolean contains(Sector sector) { + return sectors.containsValue(sector); + } + + /** + * Indicates whether the supplied key (i.e. the {@link SectorCoordinates}) has a mapping. + * + * @param coordinates The coordinates. + * @return {@code true} if the key is already mapped to a value (i.e. a {@link Sector}), otherwise {@code false}. + */ + public boolean contains(SectorCoordinates coordinates) { + return sectors.containsKey(coordinates); + } + + /** + * Gets a {@link Sector} with the specified {@link SectorCoordinates}. If the sector does not exist (i.e. + * {@link #sectors}{@code .get()} returns {@code null}) then a new sector is created, submitted to the repository, + * and returned. + * + * @param coordinates The coordinates. + * @return The sector. + */ + public Sector get(SectorCoordinates coordinates) { + Sector sector = sectors.get(coordinates); + if (sector == null) { + add(sector = new Sector(coordinates)); + } + return sector; + } + + /** + * Gets the {@link List} of {@link Sector}s. + * + * @return The list. + */ + public List getSectors() { + return new ArrayList<>(sectors.values()); + } + + /** + * Removes a {@link Sector} from the repository, if permitted. + * + * @param sector The sector to remove. + * @throws UnsupportedOperationException If this method is called on a repository that does not permit removal. + */ + public void remove(Sector sector) { + if (!permitRemoval) { + throw new UnsupportedOperationException("Cannot remove sectors from this repository."); + } + sectors.remove(sector.getCoordinates()); + } + +} \ No newline at end of file diff --git a/src/org/apollo/game/model/area/package-info.java b/src/org/apollo/game/model/area/package-info.java new file mode 100644 index 00000000..a39c9f88 --- /dev/null +++ b/src/org/apollo/game/model/area/package-info.java @@ -0,0 +1,5 @@ +/** + * Contains classes which represent in-game sectors - blocks of 8x8 tiles used to store ground items, temporary objects, etc. + * efficiently. + */ +package org.apollo.game.model.area; \ No newline at end of file diff --git a/src/org/apollo/util/MobRepository.java b/src/org/apollo/util/MobRepository.java index 11033201..22369ae4 100644 --- a/src/org/apollo/util/MobRepository.java +++ b/src/org/apollo/util/MobRepository.java @@ -178,19 +178,20 @@ public final class MobRepository implements Iterable { return false; } - /** - * Gets the mob at the given index - * - * @param index The index of the mob - * @return The mob instance - */ - public Mob get(int index) { - if (index < 0 || index >= mobs.length) { - throw new IndexOutOfBoundsException("Mob index is out of bounds."); - } + /** + * Gets the mob at the given index + * + * @param index The index of the mob + * @return The mob instance + */ + @SuppressWarnings("unchecked") + public T get(int index) { + if (index < 0 || index >= mobs.length) { + throw new IndexOutOfBoundsException("Mob index is out of bounds."); + } - return mobs[index]; - } + return (T) mobs[index]; + } /** * Gets the size of this repository.