From e3f10e200d8ce8ba41549cce9e7aac8ff5e8b7f3 Mon Sep 17 00:00:00 2001 From: Major- Date: Sun, 30 Aug 2015 18:08:30 +0100 Subject: [PATCH] Optimise GameObjectDecoder for faster start-up time. --- .../game/fs/decoder/GameObjectDecoder.java | 65 +++++++++++-------- .../game/io/player/PlayerSerializer.java | 2 +- .../org/apollo/game/model/area/Region.java | 10 +++ 3 files changed, 49 insertions(+), 28 deletions(-) diff --git a/game/src/main/org/apollo/game/fs/decoder/GameObjectDecoder.java b/game/src/main/org/apollo/game/fs/decoder/GameObjectDecoder.java index f7e86124..25a20d60 100644 --- a/game/src/main/org/apollo/game/fs/decoder/GameObjectDecoder.java +++ b/game/src/main/org/apollo/game/fs/decoder/GameObjectDecoder.java @@ -14,6 +14,7 @@ import org.apollo.cache.decoder.MapFileDecoder; import org.apollo.cache.decoder.MapFileDecoder.MapDefinition; import org.apollo.cache.decoder.ObjectDefinitionDecoder; import org.apollo.cache.def.ObjectDefinition; +import org.apollo.game.io.player.PlayerSerializer; import org.apollo.game.model.Position; import org.apollo.game.model.World; import org.apollo.game.model.area.Region; @@ -65,6 +66,11 @@ public final class GameObjectDecoder implements Runnable { */ private final World world; + /** + * The most-recently used Region. + */ + private Region previous; + /** * Creates the GameObjectDecoder. * @@ -75,6 +81,7 @@ public final class GameObjectDecoder implements Runnable { this.fs = fs; this.world = world; regions = world.getRegionRepository(); + previous = regions.fromPosition(PlayerSerializer.TUTORIAL_ISLAND_SPAWN); // dummy, so 'previous' is never null. } @Override @@ -85,9 +92,7 @@ public final class GameObjectDecoder implements Runnable { try { Map definitions = MapFileDecoder.decode(fs); - for (Entry entry : definitions.entrySet()) { - MapDefinition definition = entry.getValue(); - + for (MapDefinition definition : definitions.values()) { int packed = definition.getPackedCoordinates(); int x = (packed >> 8 & 0xFF) * 64; int y = (packed & 0xFF) * 64; @@ -117,10 +122,13 @@ public final class GameObjectDecoder implements Runnable { ObjectDefinition definition = ObjectDefinition.lookup(object.getId()); int type = object.getType(); - Region region = regions.fromPosition(position); int x = position.getX(), y = position.getY(), height = position.getHeight(); - CollisionMatrix matrix = region.getMatrix(height); + if (!previous.contains(position)) { + previous = regions.fromPosition(position); + } + + CollisionMatrix matrix = previous.getMatrix(height); boolean block = false; if (type == ObjectType.FLOOR_DECORATION.getValue() && definition.isInteractive()) { @@ -140,18 +148,19 @@ public final class GameObjectDecoder implements Runnable { } if (block) { - for (int dx = 0; dx < definition.getWidth(); dx++) { - for (int dy = 0; dy < definition.getLength(); dy++) { + int width = definition.getWidth(), length = definition.getLength(); + + for (int dx = 0; dx < width; dx++) { + for (int dy = 0; dy < length; dy++) { int localX = x % Region.SIZE + dx, localY = y % Region.SIZE + dy; if (localX > 7 || localY > 7) { int nextLocalX = localX > 7 ? x + localX - 7 : x + localX; int nextLocalY = localY > 7 ? y + localY - 7 : y - localY; - Position nextPosition = new Position(nextLocalX, nextLocalY); - Region next = regions.fromPosition(nextPosition); + Region next = regions.fromPosition(new Position(nextLocalX, nextLocalY)); - int nextX = nextPosition.getX() % Region.SIZE + dx; - int nextY = nextPosition.getY() % Region.SIZE + dy; + int nextX = nextLocalX % Region.SIZE + dx; + int nextY = nextLocalY % Region.SIZE + dy; if (nextX > 7) { nextX -= 7; @@ -175,12 +184,11 @@ public final class GameObjectDecoder implements Runnable { * Decodes the attributes of a terrain file, blocking the tile if necessary. * * @param attributes The terrain attributes. - * @param position The {@link Position} of the tile whose attributes are being decoded. + * @param x The x coordinate of the tile the attributes belong to. + * @param y The y coordinate of the tile the attributes belong to. + * @param height The level level of the tile the attributes belong to. */ - private void decodeAttributes(int attributes, Position position) { - Region region = regions.fromPosition(position); - int x = position.getX(), y = position.getY(), height = position.getHeight(); - + private void decodeAttributes(int attributes, int x, int y, int height) { boolean block = false; if ((attributes & BLOCKED_TILE) != 0) { block = true; @@ -195,7 +203,13 @@ public final class GameObjectDecoder implements Runnable { if (block) { int localX = x % Region.SIZE, localY = y % Region.SIZE; - region.getMatrix(height).block(localX, localY); + Position position = new Position(x, y, height); + + if (!previous.contains(position)) { + previous = regions.fromPosition(new Position(x, y, height)); + } + + previous.getMatrix(height).block(localX, localY); } } @@ -248,21 +262,18 @@ public final class GameObjectDecoder implements Runnable { * @param y The y coordinate of the top left tile of the map file. */ private void decodeTerrain(ByteBuffer buffer, int x, int y) { - for (int height = 0; height < 4; height++) { - for (int localX = 0; localX < 64; localX++) { - for (int localY = 0; localY < 64; localY++) { - Position position = new Position(x + localX, y + localY, height); - + for (int height = 0; height < Position.HEIGHT_LEVELS; height++) { + for (int localX = 0; localX < Region.SIZE * Region.SIZE; localX++) { + for (int localY = 0; localY < Region.SIZE * Region.SIZE; localY++) { int attributes = 0; + while (true) { int attributeId = buffer.get() & 0xFF; - if (attributeId == 0) { - decodeAttributes(attributes, position); - break; - } else if (attributeId == 1) { + if (attributeId == 1) { buffer.get(); - decodeAttributes(attributes, position); + } else if (attributeId == 0) { + decodeAttributes(attributes, x + localX, y + localY, height); break; } else if (attributeId <= 49) { buffer.get(); diff --git a/game/src/main/org/apollo/game/io/player/PlayerSerializer.java b/game/src/main/org/apollo/game/io/player/PlayerSerializer.java index d8710d8c..9505895d 100644 --- a/game/src/main/org/apollo/game/io/player/PlayerSerializer.java +++ b/game/src/main/org/apollo/game/io/player/PlayerSerializer.java @@ -17,7 +17,7 @@ public abstract class PlayerSerializer { /** * The spawn point for Players, on Tutorial Island. */ - protected static final Position TUTORIAL_ISLAND_SPAWN = new Position(3093, 3104); + public static final Position TUTORIAL_ISLAND_SPAWN = new Position(3093, 3104); /** * The World this PlayerSerializer is for. diff --git a/game/src/main/org/apollo/game/model/area/Region.java b/game/src/main/org/apollo/game/model/area/Region.java index 49f0df8c..23c0fe07 100644 --- a/game/src/main/org/apollo/game/model/area/Region.java +++ b/game/src/main/org/apollo/game/model/area/Region.java @@ -163,6 +163,16 @@ public final class Region { return local != null && local.contains(entity); } + /** + * Returns whether or not the specified {@link Position} is inside this Region. + * + * @param position The Position. + * @return {@code true} iff the specified Position is inside this Region. + */ + public boolean contains(Position position) { + return coordinates.equals(position.getRegionCoordinates()); + } + /** * Encodes the contents of this Region into a {@link Set} of {@link RegionUpdateMessage}s, to be sent to a client. *