Move some remaining bits and pieces to netty implementation, start cleaning up
This commit is contained in:
@@ -91,6 +91,8 @@ public class MapleClient extends ChannelInboundHandlerAdapter {
|
|||||||
public static final String CLIENT_NIBBLEHWID = "HWID2";
|
public static final String CLIENT_NIBBLEHWID = "HWID2";
|
||||||
public static final String CLIENT_REMOTE_ADDRESS = "REMOTE_IP";
|
public static final String CLIENT_REMOTE_ADDRESS = "REMOTE_IP";
|
||||||
|
|
||||||
|
private final Type type;
|
||||||
|
|
||||||
private Hwid hwid;
|
private Hwid hwid;
|
||||||
private String remoteHwid; // Mac address + hwid in one. Retrieved from client when attempting to enter game.
|
private String remoteHwid; // Mac address + hwid in one. Retrieved from client when attempting to enter game.
|
||||||
private String remoteAddress;
|
private String remoteAddress;
|
||||||
@@ -136,6 +138,11 @@ public class MapleClient extends ChannelInboundHandlerAdapter {
|
|||||||
private long lastPacket = System.currentTimeMillis();
|
private long lastPacket = System.currentTimeMillis();
|
||||||
private int lang = 0;
|
private int lang = 0;
|
||||||
|
|
||||||
|
public enum Type {
|
||||||
|
LOGIN,
|
||||||
|
CHANNEL
|
||||||
|
}
|
||||||
|
|
||||||
public void updateLastPacket() {
|
public void updateLastPacket() {
|
||||||
lastPacket = System.currentTimeMillis();
|
lastPacket = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
@@ -144,17 +151,23 @@ public class MapleClient extends ChannelInboundHandlerAdapter {
|
|||||||
return lastPacket;
|
return lastPacket;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MapleClient(PacketProcessor packetProcessor, int world, int channel) {
|
public MapleClient(Type type, PacketProcessor packetProcessor, int world, int channel) {
|
||||||
|
this.type = type;
|
||||||
this.packetProcessor = packetProcessor;
|
this.packetProcessor = packetProcessor;
|
||||||
this.world = world;
|
this.world = world;
|
||||||
this.channel = channel;
|
this.channel = channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MapleClient(MapleAESOFB send, MapleAESOFB receive, IoSession session) {
|
public MapleClient(MapleAESOFB send, MapleAESOFB receive, IoSession session) {
|
||||||
|
this.type = null;
|
||||||
this.send = send;
|
this.send = send;
|
||||||
this.receive = receive;
|
this.receive = receive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static MapleClient createMock() {
|
||||||
|
return new MapleClient(null, null, -123, -123);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void channelActive(ChannelHandlerContext ctx) {
|
public void channelActive(ChannelHandlerContext ctx) {
|
||||||
final io.netty.channel.Channel channel = ctx.channel();
|
final io.netty.channel.Channel channel = ctx.channel();
|
||||||
@@ -209,7 +222,6 @@ public class MapleClient extends ChannelInboundHandlerAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateLastPacket();
|
updateLastPacket();
|
||||||
super.channelRead(ctx, msg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -226,18 +238,23 @@ public class MapleClient extends ChannelInboundHandlerAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cause instanceof InvalidPacketHeaderException) {
|
if (cause instanceof InvalidPacketHeaderException) {
|
||||||
// TODO close session through MapleSessionCoordinator
|
MapleSessionCoordinator.getInstance().closeSession(this, true);
|
||||||
} else if (cause instanceof IOException) {
|
} else if (cause instanceof IOException) {
|
||||||
closeSession();
|
closeMapleSession();
|
||||||
} else {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
super.exceptionCaught(ctx, cause);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void channelInactive(ChannelHandlerContext ctx) {
|
public void channelInactive(ChannelHandlerContext ctx) {
|
||||||
|
closeMapleSession();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void closeMapleSession() {
|
||||||
|
switch (type) {
|
||||||
|
case LOGIN -> MapleSessionCoordinator.getInstance().closeLoginSession(this);
|
||||||
|
case CHANNEL -> MapleSessionCoordinator.getInstance().closeSession(this, null);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// client freeze issues on session transition states found thanks to yolinlin, Omo Oppa, Nozphex
|
// client freeze issues on session transition states found thanks to yolinlin, Omo Oppa, Nozphex
|
||||||
if (!inTransition) {
|
if (!inTransition) {
|
||||||
@@ -245,6 +262,8 @@ public class MapleClient extends ChannelInboundHandlerAdapter {
|
|||||||
}
|
}
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
log.warn("Account stuck", t);
|
log.warn("Account stuck", t);
|
||||||
|
} finally {
|
||||||
|
closeSession();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,306 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of the OdinMS Maple Story Server
|
|
||||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
|
||||||
Matthias Butz <matze@odinms.de>
|
|
||||||
Jan Christian Meyer <vimes@odinms.de>
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Affero General Public License as
|
|
||||||
published by the Free Software Foundation version 3 as published by
|
|
||||||
the Free Software Foundation. You may not use, modify or distribute
|
|
||||||
this program under any other version of the GNU Affero General Public
|
|
||||||
License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU Affero General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package net;
|
|
||||||
|
|
||||||
import client.MapleClient;
|
|
||||||
import config.YamlConfig;
|
|
||||||
import constants.net.ServerConstants;
|
|
||||||
import net.netty.InitializationVector;
|
|
||||||
import net.server.Server;
|
|
||||||
import net.server.audit.LockCollector;
|
|
||||||
import net.server.audit.locks.MonitoredLockType;
|
|
||||||
import net.server.audit.locks.MonitoredReentrantLock;
|
|
||||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
|
||||||
import net.server.coordinator.session.IpAddresses;
|
|
||||||
import net.server.coordinator.session.MapleSessionCoordinator;
|
|
||||||
import org.apache.mina.core.service.IoHandlerAdapter;
|
|
||||||
import org.apache.mina.core.session.IdleStatus;
|
|
||||||
import org.apache.mina.core.session.IoSession;
|
|
||||||
import server.TimerManager;
|
|
||||||
import tools.FilePrinter;
|
|
||||||
import tools.MapleAESOFB;
|
|
||||||
import tools.MapleLogger;
|
|
||||||
import tools.MaplePacketCreator;
|
|
||||||
import tools.data.input.ByteArrayByteStream;
|
|
||||||
import tools.data.input.GenericSeekableLittleEndianAccessor;
|
|
||||||
import tools.data.input.SeekableLittleEndianAccessor;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.concurrent.ScheduledFuture;
|
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
|
||||||
|
|
||||||
public class MapleServerHandler extends IoHandlerAdapter {
|
|
||||||
private final static Set<Short> ignoredDebugRecvPackets = new HashSet<>(Arrays.asList((short) 167, (short) 197, (short) 89, (short) 91, (short) 41, (short) 188, (short) 107));
|
|
||||||
|
|
||||||
private PacketProcessor processor;
|
|
||||||
private int world = -1, channel = -1;
|
|
||||||
private static final SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy HH:mm");
|
|
||||||
private static AtomicLong sessionId = new AtomicLong(7777);
|
|
||||||
|
|
||||||
private MonitoredReentrantLock idleLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.SRVHANDLER_IDLE, true);
|
|
||||||
private MonitoredReentrantLock tempLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.SRVHANDLER_TEMP, true);
|
|
||||||
private Map<MapleClient, Long> idleSessions = new HashMap<>(100);
|
|
||||||
private Map<MapleClient, Long> tempIdleSessions = new HashMap<>();
|
|
||||||
private ScheduledFuture<?> idleManager = null;
|
|
||||||
|
|
||||||
public MapleServerHandler() {
|
|
||||||
this.processor = PacketProcessor.getProcessor(-1, -1);
|
|
||||||
|
|
||||||
idleManagerTask();
|
|
||||||
}
|
|
||||||
|
|
||||||
public MapleServerHandler(int world, int channel) {
|
|
||||||
this.processor = PacketProcessor.getProcessor(world, channel);
|
|
||||||
this.world = world;
|
|
||||||
this.channel = channel;
|
|
||||||
|
|
||||||
idleManagerTask();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void exceptionCaught(IoSession session, Throwable cause) {
|
|
||||||
if (cause instanceof IOException) {
|
|
||||||
closeMapleSession(session);
|
|
||||||
} else {
|
|
||||||
MapleClient client = (MapleClient) session.getAttribute(MapleClient.CLIENT_KEY);
|
|
||||||
|
|
||||||
if (client != null && client.getPlayer() != null) {
|
|
||||||
FilePrinter.printError(FilePrinter.EXCEPTION_CAUGHT, cause, "Exception caught by: " + client.getPlayer());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isLoginServerHandler() {
|
|
||||||
return channel == -1 && world == -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sessionOpened(IoSession session) {
|
|
||||||
String remoteHost;
|
|
||||||
try {
|
|
||||||
remoteHost = ((InetSocketAddress) session.getRemoteAddress()).getAddress().getHostAddress();
|
|
||||||
|
|
||||||
if (remoteHost == null) {
|
|
||||||
remoteHost = "null";
|
|
||||||
} else {
|
|
||||||
remoteHost = IpAddresses.evaluateRemoteAddress(remoteHost); // thanks dyz for noticing Local/LAN/WAN connections not interacting properly
|
|
||||||
}
|
|
||||||
} catch (NullPointerException npe) { // thanks Agassy, Alchemist for pointing out possibility of remoteHost = null.
|
|
||||||
remoteHost = "null";
|
|
||||||
}
|
|
||||||
|
|
||||||
session.setAttribute(MapleClient.CLIENT_REMOTE_ADDRESS, remoteHost);
|
|
||||||
|
|
||||||
if (!Server.getInstance().isOnline()) {
|
|
||||||
MapleSessionCoordinator.getInstance().closeSession(MapleClient.getPlaceholder(), true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final InitializationVector ivSend = InitializationVector.generateSend();
|
|
||||||
final InitializationVector ivRecv = InitializationVector.generateReceive();
|
|
||||||
MapleAESOFB sendCypher = new MapleAESOFB(ivSend, (short) (0xFFFF - ServerConstants.VERSION));
|
|
||||||
MapleAESOFB recvCypher = new MapleAESOFB(ivRecv, ServerConstants.VERSION);
|
|
||||||
MapleClient client = new MapleClient(sendCypher, recvCypher, session);
|
|
||||||
|
|
||||||
if (!isLoginServerHandler()) {
|
|
||||||
if (Server.getInstance().getChannel(world, channel) == null) {
|
|
||||||
MapleSessionCoordinator.getInstance().closeSession(MapleClient.getPlaceholder(), true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!MapleSessionCoordinator.getInstance().canStartLoginSession(client)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
FilePrinter.print(FilePrinter.SESSION, "IoSession with " + session.getRemoteAddress() + " opened on " + sdf.format(Calendar.getInstance().getTime()), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
client.setWorld(world);
|
|
||||||
client.setChannel(channel);
|
|
||||||
client.setSessionId(sessionId.getAndIncrement()); // Generates a reasonable session id.
|
|
||||||
session.write(MaplePacketCreator.getHello(ServerConstants.VERSION, ivSend, ivRecv));
|
|
||||||
session.setAttribute(MapleClient.CLIENT_KEY, client);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void closeMapleSession(IoSession session) {
|
|
||||||
if (isLoginServerHandler()) {
|
|
||||||
MapleSessionCoordinator.getInstance().closeLoginSession(MapleClient.getPlaceholder());
|
|
||||||
} else {
|
|
||||||
MapleSessionCoordinator.getInstance().closeSession(MapleClient.getPlaceholder(), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
MapleClient client = (MapleClient) session.getAttribute(MapleClient.CLIENT_KEY);
|
|
||||||
if (client != null) {
|
|
||||||
try {
|
|
||||||
// client freeze issues on session transition states found thanks to yolinlin, Omo Oppa, Nozphex
|
|
||||||
if (!client.isInTransition()) {
|
|
||||||
client.disconnect(false, false);
|
|
||||||
}
|
|
||||||
} catch (Throwable t) {
|
|
||||||
FilePrinter.printError(FilePrinter.ACCOUNT_STUCK, t);
|
|
||||||
} finally {
|
|
||||||
session.close();
|
|
||||||
session.removeAttribute(MapleClient.CLIENT_KEY);
|
|
||||||
//client.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sessionClosed(IoSession session) throws Exception {
|
|
||||||
closeMapleSession(session);
|
|
||||||
super.sessionClosed(session);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void messageReceived(IoSession session, Object message) {
|
|
||||||
byte[] content = (byte[]) message;
|
|
||||||
SeekableLittleEndianAccessor slea = new GenericSeekableLittleEndianAccessor(new ByteArrayByteStream(content));
|
|
||||||
short packetId = slea.readShort();
|
|
||||||
MapleClient client = (MapleClient) session.getAttribute(MapleClient.CLIENT_KEY);
|
|
||||||
|
|
||||||
if(YamlConfig.config.server.USE_DEBUG_SHOW_RCVD_PACKET && !ignoredDebugRecvPackets.contains(packetId)) System.out.println("Received packet id " + packetId);
|
|
||||||
final MaplePacketHandler packetHandler = processor.getHandler(packetId);
|
|
||||||
if (packetHandler != null && packetHandler.validateState(client)) {
|
|
||||||
try {
|
|
||||||
MapleLogger.logRecv(client, packetId, message);
|
|
||||||
packetHandler.handlePacket(slea, client);
|
|
||||||
} catch (final Throwable t) {
|
|
||||||
FilePrinter.printError(FilePrinter.PACKET_HANDLER + packetHandler.getClass().getName() + ".txt", t, "Error for " + (client.getPlayer() == null ? "" : "player ; " + client.getPlayer() + " on map ; " + client.getPlayer().getMapId() + " - ") + "account ; " + client.getAccountName() + "\r\n" + slea.toString());
|
|
||||||
//client.announce(MaplePacketCreator.enableActions());//bugs sometimes
|
|
||||||
}
|
|
||||||
client.updateLastPacket();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void messageSent(IoSession session, Object message) {
|
|
||||||
byte[] content = (byte[]) message;
|
|
||||||
SeekableLittleEndianAccessor slea = new GenericSeekableLittleEndianAccessor(new ByteArrayByteStream(content));
|
|
||||||
slea.readShort(); //packetId
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void sessionIdle(final IoSession session, final IdleStatus status) throws Exception {
|
|
||||||
MapleClient client = (MapleClient) session.getAttribute(MapleClient.CLIENT_KEY);
|
|
||||||
if (client != null) {
|
|
||||||
registerIdleSession(client);
|
|
||||||
}
|
|
||||||
super.sessionIdle(session, status);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void registerIdleSession(MapleClient c) {
|
|
||||||
if(idleLock.tryLock()) {
|
|
||||||
try {
|
|
||||||
idleSessions.put(c, Server.getInstance().getCurrentTime());
|
|
||||||
c.announce(MaplePacketCreator.getPing());
|
|
||||||
} finally {
|
|
||||||
idleLock.unlock();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tempLock.lock();
|
|
||||||
try {
|
|
||||||
tempIdleSessions.put(c, Server.getInstance().getCurrentTime());
|
|
||||||
c.announce(MaplePacketCreator.getPing());
|
|
||||||
} finally {
|
|
||||||
tempLock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void manageIdleSessions() {
|
|
||||||
long timeNow = Server.getInstance().getCurrentTime();
|
|
||||||
long timeThen = timeNow - 15000;
|
|
||||||
|
|
||||||
Set<MapleClient> pingClients = new HashSet<>();
|
|
||||||
idleLock.lock();
|
|
||||||
try {
|
|
||||||
for(Entry<MapleClient, Long> mc : idleSessions.entrySet()) {
|
|
||||||
if(timeNow - mc.getValue() >= 15000) {
|
|
||||||
pingClients.add(mc.getKey());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
idleSessions.clear();
|
|
||||||
|
|
||||||
if(!tempIdleSessions.isEmpty()) {
|
|
||||||
tempLock.lock();
|
|
||||||
try {
|
|
||||||
for(Entry<MapleClient, Long> mc : tempIdleSessions.entrySet()) {
|
|
||||||
idleSessions.put(mc.getKey(), mc.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
tempIdleSessions.clear();
|
|
||||||
} finally {
|
|
||||||
tempLock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
idleLock.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
for(MapleClient c : pingClients) {
|
|
||||||
c.testPing(timeThen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void idleManagerTask() {
|
|
||||||
this.idleManager = TimerManager.getInstance().register(() -> manageIdleSessions(), 10000);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void cancelIdleManagerTask() {
|
|
||||||
this.idleManager.cancel(false);
|
|
||||||
this.idleManager = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void disposeLocks() {
|
|
||||||
LockCollector.getInstance().registerDisposeAction(() -> emptyLocks());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void emptyLocks() {
|
|
||||||
idleLock.dispose();
|
|
||||||
tempLock.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void dispose() {
|
|
||||||
cancelIdleManagerTask();
|
|
||||||
|
|
||||||
idleLock.lock();
|
|
||||||
try {
|
|
||||||
idleSessions.clear();
|
|
||||||
} finally {
|
|
||||||
idleLock.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
tempLock.lock();
|
|
||||||
try {
|
|
||||||
tempIdleSessions.clear();
|
|
||||||
} finally {
|
|
||||||
tempLock.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
disposeLocks();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,6 +3,8 @@ package net.netty;
|
|||||||
import client.MapleClient;
|
import client.MapleClient;
|
||||||
import io.netty.channel.socket.SocketChannel;
|
import io.netty.channel.socket.SocketChannel;
|
||||||
import net.PacketProcessor;
|
import net.PacketProcessor;
|
||||||
|
import net.server.Server;
|
||||||
|
import net.server.coordinator.session.MapleSessionCoordinator;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -20,12 +22,18 @@ public class ChannelServerInitializer extends ServerChannelInitializer {
|
|||||||
@Override
|
@Override
|
||||||
public void initChannel(SocketChannel socketChannel) {
|
public void initChannel(SocketChannel socketChannel) {
|
||||||
final String clientIp = socketChannel.remoteAddress().getHostName();
|
final String clientIp = socketChannel.remoteAddress().getHostName();
|
||||||
log.debug("Client connected to world {}, channel {} from {}", world, channel, clientIp);
|
log.debug("Client connecting to world {}, channel {} from {}", world, channel, clientIp);
|
||||||
|
|
||||||
PacketProcessor packetProcessor = PacketProcessor.getChannelServerProcessor(world, channel);
|
PacketProcessor packetProcessor = PacketProcessor.getChannelServerProcessor(world, channel);
|
||||||
final MapleClient client = new MapleClient(packetProcessor, world, channel);
|
final MapleClient client = new MapleClient(MapleClient.Type.CHANNEL, packetProcessor, world, channel);
|
||||||
client.setSessionId(sessionId.getAndIncrement());
|
client.setSessionId(sessionId.getAndIncrement());
|
||||||
|
|
||||||
|
if (Server.getInstance().getChannel(world, channel) == null) {
|
||||||
|
MapleSessionCoordinator.getInstance().closeSession(client, true);
|
||||||
|
socketChannel.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
initPipeline(socketChannel, client);
|
initPipeline(socketChannel, client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package net.netty;
|
|||||||
import client.MapleClient;
|
import client.MapleClient;
|
||||||
import io.netty.channel.socket.SocketChannel;
|
import io.netty.channel.socket.SocketChannel;
|
||||||
import net.PacketProcessor;
|
import net.PacketProcessor;
|
||||||
|
import net.server.coordinator.session.MapleSessionCoordinator;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -15,9 +16,14 @@ public class LoginServerInitializer extends ServerChannelInitializer {
|
|||||||
log.debug("Client connected to login server from {} ", clientIp);
|
log.debug("Client connected to login server from {} ", clientIp);
|
||||||
|
|
||||||
PacketProcessor packetProcessor = PacketProcessor.getLoginServerProcessor();
|
PacketProcessor packetProcessor = PacketProcessor.getLoginServerProcessor();
|
||||||
final MapleClient client = new MapleClient(packetProcessor, LoginServer.WORLD_ID, LoginServer.CHANNEL_ID);
|
final MapleClient client = new MapleClient(MapleClient.Type.LOGIN, packetProcessor, LoginServer.WORLD_ID, LoginServer.CHANNEL_ID);
|
||||||
client.setSessionId(sessionId.getAndIncrement());
|
client.setSessionId(sessionId.getAndIncrement());
|
||||||
|
|
||||||
|
if (!MapleSessionCoordinator.getInstance().canStartLoginSession(client)) {
|
||||||
|
socketChannel.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
initPipeline(socketChannel, client);
|
initPipeline(socketChannel, client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,8 +35,6 @@ import constants.game.GameConstants;
|
|||||||
import constants.inventory.ItemConstants;
|
import constants.inventory.ItemConstants;
|
||||||
import constants.net.OpcodeConstants;
|
import constants.net.OpcodeConstants;
|
||||||
import constants.net.ServerConstants;
|
import constants.net.ServerConstants;
|
||||||
import net.MapleServerHandler;
|
|
||||||
import net.mina.MapleCodecFactory;
|
|
||||||
import net.netty.LoginServer;
|
import net.netty.LoginServer;
|
||||||
import net.server.audit.ThreadTracker;
|
import net.server.audit.ThreadTracker;
|
||||||
import net.server.audit.locks.MonitoredLockType;
|
import net.server.audit.locks.MonitoredLockType;
|
||||||
@@ -54,12 +52,6 @@ import net.server.guild.MapleGuild;
|
|||||||
import net.server.guild.MapleGuildCharacter;
|
import net.server.guild.MapleGuildCharacter;
|
||||||
import net.server.task.*;
|
import net.server.task.*;
|
||||||
import net.server.world.World;
|
import net.server.world.World;
|
||||||
import org.apache.mina.core.buffer.IoBuffer;
|
|
||||||
import org.apache.mina.core.buffer.SimpleBufferAllocator;
|
|
||||||
import org.apache.mina.core.service.IoAcceptor;
|
|
||||||
import org.apache.mina.core.session.IdleStatus;
|
|
||||||
import org.apache.mina.filter.codec.ProtocolCodecFilter;
|
|
||||||
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import server.CashShop.CashItemFactory;
|
import server.CashShop.CashItemFactory;
|
||||||
@@ -74,8 +66,6 @@ import tools.DatabaseConnection;
|
|||||||
import tools.FilePrinter;
|
import tools.FilePrinter;
|
||||||
import tools.Pair;
|
import tools.Pair;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
@@ -106,7 +96,6 @@ public class Server {
|
|||||||
private static final Map<Integer, Integer> couponRates = new HashMap<>(30);
|
private static final Map<Integer, Integer> couponRates = new HashMap<>(30);
|
||||||
private static final List<Integer> activeCoupons = new LinkedList<>();
|
private static final List<Integer> activeCoupons = new LinkedList<>();
|
||||||
|
|
||||||
private IoAcceptor acceptor;
|
|
||||||
private LoginServer loginServer;
|
private LoginServer loginServer;
|
||||||
private List<Map<Integer, String>> channels = new LinkedList<>();
|
private List<Map<Integer, String>> channels = new LinkedList<>();
|
||||||
private List<World> worlds = new ArrayList<>();
|
private List<World> worlds = new ArrayList<>();
|
||||||
@@ -931,22 +920,6 @@ public class Server {
|
|||||||
return loginServer;
|
return loginServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IoAcceptor initAcceptor(int port) {
|
|
||||||
IoBuffer.setUseDirectBuffer(false); // join IO operations performed by lxconan
|
|
||||||
IoBuffer.setAllocator(new SimpleBufferAllocator());
|
|
||||||
acceptor = new NioSocketAcceptor();
|
|
||||||
acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new MapleCodecFactory()));
|
|
||||||
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 30);
|
|
||||||
acceptor.setHandler(new MapleServerHandler());
|
|
||||||
try {
|
|
||||||
acceptor.bind(new InetSocketAddress(port));
|
|
||||||
} catch (IOException ex) {
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return acceptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void setAllLoggedOut(Connection con) throws SQLException {
|
private static void setAllLoggedOut(Connection con) throws SQLException {
|
||||||
try (PreparedStatement ps = con.prepareStatement("UPDATE accounts SET loggedin = 0")) {
|
try (PreparedStatement ps = con.prepareStatement("UPDATE accounts SET loggedin = 0")) {
|
||||||
ps.executeUpdate();
|
ps.executeUpdate();
|
||||||
@@ -1958,8 +1931,7 @@ public class Server {
|
|||||||
TimerManager.getInstance().stop();
|
TimerManager.getInstance().stop();
|
||||||
|
|
||||||
System.out.println("Worlds + Channels are offline.");
|
System.out.println("Worlds + Channels are offline.");
|
||||||
acceptor.unbind();
|
loginServer.stop();
|
||||||
acceptor = null;
|
|
||||||
if (!restart) { // shutdown hook deadlocks if System.exit() method is used within its body chores, thanks MIKE for pointing that out
|
if (!restart) { // shutdown hook deadlocks if System.exit() method is used within its body chores, thanks MIKE for pointing that out
|
||||||
new Thread(() -> System.exit(0)).start();
|
new Thread(() -> System.exit(0)).start();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -24,8 +24,6 @@ package net.server.channel;
|
|||||||
import client.MapleCharacter;
|
import client.MapleCharacter;
|
||||||
import config.YamlConfig;
|
import config.YamlConfig;
|
||||||
import constants.game.GameConstants;
|
import constants.game.GameConstants;
|
||||||
import net.MapleServerHandler;
|
|
||||||
import net.mina.MapleCodecFactory;
|
|
||||||
import net.netty.ChannelServer;
|
import net.netty.ChannelServer;
|
||||||
import net.server.PlayerStorage;
|
import net.server.PlayerStorage;
|
||||||
import net.server.Server;
|
import net.server.Server;
|
||||||
@@ -40,13 +38,6 @@ import net.server.services.type.ChannelServices;
|
|||||||
import net.server.world.MapleParty;
|
import net.server.world.MapleParty;
|
||||||
import net.server.world.MaplePartyCharacter;
|
import net.server.world.MaplePartyCharacter;
|
||||||
import net.server.world.World;
|
import net.server.world.World;
|
||||||
import org.apache.mina.core.buffer.IoBuffer;
|
|
||||||
import org.apache.mina.core.buffer.SimpleBufferAllocator;
|
|
||||||
import org.apache.mina.core.service.IoAcceptor;
|
|
||||||
import org.apache.mina.core.session.IdleStatus;
|
|
||||||
import org.apache.mina.filter.codec.ProtocolCodecFilter;
|
|
||||||
import org.apache.mina.transport.socket.SocketSessionConfig;
|
|
||||||
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import scripting.event.EventScriptManager;
|
import scripting.event.EventScriptManager;
|
||||||
@@ -59,21 +50,22 @@ import tools.MaplePacketCreator;
|
|||||||
import tools.Pair;
|
import tools.Pair;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
|
||||||
public final class Channel {
|
public final class Channel {
|
||||||
private static final Logger log = LoggerFactory.getLogger(Channel.class);
|
private static final Logger log = LoggerFactory.getLogger(Channel.class);
|
||||||
|
private static final int BASE_PORT = 7575;
|
||||||
|
|
||||||
|
private final int port;
|
||||||
|
private final String ip;
|
||||||
|
private final int world;
|
||||||
|
private final int channel;
|
||||||
|
|
||||||
private int port = 7575;
|
|
||||||
private PlayerStorage players = new PlayerStorage();
|
private PlayerStorage players = new PlayerStorage();
|
||||||
private int world, channel;
|
|
||||||
private ChannelServer channelServer;
|
private ChannelServer channelServer;
|
||||||
private IoAcceptor acceptor;
|
private String serverMessage;
|
||||||
private String ip, serverMessage;
|
|
||||||
private MapleMapManager mapManager;
|
private MapleMapManager mapManager;
|
||||||
private EventScriptManager eventSM;
|
private EventScriptManager eventSM;
|
||||||
private ServicesManager services;
|
private ServicesManager services;
|
||||||
@@ -121,12 +113,11 @@ public final class Channel {
|
|||||||
|
|
||||||
this.ongoingStartTime = startTime + 10000; // rude approach to a world's last channel boot time, placeholder for the 1st wedding reservation ever
|
this.ongoingStartTime = startTime + 10000; // rude approach to a world's last channel boot time, placeholder for the 1st wedding reservation ever
|
||||||
this.mapManager = new MapleMapManager(null, world, channel);
|
this.mapManager = new MapleMapManager(null, world, channel);
|
||||||
|
this.port = BASE_PORT + (this.channel - 1) + (world * 100);
|
||||||
|
this.ip = YamlConfig.config.server.HOST + ":" + port;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
port = 7575 + this.channel - 1;
|
this.channelServer = initServer(port, world, channel);
|
||||||
port += (world * 100);
|
|
||||||
ip = YamlConfig.config.server.HOST + ":" + port;
|
|
||||||
// acceptor = initAcceptor();
|
|
||||||
channelServer = initServer(port, world, channel);
|
|
||||||
expedType.addAll(Arrays.asList(MapleExpeditionType.values()));
|
expedType.addAll(Arrays.asList(MapleExpeditionType.values()));
|
||||||
|
|
||||||
if (Server.getInstance().isOnline()) { // postpone event loading to improve boot time... thanks Riizade, daronhudson for noticing slow startup times
|
if (Server.getInstance().isOnline()) { // postpone event loading to improve boot time... thanks Riizade, daronhudson for noticing slow startup times
|
||||||
@@ -150,24 +141,12 @@ public final class Channel {
|
|||||||
|
|
||||||
log.info("Channel {}: Listening on port {}", getId(), port);
|
log.info("Channel {}: Listening on port {}", getId(), port);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
log.warn("Error during channel initialization", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IoAcceptor initAcceptor() throws IOException {
|
|
||||||
IoBuffer.setUseDirectBuffer(false);
|
|
||||||
IoBuffer.setAllocator(new SimpleBufferAllocator());
|
|
||||||
IoAcceptor acceptor = new NioSocketAcceptor();
|
|
||||||
acceptor.setHandler(new MapleServerHandler(world, channel));
|
|
||||||
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 30);
|
|
||||||
acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new MapleCodecFactory()));
|
|
||||||
acceptor.bind(new InetSocketAddress(port));
|
|
||||||
((SocketSessionConfig) acceptor.getSessionConfig()).setTcpNoDelay(true);
|
|
||||||
return acceptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ChannelServer initServer(int port, int world, int channel) {
|
private ChannelServer initServer(int port, int world, int channel) {
|
||||||
this.channelServer = new ChannelServer(port, world, channel);
|
ChannelServer channelServer = new ChannelServer(port, world, channel);
|
||||||
channelServer.start();
|
channelServer.start();
|
||||||
return channelServer;
|
return channelServer;
|
||||||
}
|
}
|
||||||
@@ -202,10 +181,8 @@ public final class Channel {
|
|||||||
|
|
||||||
closeChannelSchedules();
|
closeChannelSchedules();
|
||||||
players = null;
|
players = null;
|
||||||
|
|
||||||
MapleServerHandler handler = (MapleServerHandler) acceptor.getHandler();
|
channelServer.stop();
|
||||||
handler.dispose();
|
|
||||||
acceptor.unbind();
|
|
||||||
|
|
||||||
finishedShutdown = true;
|
finishedShutdown = true;
|
||||||
System.out.println("Successfully shut down Channel " + channel + " on World " + world + "\r\n");
|
System.out.println("Successfully shut down Channel " + channel + " on World " + world + "\r\n");
|
||||||
|
|||||||
@@ -295,7 +295,7 @@ public class MapleSessionCoordinator {
|
|||||||
client.setHwid(Hwid.fromClientString(remoteHwid));
|
client.setHwid(Hwid.fromClientString(remoteHwid));
|
||||||
}
|
}
|
||||||
|
|
||||||
MapleClient fakeClient = new MapleClient(null, null, null);
|
MapleClient fakeClient = MapleClient.createMock();
|
||||||
Integer chrId = Server.getInstance().freeCharacteridInTransition(client);
|
Integer chrId = Server.getInstance().freeCharacteridInTransition(client);
|
||||||
if (chrId != null) {
|
if (chrId != null) {
|
||||||
try {
|
try {
|
||||||
@@ -313,15 +313,14 @@ public class MapleSessionCoordinator {
|
|||||||
client = fetchInTransitionSessionClient(client);
|
client = fetchInTransitionSessionClient(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
Hwid hwid = client.getHwid();
|
final Hwid hwid = client.getHwid();
|
||||||
client.setHwid(null); // making sure to clean up calls to this function on login phase
|
client.setHwid(null); // making sure to clean up calls to this function on login phase
|
||||||
if (hwid != null) {
|
if (hwid != null) {
|
||||||
onlineRemoteHwids.remove(hwid.hwid());
|
onlineRemoteHwids.remove(hwid.hwid());
|
||||||
}
|
}
|
||||||
|
|
||||||
String remoteHwid = client.getRemoteHwid();
|
final String remoteHwid = client.getRemoteHwid();
|
||||||
client.setRemoteHwid(null);
|
client.setRemoteHwid(null);
|
||||||
// TODO: client.setHwid(null);
|
|
||||||
if (remoteHwid != null) {
|
if (remoteHwid != null) {
|
||||||
onlineRemoteHwids.remove(remoteHwid);
|
onlineRemoteHwids.remove(remoteHwid);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -588,7 +588,7 @@ public class MaplePlayerNPC extends AbstractMapleMapObject {
|
|||||||
World wserv = Server.getInstance().getWorld(world);
|
World wserv = Server.getInstance().getWorld(world);
|
||||||
if (wserv == null) return;
|
if (wserv == null) return;
|
||||||
|
|
||||||
MapleClient c = new MapleClient(null, null, null); // mock client
|
MapleClient c = MapleClient.createMock();
|
||||||
c.setWorld(world);
|
c.setWorld(world);
|
||||||
c.setChannel(1);
|
c.setChannel(1);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user