Resolve merge conflict.

This commit is contained in:
Major-
2015-04-15 18:36:00 +01:00
546 changed files with 2638 additions and 2465 deletions
+4 -3
View File
@@ -13,12 +13,12 @@ class OpenDoorAction < DistancedAction
def executeAction
mob.turn_to(@door.position)
DoorUtil::toggle(@door, mob)
DoorUtil::toggle(@door)
stop
end
def equals(other)
return (get_class == other.get_class && @door_object == other.door_object)
return (get_class == other.get_class && @door == other.door)
end
end
@@ -28,6 +28,7 @@ on :message, :first_object_action do |player, message|
if DoorUtil::is_door?(message.id)
puts "Player: #{player.position}, door: #{message.position}"
door = DoorUtil::get_door_object(message.position, message.id)
player.start_action(OpenDoorAction.new(player, door)) unless door.nil?
DoorUtil::toggle(door) unless door.nil?
# player.start_action(OpenDoorAction.new(player, door)) unless door.nil?
end
end
+2 -2
View File
@@ -46,7 +46,7 @@ module DoorUtil
end
# Toggles the given door.
def self.toggle(door, player)
def self.toggle(door)
position = door.position
region = $world.region_repository.from_position(position)
region.remove_entity(door)
@@ -59,7 +59,7 @@ module DoorUtil
else
toggled_position = translate_door_position(door)
toggled_orientation = translate_door_orientation(door)
toggled_door = DynamicGameObject.createPublic(door.id, toggled_position, door.type, toggled_orientation)
toggled_door = DynamicGameObject.createPublic($world, door.id, toggled_position, door.type, toggled_orientation)
toggled_region = $world.region_repository.from_position(toggled_position)
toggled_region.add_entity(toggled_door)
+66 -67
View File
@@ -1,78 +1,77 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>org.apollo</artifactId>
<version>1.0</version>
<groupId>apollo</groupId>
<modelVersion>4.0.0</modelVersion>
<artifactId>org.apollo</artifactId>
<version>1.0</version>
<groupId>apollo</groupId>
<build>
<sourceDirectory>src</sourceDirectory>
<testSourceDirectory>test</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<build>
<sourceDirectory>src</sourceDirectory>
<testSourceDirectory>test</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.3.2</version>
<configuration>
<mainClass>org.apollo.Server</mainClass>
<arguments>
<argument>-server</argument>
<argument>-Xmx750M</argument>
</arguments>
</configuration>
</plugin>
</plugins>
</build>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.3.2</version>
<configuration>
<mainClass>org.apollo.Server</mainClass>
<arguments>
<argument>-server</argument>
<argument>-Xmx750M</argument>
</arguments>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.9</version>
</dependency>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>org.jruby</groupId>
<artifactId>jruby-complete</artifactId>
<version>1.7.19</version>
</dependency>
<dependency>
<groupId>org.jruby</groupId>
<artifactId>jruby-complete</artifactId>
<version>1.7.19</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.0.26.Final</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.0.27.Final</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.lambdaworks</groupId>
<artifactId>scrypt</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>com.lambdaworks</groupId>
<artifactId>scrypt</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5</version>
</dependency>
</dependencies>
</dependencies>
</project>
+145 -163
View File
@@ -31,58 +31,49 @@ public final class IsaacRandom {
private static final int GOLDEN_RATIO = 0x9e3779b9;
/**
* The log of the size of the result and memory arrays.
* The log of the size of the result and state arrays.
*/
private static final int LOG_SIZE = 8;
private static final int LOG_SIZE = Long.BYTES;
/**
* The size of the result and memory arrays.
* The size of the result and states arrays.
*/
private static final int SIZE = 1 << LOG_SIZE;
/**
* A mask for pseudorandom lookup.
* A mask for pseudo-random lookup.
*/
private static int MASK = SIZE - 1 << 2;
/**
* The accumulator.
* The results given to the user.
*/
private int a;
/**
* The last result.
*/
private int b;
/**
* The counter.
*/
private int c;
/**
* The count through the results in the results array.
*/
private int count;
private final int[] results = new int[SIZE];
/**
* The internal state.
*/
private int[] mem;
private final int[] state = new int[SIZE];
/**
* The results given to the user.
* The count through the results in the results array.
*/
private int[] rsl;
private int count = SIZE;
/**
* Creates the random number generator without an initial seed.
* The accumulator.
*/
public IsaacRandom() {
mem = new int[SIZE];
rsl = new int[SIZE];
init(false);
}
private int accumulator;
/**
* The last result.
*/
private int last;
/**
* The counter.
*/
private int counter;
/**
* Creates the random number generator with the specified seed.
@@ -90,20 +81,75 @@ public final class IsaacRandom {
* @param seed The seed.
*/
public IsaacRandom(int[] seed) {
mem = new int[SIZE];
rsl = new int[SIZE];
for (int i = 0; i < seed.length; ++i) {
rsl[i] = seed[i];
}
init(true);
int length = Math.min(seed.length, results.length);
System.arraycopy(seed, 0, results, 0, length);
init();
}
/**
* Initialises this random number generator.
*
* @param hasSeed Set to {@code true} if a seed was passed to the constructor.
* Generates 256 results.
*/
private void init(boolean hasSeed) {
private void isaac() {
int i, j, x, y;
last += ++counter;
for (i = 0, j = SIZE / 2; i < SIZE / 2;) {
x = state[i];
accumulator ^= accumulator << 13;
accumulator += state[j++];
state[i] = y = state[(x & MASK) >> 2] + accumulator + last;
results[i++] = last = state[(y >> LOG_SIZE & MASK) >> 2] + x;
x = state[i];
accumulator ^= accumulator >>> 6;
accumulator += state[j++];
state[i] = y = state[(x & MASK) >> 2] + accumulator + last;
results[i++] = last = state[(y >> LOG_SIZE & MASK) >> 2] + x;
x = state[i];
accumulator ^= accumulator << 2;
accumulator += state[j++];
state[i] = y = state[(x & MASK) >> 2] + accumulator + last;
results[i++] = last = state[(y >> LOG_SIZE & MASK) >> 2] + x;
x = state[i];
accumulator ^= accumulator >>> 16;
accumulator += state[j++];
state[i] = y = state[(x & MASK) >> 2] + accumulator + last;
results[i++] = last = state[(y >> LOG_SIZE & MASK) >> 2] + x;
}
for (j = 0; j < SIZE / 2;) {
x = state[i];
accumulator ^= accumulator << 13;
accumulator += state[j++];
state[i] = y = state[(x & MASK) >> 2] + accumulator + last;
results[i++] = last = state[(y >> LOG_SIZE & MASK) >> 2] + x;
x = state[i];
accumulator ^= accumulator >>> 6;
accumulator += state[j++];
state[i] = y = state[(x & MASK) >> 2] + accumulator + last;
results[i++] = last = state[(y >> LOG_SIZE & MASK) >> 2] + x;
x = state[i];
accumulator ^= accumulator << 2;
accumulator += state[j++];
state[i] = y = state[(x & MASK) >> 2] + accumulator + last;
results[i++] = last = state[(y >> LOG_SIZE & MASK) >> 2] + x;
x = state[i];
accumulator ^= accumulator >>> 16;
accumulator += state[j++];
state[i] = y = state[(x & MASK) >> 2] + accumulator + last;
results[i++] = last = state[(y >> LOG_SIZE & MASK) >> 2] + x;
}
}
/**
* Initializes this random number generator.
*/
private void init() {
int i;
int a, b, c, d, e, f, g, h;
a = b = c = d = e = f = g = h = GOLDEN_RATIO;
@@ -136,16 +182,15 @@ public final class IsaacRandom {
}
for (i = 0; i < SIZE; i += 8) { /* fill in mem[] with messy stuff */
if (hasSeed) {
a += rsl[i];
b += rsl[i + 1];
c += rsl[i + 2];
d += rsl[i + 3];
e += rsl[i + 4];
f += rsl[i + 5];
g += rsl[i + 6];
h += rsl[i + 7];
}
a += results[i];
b += results[i + 1];
c += results[i + 2];
d += results[i + 3];
e += results[i + 4];
f += results[i + 5];
g += results[i + 6];
h += results[i + 7];
a ^= b << 11;
d += a;
b += c;
@@ -170,123 +215,60 @@ public final class IsaacRandom {
h ^= a >>> 9;
c += h;
a += b;
mem[i] = a;
mem[i + 1] = b;
mem[i + 2] = c;
mem[i + 3] = d;
mem[i + 4] = e;
mem[i + 5] = f;
mem[i + 6] = g;
mem[i + 7] = h;
state[i] = a;
state[i + 1] = b;
state[i + 2] = c;
state[i + 3] = d;
state[i + 4] = e;
state[i + 5] = f;
state[i + 6] = g;
state[i + 7] = h;
}
if (hasSeed) { /* second pass makes all of seed affect all of mem */
for (i = 0; i < SIZE; i += 8) {
a += mem[i];
b += mem[i + 1];
c += mem[i + 2];
d += mem[i + 3];
e += mem[i + 4];
f += mem[i + 5];
g += mem[i + 6];
h += mem[i + 7];
a ^= b << 11;
d += a;
b += c;
b ^= c >>> 2;
e += b;
c += d;
c ^= d << 8;
f += c;
d += e;
d ^= e >>> 16;
g += d;
e += f;
e ^= f << 10;
h += e;
f += g;
f ^= g >>> 4;
a += f;
g += h;
g ^= h << 8;
b += g;
h += a;
h ^= a >>> 9;
c += h;
a += b;
mem[i] = a;
mem[i + 1] = b;
mem[i + 2] = c;
mem[i + 3] = d;
mem[i + 4] = e;
mem[i + 5] = f;
mem[i + 6] = g;
mem[i + 7] = h;
}
for (i = 0; i < SIZE; i += 8) {
a += state[i];
b += state[i + 1];
c += state[i + 2];
d += state[i + 3];
e += state[i + 4];
f += state[i + 5];
g += state[i + 6];
h += state[i + 7];
a ^= b << 11;
d += a;
b += c;
b ^= c >>> 2;
e += b;
c += d;
c ^= d << 8;
f += c;
d += e;
d ^= e >>> 16;
g += d;
e += f;
e ^= f << 10;
h += e;
f += g;
f ^= g >>> 4;
a += f;
g += h;
g ^= h << 8;
b += g;
h += a;
h ^= a >>> 9;
c += h;
a += b;
state[i] = a;
state[i + 1] = b;
state[i + 2] = c;
state[i + 3] = d;
state[i + 4] = e;
state[i + 5] = f;
state[i + 6] = g;
state[i + 7] = h;
}
isaac();
count = SIZE;
}
/**
* Generates 256 results.
*/
private void isaac() {
int i, j, x, y;
b += ++c;
for (i = 0, j = SIZE / 2; i < SIZE / 2;) {
x = mem[i];
a ^= a << 13;
a += mem[j++];
mem[i] = y = mem[(x & MASK) >> 2] + a + b;
rsl[i++] = b = mem[(y >> LOG_SIZE & MASK) >> 2] + x;
x = mem[i];
a ^= a >>> 6;
a += mem[j++];
mem[i] = y = mem[(x & MASK) >> 2] + a + b;
rsl[i++] = b = mem[(y >> LOG_SIZE & MASK) >> 2] + x;
x = mem[i];
a ^= a << 2;
a += mem[j++];
mem[i] = y = mem[(x & MASK) >> 2] + a + b;
rsl[i++] = b = mem[(y >> LOG_SIZE & MASK) >> 2] + x;
x = mem[i];
a ^= a >>> 16;
a += mem[j++];
mem[i] = y = mem[(x & MASK) >> 2] + a + b;
rsl[i++] = b = mem[(y >> LOG_SIZE & MASK) >> 2] + x;
}
for (j = 0; j < SIZE / 2;) {
x = mem[i];
a ^= a << 13;
a += mem[j++];
mem[i] = y = mem[(x & MASK) >> 2] + a + b;
rsl[i++] = b = mem[(y >> LOG_SIZE & MASK) >> 2] + x;
x = mem[i];
a ^= a >>> 6;
a += mem[j++];
mem[i] = y = mem[(x & MASK) >> 2] + a + b;
rsl[i++] = b = mem[(y >> LOG_SIZE & MASK) >> 2] + x;
x = mem[i];
a ^= a << 2;
a += mem[j++];
mem[i] = y = mem[(x & MASK) >> 2] + a + b;
rsl[i++] = b = mem[(y >> LOG_SIZE & MASK) >> 2] + x;
x = mem[i];
a ^= a >>> 16;
a += mem[j++];
mem[i] = y = mem[(x & MASK) >> 2] + a + b;
rsl[i++] = b = mem[(y >> LOG_SIZE & MASK) >> 2] + x;
}
}
/**
@@ -299,7 +281,7 @@ public final class IsaacRandom {
isaac();
count = SIZE - 1;
}
return rsl[count];
return results[count];
}
}
+16 -13
View File
@@ -10,6 +10,7 @@ import io.netty.channel.socket.nio.NioServerSocketChannel;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.file.Paths;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -25,6 +26,8 @@ import org.apollo.net.release.r317.Release317;
import org.apollo.util.plugin.PluginContext;
import org.apollo.util.plugin.PluginManager;
import com.google.common.base.Stopwatch;
/**
* The core class of the Apollo server.
*
@@ -43,8 +46,9 @@ public final class Server {
* @param args The command-line arguments passed to the application.
*/
public static void main(String[] args) {
Stopwatch stopwatch = Stopwatch.createStarted();
try {
long start = System.currentTimeMillis();
Server server = new Server();
server.init(args.length == 1 ? args[0] : Release317.class.getName());
@@ -53,10 +57,11 @@ public final class Server {
SocketAddress jaggrab = new InetSocketAddress(NetworkConstants.JAGGRAB_PORT);
server.bind(service, http, jaggrab);
logger.fine("Starting apollo took " + (System.currentTimeMillis() - start) + " ms.");
} catch (Throwable t) {
logger.log(Level.SEVERE, "Error whilst starting server.", t);
}
logger.fine("Starting apollo took " + stopwatch.elapsed(TimeUnit.MILLISECONDS) + " ms.");
}
/**
@@ -81,10 +86,8 @@ public final class Server {
/**
* Creates the Apollo server.
*
* @throws Exception If an error occurs whilst creating services.
*/
public Server() throws Exception {
public Server() {
logger.info("Starting Apollo...");
}
@@ -98,14 +101,14 @@ public final class Server {
public void bind(SocketAddress serviceAddress, SocketAddress httpAddress, SocketAddress jagGrabAddress) {
try {
logger.fine("Binding service listener to address: " + serviceAddress + "...");
serviceBootstrap.bind(serviceAddress).syncUninterruptibly();
serviceBootstrap.bind(serviceAddress).sync();
logger.fine("Binding HTTP listener to address: " + httpAddress + "...");
httpBootstrap.bind(httpAddress).syncUninterruptibly();
httpBootstrap.bind(httpAddress).sync();
logger.fine("Binding JAGGRAB listener to address: " + jagGrabAddress + "...");
jagGrabBootstrap.bind(jagGrabAddress).syncUninterruptibly();
} catch (Exception e) {
jagGrabBootstrap.bind(jagGrabAddress).sync();
} catch (InterruptedException e) {
logger.log(Level.SEVERE, "Binding to a port failed: ensure apollo isn't already running.", e);
System.exit(1);
}
@@ -122,8 +125,9 @@ public final class Server {
public void init(String releaseClassName) throws Exception {
Class<?> clazz = Class.forName(releaseClassName);
Release release = (Release) clazz.newInstance();
int releaseNo = release.getReleaseNumber();
logger.info("Initialized release #" + release.getReleaseNumber() + ".");
logger.info("Initialized release #" + releaseNo + ".");
serviceBootstrap.group(loopGroup);
httpBootstrap.group(loopGroup);
@@ -131,7 +135,8 @@ public final class Server {
World world = new World();
ServiceManager serviceManager = new ServiceManager(world);
ServerContext context = new ServerContext(release, serviceManager);
IndexedFileSystem fs = new IndexedFileSystem(Paths.get("data/fs", Integer.toString(releaseNo)), true);
ServerContext context = new ServerContext(release, serviceManager, fs);
ApolloHandler handler = new ApolloHandler(context);
ChannelInitializer<SocketChannel> serviceInitializer = new ServiceChannelInitializer(handler);
@@ -149,8 +154,6 @@ public final class Server {
PluginManager manager = new PluginManager(world, new PluginContext(context));
serviceManager.startAll();
int releaseNo = release.getReleaseNumber();
IndexedFileSystem fs = new IndexedFileSystem(Paths.get("data/fs", Integer.toString(releaseNo)), true);
world.init(releaseNo, fs, manager);
}
+22 -3
View File
@@ -1,5 +1,8 @@
package org.apollo;
import java.util.Objects;
import org.apollo.fs.IndexedFileSystem;
import org.apollo.net.release.Release;
/**
@@ -21,16 +24,23 @@ public final class ServerContext {
*/
private final ServiceManager serviceManager;
/**
* The IndexedFileSystem.
*/
private final IndexedFileSystem fileSystem;
/**
* Creates a new server context.
*
* @param release The current release.
* @param serviceManager The service manager.
* @param fileSystem The indexed file system.
*/
ServerContext(Release release, ServiceManager serviceManager) {
this.release = release;
this.serviceManager = serviceManager;
protected ServerContext(Release release, ServiceManager serviceManager, IndexedFileSystem fileSystem) {
this.release = Objects.requireNonNull(release);
this.serviceManager = Objects.requireNonNull(serviceManager);
this.serviceManager.setContext(this);
this.fileSystem = Objects.requireNonNull(fileSystem);
}
/**
@@ -42,6 +52,15 @@ public final class ServerContext {
return release;
}
/**
* Gets the IndexeFileSystem
*
* @return The IndexedFileSystem.
*/
public IndexedFileSystem getFileSystem() {
return fileSystem;
}
/**
* Gets a service. This method is shorthand for {@code getServiceManager().getService(...)}.
*
+1 -1
View File
@@ -27,7 +27,7 @@ public final class ServiceManager {
/**
* The service map.
*/
private Map<Class<? extends Service>, Service> services = new HashMap<>();
private final Map<Class<? extends Service>, Service> services = new HashMap<>();
/**
* Creates and initializes the {@link ServiceManager}.
+24 -1
View File
@@ -7,6 +7,7 @@ import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.zip.CRC32;
import com.google.common.base.Preconditions;
@@ -24,6 +25,11 @@ public final class IndexedFileSystem implements Closeable {
*/
private ByteBuffer crcTable;
/**
* The {@link #crcTable} represented as an {@code int} array.
*/
private int[] crcs;
/**
* The data file.
*/
@@ -32,7 +38,7 @@ public final class IndexedFileSystem implements Closeable {
/**
* The index files.
*/
private RandomAccessFile[] indices = new RandomAccessFile[256];
private final RandomAccessFile[] indices = new RandomAccessFile[256];
/**
* Read only flag.
@@ -143,6 +149,23 @@ public final class IndexedFileSystem implements Closeable {
throw new IllegalStateException("Cannot get CRC table from a writable file system.");
}
/**
* Gets the CRC table as an {@code int} array.
*
* @return The CRC table as an {@code int} array.
* @throws IOException If there is an error accessing files to create the table.
*/
public int[] getCrcs() throws IOException {
if (crcs != null) {
return crcs;
}
ByteBuffer buffer = getCrcTable();
crcs = new int[(buffer.remaining() / Integer.BYTES) - 1];
Arrays.setAll(crcs, crc -> buffer.getInt());
return crcs;
}
/**
* Gets a file.
*
@@ -133,7 +133,7 @@ public final class GameObjectDecoder {
if (block) {
for (int dx = 0; dx < definition.getWidth(); dx++) {
for (int dy = 0; dy < definition.getLength(); dy++) {
int localX = (x % Region.SIZE) + dx, localY = (y % Region.SIZE) + 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;
@@ -141,11 +141,13 @@ public final class GameObjectDecoder {
Position nextPosition = new Position(nextLocalX, nextLocalY);
Region next = regions.fromPosition(nextPosition);
int nextX = (nextPosition.getX() % Region.SIZE) + dx, nextY = (nextPosition.getY() % Region.SIZE) + dy;
if (nextX > 7)
int nextX = nextPosition.getX() % Region.SIZE + dx, nextY = nextPosition.getY() % Region.SIZE + dy;
if (nextX > 7) {
nextX -= 7;
if (nextY > 7)
}
if (nextY > 7) {
nextY -= 7;
}
next.getMatrix(height).block(nextX, nextY);
continue;
@@ -181,7 +183,7 @@ public final class GameObjectDecoder {
}
if (block) {
int localX = (x % Region.SIZE), localY = (y % Region.SIZE);
int localX = x % Region.SIZE, localY = y % Region.SIZE;
current.block(localX, localY);
}
}
@@ -209,7 +211,7 @@ public final class GameObjectDecoder {
int localY = packed & 0x3F;
int localX = packed >> 6 & 0x3F;
int height = (packed >> 12) & 0x3;
int height = packed >> 12 & 0x3;
int attributes = buffer.get() & 0xFF;
int type = attributes >> 2;
@@ -121,17 +121,13 @@ public final class NpcDefinitionDecoder {
} else if (opcode == 102 || opcode == 103) {
buffer.getShort();
} else if (opcode == 106) {
@SuppressWarnings("unused")
int morphVariableBitsIndex = wrap(buffer.getShort());
@SuppressWarnings("unused")
int morphismCount = wrap(buffer.getShort());
wrap(buffer.getShort());
wrap(buffer.getShort());
int count = buffer.get() & 0xFF;
int[] morphisms = new int[count + 1];
Arrays.setAll(morphisms, index -> wrap(buffer.getShort()));
} else if (opcode == 107) {
@SuppressWarnings("unused")
boolean clickable = false;
}
}
}
+2 -3
View File
@@ -20,12 +20,11 @@ import org.apollo.io.MessageHandlerChainSetParser;
import org.apollo.login.LoginService;
import org.apollo.net.session.GameSession;
import org.apollo.util.MobRepository;
import org.apollo.util.ThreadUtil;
import org.apollo.util.xml.XmlNode;
import org.apollo.util.xml.XmlParser;
import org.xml.sax.SAXException;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
/**
* The {@link GameService} class schedules and manages the execution of the {@link GamePulseHandler} class.
*
@@ -52,7 +51,7 @@ public final class GameService extends Service {
/**
* The scheduled executor service.
*/
private final ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryBuilder().setNameFormat("GameService").build());
private final ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor(ThreadUtil.build("GameService"));
/**
* The {@link ClientSynchronizer}.
@@ -30,7 +30,7 @@ public final class MessageHandlerChainSet {
public <M extends Message> boolean notify(Player player, M message) {
@SuppressWarnings("unchecked")
MessageHandlerChain<M> chain = (MessageHandlerChain<M>) chains.get(message.getClass());
return (chain == null) || chain.notify(player, message);
return chain == null || chain.notify(player, message);
}
/**
@@ -98,8 +98,7 @@ public final class EquipItemHandler extends MessageHandler<ItemOptionMessage> {
return;
}
if (definition.getSlot() == EquipmentConstants.SHIELD && weapon != null
&& EquipmentDefinition.lookup(weapon.getId()).isTwoHanded()) {
if (definition.getSlot() == EquipmentConstants.SHIELD && weapon != null && EquipmentDefinition.lookup(weapon.getId()).isTwoHanded()) {
equipment.set(EquipmentConstants.SHIELD, inventory.reset(inventorySlot));
inventory.add(equipment.reset(EquipmentConstants.WEAPON));
return;
@@ -27,8 +27,7 @@ public final class ItemOnObjectVerificationHandler extends MessageHandler<ItemOn
@Override
public void handle(Player player, ItemOnObjectMessage message) {
if (message.getInterfaceId() != SynchronizationInventoryListener.INVENTORY_ID
&& message.getInterfaceId() != BankConstants.SIDEBAR_INVENTORY_ID) {
if (message.getInterfaceId() != SynchronizationInventoryListener.INVENTORY_ID && message.getInterfaceId() != BankConstants.SIDEBAR_INVENTORY_ID) {
message.terminate();
return;
}
@@ -34,7 +34,7 @@ public final class ForwardPrivateChatMessage extends Message {
*/
public ForwardPrivateChatMessage(String username, PrivilegeLevel level, byte[] message) {
this.username = username;
this.privilege = level;
privilege = level;
this.message = message;
}
@@ -14,9 +14,9 @@ import org.apollo.game.model.area.RegionCoordinates;
public final class GroupedRegionUpdateMessage extends Message {
/**
* The Position of the Player.
* The last known region Position of the Player.
*/
private final Position player;
private final Position lastKnownRegion;
/**
* The Position of the Region being updated.
@@ -31,13 +31,13 @@ public final class GroupedRegionUpdateMessage extends Message {
/**
* Creates the GroupedRegionUpdateMessage.
*
* @param player The {@link Position} of the Player.
* @param lastKnownRegion The last known region {@link Position} of the Player.
* @param coordinates The {@link RegionCoordinates} of the Region being updated.
* @param messages The {@link List} of {@link RegionUpdateMessage}s.
*/
public GroupedRegionUpdateMessage(Position player, RegionCoordinates coordinates, List<RegionUpdateMessage> messages) {
this.player = player;
this.region = new Position(coordinates.getAbsoluteX(), coordinates.getAbsoluteY());
public GroupedRegionUpdateMessage(Position lastKnownRegion, RegionCoordinates coordinates, List<RegionUpdateMessage> messages) {
this.lastKnownRegion = lastKnownRegion;
region = new Position(coordinates.getAbsoluteX(), coordinates.getAbsoluteY());
this.messages = messages;
}
@@ -46,8 +46,8 @@ public final class GroupedRegionUpdateMessage extends Message {
*
* @return The Position.
*/
public Position getPlayerPosition() {
return player;
public Position getLastKnownRegion() {
return lastKnownRegion;
}
/**
@@ -33,7 +33,7 @@ public final class ItemOnObjectMessage extends InventoryItemMessage {
public ItemOnObjectMessage(int interfaceId, int itemId, int itemSlot, int objectId, int x, int y) {
super(0, interfaceId, itemId, itemSlot);
this.objectId = objectId;
this.position = new Position(x, y);
position = new Position(x, y);
}
/**
@@ -33,8 +33,8 @@ public final class RemoveObjectMessage extends RegionUpdateMessage {
*/
public RemoveObjectMessage(GameObject object, int positionOffset) {
this.positionOffset = positionOffset;
this.type = object.getType();
this.orientation = object.getOrientation();
type = object.getType();
orientation = object.getOrientation();
}
@Override
@@ -37,10 +37,10 @@ public final class SendObjectMessage extends RegionUpdateMessage {
* @param positionOffset The offset of the object's position from the region's central position.
*/
public SendObjectMessage(GameObject object, int positionOffset) {
this.id = object.getId();
id = object.getId();
this.positionOffset = positionOffset;
this.type = object.getType();
this.orientation = object.getOrientation();
type = object.getType();
orientation = object.getOrientation();
}
@Override
@@ -44,7 +44,7 @@ public final class SetPlayerActionMessage extends Message {
public SetPlayerActionMessage(String text, int slot, boolean primaryInteraction) {
this.text = text;
this.slot = slot;
this.primaryAction = primaryInteraction;
primaryAction = primaryInteraction;
}
/**
@@ -15,7 +15,7 @@ public final class WalkMessage extends Message {
/**
* The running flag.
*/
private boolean run;
private final boolean run;
/**
* The steps.
+1 -1
View File
@@ -47,7 +47,7 @@ public final class Item {
Preconditions.checkArgument(amount >= 0, "Amount cannot be negative.");
this.id = id;
this.amount = amount;
this.definition = ItemDefinition.lookup(id);
definition = ItemDefinition.lookup(id);
}
@Override
+1 -1
View File
@@ -192,7 +192,7 @@ public final class Position {
* @return The y coordinate.
*/
public int getY() {
return (packed >> 15) & 0x7FFF;
return packed >> 15 & 0x7FFF;
}
@Override
+4 -4
View File
@@ -80,7 +80,7 @@ public final class World {
/**
* The command dispatcher.
*/
private CommandDispatcher commandDispatcher = new CommandDispatcher();
private final CommandDispatcher commandDispatcher = new CommandDispatcher();
/**
* The EventListenerChainSet for this World.
@@ -208,7 +208,7 @@ public final class World {
* @throws Exception If any definitions could not be loaded or there was a failure when loading plugins.
*/
public void init(int release, IndexedFileSystem fs, PluginManager manager) throws Exception {
this.releaseNumber = release;
releaseNumber = release;
ItemDefinitionDecoder itemDecoder = new ItemDefinitionDecoder(fs);
ItemDefinition[] items = itemDecoder.decode();
@@ -385,12 +385,12 @@ public final class World {
}
/**
* Adds entities to regions in the {@link RegionRepository}.
* Adds entities to regions in the {@link RegionRepository}. By default, we do not notify listeners.
*
* @param entities The entities.
*/
private void placeEntities(Entity... entities) {
Arrays.stream(entities).forEach(entity -> regions.fromPosition(entity.getPosition()).addEntity(entity));
Arrays.stream(entities).forEach(entity -> regions.fromPosition(entity.getPosition()).addEntity(entity, false));
}
}
+258 -236
View File
@@ -31,280 +31,302 @@ import com.google.common.collect.ImmutableSet;
*/
public final class Region {
/**
* A {@link RegionListener} for {@link UpdateOperation}s.
*
* @author Major
*/
private static final class UpdateRegionListener implements RegionListener {
/**
* A {@link RegionListener} for {@link UpdateOperation}s.
*
* @author Major
*/
private static final class UpdateRegionListener implements RegionListener {
@Override
public void execute(Region region, Entity entity, EntityUpdateType update) {
EntityType type = entity.getEntityType();
if (type != EntityType.PLAYER && type != EntityType.NPC && (type != EntityType.STATIC_OBJECT || update == EntityUpdateType.REMOVE)) {
region.record(entity, update);
}
}
@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);
}
}
}
}
/**
* The width and length of a Region, in tiles.
*/
public static final int SIZE = 8;
/**
* The width and length of a Region, in tiles.
*/
public static final int SIZE = 8;
static final long start = System.currentTimeMillis();
static final long start = System.currentTimeMillis();
/**
* The default size of newly-created sets, to reduce memory usage.
*/
private static final int DEFAULT_SET_SIZE = 2;
/**
* The default size of newly-created sets, to reduce memory usage.
*/
private static final int DEFAULT_SET_SIZE = 2;
/**
* The RegionCoordinates of this Region.
*/
private final RegionCoordinates coordinates;
/**
* The RegionCoordinates of this Region.
*/
private final RegionCoordinates coordinates;
/**
* The Map of Positions to Entities in that Position.
*/
private final Map<Position, Set<Entity>> entities = new HashMap<>();
/**
* The Map of Positions to Entities in that Position.
*/
private final Map<Position, Set<Entity>> entities = new HashMap<>();
/**
* A List of RegionListeners registered to this Region.
*/
private final List<RegionListener> listeners = new ArrayList<>();
/**
* A List of RegionListeners registered to this Region.
*/
private final List<RegionListener> listeners = new ArrayList<>();
/**
* The CollisionMatrix.
*/
private final CollisionMatrix[] matrices = CollisionMatrix.createMatrices(Position.HEIGHT_LEVELS, SIZE, SIZE);
/**
* The CollisionMatrix.
*/
private final CollisionMatrix[] matrices = CollisionMatrix.createMatrices(Position.HEIGHT_LEVELS, SIZE, SIZE);
/**
* The Set containing RegionUpdateMessages which can be sent to add every non-Mob Entity in this Region.
*/
private final List<List<RegionUpdateMessage>> snapshots = new ArrayList<>(Position.HEIGHT_LEVELS);
/**
* The Set containing RegionUpdateMessages which can be sent to add every non-Mob Entity in this Region.
*/
private final List<Map<Entity, RegionUpdateMessage>> snapshots = new ArrayList<>(Position.HEIGHT_LEVELS);
/**
* The Set containing UpdateOperations.
*/
private final List<List<RegionUpdateMessage>> updates = new ArrayList<>(Position.HEIGHT_LEVELS);
/**
* The Set containing UpdateOperations.
*/
private final List<List<RegionUpdateMessage>> updates = new ArrayList<>(Position.HEIGHT_LEVELS);
/**
* Creates a new Region.
*
* @param x The x coordinate of the Region.
* @param y The y coordinate of the Region.
*/
public Region(int x, int y) {
this(new RegionCoordinates(x, y));
}
/**
* Creates a new Region.
*
* @param x The x coordinate of the Region.
* @param y The y coordinate of the Region.
*/
public Region(int x, int y) {
this(new RegionCoordinates(x, y));
}
/**
* Creates a new Region with the specified {@link RegionCoordinates}.
*
* @param coordinates The coordinates.
*/
public Region(RegionCoordinates coordinates) {
this.coordinates = coordinates;
listeners.add(new UpdateRegionListener());
/**
* Creates a new Region with the specified {@link RegionCoordinates}.
*
* @param coordinates The coordinates.
*/
public Region(RegionCoordinates coordinates) {
this.coordinates = coordinates;
listeners.add(new UpdateRegionListener());
for (int height = 0; height < Position.HEIGHT_LEVELS; height++) {
snapshots.add(new ArrayList<>());
updates.add(new ArrayList<>(DEFAULT_SET_SIZE));
}
}
for (int height = 0; height < Position.HEIGHT_LEVELS; height++) {
snapshots.add(new HashMap<>());
updates.add(new ArrayList<>(DEFAULT_SET_SIZE));
}
}
/**
* Adds a {@link Entity} from to Region. Note that this does not spawn the Entity, or do any other action other than
* register it to this Region.
*
* @param entity The Entity.
* @throws IllegalArgumentException If the Entity does not belong in this Region.
*/
public void addEntity(Entity entity) {
Position position = entity.getPosition();
checkPosition(position);
/**
* Adds a {@link Entity} to the Region. Note that this does not spawn the Entity, or do any other action other than
* register it to this Region.
*
* @param entity The Entity.
* @param notify A flag indicating whether the {@link RegionListener}s for this Region should be notified.
* @throws IllegalArgumentException If the Entity does not belong in this Region.
*/
public void addEntity(Entity entity, boolean notify) {
Position position = entity.getPosition();
checkPosition(position);
Set<Entity> local = entities.computeIfAbsent(position, key -> new HashSet<>(DEFAULT_SET_SIZE));
local.add(entity);
Set<Entity> local = entities.computeIfAbsent(position, key -> new HashSet<>(DEFAULT_SET_SIZE));
local.add(entity);
if ((System.currentTimeMillis() - start) / 1000 > 10 && (entity instanceof GameObject)) {
System.out.println("Adding entity " + entity + " to " + entity.getPosition());
}
if ((System.currentTimeMillis() - start) / 1000 > 10 && (entity instanceof GameObject)) {
System.out.println("Adding entity " + entity + " to " + entity.getPosition());
}
notifyListeners(entity, EntityUpdateType.ADD);
}
if (notify) {
notifyListeners(entity, EntityUpdateType.ADD);
}
}
/**
* Checks if this Region contains the specified Entity.
* <p>
* This method operates in constant time.
*
* @param entity The Entity.
* @return {@code true} if this Region contains the Entity, otherwise {@code false}.
*/
public boolean contains(Entity entity) {
Position position = entity.getPosition();
Set<Entity> local = entities.get(position);
/**
* Adds a {@link Entity} to the Region. Note that this does not spawn the Entity, or do any other action other than
* register it to this Region.
* <p/>
* By default, this method notifies RegionListeners for this region of the addition.
*
* @param entity The Entity.
* @throws IllegalArgumentException If the Entity does not belong in this Region.
*/
public void addEntity(Entity entity) {
addEntity(entity, true);
}
return local != null && local.contains(entity);
}
/**
* Checks if this Region contains the specified Entity.
* <p/>
* This method operates in constant time.
*
* @param entity The Entity.
* @return {@code true} if this Region contains the Entity, otherwise {@code false}.
*/
/**
* Gets this Region's {@link RegionCoordinates}.
*
* @return The Region coordinates.
*/
public RegionCoordinates getCoordinates() {
return coordinates;
}
public boolean contains(Entity entity) {
Position position = entity.getPosition();
Set<Entity> local = entities.get(position);
/**
* Gets a shallow copy of the {@link Set} of {@link Entity} objects at the specified {@link Position}. The returned
* type will be immutable.
*
* @param position The position containing the entities.
* @return The list.
*/
public Set<Entity> getEntities(Position position) {
Set<Entity> set = entities.get(position);
return (set == null) ? ImmutableSet.of() : ImmutableSet.copyOf(set);
}
return local != null && local.contains(entity);
}
/**
* Gets a shallow copy of the {@link Set} of {@link Entity}s with the specified {@link EntityType}(s). The returned
* type will be immutable. Type will be inferred from the call, so ensure that the Entity type and the reference
* correspond, or this method will fail at runtime.
*
* @param position The {@link Position} containing the entities.
* @param types The {@link EntityType}s.
* @return The set of entities.
*/
public <T extends Entity> Set<T> getEntities(Position position, EntityType... types) {
Set<Entity> local = entities.get(position);
if (local == null) {
return ImmutableSet.of();
}
/**
* Gets this Region's {@link RegionCoordinates}.
*
* @return The Region coordinates.
*/
public RegionCoordinates getCoordinates() {
return coordinates;
}
Set<EntityType> set = new HashSet<>(Arrays.asList(types));
@SuppressWarnings("unchecked")
Set<T> filtered = (Set<T>) local.stream().filter(entity -> set.contains(entity.getEntityType())).collect(Collectors.toSet());
return ImmutableSet.copyOf(filtered);
}
/**
* Gets a shallow copy of the {@link Set} of {@link Entity} objects at the specified {@link Position}. The returned
* type will be immutable.
*
* @param position The position containing the entities.
* @return The list.
*/
public Set<Entity> getEntities(Position position) {
Set<Entity> set = entities.get(position);
return (set == null) ? ImmutableSet.of() : ImmutableSet.copyOf(set);
}
/**
* Gets the {@link CollisionMatrix} at the specified height level.
*
* @param height The height level.
* @return The CollisionMatrix.
*/
public CollisionMatrix getMatrix(int height) {
Preconditions.checkElementIndex(height, matrices.length, "Matrix height level must be [0, " + matrices.length + ").");
return matrices[height];
}
/**
* Gets a shallow copy of the {@link Set} of {@link Entity}s with the specified {@link EntityType}(s). The returned
* type will be immutable. Type will be inferred from the call, so ensure that the Entity type and the reference
* correspond, or this method will fail at runtime.
*
* @param position The {@link Position} containing the entities.
* @param types The {@link EntityType}s.
* @return The set of entities.
*/
public <T extends Entity> Set<T> getEntities(Position position, EntityType... types) {
Set<Entity> local = entities.get(position);
if (local == null) {
return ImmutableSet.of();
}
/**
* Gets a {@link Set} containing {@link RegionUpdateMessage}s that add every {@link Entity} in this Region.
*
* @param height The height level to get the Set of RegionUpdateMessages for.
* @return The Set of RegionUpdateMessages.
*/
public List<RegionUpdateMessage> getSnapshot(int height) {
List<RegionUpdateMessage> copy = new ArrayList<>(snapshots.get(height));
Collections.sort(copy);
return ImmutableList.copyOf(copy);
}
Set<EntityType> set = new HashSet<>(Arrays.asList(types));
@SuppressWarnings("unchecked")
Set<T> filtered = (Set<T>) local.stream().filter(entity -> set.contains(entity.getEntityType())).collect(Collectors.toSet());
return ImmutableSet.copyOf(filtered);
}
/**
* Gets the updates that have occurred in the last tick in this Region, as a {@link Set} of
* {@link RegionUpdateMessage}s.
*
* @param height The height level to get the Set of RegionUpdateMessages for.
* @return The Set of RegionUpdateMessages.
*/
public List<RegionUpdateMessage> getUpdates(int height) {
List<RegionUpdateMessage> original = this.updates.get(height);
List<RegionUpdateMessage> updates = new ArrayList<>(original);
original.clear();
/**
* Gets the {@link CollisionMatrix} at the specified height level.
*
* @param height The height level.
* @return The CollisionMatrix.
*/
public CollisionMatrix getMatrix(int height) {
Preconditions.checkElementIndex(height, matrices.length, "Matrix height level must be [0, " + matrices.length + ").");
return matrices[height];
}
Collections.sort(updates);
return ImmutableList.copyOf(updates);
}
/**
* Gets a {@link Set} containing {@link RegionUpdateMessage}s that add every {@link Entity} in this Region.
*
* @param height The height level to get the Set of RegionUpdateMessages for.
* @return The Set of RegionUpdateMessages.
*/
public List<RegionUpdateMessage> getSnapshot(int height) {
List<RegionUpdateMessage> copy = new ArrayList<>(snapshots.get(height).values());
Collections.sort(copy);
return ImmutableList.copyOf(copy);
}
/**
* Notifies the {@link RegionListener}s registered to this Region that an update has occurred.
*
* @param entity The {@link Entity} that was updated.
* @param type The {@link EntityUpdateType} that occurred.
*/
public void notifyListeners(Entity entity, EntityUpdateType type) {
listeners.forEach(listener -> listener.execute(this, entity, type));
}
/**
* Gets the updates that have occurred in the last tick in this Region, as a {@link Set} of
* {@link RegionUpdateMessage}s.
*
* @param height The height level to get the Set of RegionUpdateMessages for.
* @return The Set of RegionUpdateMessages.
*/
public List<RegionUpdateMessage> getUpdates(int height) {
List<RegionUpdateMessage> original = this.updates.get(height);
List<RegionUpdateMessage> updates = new ArrayList<>(original);
original.clear();
/**
* Removes a {@link Entity} from this Region.
*
* @param entity The Entity.
* @throws IllegalArgumentException If the Entity does not belong in this Region, or if it was never added.
*/
public void removeEntity(Entity entity) {
Position position = entity.getPosition();
checkPosition(position);
Collections.sort(updates);
return ImmutableList.copyOf(updates);
}
Set<Entity> local = entities.get(position);
/**
* Notifies the {@link RegionListener}s registered to this Region that an update has occurred.
*
* @param entity The {@link Entity} that was updated.
* @param type The {@link EntityUpdateType} that occurred.
*/
public void notifyListeners(Entity entity, EntityUpdateType type) {
listeners.forEach(listener -> listener.execute(this, entity, type));
}
if (local == null || !local.remove(entity)) {
throw new IllegalArgumentException("Entity belongs in this Region (" + this + ") but does not exist.");
}
/**
* Removes a {@link Entity} from this Region.
*
* @param entity The Entity.
* @throws IllegalArgumentException If the Entity does not belong in this Region, or if it was never added.
*/
public void removeEntity(Entity entity) {
Position position = entity.getPosition();
checkPosition(position);
notifyListeners(entity, EntityUpdateType.REMOVE);
}
Set<Entity> local = entities.get(position);
@Override
public String toString() {
return MoreObjects.toStringHelper(this).add("coordinates", coordinates).toString();
}
if (local == null || !local.remove(entity)) {
throw new IllegalArgumentException("Entity belongs in this Region (" + this + ") but does not exist.");
}
/**
* Returns whether or not an Entity of the specified {@link EntityType type} can traverse the tile at the specified
* coordinate pair.
*
* @param position The {@link Position} of the tile.
* @param entity The {@link EntityType}.
* @param direction The {@link Direction} the Entity is approaching from.
* @return {@code true} if the tile at the specified coordinate pair is traversable, {@code false} if not.
*/
public boolean traversable(Position position, EntityType entity, Direction direction) {
CollisionMatrix matrix = matrices[position.getHeight()];
int x = position.getX(), y = position.getY();
notifyListeners(entity, EntityUpdateType.REMOVE);
}
return !matrix.untraversable(x % SIZE, y % SIZE, entity, direction);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this).add("coordinates", coordinates).toString();
}
/**
* Checks that the specified {@link Position} is included in this Region.
*
* @param position The position.
* @throws IllegalArgumentException If the specified position is not included in this Region.
*/
private void checkPosition(Position position) {
Preconditions.checkArgument(coordinates.equals(RegionCoordinates.fromPosition(position)), "Position is not included in this Region.");
}
/**
* Returns whether or not an Entity of the specified {@link EntityType type} can traverse the tile at the specified
* coordinate pair.
*
* @param position The {@link Position} of the tile.
* @param entity The {@link EntityType}.
* @param direction The {@link Direction} the Entity is approaching from.
* @return {@code true} if the tile at the specified coordinate pair is traversable, {@code false} if not.
*/
public boolean traversable(Position position, EntityType entity, Direction direction) {
CollisionMatrix matrix = matrices[position.getHeight()];
int x = position.getX(), y = position.getY();
/**
* Records the specified {@link Entity} as being updated this pulse.
*
* @param entity The Entity.
* @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) {
RegionUpdateMessage message = entity.toUpdateOperation(this, type).toMessage();
int height = entity.getPosition().getHeight();
return !matrix.untraversable(x % SIZE, y % SIZE, entity, direction);
}
updates.get(height).add(message);
snapshots.get(height).add(message);
}
/**
* Checks that the specified {@link Position} is included in this Region.
*
* @param position The position.
* @throws IllegalArgumentException If the specified position is not included in this Region.
*/
private void checkPosition(Position position) {
Preconditions.checkArgument(coordinates.equals(RegionCoordinates.fromPosition(position)), "Position is not included in this Region.");
}
/**
* Records the specified {@link Entity} as being updated this pulse.
*
* @param entity The Entity.
* @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) {
RegionUpdateMessage message = entity.toUpdateOperation(this, type).toMessage();
int height = entity.getPosition().getHeight();
updates.get(height).add(message);
snapshots.get(height).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);
}
}
}
@@ -56,7 +56,7 @@ public enum CollisionFlag {
* @return The array of CollisionFlags.
*/
public static CollisionFlag[] forType(EntityType type) {
return (type == EntityType.PROJECTILE) ? projectiles() : mobs();
return type == EntityType.PROJECTILE ? projectiles() : mobs();
}
/**
@@ -95,7 +95,7 @@ public abstract class UpdateOperation<E extends Entity> {
Preconditions.checkArgument(dx >= 0 && dx < Region.SIZE, position + " not in expected Region of " + region + ".");
Preconditions.checkArgument(dy >= 0 && dy < Region.SIZE, position + " not in expected Region of " + region + ".");
return (dx << 4) | dy;
return dx << 4 | dy;
}
}
@@ -67,7 +67,7 @@ public final class EquipmentDefinition {
/**
* The array of skill requirement levels.
*/
private int[] levels = { 1, 1, 1, 1, 1, 1, 1 };
private final int[] levels = { 1, 1, 1, 1, 1, 1, 1 };
/**
* The slot this equipment goes into.
@@ -114,7 +114,7 @@ public final class ItemDefinition {
/**
* The ground actions array.
*/
private String[] groundActions = new String[5];
private final String[] groundActions = new String[5];
/**
* The item's id.
@@ -124,7 +124,7 @@ public final class ItemDefinition {
/**
* The inventory actions array.
*/
private String[] inventoryActions = new String[5];
private final String[] inventoryActions = new String[5];
/**
* A flag indicating if this item is members only.
@@ -80,7 +80,7 @@ public final class NpcDefinition {
/**
* An array of interaction options.
*/
private String[] interactions = new String[5];
private final String[] interactions = new String[5];
/**
* The name of the npc.
+1 -1
View File
@@ -535,7 +535,7 @@ public abstract class Mob extends Entity {
* @param position The position to face.
*/
public final void turnTo(Position position) {
this.facingPosition = position;
facingPosition = position;
blockSet.add(SynchronizationBlock.createTurnToPositionBlock(position));
}
+2 -2
View File
@@ -88,7 +88,7 @@ public final class Player extends Mob {
/**
* This player's credentials.
*/
private PlayerCredentials credentials;
private final PlayerCredentials credentials;
/**
* A flag which indicates there are npcs that couldn't be added.
@@ -870,7 +870,7 @@ public final class Player extends Mob {
* @param brightness The screen brightness.
*/
public void setScreenBrightness(ScreenBrightness brightness) {
this.screenBrightness = brightness;
screenBrightness = brightness;
}
/**
@@ -223,7 +223,7 @@ public final class SkillSet {
continue;
}
current += (current < max ? 1 : -1);
current += current < max ? 1 : -1;
setSkill(id, new Skill(skills[id].getExperience(), current, max));
}
}
@@ -67,7 +67,7 @@ public final class AttributeMap {
/**
* The map of attribute names to attributes.
*/
private Map<String, Attribute<?>> attributes = new HashMap<>(DEFAULT_MAP_SIZE);
private final Map<String, Attribute<?>> attributes = new HashMap<>(DEFAULT_MAP_SIZE);
/**
* Gets the {@link Attribute} with the specified name.
@@ -30,13 +30,13 @@ public final class NumericalAttribute extends Attribute<Number> {
@Override
public byte[] encode() {
long encoded = (type == AttributeType.DOUBLE) ? Double.doubleToLongBits((double) value) : (long) value;
long encoded = type == AttributeType.DOUBLE ? Double.doubleToLongBits((double) value) : (long) value;
return Longs.toByteArray(encoded);
}
@Override
public String toString() {
return (type == AttributeType.DOUBLE) ? Double.toString((double) value) : Long.toString((long) value);
return type == AttributeType.DOUBLE ? Double.toString((double) value) : Long.toString((long) value);
}
}
@@ -44,7 +44,7 @@ public final class DynamicGameObject extends GameObject {
@Override
public int hashCode() {
Player player = get();
return (player == null) ? 0 : player.hashCode();
return player == null ? 0 : player.hashCode();
}
}
@@ -35,7 +35,7 @@ public abstract class GameObject extends Entity {
*/
public GameObject(World world, int id, Position position, int type, int orientation) {
super(world, position);
this.packed = id << 8 | (type & 0x3F) << 2 | orientation & 0x3;
packed = id << 8 | (type & 0x3F) << 2 | orientation & 0x3;
}
@Override
@@ -81,7 +81,7 @@ public abstract class GameObject extends Entity {
* @return The type.
*/
public int getType() {
return (packed >> 2) & 0x3F;
return packed >> 2 & 0x3F;
}
@Override
@@ -88,7 +88,7 @@ public final class SimplePathfindingAlgorithm extends PathfindingAlgorithm {
}
Position last = new Position(x, y, height);
if (!start.equals(last) && dy != 0 && traversable(last, boundaries, (dy > 0) ? Direction.SOUTH : Direction.NORTH)) {
if (!start.equals(last) && dy != 0 && traversable(last, boundaries, dy > 0 ? Direction.SOUTH : Direction.NORTH)) {
return addVertical(last, target, positions);
}
@@ -132,7 +132,7 @@ public final class SimplePathfindingAlgorithm extends PathfindingAlgorithm {
}
Position last = new Position(x, y, height);
if (!last.equals(target) && dx != 0 && traversable(last, boundaries, (dx > 0) ? Direction.WEST : Direction.EAST)) {
if (!last.equals(target) && dx != 0 && traversable(last, boundaries, dx > 0 ? Direction.WEST : Direction.EAST)) {
return addHorizontal(last, target, positions);
}
@@ -24,7 +24,7 @@ public final class EventListenerChainSet {
public <E extends Event> boolean notify(E event) {
@SuppressWarnings("unchecked")
EventListenerChain<E> chain = (EventListenerChain<E>) chains.get(event.getClass());
return (chain == null) || chain.notify(event);
return chain == null || chain.notify(event);
}
/**
@@ -6,9 +6,6 @@ import org.apollo.game.model.event.Event;
/**
* An {@link Event} created when a Mob's Position is being updated.
* <p>
* This Event intentionally ignores the result of execution - it should not be possible for a plugin to prevent this
* Event from happening, only to listen for it.
*
* @author Major
*/
@@ -51,7 +51,7 @@ public final class InterfaceSet {
/**
* A map of open interfaces.
*/
private Map<InterfaceType, Integer> interfaces = new HashMap<>();
private final Map<InterfaceType, Integer> interfaces = new HashMap<>();
/**
* The current listener.
@@ -150,7 +150,7 @@ public final class InterfaceSet {
public void openDialogue(DialogueListener listener, int dialogueId) {
closeAndNotify();
this.dialogueListener = Optional.ofNullable(listener);
dialogueListener = Optional.ofNullable(listener);
this.listener = Optional.ofNullable(listener);
interfaces.put(InterfaceType.DIALOGUE, dialogueId);
@@ -175,7 +175,7 @@ public final class InterfaceSet {
public void openDialogueOverlay(DialogueListener listener, int dialogueId) {
closeAndNotify();
this.dialogueListener = Optional.ofNullable(listener);
dialogueListener = Optional.ofNullable(listener);
this.listener = Optional.ofNullable(listener);
interfaces.put(InterfaceType.DIALOGUE, dialogueId);
@@ -18,7 +18,8 @@ public interface DialogueListener extends InterfaceListener {
* </p>
*
* @param button The button interface id.
* @return {@code true} if the {@link MessageHandlerChain} should be broken, {@code false} if it should be continued.
* @return {@code true} if the {@link MessageHandlerChain} should be broken, {@code false} if it should be
* continued.
*/
public boolean buttonClicked(int button);
+1 -1
View File
@@ -540,7 +540,7 @@ public final class Inventory {
int removed = Math.min(amount, itemAmount);
int remainder = itemAmount - removed;
set(slot, (remainder > 0) ? new Item(item.getId(), remainder) : null);
set(slot, remainder > 0 ? new Item(item.getId(), remainder) : null);
return removed;
}
}
@@ -82,8 +82,8 @@ public final class NpcMovementTask extends ScheduledTask {
int currentX = current.getX(), currentY = current.getY();
boolean negativeX = RANDOM.nextBoolean(), negativeY = RANDOM.nextBoolean();
int x = RANDOM.nextInt(negativeX ? (currentX - min.getX()) : (max.getX() - currentX));
int y = RANDOM.nextInt(negativeY ? (currentY - min.getY()) : (max.getY() - currentY));
int x = RANDOM.nextInt(negativeX ? currentX - min.getX() : max.getX() - currentX);
int y = RANDOM.nextInt(negativeY ? currentY - min.getY() : max.getY() - currentY);
int dx = negativeX ? -x : x;
int dy = negativeY ? -y : y;
@@ -6,7 +6,6 @@ import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Phaser;
import java.util.concurrent.ThreadFactory;
import org.apollo.game.GameService;
import org.apollo.game.message.impl.RegionUpdateMessage;
@@ -22,8 +21,7 @@ import org.apollo.game.sync.task.PreNpcSynchronizationTask;
import org.apollo.game.sync.task.PrePlayerSynchronizationTask;
import org.apollo.game.sync.task.SynchronizationTask;
import org.apollo.util.MobRepository;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.apollo.util.ThreadUtil;
/**
* An implementation of {@link ClientSynchronizer} which runs in a thread pool. A {@link Phaser} is used to ensure that
@@ -49,12 +47,10 @@ public final class ParallelClientSynchronizer extends ClientSynchronizer {
/**
* Creates the parallel client synchronizer backed by a thread pool with a number of threads equal to the number of
* processing cores available (this is found by the {@link Runtime#availableProcessors()} method.
* processing cores available (this is found by the {@link ThreadUtil#AVAILABLE_PROCESSORS} method.
*/
public ParallelClientSynchronizer() {
int processors = Runtime.getRuntime().availableProcessors();
ThreadFactory factory = new ThreadFactoryBuilder().setNameFormat("ClientSynchronizer").build();
executor = Executors.newFixedThreadPool(processors, factory);
executor = Executors.newFixedThreadPool(ThreadUtil.AVAILABLE_PROCESSORS, ThreadUtil.build("ClientSynchronizer"));
}
@Override
@@ -49,8 +49,7 @@ public final class NpcSynchronizationTask extends SynchronizationTask {
for (Iterator<Npc> it = localNpcs.iterator(); it.hasNext();) {
Npc npc = it.next();
if (!npc.isActive() || npc.isTeleporting()
|| npc.getPosition().getLongestDelta(playerPosition) > player.getViewingDistance()) {
if (!npc.isActive() || npc.isTeleporting() || npc.getPosition().getLongestDelta(playerPosition) > player.getViewingDistance()) {
it.remove();
segments.add(new RemoveMobSegment());
} else {
@@ -69,8 +68,7 @@ public final class NpcSynchronizationTask extends SynchronizationTask {
}
Position npcPosition = npc.getPosition();
if (npcPosition.isWithinDistance(playerPosition, player.getViewingDistance()) && !localNpcs.contains(npc)
&& npcPosition.getHeight() == playerPosition.getHeight()) {
if (npcPosition.isWithinDistance(playerPosition, player.getViewingDistance()) && !localNpcs.contains(npc) && npcPosition.getHeight() == playerPosition.getHeight()) {
localNpcs.add(npc);
added++;
npc.turnTo(npc.getFacingPosition());
@@ -80,8 +80,7 @@ public final class PlayerSynchronizationTask extends SynchronizationTask {
int added = 0;
MobRepository<Player> repository = player.getWorld().getPlayerRepository();
for (Iterator<Player> it = repository.iterator(); it.hasNext();) {
Player other = it.next();
for (Player other : repository) {
if (localPlayers.size() >= 255) {
player.flagExcessivePlayers();
break;
@@ -181,7 +181,7 @@ public final class PrePlayerSynchronizationTask extends SynchronizationTask {
player.send(new ClearRegionMessage(position, coordinates));
}
Optional<GroupedRegionUpdateMessage> message = toUpdateMessage(local, position, coordinates, repository);
Optional<GroupedRegionUpdateMessage> message = toUpdateMessage(local, player.getLastKnownRegion(), coordinates, repository);
if (message.isPresent()) {
messages.add(message.get());
}
@@ -208,7 +208,7 @@ public final class PrePlayerSynchronizationTask extends SynchronizationTask {
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);
return deltaX <= Position.MAX_DISTANCE || deltaX >= VIEWPORT_WIDTH - Position.MAX_DISTANCE - 1 || deltaY <= Position.MAX_DISTANCE || deltaY >= VIEWPORT_WIDTH - Position.MAX_DISTANCE - 1;
}
/**
@@ -216,12 +216,12 @@ public final class PrePlayerSynchronizationTask extends SynchronizationTask {
* {@link Optional#empty()} if no update message is required.
*
* @param mode The RegionUpdateMode for the Message.
* @param position The {@link Position} of the Player.
* @param lastKnownRegion The last known region {@link Position} of the Player.
* @param coordinates The {@link RegionCoordinates} of the {@link Region}.
* @param repository The {@link RegionRepository} containing the Regions.
* @return The Optional containing the GroupedRegionUpdateMessage.
*/
private Optional<GroupedRegionUpdateMessage> toUpdateMessage(RegionUpdateMode mode, Position position, RegionCoordinates coordinates, RegionRepository repository) {
private Optional<GroupedRegionUpdateMessage> toUpdateMessage(RegionUpdateMode mode, Position lastKnownRegion, RegionCoordinates coordinates, RegionRepository repository) {
List<RegionUpdateMessage> messages;
/*
@@ -237,7 +237,7 @@ public final class PrePlayerSynchronizationTask extends SynchronizationTask {
messages = updates.get(coordinates);
if (messages == null) {
synchronized (updates) {
messages = updates.computeIfAbsent(coordinates, coords -> repository.get(coords).getUpdates(position.getHeight()));
messages = updates.computeIfAbsent(coordinates, coords -> repository.get(coords).getUpdates(lastKnownRegion.getHeight()));
}
}
@@ -246,7 +246,7 @@ public final class PrePlayerSynchronizationTask extends SynchronizationTask {
messages = snapshots.get(coordinates);
if (messages == null) {
synchronized (snapshots) {
messages = snapshots.computeIfAbsent(coordinates, coords -> repository.get(coords).getSnapshot(position.getHeight()));
messages = snapshots.computeIfAbsent(coordinates, coords -> repository.get(coords).getSnapshot(lastKnownRegion.getHeight()));
}
}
@@ -255,7 +255,7 @@ public final class PrePlayerSynchronizationTask extends SynchronizationTask {
throw new IllegalArgumentException("Unrecognised RegionUpdateMode " + mode + ".");
}
return messages.isEmpty() ? Optional.empty() : Optional.of(new GroupedRegionUpdateMessage(position, coordinates, messages));
return messages.isEmpty() ? Optional.empty() : Optional.of(new GroupedRegionUpdateMessage(lastKnownRegion, coordinates, messages));
}
}
@@ -107,7 +107,7 @@ public final class BinaryPlayerSerializer extends PlayerSerializer {
int y = in.readUnsignedShort();
int height = in.readUnsignedByte();
Gender gender = (in.readUnsignedByte() == Gender.MALE.toInteger()) ? Gender.MALE : Gender.FEMALE;
Gender gender = in.readUnsignedByte() == Gender.MALE.toInteger() ? Gender.MALE : Gender.FEMALE;
int[] style = new int[7];
for (int slot = 0; slot < style.length; slot++) {
style[slot] = in.readUnsignedByte();
+39 -13
View File
@@ -3,6 +3,7 @@ package org.apollo.login;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -16,12 +17,11 @@ import org.apollo.net.codec.login.LoginRequest;
import org.apollo.net.release.Release;
import org.apollo.net.session.GameSession;
import org.apollo.net.session.LoginSession;
import org.apollo.util.ThreadUtil;
import org.apollo.util.xml.XmlNode;
import org.apollo.util.xml.XmlParser;
import org.xml.sax.SAXException;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
/**
* The {@link LoginService} manages {@link LoginRequest}s.
*
@@ -33,7 +33,7 @@ public final class LoginService extends Service {
/**
* The {@link ExecutorService} to which workers are submitted.
*/
private final ExecutorService executor = Executors.newCachedThreadPool(new ThreadFactoryBuilder().setNameFormat("LoginService").build());
private final ExecutorService executor = Executors.newCachedThreadPool(ThreadUtil.build("LoginService"));
/**
* The current {@link PlayerSerializer}.
@@ -79,9 +79,6 @@ public final class LoginService extends Service {
this.serializer = (PlayerSerializer) clazz.getConstructor(World.class).newInstance(world);
}
/**
* Starts the login service.
*/
@Override
public void start() {
@@ -92,15 +89,44 @@ public final class LoginService extends Service {
*
* @param session The session submitting this request.
* @param request The login request.
* @throws IOException If some I/O exception occurs.
*/
public void submitLoadRequest(LoginSession session, LoginRequest request) {
Release release = session.getRelease();
if (release.getReleaseNumber() != request.getReleaseNumber()) {
// TODO check archive 0 CRCs
session.handlePlayerLoaderResponse(request, new PlayerLoaderResponse(LoginConstants.STATUS_GAME_UPDATED));
} else {
executor.submit(new PlayerLoaderWorker(serializer, session, request));
public void submitLoadRequest(LoginSession session, LoginRequest request) throws IOException {
int response = LoginConstants.STATUS_OK;
if (requiresUpdate(session, request)) {
response = LoginConstants.STATUS_GAME_UPDATED;
}
if (response == LoginConstants.STATUS_OK) {
executor.submit(new PlayerLoaderWorker(serializer, session, request));
} else {
session.handlePlayerLoaderResponse(request, new PlayerLoaderResponse(response));
}
}
/**
* Checks if an update is required whenever a {@link Player} submits a login request.
*
* @param session The login session.
* @param request The login request.
* @return {@code true} if an update is required, otherwise return {@code false}.
* @throws IOException If some I/O exception occurs.
*/
private boolean requiresUpdate(LoginSession session, LoginRequest request) throws IOException {
Release release = getContext().getRelease();
if (release.getReleaseNumber() != request.getReleaseNumber()) {
return true;
}
int[] clientCrcs = request.getArchiveCrcs();
int[] serverCrcs = getContext().getFileSystem().getCrcs();
if (Arrays.equals(clientCrcs, serverCrcs)) {
return false;
}
return true;
}
/**
+6 -5
View File
@@ -66,13 +66,14 @@ public final class ApolloHandler extends ChannelInboundHandlerAdapter {
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object message) {
public void channelRead(ChannelHandlerContext ctx, Object message) throws Exception {
try {
Attribute<Session> attribute = ctx.attr(NetworkConstants.SESSION_KEY);
Channel channel = ctx.channel();
Attribute<Session> attribute = channel.attr(NetworkConstants.SESSION_KEY);
Session session = attribute.get();
if (message instanceof HttpRequest || message instanceof JagGrabRequest) {
session = new UpdateSession(ctx.channel(), serverContext);
session = new UpdateSession(channel, serverContext);
}
if (session != null) {
@@ -86,11 +87,11 @@ public final class ApolloHandler extends ChannelInboundHandlerAdapter {
switch (handshakeMessage.getServiceId()) {
case HandshakeConstants.SERVICE_GAME:
attribute.set(new LoginSession(ctx, serverContext));
attribute.set(new LoginSession(channel, serverContext));
break;
case HandshakeConstants.SERVICE_UPDATE:
attribute.set(new UpdateSession(ctx.channel(), serverContext));
attribute.set(new UpdateSession(channel, serverContext));
break;
}
}
@@ -19,8 +19,8 @@ public final class FlaggedMouseEventMessageDecoder extends MessageDecoder<Flagge
int read;
if (reader.getLength() == 2) {
read = (int) reader.getUnsigned(DataType.SHORT);
int clicks = (read >> 12);
int dX = (read >> 6) & 0x3f;
int clicks = read >> 12;
int dX = read >> 6 & 0x3f;
int dY = read & 0x3f;
return new FlaggedMouseEventMessage(clicks, dX, dY, true);
} else if (reader.getLength() == 3) {
@@ -29,7 +29,7 @@ public final class FlaggedMouseEventMessageDecoder extends MessageDecoder<Flagge
read = (int) reader.getUnsigned(DataType.INT) & ~0xc0000000;
}
int clicks = (read >> 19);
int clicks = read >> 19;
int x = (read & 0x7f) % 765;
int y = (read & 0x7f) / 765;
@@ -35,11 +35,11 @@ public final class GroupedRegionUpdateMessageEncoder extends MessageEncoder<Grou
@Override
public GamePacket encode(GroupedRegionUpdateMessage message) {
GamePacketBuilder builder = new GamePacketBuilder(60, PacketType.VARIABLE_SHORT);
Position player = message.getPlayerPosition(), region = message.getRegionPosition();
Position lastKnownRegion = message.getLastKnownRegion(), region = message.getRegionPosition();
builder.put(DataType.BYTE, player.getLocalY(region));
System.out.println("Grum: local x: " + player.getLocalX(region) + ", local y: " + player.getLocalY(region));
builder.put(DataType.BYTE, DataTransformation.NEGATE, player.getLocalX(region));
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");
@@ -19,9 +19,9 @@ public final class MouseClickedMessageDecoder extends MessageDecoder<MouseClicke
int value = (int) reader.getUnsigned(DataType.INT);
long delay = (value >> 20) * 50;
boolean right = ((value >> 19) & 0x1) == 1;
boolean right = (value >> 19 & 0x1) == 1;
int cords = (value & 0x3FFFF);
int cords = value & 0x3FFFF;
int x = cords % 765;
int y = cords / 765;
@@ -20,8 +20,8 @@ public final class FlaggedMouseEventMessageDecoder extends MessageDecoder<Flagge
if (reader.getLength() == 2) {
read = (int) reader.getUnsigned(DataType.SHORT);
clicks = (read >> 12);
x = (read >> 6) & 0x3f;
clicks = read >> 12;
x = read >> 6 & 0x3f;
y = read & 0x3f;
return new FlaggedMouseEventMessage(clicks, x, y, true);
} else if (reader.getLength() == 3) {
@@ -30,7 +30,7 @@ public final class FlaggedMouseEventMessageDecoder extends MessageDecoder<Flagge
read = (int) reader.getUnsigned(DataType.INT) & ~0xc0000000;
}
clicks = (read >> 19);
clicks = read >> 19;
x = (read & 0x7f) % 765;
y = (read & 0x7f) / 765;
return new FlaggedMouseEventMessage(clicks, x, y, false);
@@ -39,7 +39,7 @@ public final class GroupedRegionUpdateMessageEncoder extends MessageEncoder<Grou
@Override
public GamePacket encode(GroupedRegionUpdateMessage message) {
GamePacketBuilder builder = new GamePacketBuilder(183, PacketType.VARIABLE_SHORT);
Position base = message.getPlayerPosition(), region = message.getRegionPosition();
Position base = message.getLastKnownRegion(), region = message.getRegionPosition();
builder.put(DataType.BYTE, region.getLocalX(base));
builder.put(DataType.BYTE, DataTransformation.ADD, region.getLocalY(base));
@@ -19,9 +19,9 @@ public final class MouseClickedMessageDecoder extends MessageDecoder<MouseClicke
int value = (int) reader.getUnsigned(DataType.INT);
long delay = (value >> 20) * 50;
boolean right = ((value >> 19) & 0x1) == 1;
boolean right = (value >> 19 & 0x1) == 1;
int cords = (value & 0x3FFFF);
int cords = value & 0x3FFFF;
int x = cords % 765;
int y = cords / 765;
+3 -3
View File
@@ -16,7 +16,6 @@ import org.apollo.game.message.Message;
import org.apollo.game.message.MessageHandlerChainSet;
import org.apollo.game.message.impl.LogoutMessage;
import org.apollo.game.model.entity.Player;
import org.apollo.util.CollectionUtil;
/**
* A game session.
@@ -84,13 +83,14 @@ public final class GameSession extends Session {
* @param chainSet The {@link MessageHandlerChainSet}
*/
public void handlePendingMessages(MessageHandlerChainSet chainSet) {
CollectionUtil.pollAll(messageQueue, message -> {
Message message;
while ((message = messageQueue.poll()) != null) {
try {
chainSet.notify(player, message);
} catch (Exception reason) {
logger.log(Level.SEVERE, "Uncaught exception thrown while handling message: " + message, reason);
}
});
}
}
/**
+17 -32
View File
@@ -3,8 +3,8 @@ package org.apollo.net.session;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import java.io.IOException;
import java.util.Optional;
import org.apollo.ServerContext;
@@ -13,7 +13,6 @@ import org.apollo.game.model.World.RegistrationStatus;
import org.apollo.game.model.entity.Player;
import org.apollo.io.player.PlayerLoaderResponse;
import org.apollo.login.LoginService;
import org.apollo.net.ApolloHandler;
import org.apollo.net.NetworkConstants;
import org.apollo.net.codec.game.GameMessageDecoder;
import org.apollo.net.codec.game.GameMessageEncoder;
@@ -32,26 +31,20 @@ import org.apollo.security.IsaacRandomPair;
*/
public final class LoginSession extends Session {
/**
* The context of the {@link ApolloHandler}.
*/
private final ChannelHandlerContext channelContext;
/**
* The server context.
*/
private final ServerContext serverContext;
private final ServerContext context;
/**
* Creates a login session for the specified channel.
*
* @param ctx The context of the {@link ApolloHandler}.
* @param serverContext The server context.
* @param channel The channel.
* @param context The server context.
*/
public LoginSession(ChannelHandlerContext ctx, ServerContext serverContext) {
super(ctx.channel());
this.channelContext = ctx;
this.serverContext = serverContext;
public LoginSession(Channel channel, ServerContext context) {
super(channel);
this.context = context;
}
@Override
@@ -59,22 +52,14 @@ public final class LoginSession extends Session {
}
/**
* Gets the release.
*
* @return The release.
*/
public Release getRelease() {
return serverContext.getRelease();
}
/**
* Handles a login request.
*
* @param request The login request.
* @throws IOException If some I/O exception occurs.
*/
private void handleLoginRequest(LoginRequest request) {
LoginService loginService = serverContext.getService(LoginService.class);
private void handleLoginRequest(LoginRequest request) throws IOException {
LoginService loginService = context.getService(LoginService.class);
loginService.submitLoadRequest(this, request);
}
@@ -85,7 +70,7 @@ public final class LoginSession extends Session {
* @param response The response.
*/
public void handlePlayerLoaderResponse(LoginRequest request, PlayerLoaderResponse response) {
GameService service = serverContext.getService(GameService.class);
GameService service = context.getService(GameService.class);
Channel channel = getChannel();
Optional<Player> optional = response.getPlayer();
@@ -96,14 +81,14 @@ public final class LoginSession extends Session {
Player player = optional.get();
rights = player.getPrivilegeLevel().toInteger();
GameSession session = new GameSession(channel, serverContext, player);
GameSession session = new GameSession(channel, context, player);
RegistrationStatus registration = service.registerPlayer(player, session);
if (registration != RegistrationStatus.OK) {
optional = Optional.empty();
rights = 0;
status = (registration == RegistrationStatus.ALREADY_ONLINE) ? LoginConstants.STATUS_ACCOUNT_ONLINE : LoginConstants.STATUS_SERVER_FULL;
status = registration == RegistrationStatus.ALREADY_ONLINE ? LoginConstants.STATUS_ACCOUNT_ONLINE : LoginConstants.STATUS_SERVER_FULL;
}
}
@@ -113,18 +98,18 @@ public final class LoginSession extends Session {
if (optional.isPresent()) {
IsaacRandomPair randomPair = request.getRandomPair();
Release release = serverContext.getRelease();
Release release = context.getRelease();
channel.pipeline().addFirst("messageEncoder", new GameMessageEncoder(release));
channel.pipeline().addBefore("messageEncoder", "gameEncoder", new GamePacketEncoder(randomPair.getEncodingRandom()));
channel.pipeline().addBefore("handler", "gameDecoder", new GamePacketDecoder(randomPair.getDecodingRandom(), serverContext.getRelease()));
channel.pipeline().addBefore("handler", "gameDecoder", new GamePacketDecoder(randomPair.getDecodingRandom(), context.getRelease()));
channel.pipeline().addAfter("gameDecoder", "messageDecoder", new GameMessageDecoder(release));
channel.pipeline().remove("loginDecoder");
channel.pipeline().remove("loginEncoder");
channelContext.attr(NetworkConstants.SESSION_KEY).set(optional.get().getSession());
channel.attr(NetworkConstants.SESSION_KEY).set(optional.get().getSession());
} else {
future.addListener(ChannelFutureListener.CLOSE);
}
@@ -135,7 +120,7 @@ public final class LoginSession extends Session {
}
@Override
public void messageReceived(Object message) {
public void messageReceived(Object message) throws Exception {
if (message.getClass() == LoginRequest.class) {
handleLoginRequest((LoginRequest) message);
}
+2 -1
View File
@@ -42,7 +42,8 @@ public abstract class Session {
* Processes a message received from the channel.
*
* @param message The message.
* @throws Exception If some error occurs.
*/
public abstract void messageReceived(Object message);
public abstract void messageReceived(Object message) throws Exception;
}
+2 -3
View File
@@ -31,12 +31,11 @@ public final class RsaKeyGenerator {
do {
p = BigInteger.probablePrime(BIT_COUNT / 2, random);
q = BigInteger.probablePrime(BIT_COUNT / 2, random);
phi = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE));
phi = p.subtract(BigInteger.ONE).multiply(q.subtract(BigInteger.ONE));
modulus = p.multiply(q);
privateKey = publicKey.modInverse(phi);
} while (modulus.bitLength() != BIT_COUNT || privateKey.bitLength() != BIT_COUNT
|| !phi.gcd(publicKey).equals(BigInteger.ONE));
} while (modulus.bitLength() != BIT_COUNT || privateKey.bitLength() != BIT_COUNT || !phi.gcd(publicKey).equals(BigInteger.ONE));
System.out.println("modulus: " + modulus);
System.out.println("public key: " + publicKey);
+10 -19
View File
@@ -23,27 +23,18 @@ public final class TextUtil {
* @return The string with correct capitalization.
*/
public static String capitalize(String str) {
char[] chars = str.toCharArray();
boolean sentenceStart = true;
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
if (sentenceStart) {
if (c >= 'a' && c <= 'z') {
chars[i] -= 0x20;
sentenceStart = false;
} else if (c >= 'A' && c <= 'Z') {
sentenceStart = false;
}
} else {
if (c >= 'A' && c <= 'Z') {
chars[i] += 0x20;
}
}
if (c == '.' || c == '!' || c == '?') {
sentenceStart = true;
boolean capitalize = true;
StringBuilder bldr = new StringBuilder(str);
for (int index = 0, length = str.length(); index < length; index++) {
char character = bldr.charAt(index);
if (character == '.' || character == '!' || character == '?') {
capitalize = true;
} else if (capitalize && !Character.isWhitespace(character)) {
bldr.setCharAt(index, Character.toUpperCase(character));
capitalize = false;
}
}
return new String(chars, 0, chars.length);
return bldr.toString();
}
/**
+136
View File
@@ -0,0 +1,136 @@
package org.apollo.util;
import static com.google.common.base.Preconditions.checkArgument;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.Objects;
import java.util.concurrent.ThreadFactory;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
/**
* A static utility class which provides ease of use functionality for {@link Thread}s
*
* @author Ryley Kimmel <ryley.kimmel@live.com>
*/
public final class ThreadUtil {
/**
* Returns the amount of available processors available to the Java virtual machine.
*/
public static final int AVAILABLE_PROCESSORS = Runtime.getRuntime().availableProcessors();
/**
* A {@link Logger} used to debug messages to the console.
*/
private static final Logger LOGGER = Logger.getLogger(ThreadUtil.class.getSimpleName());
/**
* The default {@link UncaughtExceptionHandler} which raises an error from the logger with the exception and name of
* the specified thread the exception occurred in.
*/
private static final UncaughtExceptionHandler DEFAULT_EXCEPTION_HANDLER = (thread, exception) -> LOGGER.log(Level.SEVERE, "Exception occured in thread " + thread.getName(), exception);
/**
* Builds a {@link ThreadFactory} using the specified {@code String} name-format, {@link ThreadPriority} and
* {@link UncaughtExceptionHandler}.
*
* @param name The name-format used when creating threads, may not be {@code null}.
* @param priority The priority used when creating threads, may not be {@code null}.
* @param handler The {@link UncaughtExceptionHandler} used when creating threads, may not be {@code null}.
* @return A new {@link ThreadFactory} from the specified parameters, never {@code null}.
*/
public static ThreadFactory build(String name, ThreadPriority priority, UncaughtExceptionHandler handler) {
Objects.requireNonNull(priority);
ThreadFactoryBuilder bldr = new ThreadFactoryBuilder();
bldr.setNameFormat(name);
bldr.setPriority(priority.getValue());
bldr.setUncaughtExceptionHandler(handler);
return bldr.build();
}
/**
* Builds a {@link ThreadFactory} using the specified {@code String} name-format, {@link ThreadPriority} and the
* default {@link UncaughtExceptionHandler}.
*
* @param name The name-format used when creating threads, may not be {@code null}.
* @param priority The priority used when creating threads, may not be {@code null}.
* @return A new {@link ThreadFactory} from the specified parameters, never {@code null}.
* @see {@link #DEFAULT_EXCEPTION_HANDLER}
*/
public static ThreadFactory build(String name, ThreadPriority priority) {
return build(name, priority, DEFAULT_EXCEPTION_HANDLER);
}
/**
* Builds a {@link ThreadFactory} using the specified {@code String} name-format, normal thread priority and the
* default {@link UncaughtExceptionHandler}.
*
* @param name The name-format used when creating threads, may not be {@code null}.
* @return A new {@link ThreadFactory} from the specified parameters, never {@code null}.
* @see {@link #DEFAULT_EXCEPTION_HANDLER}
* @see {@link ThreadPriority#NORMAL_PRIORITY}
*/
public static ThreadFactory build(String name) {
return build(name, ThreadPriority.NORMAL_PRIORITY, DEFAULT_EXCEPTION_HANDLER);
}
/**
* An enumeration representing the priority of a {@link Thread}.
*
* @author Ryley Kimmel <ryley.kimmel@live.com>
*/
public enum ThreadPriority {
/**
* Represents the minimum priority of a thread.
*/
MINIMUM_PRIORITY(1),
/**
* Represents the normal priority of a thread.
*/
NORMAL_PRIORITY(5),
/**
* Represents the maximum priority of a thread.
*/
MAXIMUM_PRIORITY(10);
/**
* The value of this thread priority.
*/
private final int value;
/**
* Constructs a new {@link ThreadPriority} with the specified value.
*
* @param value The value of this thread priority, must be within the bounds of {@link Thread#MIN_PRIORITY} and
* {@link Thread#MAX_PRIORITY}.
*/
private ThreadPriority(int value) {
// fail-fast for invalid priority values
checkArgument(value >= Thread.MIN_PRIORITY, "Thread priority (%s) must be >= %s", value, Thread.MIN_PRIORITY);
checkArgument(value <= Thread.MAX_PRIORITY, "Thread priority (%s) must be <= %s", value, Thread.MAX_PRIORITY);
this.value = value;
}
/**
* Returns the value of this thread priority.
*/
public final int getValue() {
return value;
}
}
/**
* Prevents the default-public constructor to discourage instantiation of this class.
*/
private ThreadUtil() {
}
}
@@ -29,7 +29,7 @@ public final class PluginManager {
/**
* A set of all author names.
*/
private SortedSet<String> authors = new TreeSet<>();
private final SortedSet<String> authors = new TreeSet<>();
/**
* The plugin context.
@@ -164,8 +164,7 @@ public final class PluginManager {
* @throws DependencyException If a dependency error occurs.
* @throws IOException If an I/O error occurs.
*/
private void start(PluginEnvironment env, PluginMetaData plugin, Map<String, PluginMetaData> plugins,
Set<PluginMetaData> started) throws DependencyException, IOException {
private void start(PluginEnvironment env, PluginMetaData plugin, Map<String, PluginMetaData> plugins, Set<PluginMetaData> started) throws DependencyException, IOException {
// TODO check for cyclic dependencies! this way just won't cut it, we need an exception
if (started.contains(plugin)) {
return;
+1 -1
View File
@@ -74,7 +74,7 @@ public final class XmlParser {
/**
* The stack of nodes, used when traversing the document and going through child nodes.
*/
private Stack<XmlNode> nodeStack = new Stack<>();
private final Stack<XmlNode> nodeStack = new Stack<>();
/**
* The current root node.