Add GroupableEntity.

This commit is contained in:
Major-
2015-08-01 14:18:10 +01:00
parent 02a3170382
commit effcca0c3b
10 changed files with 74 additions and 63 deletions
@@ -14,6 +14,7 @@ import org.apollo.game.message.impl.RegionUpdateMessage;
import org.apollo.game.model.Direction;
import org.apollo.game.model.Position;
import org.apollo.game.model.area.collision.CollisionMatrix;
import org.apollo.game.model.area.update.GroupableEntity;
import org.apollo.game.model.area.update.UpdateOperation;
import org.apollo.game.model.entity.Entity;
import org.apollo.game.model.entity.EntityType;
@@ -40,8 +41,8 @@ public final class Region {
@Override
public void execute(Region region, Entity entity, EntityUpdateType update) {
EntityType type = entity.getEntityType();
if (type != EntityType.PLAYER && type != EntityType.NPC) {
region.record(entity, update);
if (!type.isMob()) {
region.record((Entity & GroupableEntity) entity, update);
}
}
@@ -53,9 +54,9 @@ public final class Region {
public static final int SIZE = 8;
/**
* The default size of newly-created sets, to reduce memory usage.
* The default size of newly-created Lists, to reduce memory usage.
*/
private static final int DEFAULT_SET_SIZE = 2;
private static final int DEFAULT_LIST_SIZE = 2;
/**
* The RegionCoordinates of this Region.
@@ -108,7 +109,7 @@ public final class Region {
for (int height = 0; height < Position.HEIGHT_LEVELS; height++) {
snapshots.add(new HashMap<>());
updates.add(new ArrayList<>(DEFAULT_SET_SIZE));
updates.add(new ArrayList<>(DEFAULT_LIST_SIZE));
}
}
@@ -124,7 +125,7 @@ public final class Region {
Position position = entity.getPosition();
checkPosition(position);
Set<Entity> local = entities.computeIfAbsent(position, key -> new HashSet<>(DEFAULT_SET_SIZE));
Set<Entity> local = entities.computeIfAbsent(position, key -> new HashSet<>(DEFAULT_LIST_SIZE));
local.add(entity);
if (notify) {
@@ -212,7 +213,7 @@ public final class Region {
*/
public CollisionMatrix getMatrix(int height) {
Preconditions.checkElementIndex(height, matrices.length, "Matrix height level must be [0, " + matrices.length
+ ").");
+ "), received " + height + ".");
return matrices[height];
}
@@ -307,22 +308,23 @@ public final class Region {
}
/**
* Records the specified {@link Entity} as being updated this pulse.
* Records the specified {@link GroupableEntity} as being updated this pulse.
*
* @param entity The Entity.
* @param entity The GroupableEntity.
* @param type The {@link EntityUpdateType}.
* @throws UnsupportedOperationException If the specified Entity cannot be operated on in this manner.
*/
private void record(Entity entity, EntityUpdateType type) {
private <T extends Entity & GroupableEntity> void record(T entity, EntityUpdateType type) {
RegionUpdateMessage message = entity.toUpdateOperation(this, type).toMessage();
int height = entity.getPosition().getHeight();
Map<Entity, RegionUpdateMessage> snapshot = snapshots.get(height);
updates.get(height).add(message);
snapshots.get(height).remove(entity);
snapshot.remove(entity);
if ((entity.getEntityType() == EntityType.STATIC_OBJECT && type == EntityUpdateType.REMOVE)
|| (entity.getEntityType() != EntityType.STATIC_OBJECT && type == EntityUpdateType.ADD)) {
snapshots.get(height).put(entity, message);
snapshot.put(entity, message);
}
}
@@ -0,0 +1,24 @@
package org.apollo.game.model.area.update;
import org.apollo.game.model.area.EntityUpdateType;
import org.apollo.game.model.area.Region;
/**
* An entity that can be sent as part of a grouped region update message.
* <p>
* Only {@link org.apollo.game.model.entity.Entity} extensions may implement this interface.
*
* @author Major
*/
public interface GroupableEntity {
/**
* Gets this Entity, as an {@link UpdateOperation} of a {@link Region}.
*
* @param region The Region.
* @param type The EntityUpdateType.
* @return The UpdateOperation.
*/
public UpdateOperation<?> toUpdateOperation(Region region, EntityUpdateType type);
}
@@ -2,9 +2,6 @@ package org.apollo.game.model.entity;
import org.apollo.game.model.Position;
import org.apollo.game.model.World;
import org.apollo.game.model.area.EntityUpdateType;
import org.apollo.game.model.area.Region;
import org.apollo.game.model.area.update.UpdateOperation;
/**
* Represents an in-game entity, such as a mob, object, projectile, etc.
@@ -65,13 +62,4 @@ public abstract class Entity {
@Override
public abstract int hashCode();
/**
* Gets this Entity, as an {@link UpdateOperation} of a {@link Region}.
*
* @param region The Region.
* @param type The EntityUpdateType.
* @return The UpdateOperation.
*/
public abstract UpdateOperation<?> toUpdateOperation(Region region, EntityUpdateType type);
}
@@ -5,6 +5,7 @@ import org.apollo.game.model.Position;
import org.apollo.game.model.World;
import org.apollo.game.model.area.EntityUpdateType;
import org.apollo.game.model.area.Region;
import org.apollo.game.model.area.update.GroupableEntity;
import org.apollo.game.model.area.update.ItemUpdateOperation;
import org.apollo.game.model.area.update.UpdateOperation;
@@ -13,7 +14,7 @@ import org.apollo.game.model.area.update.UpdateOperation;
*
* @author Major
*/
public final class GroundItem extends Entity {
public final class GroundItem extends Entity implements GroupableEntity {
/**
* Creates a new GroundItem.
@@ -12,10 +12,8 @@ import org.apollo.game.model.Direction;
import org.apollo.game.model.Graphic;
import org.apollo.game.model.Position;
import org.apollo.game.model.World;
import org.apollo.game.model.area.EntityUpdateType;
import org.apollo.game.model.area.Region;
import org.apollo.game.model.area.RegionRepository;
import org.apollo.game.model.area.update.UpdateOperation;
import org.apollo.game.model.entity.attr.Attribute;
import org.apollo.game.model.entity.attr.AttributeMap;
import org.apollo.game.model.event.impl.MobPositionUpdateEvent;
@@ -53,7 +51,8 @@ public abstract class Mob extends Entity {
/**
* This mob's equipment.
*/
protected final Inventory equipment = new Inventory(InventoryConstants.EQUIPMENT_CAPACITY, StackMode.STACK_ALWAYS);
protected final Inventory equipment = new Inventory(InventoryConstants.EQUIPMENT_CAPACITY,
StackMode.STACK_ALWAYS);
/**
* The index of this mob.
@@ -198,8 +197,8 @@ public abstract class Mob extends Entity {
*/
public final Direction[] getDirections() {
if (firstDirection != Direction.NONE) {
return secondDirection == Direction.NONE ? new Direction[] { firstDirection } : new Direction[] {
firstDirection, secondDirection };
return secondDirection == Direction.NONE ? new Direction[] { firstDirection }
: new Direction[] { firstDirection, secondDirection };
}
return Direction.EMPTY_DIRECTION_ARRAY;
@@ -430,14 +429,14 @@ public abstract class Mob extends Entity {
/**
* Sets the {@link Position} of this mob.
* <p>
* This method may be intercepted using a {@link MobPositionUpdateEvent}, which can be terminated like any other.
* Plugins that intercept this Event <strong>must</strong> be cautious, because movement will not be possible (even
* through mechanisms such as teleporting) if the Event is terminated.
* This method may be intercepted using a {@link MobPositionUpdateEvent}, which can be terminated like any
* other. Plugins that intercept this Event <strong>must</strong> be cautious, because movement will not be
* possible (even through mechanisms such as teleporting) if the Event is terminated.
*
* @param position The Position.
*/
public final void setPosition(Position position) {
if (world.submit(new MobPositionUpdateEvent(this, position))) {
if (!position.equals(this.position) && world.submit(new MobPositionUpdateEvent(this, position))) {
Position old = this.position;
RegionRepository repository = world.getRegionRepository();
Region current = repository.fromPosition(old), next = repository.fromPosition(position);
@@ -524,11 +523,6 @@ public abstract class Mob extends Entity {
stopAction();
}
@Override
public final UpdateOperation<Entity> toUpdateOperation(Region region, EntityUpdateType operation) {
throw new UnsupportedOperationException("Mobs cannot be recorded as a Region update.");
}
/**
* Turns this mob to face the specified {@link Position}.
*
@@ -46,7 +46,8 @@ public final class WalkingQueue {
@Override
public String toString() {
return MoreObjects.toStringHelper(this).add("direction", direction).add("position", position).toString();
return MoreObjects.toStringHelper(this).add("direction", direction).add("position", position)
.toString();
}
}
@@ -86,8 +87,8 @@ public final class WalkingQueue {
}
/**
* Adds the first step to the queue, attempting to connect the server and client position by looking at the previous
* queue.
* Adds the first step to the queue, attempting to connect the server and client position by looking at the
* previous queue.
*
* @param clientPosition The first step.
* @return {@code true} if the queues could be connected correctly, {@code false} if not.
@@ -202,11 +203,7 @@ public final class WalkingQueue {
* @return The last point.
*/
private Point getLast() {
Point last = points.peekLast();
if (last == null) {
return new Point(mob.getPosition(), Direction.NONE);
}
return last;
return points.isEmpty() ? new Point(mob.getPosition(), Direction.NONE) : points.peekLast();
}
/**
@@ -223,13 +220,16 @@ public final class WalkingQueue {
if (runningQueue /* and enough energy */) {
next = points.poll();
if (next != null) {
second = next.direction;
position = next.position;
}
}
mob.setPosition(position);
}
mob.setDirections(first, second);
}
@@ -39,7 +39,8 @@ public final class DynamicGameObject extends GameObject {
* @param orientation The orientation of the DynamicGameObject.
* @return The DynamicGameObject.
*/
public static DynamicGameObject createPublic(World world, int id, Position position, int type, int orientation) {
public static DynamicGameObject createPublic(World world, int id, Position position, int type,
int orientation) {
return new DynamicGameObject(world, id, position, type, orientation, true);
}
@@ -49,9 +50,9 @@ public final class DynamicGameObject extends GameObject {
private final boolean alwaysVisible;
/**
* The Set of Players that can view this DynamicGameObject.
* The Set of Player usernames that can view this DynamicGameObject.
*/
private final Set<Player> players = new HashSet<>();
private final Set<String> players = new HashSet<>(); // TODO more appropriate type?
/**
* Creates the DynamicGameObject.
@@ -63,7 +64,8 @@ public final class DynamicGameObject extends GameObject {
* @param orientation The orientation of the DynamicGameObject.
* @param alwaysVisible The flag indicates whether or not this DynamicGameObject is visible to every player.
*/
private DynamicGameObject(World world, int id, Position position, int type, int orientation, boolean alwaysVisible) {
private DynamicGameObject(World world, int id, Position position, int type, int orientation,
boolean alwaysVisible) {
super(world, id, position, type, orientation);
this.alwaysVisible = alwaysVisible;
}
@@ -72,10 +74,10 @@ public final class DynamicGameObject extends GameObject {
* Adds this DynamicGameObject to the view of the specified {@link Player}.
*
* @param player The Player.
* @return {@code true} if this GameObject was not already visible to the specified Player.
* @return {@code true} if this DynamicGameObject was not already visible to the specified Player.
*/
public boolean addTo(Player player) {
return players.add(player);
return players.add(player.getUsername());
}
@Override
@@ -87,15 +89,15 @@ public final class DynamicGameObject extends GameObject {
* Removes this DynamicGameObject from the view of the specified {@link Player}.
*
* @param player The Player.
* @return {@code true} if this GameObject was visible to the specified Player.
* @return {@code true} if this DynamicGameObject was visible to the specified Player.
*/
public boolean removeFrom(Player player) {
return players.remove(player);
return players.remove(player.getUsername());
}
@Override
public boolean viewableBy(Player player, World world) {
return alwaysVisible || players.contains(player);
return alwaysVisible || players.contains(player.getUsername());
}
}
@@ -5,6 +5,7 @@ import org.apollo.game.model.Position;
import org.apollo.game.model.World;
import org.apollo.game.model.area.EntityUpdateType;
import org.apollo.game.model.area.Region;
import org.apollo.game.model.area.update.GroupableEntity;
import org.apollo.game.model.area.update.ObjectUpdateOperation;
import org.apollo.game.model.entity.Entity;
import org.apollo.game.model.entity.Player;
@@ -17,7 +18,7 @@ import com.google.common.base.MoreObjects;
* @author Chris Fletcher
* @author Major
*/
public abstract class GameObject extends Entity {
public abstract class GameObject extends Entity implements GroupableEntity {
/**
* The packed value that stores this object's id, type, and orientation.
@@ -91,7 +92,8 @@ public abstract class GameObject extends Entity {
@Override
public String toString() {
return MoreObjects.toStringHelper(this).add("id", getId()).add("type", getType()).add("orientation", getOrientation()).toString();
return MoreObjects.toStringHelper(this).add("id", getId()).add("type", getType())
.add("orientation", getOrientation()).toString();
}
@Override
@@ -26,7 +26,8 @@ public final class GroupedRegionUpdateMessageEncoder extends MessageEncoder<Grou
/**
* Creates the GroupedRegionUpdateMessageEncoder.
*
* @param release The {@link Release} containing the {@link MessageEncoder}s for the {@link RegionUpdateMessage}s.
* @param release The {@link Release} containing the {@link MessageEncoder}s for the {@link RegionUpdateMessage}
* s.
*/
public GroupedRegionUpdateMessageEncoder(Release release) {
this.release = release;
@@ -39,11 +40,8 @@ public final class GroupedRegionUpdateMessageEncoder extends MessageEncoder<Grou
builder.put(DataType.BYTE, region.getLocalY(lastKnownRegion));
builder.put(DataType.BYTE, DataTransformation.NEGATE, region.getLocalX(lastKnownRegion));
System.out.println("Grum: local x: " + lastKnownRegion.getLocalX(region) + ", local y: "
+ lastKnownRegion.getLocalY(region));
for (RegionUpdateMessage update : message.getMessages()) {
System.out.println("==== Sending " + update + " as part of grum");
@SuppressWarnings("unchecked")
MessageEncoder<RegionUpdateMessage> encoder = (MessageEncoder<RegionUpdateMessage>) release
.getMessageEncoder(update.getClass());
@@ -94,7 +94,7 @@ public final class NpcMovementTask extends ScheduledTask {
Position first = positions.pollFirst();
if (first != null && queue.addFirstStep(first)) {
positions.forEach(npc.getWalkingQueue()::addStep);
positions.forEach(queue::addStep);
}
npcs.offer(npc);