mirror of
https://github.com/2006-Scape/apollo.git
synced 2026-07-07 08:39:17 +00:00
Fix travelback implementation.
This commit is contained in:
@@ -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;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Reference in New Issue
Block a user