Fix travelback implementation.

This commit is contained in:
Major-
2015-08-24 14:41:19 +01:00
parent d9c34cd9ed
commit ed160ef70e
9 changed files with 264 additions and 320 deletions
@@ -13,7 +13,7 @@ import org.apollo.game.service.GameService;
public final class GamePulseHandler implements Runnable { public final class GamePulseHandler implements Runnable {
/** /**
* The logger for this class. * The Logger for this class.
*/ */
private static final Logger logger = Logger.getLogger(GamePulseHandler.class.getName()); private static final Logger logger = Logger.getLogger(GamePulseHandler.class.getName());
@@ -23,7 +23,7 @@ public final class GamePulseHandler implements Runnable {
private final GameService service; private final GameService service;
/** /**
* Creates the game pulse handler object. * Creates the GamePulseHandler.
* *
* @param service The {@link GameService}. * @param service The {@link GameService}.
*/ */
@@ -35,8 +35,8 @@ public final class GamePulseHandler implements Runnable {
public void run() { public void run() {
try { try {
service.pulse(); service.pulse();
} catch (Throwable reason) { } catch (Throwable throwable) {
logger.log(Level.SEVERE, "Exception occured during pulse!", reason); logger.log(Level.SEVERE, "Exception occurred during pulse!", throwable);
} }
} }
@@ -30,15 +30,13 @@ public final class WalkMessageHandler extends MessageHandler<WalkMessage> {
for (int index = 0; index < steps.length; index++) { for (int index = 0; index < steps.length; index++) {
Position step = steps[index]; Position step = steps[index];
if (index == 0) { if (index == 0) {
if (!queue.addFirstStep(step)) { queue.addFirstStep(step);
return; // ignore packet
}
} else { } else {
queue.addStep(step); queue.addStep(step);
} }
} }
queue.setRunningQueue(message.isRunning() || player.isRunning()); queue.setRunning(message.isRunning() || player.isRunning());
player.getInterfaceSet().close(); player.getInterfaceSet().close();
if (queue.size() > 0) { if (queue.size() > 0) {
@@ -58,48 +58,43 @@ public enum Direction {
public static final Direction[] EMPTY_DIRECTION_ARRAY = new Direction[0]; public static final Direction[] EMPTY_DIRECTION_ARRAY = new Direction[0];
/** /**
* Creates a direction from the differences between X and Y. * Gets the Direction between the two {@link Position}s..
* *
* @param deltaX The difference between two X coordinates. * @param current The difference between two X coordinates.
* @param deltaY The difference between two Y coordinates. * @param next The difference between two Y coordinates.
* @return The direction. * @return The direction.
*/ */
public static Direction fromDeltas(int deltaX, int deltaY) { public static Direction between(Position current, Position next) {
int deltaX = next.getX() - current.getX();
int deltaY = next.getY() - current.getY();
if (deltaY == 1) { if (deltaY == 1) {
if (deltaX == 1) { if (deltaX == 1) {
return Direction.NORTH_EAST; return NORTH_EAST;
} else if (deltaX == 0) { } else if (deltaX == 0) {
return Direction.NORTH; return NORTH;
} else if (deltaX == -1) {
return NORTH_WEST;
} }
return Direction.NORTH_WEST;
} else if (deltaY == -1) { } else if (deltaY == -1) {
if (deltaX == 1) { if (deltaX == 1) {
return Direction.SOUTH_EAST; return SOUTH_EAST;
} else if (deltaX == 0) { } else if (deltaX == 0) {
return Direction.SOUTH; return SOUTH;
}
return Direction.SOUTH_WEST;
} else {
if (deltaX == 1) {
return Direction.EAST;
} else if (deltaX == -1) { } else if (deltaX == -1) {
return Direction.WEST; return SOUTH_WEST;
}
} else if (deltaY == 0) {
if (deltaX == 1) {
return EAST;
} else if (deltaX == 0) {
return NONE;
} else if (deltaX == -1) {
return WEST;
} }
} }
return Direction.NONE; throw new IllegalArgumentException("Difference between Positions must be [-1, 1].");
}
/**
* Checks if the direction represented by the two delta values can connect two points together in a single
* direction.
*
* @param deltaX The difference in X coordinates.
* @param deltaY The difference in X coordinates.
* @return {@code true} if so, {@code false} if not.
*/
public static boolean isConnectable(int deltaX, int deltaY) {
return Math.abs(deltaX) == Math.abs(deltaY) || deltaX == 0 || deltaY == 0;
} }
/** /**
@@ -112,7 +107,7 @@ public enum Direction {
* *
* @param intValue The direction as an integer. * @param intValue The direction as an integer.
*/ */
private Direction(int intValue) { Direction(int intValue) {
this.intValue = intValue; this.intValue = intValue;
} }
@@ -67,16 +67,36 @@ public final class Player extends Mob {
AttributeMap.define("run_energy", AttributeDefinition.forInt(100, AttributePersistence.PERSISTENT)); AttributeMap.define("run_energy", AttributeDefinition.forInt(100, AttributePersistence.PERSISTENT));
} }
/**
* The player's appearance.
*/
private Appearance appearance = Appearance.DEFAULT_APPEARANCE;
/** /**
* This player's bank. * This player's bank.
*/ */
private final Inventory bank = new Inventory(InventoryConstants.BANK_CAPACITY, StackMode.STACK_ALWAYS); private final Inventory bank = new Inventory(InventoryConstants.BANK_CAPACITY, StackMode.STACK_ALWAYS);
/**
* This player's credentials.
*/
private final PlayerCredentials credentials;
/**
* This player's interface set.
*/
private final InterfaceSet interfaceSet = new InterfaceSet(this);
/**
* The Set of DynamicGameObjects that are visible to this Player.
*/
private final Set<DynamicGameObject> localObjects = new HashSet<>();
/**
* A temporary queue of messages sent during the login process.
*/
private final Deque<Message> queuedMessages = new ArrayDeque<>();
/**
* The player's appearance.
*/
private Appearance appearance = Appearance.DEFAULT_APPEARANCE;
/** /**
* The privacy state of this player's public chat. * The privacy state of this player's public chat.
*/ */
@@ -87,11 +107,6 @@ public final class Player extends Mob {
*/ */
private Deque<Point> clicks = new ArrayDeque<>(); private Deque<Point> clicks = new ArrayDeque<>();
/**
* This player's credentials.
*/
private final PlayerCredentials credentials;
/** /**
* A flag which indicates there are npcs that couldn't be added. * A flag which indicates there are npcs that couldn't be added.
*/ */
@@ -122,11 +137,6 @@ public final class Player extends Mob {
*/ */
private List<String> ignores = new ArrayList<>(); private List<String> ignores = new ArrayList<>();
/**
* This player's interface set.
*/
private final InterfaceSet interfaceSet = new InterfaceSet(this);
/** /**
* Whether or not the player is skulled. * Whether or not the player is skulled.
*/ */
@@ -137,11 +147,6 @@ public final class Player extends Mob {
*/ */
private Position lastKnownRegion; private Position lastKnownRegion;
/**
* The Set of DynamicGameObjects that are visible to this Player.
*/
private final Set<DynamicGameObject> localObjects = new HashSet<>();
/** /**
* The MembershipStatus of this Player. * The MembershipStatus of this Player.
*/ */
@@ -157,11 +162,6 @@ public final class Player extends Mob {
*/ */
private PrivilegeLevel privilegeLevel = PrivilegeLevel.STANDARD; private PrivilegeLevel privilegeLevel = PrivilegeLevel.STANDARD;
/**
* A temporary queue of messages sent during the login process.
*/
private final Deque<Message> queuedMessages = new ArrayDeque<>();
/** /**
* A flag indicating if the region changed in the last cycle. * A flag indicating if the region changed in the last cycle.
*/ */
@@ -506,11 +506,6 @@ public final class Player extends Mob {
return worldId; return worldId;
} }
@Override
public int hashCode() {
return credentials.hashCode();
}
/** /**
* Indicates whether or not the player with the specified username is on this player's ignore list. * Indicates whether or not the player with the specified username is on this player's ignore list.
* *
@@ -539,6 +534,11 @@ public final class Player extends Mob {
return regionChanged; return regionChanged;
} }
@Override
public int hashCode() {
return credentials.hashCode();
}
/** /**
* Increments this player's viewing distance if it is less than the maximum viewing distance. * Increments this player's viewing distance if it is less than the maximum viewing distance.
*/ */
@@ -790,15 +790,6 @@ public final class Player extends Mob {
this.chatPrivacy = chatPrivacy; this.chatPrivacy = chatPrivacy;
} }
/**
* Sets the value denoting the client's modified version.
*
* @param version The client version.
*/
public void setClientVersion(int version) {
attributes.set("client_version", new NumericalAttribute(version));
}
/** /**
* Sets the friend {@link PrivacyState}. * Sets the friend {@link PrivacyState}.
* *
@@ -939,6 +930,12 @@ public final class Player extends Mob {
} }
} }
@Override
public String toString() {
return MoreObjects.toStringHelper(this).add("username", getUsername()).add("privilege", privilegeLevel)
.toString();
}
/** /**
* Toggles the message filter. * Toggles the message filter.
* *
@@ -953,16 +950,10 @@ public final class Player extends Mob {
*/ */
public void toggleRunning() { public void toggleRunning() {
running = !running; running = !running;
walkingQueue.setRunningQueue(running); walkingQueue.setRunning(running);
send(new ConfigMessage(173, running ? 1 : 0)); send(new ConfigMessage(173, running ? 1 : 0));
} }
@Override
public String toString() {
return MoreObjects.toStringHelper(this).add("username", getUsername()).add("privilege", privilegeLevel)
.toString();
}
/** /**
* Initialises this player. * Initialises this player.
*/ */
@@ -7,8 +7,6 @@ import java.util.Queue;
import org.apollo.game.model.Direction; import org.apollo.game.model.Direction;
import org.apollo.game.model.Position; import org.apollo.game.model.Position;
import com.google.common.base.MoreObjects;
/** /**
* A queue of {@link Direction}s which a {@link Mob} will follow. * A queue of {@link Direction}s which a {@link Mob} will follow.
* *
@@ -17,162 +15,167 @@ import com.google.common.base.MoreObjects;
public final class WalkingQueue { public final class WalkingQueue {
/** /**
* Represents a single point in the queue. * The Mob this WalkingQueue belongs to.
*
* @author Graham
*/
private static final class Point {
/**
* The direction to walk to this point.
*/
private final Direction direction;
/**
* The point's position.
*/
private final Position position;
/**
* Creates a point.
*
* @param position The position.
* @param direction The direction.
*/
public Point(Position position, Direction direction) {
this.position = position;
this.direction = direction;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this).add("direction", direction).add("position", position)
.toString();
}
}
/**
* The maximum size of the queue. If any additional steps are added, they are discarded.
*/
private static final int MAXIMUM_SIZE = 128;
/**
* The mob whose walking queue this is.
*/ */
private final Mob mob; private final Mob mob;
/** /**
* The old queue of directions. * The Deque of active points in this WalkingQueue.
*/ */
private final Deque<Point> oldPoints = new ArrayDeque<>(); private final Deque<Position> points = new ArrayDeque<>();
/** /**
* The queue of directions. * The Deque of previous points in this WalkingQueue.
*/ */
private final Deque<Point> points = new ArrayDeque<>(); private final Deque<Position> previousPoints = new ArrayDeque<>();
/** /**
* Flag indicating if this queue (only) should be ran. * The running status of this WalkingQueue.
*/ */
private boolean runningQueue; private boolean running;
/** /**
* Creates a walking queue for the specified mob. * Creates the WalkingQueue.
* *
* @param mob The mob. * @param mob The {@link Mob} the WalkingQueue is for.
*/ */
public WalkingQueue(Mob mob) { public WalkingQueue(Mob mob) {
this.mob = mob; this.mob = mob;
} }
/** /**
* Adds the first step to the queue, attempting to connect the server and client position by looking at the * Adds a first step into this WalkingQueue.
* previous queue.
* *
* @param clientPosition The first step. * @param next The {@link Position} of the step.
* @return {@code true} if the queues could be connected correctly, {@code false} if not.
*/ */
public boolean addFirstStep(Position clientPosition) { public void addFirstStep(Position next) {
Position serverPosition = mob.getPosition(); points.clear();
running = false;
int deltaX = clientPosition.getX() - serverPosition.getX(); /*
int deltaY = clientPosition.getY() - serverPosition.getY(); * We need to connect 'current' and 'next' whilst accounting for the
* fact that the client and server might be out of sync (i.e. what the
* client thinks is 'current' is different to what the server thinks is
* 'current').
*
* First try to connect them via points from the previous queue.
*/
Queue<Position> backtrack = new ArrayDeque<>();
if (Direction.isConnectable(deltaX, deltaY)) { while (!previousPoints.isEmpty()) {
points.clear(); Position position = previousPoints.pollLast();
oldPoints.clear(); backtrack.add(position);
addStep(clientPosition); if (position.equals(next)) {
return true; backtrack.forEach(this::addStep);
} previousPoints.clear();
return;
Queue<Position> travelBackQueue = new ArrayDeque<>();
Point oldPoint;
while ((oldPoint = oldPoints.pollLast()) != null) {
Position oldPosition = oldPoint.position;
deltaX = oldPosition.getX() - serverPosition.getX();
deltaY = oldPosition.getX() - serverPosition.getY();
travelBackQueue.add(oldPosition);
if (Direction.isConnectable(deltaX, deltaY)) {
points.clear();
oldPoints.clear();
travelBackQueue.forEach(this::addStep);
addStep(clientPosition);
return true;
} }
} }
oldPoints.clear(); /* If that doesn't work, connect the points directly. */
return false; previousPoints.clear();
addStep(next);
} }
/** /**
* Adds a step. * Adds a step to this WalkingQueue.
* *
* @param x The x coordinate of this step. * @param next The {@link Position} of the step.
* @param y The y coordinate of this step.
*/ */
private void addStep(int x, int y) { public void addStep(Position next) {
if (points.size() >= MAXIMUM_SIZE) { Position current = points.peekLast();
return;
/*
* If current equals next, addFirstStep doesn't end up adding anything points queue. This makes peekLast()
* return null. If it does, the correct behaviour is to fill it in with mob.getPosition().
*/
if (current == null) {
current = mob.getPosition();
} }
Point last = getLast(); addStep(current, next);
int deltaX = x - last.position.getX();
int deltaY = y - last.position.getY();
Direction direction = Direction.fromDeltas(deltaX, deltaY);
if (direction != Direction.NONE) {
Point point = new Point(new Position(x, y, mob.getPosition().getHeight()), direction);
points.add(point);
oldPoints.add(point);
}
} }
/** /**
* Adds a step to the queue. * Clears this WalkingQueue.
*
* @param step The step to add.
*/ */
public void addStep(Position step) { public void clear() {
int x = step.getX(), y = step.getY(); points.clear();
Point last = getLast(); running = false;
previousPoints.clear();
}
int deltaX = x - last.position.getX(); /**
int deltaY = y - last.position.getY(); * Returns whether or not this WalkingQueue has running enabled.
*
* @return {@code true} iff this WalkingQueue has running enabled.
*/
public boolean isRunning() {
return running;
}
/**
* Pulses this WalkingQueue.
*/
public void pulse() {
Position position = mob.getPosition();
Direction firstDirection = Direction.NONE;
Direction secondDirection = Direction.NONE;
Position next = points.poll();
if (next != null) {
previousPoints.add(next);
firstDirection = Direction.between(position, next);
position = next;
if (running) {
next = points.poll();
if (next != null) {
previousPoints.add(next);
secondDirection = Direction.between(position, next);
position = next;
}
}
}
mob.setDirections(firstDirection, secondDirection);
mob.setPosition(position);
}
/**
* Sets the running flag status of this WalkingQueue.
*
* @param running The running flag.
*/
public void setRunning(boolean running) {
this.running = running;
}
/**
* Gets the size of this WalkingQueue, which is the number of points remaining in it.
*
* @return The size.
*/
public int size() {
return points.size();
}
/**
* Adds the {@code next} step to this WalkingQueue.
*
* @param current The current {@link Position}.
* @param next The next Position.
*/
private void addStep(Position current, Position next) {
int nextX = next.getX(), nextY = next.getY(), height = next.getHeight();
int deltaX = nextX - current.getX();
int deltaY = nextY - current.getY();
int max = Math.max(Math.abs(deltaX), Math.abs(deltaY)); int max = Math.max(Math.abs(deltaX), Math.abs(deltaY));
for (int i = 0; i < max; i++) { for (int count = 0; count < max; count++) {
if (deltaX < 0) { if (deltaX < 0) {
deltaX++; deltaX++;
} else if (deltaX > 0) { } else if (deltaX > 0) {
@@ -185,70 +188,8 @@ public final class WalkingQueue {
deltaY--; deltaY--;
} }
addStep(x - deltaX, y - deltaY); points.add(new Position(nextX - deltaX, nextY - deltaY, height));
} }
} }
/**
* Clears the walking queue.
*/
public void clear() {
points.clear();
oldPoints.clear();
}
/**
* Gets the last point.
*
* @return The last point.
*/
private Point getLast() {
return points.isEmpty() ? new Point(mob.getPosition(), Direction.NONE) : points.peekLast();
}
/**
* Called every pulse, updates the queue.
*/
public void pulse() {
Position position = mob.getPosition();
Direction first = Direction.NONE, second = Direction.NONE;
Point next = points.poll();
if (next != null) {
first = next.direction;
position = next.position;
if (runningQueue /* and enough energy */) {
next = points.poll();
if (next != null) {
second = next.direction;
position = next.position;
}
}
mob.setPosition(position);
}
mob.setDirections(first, second);
}
/**
* Sets the running queue flag.
*
* @param running The running queue flag.
*/
public void setRunningQueue(boolean running) {
runningQueue = running;
}
/**
* Gets the size of the queue.
*
* @return The size of the queue.
*/
public int size() {
return points.size();
}
} }
@@ -93,7 +93,9 @@ public final class NpcMovementTask extends ScheduledTask {
WalkingQueue queue = npc.getWalkingQueue(); WalkingQueue queue = npc.getWalkingQueue();
Position first = positions.pollFirst(); Position first = positions.pollFirst();
if (first != null && queue.addFirstStep(first)) {
if (first != null) {
queue.addFirstStep(first);
positions.forEach(queue::addStep); positions.forEach(queue::addStep);
} }
@@ -33,11 +33,6 @@ import org.xml.sax.SAXException;
*/ */
public final class GameService extends Service { public final class GameService extends Service {
/**
* The World this Service is for.
*/
protected final World world;
/** /**
* The number of times to unregister players per cycle. This is to ensure the saving threads don't get swamped with * The number of times to unregister players per cycle. This is to ensure the saving threads don't get swamped with
* requests and slow everything down. * requests and slow everything down.
@@ -45,9 +40,9 @@ public final class GameService extends Service {
private static final int UNREGISTERS_PER_CYCLE = 50; private static final int UNREGISTERS_PER_CYCLE = 50;
/** /**
* The {@link MessageHandlerChainSet}. * The World this Service is for.
*/ */
private MessageHandlerChainSet messageHandlerChainSet; protected final World world;
/** /**
* A queue of players to remove. * A queue of players to remove.
@@ -60,6 +55,11 @@ public final class GameService extends Service {
private final ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor(ThreadUtil private final ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor(ThreadUtil
.create("GameService")); .create("GameService"));
/**
* The {@link MessageHandlerChainSet}.
*/
private MessageHandlerChainSet handlers;
/** /**
* The {@link ClientSynchronizer}. * The {@link ClientSynchronizer}.
*/ */
@@ -90,30 +90,28 @@ public final class GameService extends Service {
/** /**
* Gets the MessageHandlerChainSet * Gets the MessageHandlerChainSet
* *
* @return The set of MessageHandlerChain's. * @return The MessageHandlerChainSet.
*/ */
public MessageHandlerChainSet getMessageHandlerChainSet() { public MessageHandlerChainSet getMessageHandlerChainSet() {
return messageHandlerChainSet; return handlers;
} }
/** /**
* Called every pulse. * Called every pulse.
*/ */
public void pulse() { public synchronized void pulse() {
synchronized (this) { finalizeUnregistrations();
finalizeUnregisters();
MobRepository<Player> players = world.getPlayerRepository(); MobRepository<Player> players = world.getPlayerRepository();
for (Player player : players) { for (Player player : players) {
GameSession session = player.getSession(); GameSession session = player.getSession();
if (session != null) { if (session != null) {
session.handlePendingMessages(messageHandlerChainSet); session.handlePendingMessages(handlers);
}
} }
world.pulse();
synchronizer.synchronize(players, world.getNpcRepository());
} }
world.pulse();
synchronizer.synchronize(players, world.getNpcRepository());
} }
/** /**
@@ -123,18 +121,16 @@ public final class GameService extends Service {
* @param session The {@link GameSession} of the Player. * @param session The {@link GameSession} of the Player.
* @return A {@link RegistrationStatus}. * @return A {@link RegistrationStatus}.
*/ */
public RegistrationStatus registerPlayer(Player player, GameSession session) { public synchronized RegistrationStatus registerPlayer(Player player, GameSession session) {
synchronized (this) { RegistrationStatus status = world.register(player);
RegistrationStatus status = world.register(player); if (status == RegistrationStatus.OK) {
if (status == RegistrationStatus.OK) { player.setSession(session);
player.setSession(session);
Region region = world.getRegionRepository().get(player.getPosition().getRegionCoordinates()); Region region = world.getRegionRepository().fromPosition(player.getPosition());
region.addEntity(player); region.addEntity(player);
}
return status;
} }
return status;
} }
/** /**
@@ -165,7 +161,7 @@ public final class GameService extends Service {
/** /**
* Finalizes the unregistration of Player's queued to be unregistered. * Finalizes the unregistration of Player's queued to be unregistered.
*/ */
private void finalizeUnregisters() { private void finalizeUnregistrations() {
LoginService loginService = context.getLoginService(); LoginService loginService = context.getLoginService();
for (int count = 0; count < UNREGISTERS_PER_CYCLE; count++) { for (int count = 0; count < UNREGISTERS_PER_CYCLE; count++) {
@@ -188,7 +184,7 @@ public final class GameService extends Service {
private void init() throws IOException, SAXException, ReflectiveOperationException { private void init() throws IOException, SAXException, ReflectiveOperationException {
try (InputStream input = new FileInputStream("data/messages.xml")) { try (InputStream input = new FileInputStream("data/messages.xml")) {
MessageHandlerChainSetParser chainSetParser = new MessageHandlerChainSetParser(input); MessageHandlerChainSetParser chainSetParser = new MessageHandlerChainSetParser(input);
messageHandlerChainSet = chainSetParser.parse(world); handlers = chainSetParser.parse(world);
} }
try (InputStream input = new FileInputStream("data/synchronizer.xml")) { try (InputStream input = new FileInputStream("data/synchronizer.xml")) {
@@ -67,9 +67,10 @@ public final class PlayerSynchronizationTask extends SynchronizationTask {
int oldLocalPlayers = localPlayers.size(); int oldLocalPlayers = localPlayers.size();
List<SynchronizationSegment> segments = new ArrayList<>(); List<SynchronizationSegment> segments = new ArrayList<>();
for (Iterator<Player> it = localPlayers.iterator(); it.hasNext();) { for (Iterator<Player> it = localPlayers.iterator(); it.hasNext(); ) {
Player other = it.next(); Player other = it.next();
if (!other.isActive() || other.isTeleporting() || other.getPosition().getLongestDelta(player.getPosition()) > player.getViewingDistance() || !other.getPosition().isWithinDistance(player.getPosition(), player.getViewingDistance())) {
if (removePlayer(other)) {
it.remove(); it.remove();
segments.add(new RemoveMobSegment()); segments.add(new RemoveMobSegment());
} else { } else {
@@ -103,8 +104,27 @@ public final class PlayerSynchronizationTask extends SynchronizationTask {
} }
} }
PlayerSynchronizationMessage message = new PlayerSynchronizationMessage(lastKnownRegion, player.getPosition(), regionChanged, segment, oldLocalPlayers, segments); PlayerSynchronizationMessage message = new PlayerSynchronizationMessage(lastKnownRegion, player.getPosition(),
regionChanged, segment, oldLocalPlayers, segments);
player.send(message); player.send(message);
} }
/**
* Returns whether or not the specified {@link Player} should be removed.
*
* @param other The Player being tested.
* @return {@code true} iff the specified Player should be removed.
*/
private boolean removePlayer(Player other) {
if (other.isTeleporting() || !other.isActive()) {
return true;
}
Position position = player.getPosition();
Position otherPosition = other.getPosition();
int distance = player.getViewingDistance();
return otherPosition.getLongestDelta(position) > distance || !otherPosition.isWithinDistance(position, distance);
}
} }
@@ -66,7 +66,8 @@ public final class PrePlayerSynchronizationTask extends SynchronizationTask {
private final Map<RegionCoordinates, List<RegionUpdateMessage>> snapshots; private final Map<RegionCoordinates, List<RegionUpdateMessage>> snapshots;
/** /**
* The Map of RegionCoordinates to Sets of RegionUpdateMessages, which contain the updates for a Region a Player can * The Map of RegionCoordinates to Sets of RegionUpdateMessages, which contain the updates for a Region a Player
* can
* already view. * already view.
*/ */
private final Map<RegionCoordinates, List<RegionUpdateMessage>> updates; private final Map<RegionCoordinates, List<RegionUpdateMessage>> updates;
@@ -78,7 +79,8 @@ public final class PrePlayerSynchronizationTask extends SynchronizationTask {
* @param updates The {@link Map} containing {@link Region} updates. * @param updates The {@link Map} containing {@link Region} updates.
* @param snapshots The Map containing Region snapshots. * @param snapshots The Map containing Region snapshots.
*/ */
public PrePlayerSynchronizationTask(Player player, Map<RegionCoordinates, List<RegionUpdateMessage>> updates, Map<RegionCoordinates, List<RegionUpdateMessage>> snapshots) { public PrePlayerSynchronizationTask(Player player, Map<RegionCoordinates, List<RegionUpdateMessage>> updates,
Map<RegionCoordinates, List<RegionUpdateMessage>> snapshots) {
this.player = player; this.player = player;
this.updates = updates; this.updates = updates;
this.snapshots = snapshots; this.snapshots = snapshots;
@@ -156,6 +158,22 @@ public final class PrePlayerSynchronizationTask extends SynchronizationTask {
return coordinates; return coordinates;
} }
/**
* Checks if a region update is required.
*
* @return {@code true} if a Region update is required, {@code false} if not.
*/
private boolean isRegionUpdateRequired() {
Position current = player.getPosition();
Position last = player.getLastKnownRegion();
int deltaX = current.getLocalX(last);
int deltaY = current.getLocalY(last);
return deltaX <= Position.MAX_DISTANCE || deltaX >= VIEWPORT_WIDTH - Position.MAX_DISTANCE - 1
|| deltaY <= Position.MAX_DISTANCE || deltaY >= VIEWPORT_WIDTH - Position.MAX_DISTANCE - 1;
}
/** /**
* Gets the {@link List} of {@link GroupedRegionUpdateMessage}s. * Gets the {@link List} of {@link GroupedRegionUpdateMessage}s.
* *
@@ -181,31 +199,13 @@ public final class PrePlayerSynchronizationTask extends SynchronizationTask {
player.send(new ClearRegionMessage(position, coordinates)); player.send(new ClearRegionMessage(position, coordinates));
} }
Optional<GroupedRegionUpdateMessage> message = toUpdateMessage(local, player.getLastKnownRegion(), coordinates, repository); toUpdateMessage(local, player.getLastKnownRegion(), coordinates, repository).ifPresent(messages::add);
if (message.isPresent()) {
messages.add(message.get());
}
} }
} }
messages.forEach(player::send); messages.forEach(player::send);
} }
/**
* Checks if a region update is required.
*
* @return {@code true} if a Region update is required, {@code false} if not.
*/
private boolean isRegionUpdateRequired() {
Position current = player.getPosition();
Position last = player.getLastKnownRegion();
int deltaX = current.getLocalX(last);
int deltaY = current.getLocalY(last);
return deltaX <= Position.MAX_DISTANCE || deltaX >= VIEWPORT_WIDTH - Position.MAX_DISTANCE - 1 || deltaY <= Position.MAX_DISTANCE || deltaY >= VIEWPORT_WIDTH - Position.MAX_DISTANCE - 1;
}
/** /**
* Creates a {@link GroupedRegionUpdateMessage} using the specified {@link RegionUpdateMode}, returning * Creates a {@link GroupedRegionUpdateMessage} using the specified {@link RegionUpdateMode}, returning
* {@link Optional#empty()} if no update message is required. * {@link Optional#empty()} if no update message is required.
@@ -216,7 +216,8 @@ public final class PrePlayerSynchronizationTask extends SynchronizationTask {
* @param repository The {@link RegionRepository} containing the Regions. * @param repository The {@link RegionRepository} containing the Regions.
* @return The Optional containing the GroupedRegionUpdateMessage. * @return The Optional containing the GroupedRegionUpdateMessage.
*/ */
private Optional<GroupedRegionUpdateMessage> toUpdateMessage(RegionUpdateMode mode, Position lastKnownRegion, RegionCoordinates coordinates, RegionRepository repository) { private Optional<GroupedRegionUpdateMessage> toUpdateMessage(RegionUpdateMode mode, Position lastKnownRegion,
RegionCoordinates coordinates, RegionRepository repository) {
List<RegionUpdateMessage> messages; List<RegionUpdateMessage> messages;
/* /*