New players will be queued rather than added right away.

This commit is contained in:
lare96
2015-08-29 14:25:41 -04:00
parent b134f6fdf5
commit dfa852491f
5 changed files with 96 additions and 45 deletions
+4 -14
View File
@@ -298,24 +298,14 @@ public final class World {
* Registers the specified player.
*
* @param player The player.
* @return A {@link RegistrationStatus}.
*/
public RegistrationStatus register(Player player) {
public void register(Player player) {
String username = player.getUsername();
if (isPlayerOnline(username)) {
return RegistrationStatus.ALREADY_ONLINE;
}
boolean success = playerRepository.add(player);
if (success) {
players.put(NameUtil.encodeBase37(username), player);
playerRepository.add(player);
players.put(NameUtil.encodeBase37(username), player);
logger.info("Registered player: " + player + " [count=" + playerRepository.size() + "]");
return RegistrationStatus.OK;
}
logger.warning("Failed to register player: " + player + " [count=" + playerRepository.size() + "]");
return RegistrationStatus.WORLD_FULL;
logger.info("Registered player: " + player + " [count=" + playerRepository.size() + "]");
}
/**
@@ -19,6 +19,7 @@ import org.apollo.game.message.impl.UpdateRunEnergyMessage;
import org.apollo.game.model.Appearance;
import org.apollo.game.model.Position;
import org.apollo.game.model.World;
import org.apollo.game.model.World.RegistrationStatus;
import org.apollo.game.model.entity.attr.Attribute;
import org.apollo.game.model.entity.attr.AttributeDefinition;
import org.apollo.game.model.entity.attr.AttributeMap;
@@ -602,6 +603,24 @@ public final class Player extends Mob {
return withdrawingNotes;
}
/**
* 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;
}
/**
* Logs the player out, if possible.
*/
@@ -15,7 +15,6 @@ import org.apollo.game.GamePulseHandler;
import org.apollo.game.io.MessageHandlerChainSetParser;
import org.apollo.game.message.handler.MessageHandlerChainSet;
import org.apollo.game.model.World;
import org.apollo.game.model.World.RegistrationStatus;
import org.apollo.game.model.area.Region;
import org.apollo.game.model.entity.MobRepository;
import org.apollo.game.model.entity.Player;
@@ -38,6 +37,11 @@ public final class GameService extends Service {
* requests and slow everything down.
*/
private static final int UNREGISTERS_PER_CYCLE = 50;
/**
* The number of times to register players per cycle.
*/
private static final int REGISTERS_PER_CYCLE = 25;
/**
* The World this Service is for.
@@ -48,6 +52,11 @@ public final class GameService extends Service {
* A queue of players to remove.
*/
private final Queue<Player> oldPlayers = new ConcurrentLinkedQueue<>();
/**
* A queue of players to add.
*/
private final Queue<Player> newPlayers = new ConcurrentLinkedQueue<>();
/**
* The scheduled executor service.
@@ -84,6 +93,21 @@ public final class GameService extends Service {
public synchronized void finalizePlayerUnregistration(Player player) {
world.unregister(player);
}
/**
* Finalizes the registration of a player.
*
* @param player The player.
*/
public void finalizePlayerRegistration(Player player) {
world.register(player);
Region region = world.getRegionRepository().fromPosition(player.getPosition());
region.addEntity(player);
if (player.getSession().isReconnecting()) {
player.sendInitialMessages();
}
}
/**
* Gets the MessageHandlerChainSet
@@ -97,7 +121,8 @@ public final class GameService extends Service {
/**
* Called every pulse.
*/
public synchronized void pulse() {
public void pulse() {
finalizeRegistrations();
finalizeUnregistrations();
MobRepository<Player> players = world.getPlayerRepository();
@@ -112,25 +137,6 @@ public final class GameService extends Service {
synchronizer.synchronize(players, world.getNpcRepository());
}
/**
* Registers a {@link Player} (may block!).
*
* @param player The Player.
* @param session The {@link GameSession} of the Player.
* @return A {@link RegistrationStatus}.
*/
public synchronized RegistrationStatus registerPlayer(Player player, GameSession session) {
RegistrationStatus status = world.register(player);
if (status == RegistrationStatus.OK) {
player.setSession(session);
Region region = world.getRegionRepository().fromPosition(player.getPosition());
region.addEntity(player);
}
return status;
}
/**
* Shuts down this game service.
*
@@ -155,6 +161,15 @@ public final class GameService extends Service {
public void unregisterPlayer(Player player) {
oldPlayers.add(player);
}
/**
* Registers a player. Returns immediately. The player is registered at the start of the next cycle.
*
* @param player The player.
*/
public void registerPlayer(Player player) {
newPlayers.add(player);
}
/**
* Finalizes the unregistration of Player's queued to be unregistered.
@@ -171,6 +186,20 @@ public final class GameService extends Service {
loginService.submitSaveRequest(player.getSession(), player);
}
}
/**
* Finalizes the registration of Player's queued to be registered.
*/
private void finalizeRegistrations() {
for (int count = 0; count < REGISTERS_PER_CYCLE; count++) {
Player player = oldPlayers.poll();
if (player == null) {
break;
}
finalizePlayerRegistration(player);
}
}
/**
* Initializes the game service.
@@ -42,6 +42,11 @@ public final class GameSession extends Session {
* The player.
*/
private final Player player;
/**
* If the player was reconnecting.
*/
private final boolean reconnecting;
/**
* Creates a login session for the specified channel.
@@ -49,11 +54,13 @@ public final class GameSession extends Session {
* @param channel The channel.
* @param context The server context.
* @param player The player.
* @param reconnecting If the player was reconnecting.
*/
public GameSession(Channel channel, ServerContext context, Player player) {
public GameSession(Channel channel, ServerContext context, Player player, boolean reconnecting) {
super(channel);
this.context = context;
this.player = player;
this.reconnecting = reconnecting;
}
@Override
@@ -111,4 +118,13 @@ public final class GameSession extends Session {
}
}
/**
* Determines if this player is reconnecting.
*
* @return {@code true} if reconnecting, {@code false} otherwise.
*/
public boolean isReconnecting() {
return reconnecting;
}
}
@@ -80,14 +80,17 @@ public final class LoginSession extends Session {
Player player = optional.get();
rights = player.getPrivilegeLevel().toInteger();
GameSession session = new GameSession(channel, context, player);
RegistrationStatus registration = service.registerPlayer(player, session);
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);
}
}
@@ -107,15 +110,10 @@ public final class LoginSession extends Session {
channel.pipeline().remove("loginDecoder");
channel.pipeline().remove("loginEncoder");
channel.attr(ApolloHandler.SESSION_KEY).set(optional.get().getSession());
service.registerPlayer(optional.get());
} else {
future.addListener(ChannelFutureListener.CLOSE);
}
if (optional.isPresent() && !request.isReconnecting()) {
optional.get().sendInitialMessages();
}
}
@Override
@@ -124,5 +122,4 @@ public final class LoginSession extends Session {
handleLoginRequest((LoginRequest) message);
}
}
}