@Override
public void handlePacket(ChannelHandlerContext ctx, P041_CharacterPlayInfo packet, LoginServerSession serverData, List<QueueAction> actions) throws Exception {
serverData.setLoginCount(serverData.getLoginCount() + 1);
GameServer selectedGameServer = LoginServer.getBestGameServer();
if (selectedGameServer == null) {
// No available GameServer was found
P003_StreamTerminator streamTerminator = new P003_StreamTerminator();
streamTerminator.setErrorCode(5);
streamTerminator.setLoginCount(serverData.getLoginCount());
ctx.write(streamTerminator);
} else {
// An available Game Server was found. Let the Game Server know he can expect some new client
// Gather the info for the Game Server
int accountId = serverData.getAccId();
int characterId = serverData.getCharId();
int mapId = serverData.getMapId();
byte[] keys1 = new byte[4];
byte[] keys2 = new byte[4];
Random r = new Random();
r.nextBytes(keys1);
r.nextBytes(keys2);
short[] newKeys1 = new short[keys1.length], newKeys2 = new short[keys2.length];
for (int i = 0; i < keys1.length; i++) {
newKeys1[i] = (short) (keys1[i] & 0xFF);
newKeys2[i] = (short) (keys2[i] & 0xFF);
}
// Retrieve the connection with the GameServer
GameServerPortal gameServerPortal = selectedGameServer.getGameServerPortal();
// tell the Game Server to accept connections from this client
try {
gameServerPortal.acceptPlayerRequest(new LoginServerPlayerData(accountId, characterId, mapId, newKeys1, newKeys2));
} catch (RemoteException e) {
LOGGER.error("Failed to register this player with a game server");
throw new RuntimeException("Failed to register this player with a game server", e);
}
// This returned, the Game Server knows about the new client that should connect soon
// TODO: if the game server returns he's full, choose another one (while !accepted ....)
// TODO: Servers that are unavailable will be detected here in a catch(some exception) and REMOVED from the list + logs
// TODO: Game Servers that are full should warn the login server when they're good again
// Redirect the client to the chosen Game Server
ByteBuf buffer = Unpooled.buffer(24);
buffer = buffer.order(ByteOrder.LITTLE_ENDIAN);
// Why we need this is unknown
buffer.writeShort(2);
int selectedGameServerPort = selectedGameServer.getHostAndPort().getPort();
// The bytes of the port must be reversed
buffer = buffer.order(ByteOrder.BIG_ENDIAN);
buffer.writeShort(selectedGameServerPort);
buffer = buffer.order(ByteOrder.LITTLE_ENDIAN);
// the GS should pass its public IP when it registers itself to the LS
byte[] ipBytes = selectedGameServer.getHostAndPort().getAddress().getAddress();
LOGGER.info("The Game Server's IP: {}.{}.{}.{}", new Object[] { ipBytes[0] & 0xFF, ipBytes[1] & 0xFF, ipBytes[2] & 0xFF, ipBytes[3] & 0xFF });
short[] newIpBytes = new short[ipBytes.length];
for (int i = 0; i < ipBytes.length; i++) {
newIpBytes[i] = (short) (ipBytes[i] & 0xFF);