mirror of
https://github.com/2006-Scape/apollo.git
synced 2026-07-03 00:38:21 +00:00
Fix login queue.
This commit is contained in:
@@ -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 <T> The type of Mob.
|
||||
* @author Graham
|
||||
* @author Ryley
|
||||
* @param <T> The type of Mob.
|
||||
*/
|
||||
public final class MobRepository<T extends Mob> implements Iterable<T> {
|
||||
|
||||
@@ -95,10 +95,10 @@ public final class MobRepository<T extends Mob> implements Iterable<T> {
|
||||
* 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<T extends Mob> implements Iterable<T> {
|
||||
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.
|
||||
*
|
||||
|
||||
@@ -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<Player> 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.
|
||||
*
|
||||
|
||||
@@ -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<Player> newPlayers = new ConcurrentLinkedQueue<>();
|
||||
private final Queue<LoginPlayerRequest> newPlayers = new ConcurrentLinkedQueue<>();
|
||||
|
||||
/**
|
||||
* A queue of players to remove.
|
||||
* The Queue of Players to remove.
|
||||
*/
|
||||
private final Queue<Player> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Player> 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.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user