diff --git a/game/src/main/org/apollo/game/model/entity/MobRepository.java b/game/src/main/org/apollo/game/model/entity/MobRepository.java index 749654b2..f38253f8 100644 --- a/game/src/main/org/apollo/game/model/entity/MobRepository.java +++ b/game/src/main/org/apollo/game/model/entity/MobRepository.java @@ -7,9 +7,9 @@ import com.google.common.base.Preconditions; /** * A {@link MobRepository} is a repository of {@link Mob}s that are currently active in the game world. * + * @param The type of Mob. * @author Graham * @author Ryley - * @param The type of Mob. */ public final class MobRepository implements Iterable { @@ -95,10 +95,10 @@ public final class MobRepository implements Iterable { * Adds a Mob to the repository. * * @param mob The Mob to add. - * @return {@code true} if the Mob was added, {@code false} if the size has reached the capacity of this repository. + * @return {@code true} if the Mob was added, {@code false} if this MobRepository is at maximum capacity. */ public boolean add(T mob) { - if (size == capacity()) { + if (full()) { return false; } @@ -126,6 +126,15 @@ public final class MobRepository implements Iterable { return mobs.length; } + /** + * Returns whether or not this MobRepository has reached its maxmimum capacity. + * + * @return {@code true} iff this MobRepository is full. + */ + public boolean full() { + return size == mobs.length; + } + /** * Gets the Mob at the given index. * diff --git a/game/src/main/org/apollo/game/model/entity/Player.java b/game/src/main/org/apollo/game/model/entity/Player.java index 105319e0..ddde02f0 100644 --- a/game/src/main/org/apollo/game/model/entity/Player.java +++ b/game/src/main/org/apollo/game/model/entity/Player.java @@ -447,25 +447,6 @@ public final class Player extends Mob { public PrivilegeLevel getPrivilegeLevel() { return privilegeLevel; } - - /** - * Determines the {@link RegistrationStatus} for this player. This method - * can remain lock-free since writes to the player {@link MobRepository} are - * only happening on the game thread. - * - * @return The status. - */ - public RegistrationStatus getRegistrationStatus() { - MobRepository repository = world.getPlayerRepository(); - - if (world.isPlayerOnline(getUsername())) { - return RegistrationStatus.ALREADY_ONLINE; - } else if (repository.capacity() == repository.size()) { - return RegistrationStatus.WORLD_FULL; - } - return RegistrationStatus.OK; - } - /** * Gets the player's run energy. * diff --git a/game/src/main/org/apollo/game/service/GameService.java b/game/src/main/org/apollo/game/service/GameService.java index afb2af38..1f697ead 100644 --- a/game/src/main/org/apollo/game/service/GameService.java +++ b/game/src/main/org/apollo/game/service/GameService.java @@ -19,7 +19,9 @@ import org.apollo.game.model.area.Region; import org.apollo.game.model.entity.MobRepository; import org.apollo.game.model.entity.Player; import org.apollo.game.session.GameSession; +import org.apollo.game.session.LoginSession; import org.apollo.game.sync.ClientSynchronizer; +import org.apollo.net.codec.login.LoginConstants; import org.apollo.util.ThreadUtil; import org.apollo.util.xml.XmlNode; import org.apollo.util.xml.XmlParser; @@ -32,6 +34,34 @@ import org.xml.sax.SAXException; */ public final class GameService extends Service { + /** + * A utility class wrapping a {@link Player} and their corresponding {@link LoginSession}. + */ + private static final class LoginPlayerRequest { + + /** + * The Player. + */ + private final Player player; + + /** + * The LoginSession. + */ + private final LoginSession session; + + /** + * Creates the LoginPlayerRequest. + * + * @param player The {@link Player} logging in. + * @param session The {@link LoginSession} of the Player. + */ + public LoginPlayerRequest(Player player, LoginSession session) { + this.player = player; + this.session = session; + } + + } + /** * The amount of players to deregister per cycle. This is to ensure the saving threads don't get swamped with * requests and slow everything down. @@ -54,12 +84,12 @@ public final class GameService extends Service { private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(ThreadUtil.create("GameService")); /** - * A queue of players to add. + * The Queue of LoginPlayers to add. */ - private final Queue newPlayers = new ConcurrentLinkedQueue<>(); + private final Queue newPlayers = new ConcurrentLinkedQueue<>(); /** - * A queue of players to remove. + * The Queue of Players to remove. */ private final Queue oldPlayers = new ConcurrentLinkedQueue<>(); @@ -138,13 +168,13 @@ public final class GameService extends Service { } /** - * Registers a player. Returns immediately. The player is registered at the - * start of the next cycle. + * Registers a {@link Player} at the end of the next cycle. * - * @param player The player. + * @param player The Player to register. + * @param session the {@link LoginSession} of the Player. */ - public void registerPlayer(Player player) { - newPlayers.add(player); + public void registerPlayer(Player player, LoginSession session) { + newPlayers.add(new LoginPlayerRequest(player, session)); } /** @@ -177,11 +207,20 @@ public final class GameService extends Service { */ private void finalizeRegistrations() { for (int count = 0; count < REGISTRATIONS_PER_CYCLE; count++) { - Player player = newPlayers.poll(); - if (player == null) { + LoginPlayerRequest request = newPlayers.poll(); + if (request == null) { break; } + Player player = request.player; + if (world.isPlayerOnline(player.getUsername())) { + request.session.sendLoginFailure(LoginConstants.STATUS_ACCOUNT_ONLINE); + } else if (world.getPlayerRepository().full()) { + request.session.sendLoginFailure(LoginConstants.STATUS_SERVER_FULL); + } else { + request.session.sendLoginSuccess(player); + } + finalizePlayerRegistration(player); } } diff --git a/game/src/main/org/apollo/game/session/LoginSession.java b/game/src/main/org/apollo/game/session/LoginSession.java index 4be9cd9d..a87e4896 100644 --- a/game/src/main/org/apollo/game/session/LoginSession.java +++ b/game/src/main/org/apollo/game/session/LoginSession.java @@ -31,10 +31,15 @@ import org.apollo.util.security.IsaacRandomPair; public final class LoginSession extends Session { /** - * The server context. + * The ServerContext. */ private final ServerContext context; + /** + * The LoginRequest for this LoginSession. + */ + private LoginRequest request; + /** * Creates a login session for the specified channel. * @@ -58,52 +63,14 @@ public final class LoginSession extends Session { * @param response The response. */ public void handlePlayerLoaderResponse(LoginRequest request, PlayerLoaderResponse response) { + this.request = request; GameService service = context.getGameService(); - Channel channel = getChannel(); - Optional optional = response.getPlayer(); - int status = response.getStatus(), rights = 0; - boolean flagged = false; if (optional.isPresent()) { - Player player = optional.get(); - rights = player.getPrivilegeLevel().toInteger(); - - RegistrationStatus registration = player.getRegistrationStatus(); - - if (registration != RegistrationStatus.OK) { - optional = Optional.empty(); - rights = 0; - - status = registration == RegistrationStatus.ALREADY_ONLINE ? LoginConstants.STATUS_ACCOUNT_ONLINE - : LoginConstants.STATUS_SERVER_FULL; - } else { - GameSession session = new GameSession(channel, context, player, request.isReconnecting()); - channel.attr(ApolloHandler.SESSION_KEY).set(session); - player.setSession(session); - } - } - - ChannelFuture future = channel.write(new LoginResponse(status, rights, flagged)); - - destroy(); - - if (optional.isPresent()) { - IsaacRandomPair randomPair = request.getRandomPair(); - 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(), context.getRelease())); - channel.pipeline().addAfter("gameDecoder", "messageDecoder", new GameMessageDecoder(release)); - - channel.pipeline().remove("loginDecoder"); - channel.pipeline().remove("loginEncoder"); - service.registerPlayer(optional.get()); + service.registerPlayer(optional.get(), this); } else { - future.addListener(ChannelFutureListener.CLOSE); + sendLoginFailure(response.getStatus()); } } @@ -114,6 +81,46 @@ public final class LoginSession extends Session { } } + /** + * Sends a failed {@link LoginResponse} to the client. + * + * @param status The failure status. + */ + public void sendLoginFailure(int status) { + boolean flagged = false; + LoginResponse response = new LoginResponse(status, 0, flagged); + channel.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); + } + + /** + * Sends a succesfull {@link LoginResponse} to the client. + * + * @param player The {@link Player} that successfully logged in. + */ + public void sendLoginSuccess(Player player) { + IsaacRandomPair randomPair = request.getRandomPair(); + boolean flagged = false; + + GameSession session = new GameSession(channel, context, player, request.isReconnecting()); + channel.attr(ApolloHandler.SESSION_KEY).set(session); + player.setSession(session); + + int rights = player.getPrivilegeLevel().toInteger(); + channel.writeAndFlush(new LoginResponse(LoginConstants.STATUS_OK, rights, flagged)); + + 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(), context.getRelease())); + channel.pipeline().addAfter("gameDecoder", "messageDecoder", new GameMessageDecoder(release)); + + channel.pipeline().remove("loginDecoder"); + channel.pipeline().remove("loginEncoder"); + } + /** * Handles a login request. * diff --git a/net/src/main/org/apollo/net/codec/login/LoginDecoder.java b/net/src/main/org/apollo/net/codec/login/LoginDecoder.java index c1607dfe..394d70d5 100644 --- a/net/src/main/org/apollo/net/codec/login/LoginDecoder.java +++ b/net/src/main/org/apollo/net/codec/login/LoginDecoder.java @@ -213,8 +213,6 @@ public final class LoginDecoder extends StatefulFrameDecoder private void writeResponseCode(ChannelHandlerContext ctx, int response) { ByteBuf buffer = ctx.alloc().buffer(Byte.BYTES); buffer.writeByte(response); - System.out.println("Sending response: " + response); - ctx.writeAndFlush(buffer).addListener(ChannelFutureListener.CLOSE); }