diff --git a/src/org/apollo/Server.java b/src/org/apollo/Server.java index 57cda878..9b898ae6 100644 --- a/src/org/apollo/Server.java +++ b/src/org/apollo/Server.java @@ -122,8 +122,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 +132,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 serviceInitializer = new ServiceChannelInitializer(handler); @@ -149,8 +151,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); } diff --git a/src/org/apollo/ServerContext.java b/src/org/apollo/ServerContext.java index ebfe295f..54248044 100644 --- a/src/org/apollo/ServerContext.java +++ b/src/org/apollo/ServerContext.java @@ -1,5 +1,6 @@ package org.apollo; +import org.apollo.fs.IndexedFileSystem; import org.apollo.net.release.Release; /** @@ -21,16 +22,22 @@ 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. */ - ServerContext(Release release, ServiceManager serviceManager) { + ServerContext(Release release, ServiceManager serviceManager, IndexedFileSystem fileSystem) { this.release = release; this.serviceManager = serviceManager; this.serviceManager.setContext(this); + this.fileSystem = fileSystem; } /** @@ -42,6 +49,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(...)}. * diff --git a/src/org/apollo/login/LoginService.java b/src/org/apollo/login/LoginService.java index 206f43e9..81721a05 100644 --- a/src/org/apollo/login/LoginService.java +++ b/src/org/apollo/login/LoginService.java @@ -3,6 +3,8 @@ package org.apollo.login; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.ByteBuffer; +import java.util.Arrays; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -16,12 +18,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 +34,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 +80,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 +90,48 @@ 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) { + 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 = 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)); + return true; } + + ByteBuffer buffer = getContext().getFileSystem().getCrcTable(); + + int[] clientCrcs = request.getArchiveCrcs(); + int[] serverCrcs = new int[clientCrcs.length]; + + Arrays.setAll(serverCrcs, crc -> buffer.getInt()); + + if (Arrays.equals(clientCrcs, serverCrcs)) { + return false; + } + + return true; } /** diff --git a/src/org/apollo/net/ApolloHandler.java b/src/org/apollo/net/ApolloHandler.java index 312f2076..f78d86a6 100644 --- a/src/org/apollo/net/ApolloHandler.java +++ b/src/org/apollo/net/ApolloHandler.java @@ -66,7 +66,7 @@ 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 attribute = ctx.attr(NetworkConstants.SESSION_KEY); Session session = attribute.get(); diff --git a/src/org/apollo/net/session/LoginSession.java b/src/org/apollo/net/session/LoginSession.java index 55ef7f9f..9a137fc0 100644 --- a/src/org/apollo/net/session/LoginSession.java +++ b/src/org/apollo/net/session/LoginSession.java @@ -5,6 +5,7 @@ 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; @@ -72,8 +73,9 @@ public final class LoginSession extends Session { * Handles a login request. * * @param request The login request. + * @throws IOException If some I/O exception occurs. */ - private void handleLoginRequest(LoginRequest request) { + private void handleLoginRequest(LoginRequest request) throws IOException { LoginService loginService = serverContext.getService(LoginService.class); loginService.submitLoadRequest(this, request); } @@ -135,7 +137,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); } diff --git a/src/org/apollo/net/session/Session.java b/src/org/apollo/net/session/Session.java index 118078a3..8ae49027 100644 --- a/src/org/apollo/net/session/Session.java +++ b/src/org/apollo/net/session/Session.java @@ -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; } \ No newline at end of file