diff --git a/pom.xml b/pom.xml
index 12b00548cf..0334d6b9c4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -19,24 +19,11 @@
2.14.1
21.1.0
+ 4.1.65.Final
+ 5.7.2
-
- com.zaxxer
- HikariCP
- 4.0.3
-
-
- org.apache.mina
- mina-core
- 2.1.3
-
-
- mysql
- mysql-connector-java
- 8.0.23
-
com.esotericsoftware.yamlbeans
yamlbeans
@@ -52,10 +39,39 @@
commons-io
2.10.0
+
+
+
+ com.zaxxer
+ HikariCP
+ 4.0.3
+
+
+ mysql
+ mysql-connector-java
+ 8.0.23
+
+
+
+
+ io.netty
+ netty-transport
+ ${netty.version}
+
+
+ io.netty
+ netty-codec
+ ${netty.version}
+
io.netty
netty-buffer
- 4.1.65.Final
+ ${netty.version}
+
+
+ io.netty
+ netty-handler
+ ${netty.version}
@@ -96,12 +112,12 @@
org.junit.jupiter
junit-jupiter-api
- 5.7.2
+ ${junit.version}
org.junit.jupiter
junit-jupiter-engine
- 5.7.2
+ ${junit.version}
diff --git a/src/main/java/client/MapleCharacter.java b/src/main/java/client/MapleCharacter.java
index f3fc390ed5..5434e00e2d 100644
--- a/src/main/java/client/MapleCharacter.java
+++ b/src/main/java/client/MapleCharacter.java
@@ -52,7 +52,6 @@ import net.server.services.task.world.CharacterSaveService;
import net.server.services.type.ChannelServices;
import net.server.services.type.WorldServices;
import net.server.world.*;
-import org.apache.mina.util.ConcurrentHashSet;
import scripting.AbstractPlayerInteraction;
import scripting.event.EventInstanceManager;
import scripting.item.ItemScriptManager;
@@ -85,6 +84,7 @@ import java.time.LocalDateTime;
import java.util.List;
import java.util.*;
import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@@ -177,7 +177,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
private final Map quests;
private Set controlled = new LinkedHashSet<>();
private Map entered = new LinkedHashMap<>();
- private Set visibleMapObjects = new ConcurrentHashSet<>();
+ private Set visibleMapObjects = Collections.newSetFromMap(new ConcurrentHashMap<>());
private Map skills = new LinkedHashMap<>();
private Map activeCoupons = new LinkedHashMap<>();
private Map activeCouponRates = new LinkedHashMap<>();
diff --git a/src/main/java/client/MapleClient.java b/src/main/java/client/MapleClient.java
index 83f76f6e5b..4d72ec87ba 100644
--- a/src/main/java/client/MapleClient.java
+++ b/src/main/java/client/MapleClient.java
@@ -24,17 +24,31 @@ package client;
import client.inventory.MapleInventoryType;
import config.YamlConfig;
import constants.game.GameConstants;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import io.netty.handler.timeout.IdleStateEvent;
+import net.MaplePacketHandler;
+import net.PacketProcessor;
+import net.netty.InvalidPacketHeaderException;
+import net.packet.logging.LoggingUtil;
+import net.packet.logging.MapleLogger;
+import net.packet.ByteBufOutPacket;
+import net.packet.InPacket;
+import net.packet.OutPacket;
import net.server.Server;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
import net.server.channel.Channel;
import net.server.coordinator.login.MapleLoginBypassCoordinator;
-import net.server.coordinator.session.MapleSessionCoordinator;
-import net.server.coordinator.session.MapleSessionCoordinator.AntiMulticlientResult;
+import net.server.coordinator.session.Hwid;
+import net.server.coordinator.session.IpAddresses;
+import net.server.coordinator.session.SessionCoordinator;
+import net.server.coordinator.session.SessionCoordinator.AntiMulticlientResult;
import net.server.guild.MapleGuild;
import net.server.guild.MapleGuildCharacter;
import net.server.world.*;
-import org.apache.mina.core.session.IoSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import scripting.AbstractPlayerInteraction;
import scripting.event.EventInstanceManager;
import scripting.event.EventManager;
@@ -43,1418 +57,1551 @@ import scripting.npc.NPCScriptManager;
import scripting.quest.QuestActionManager;
import scripting.quest.QuestScriptManager;
import server.ThreadManager;
+import server.TimerManager;
import server.life.MapleMonster;
import server.maps.FieldLimit;
import server.maps.MapleMap;
import server.maps.MapleMiniDungeonInfo;
import tools.*;
+import tools.data.input.ByteArrayByteStream;
+import tools.data.input.GenericSeekableLittleEndianAccessor;
import javax.script.ScriptEngine;
import java.io.IOException;
-import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.*;
import java.util.Date;
import java.util.*;
import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
-public class MapleClient {
+public class MapleClient extends ChannelInboundHandlerAdapter {
+ private static final Logger log = LoggerFactory.getLogger(MapleClient.class);
- public static final int LOGIN_NOTLOGGEDIN = 0;
- public static final int LOGIN_SERVER_TRANSITION = 1;
- public static final int LOGIN_LOGGEDIN = 2;
- public static final String CLIENT_KEY = "CLIENT";
- public static final String CLIENT_HWID = "HWID";
- public static final String CLIENT_NIBBLEHWID = "HWID2";
- public static final String CLIENT_REMOTE_ADDRESS = "REMOTE_IP";
- public static final String CLIENT_TRANSITION = "TRANSITION";
- private MapleAESOFB send;
- private MapleAESOFB receive;
- private final IoSession session;
- private MapleCharacter player;
- private int channel = 1;
- private int accId = -4;
- private boolean loggedIn = false;
- private boolean serverTransition = false;
- private Calendar birthday = null;
- private String accountName = null;
- private int world;
- private long lastPong;
- private int gmlevel;
- private Set macs = new HashSet<>();
- private Map engines = new HashMap<>();
- private byte characterSlots = 3;
- private byte loginattempt = 0;
- private String pin = "";
- private int pinattempt = 0;
- private String pic = "";
- private int picattempt = 0;
- private String hwid = null;
- private byte csattempt = 0;
- private byte gender = -1;
- private boolean disconnecting = false;
- private final Semaphore actionsSemaphore = new Semaphore(7);
- private final Lock lock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT, true);
- private final Lock encoderLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT_ENCODER, true);
- private final Lock announcerLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT_ANNOUNCER, true);
- // thanks Masterrulax & try2hack for pointing out a bottleneck issue with shared locks, shavit for noticing an opportunity for improvement
- private Calendar tempBanCalendar;
- private int votePoints;
- private int voteTime = -1;
- private int visibleWorlds;
- private long lastNpcClick;
- private long sessionId;
- private long lastPacket = System.currentTimeMillis();
- private int lang = 0;
-
- public void updateLastPacket() {
- lastPacket = System.currentTimeMillis();
- }
+ public static final int LOGIN_NOTLOGGEDIN = 0;
+ public static final int LOGIN_SERVER_TRANSITION = 1;
+ public static final int LOGIN_LOGGEDIN = 2;
- public long getLastPacket() {
- return lastPacket;
- }
+ private final Type type;
+ private final long sessionId;
+ private final PacketProcessor packetProcessor;
- public MapleClient(MapleAESOFB send, MapleAESOFB receive, IoSession session) {
- this.send = send;
- this.receive = receive;
- this.session = session;
- }
+ private Hwid hwid;
+ private String remoteAddress;
+ private volatile boolean inTransition;
- public MapleAESOFB getReceiveCrypto() {
- return receive;
- }
+ private io.netty.channel.Channel ioChannel;
+ private MapleCharacter player;
+ private int channel = 1;
+ private int accId = -4;
+ private boolean loggedIn = false;
+ private boolean serverTransition = false;
+ private Calendar birthday = null;
+ private String accountName = null;
+ private int world;
+ private volatile long lastPong;
+ private int gmlevel;
+ private Set macs = new HashSet<>();
+ private Map engines = new HashMap<>();
+ private byte characterSlots = 3;
+ private byte loginattempt = 0;
+ private String pin = "";
+ private int pinattempt = 0;
+ private String pic = "";
+ private int picattempt = 0;
+ private byte csattempt = 0;
+ private byte gender = -1;
+ private boolean disconnecting = false;
+ private final Semaphore actionsSemaphore = new Semaphore(7);
+ private final Lock lock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT, true);
+ private final Lock encoderLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT_ENCODER, true);
+ private final Lock announcerLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT_ANNOUNCER, true);
+ // thanks Masterrulax & try2hack for pointing out a bottleneck issue with shared locks, shavit for noticing an opportunity for improvement
+ private Calendar tempBanCalendar;
+ private int votePoints;
+ private int voteTime = -1;
+ private int visibleWorlds;
+ private long lastNpcClick;
+ private long lastPacket = System.currentTimeMillis();
+ private int lang = 0;
- public MapleAESOFB getSendCrypto() {
- return send;
- }
+ public enum Type {
+ LOGIN,
+ CHANNEL
+ }
- public IoSession getSession() {
- return session;
- }
-
- public EventManager getEventManager(String event) {
- return getChannelServer().getEventSM().getEventManager(event);
+ public MapleClient(Type type, long sessionId, String remoteAddress, PacketProcessor packetProcessor, int world, int channel) {
+ this.type = type;
+ this.sessionId = sessionId;
+ this.remoteAddress = remoteAddress;
+ this.packetProcessor = packetProcessor;
+ this.world = world;
+ this.channel = channel;
+ }
+
+ public static MapleClient createLoginClient(long sessionId, String remoteAddress, PacketProcessor packetProcessor,
+ int world, int channel) {
+ return new MapleClient(Type.LOGIN, sessionId, remoteAddress, packetProcessor, world, channel);
+ }
+
+ public static MapleClient createChannelClient(long sessionId, String remoteAddress, PacketProcessor packetProcessor,
+ int world, int channel) {
+ return new MapleClient(Type.CHANNEL, sessionId, remoteAddress, packetProcessor, world, channel);
+ }
+
+ public static MapleClient createMock() {
+ return new MapleClient(null, -1,null, null, -123, -123);
+ }
+
+ @Override
+ public void channelActive(ChannelHandlerContext ctx) {
+ final io.netty.channel.Channel channel = ctx.channel();
+ if (!Server.getInstance().isOnline()) {
+ channel.close();
+ return;
}
- public MapleCharacter getPlayer() {
- return player;
- }
+ this.remoteAddress = getRemoteAddress(channel);
+ this.ioChannel = channel;
+ }
- public void setPlayer(MapleCharacter player) {
- this.player = player;
- }
-
- public AbstractPlayerInteraction getAbstractPlayerInteraction() {
- return new AbstractPlayerInteraction(this);
+ private static String getRemoteAddress(io.netty.channel.Channel channel) {
+ String remoteAddress = "null";
+ try {
+ String hostAddress = ((InetSocketAddress) channel.remoteAddress()).getAddress().getHostAddress();
+ if (hostAddress != null) {
+ remoteAddress = IpAddresses.evaluateRemoteAddress(hostAddress); // thanks dyz for noticing Local/LAN/WAN connections not interacting properly
+ }
+ } catch (NullPointerException npe) {
+ log.warn("Unable to get remote address for client", npe);
}
- public void sendCharList(int server) {
- this.announce(MaplePacketCreator.getCharList(this, server, 0));
- }
+ return remoteAddress;
+ }
- public List loadCharacters(int serverId) {
- List chars = new ArrayList<>(15);
- try {
- for (CharNameAndId cni : loadCharactersInternal(serverId)) {
- chars.add(MapleCharacter.loadCharFromDB(cni.id, this, false));
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return chars;
- }
-
- public List loadCharacterNames(int worldId) {
- List chars = new ArrayList<>(15);
- for (CharNameAndId cni : loadCharactersInternal(worldId)) {
- chars.add(cni.name);
- }
- return chars;
- }
-
- private List loadCharactersInternal(int worldId) {
- List chars = new ArrayList<>(15);
- try (Connection con = DatabaseConnection.getConnection();
- PreparedStatement ps = con.prepareStatement("SELECT id, name FROM characters WHERE accountid = ? AND world = ?")) {
- ps.setInt(1, this.getAccID());
- ps.setInt(2, worldId);
-
- try (ResultSet rs = ps.executeQuery()) {
- while (rs.next()) {
- chars.add(new CharNameAndId(rs.getString("name"), rs.getInt("id")));
- }
- }
- } catch (SQLException e) {
- e.printStackTrace();
- }
- return chars;
- }
-
- public boolean isLoggedIn() {
- return loggedIn;
- }
-
- public boolean hasBannedIP() {
- boolean ret = false;
- try (Connection con = DatabaseConnection.getConnection();
- PreparedStatement ps = con.prepareStatement("SELECT COUNT(*) FROM ipbans WHERE ? LIKE CONCAT(ip, '%')")) {
- ps.setString(1, session.getRemoteAddress().toString());
- try (ResultSet rs = ps.executeQuery()) {
- rs.next();
- if (rs.getInt(1) > 0) {
- ret = true;
- }
- }
- } catch (SQLException e) {
- e.printStackTrace();
- }
- return ret;
- }
-
- public int getVoteTime() {
- if (voteTime != -1) {
- return voteTime;
- }
-
- try (Connection con = DatabaseConnection.getConnection();
- PreparedStatement ps = con.prepareStatement("SELECT date FROM bit_votingrecords WHERE UPPER(account) = UPPER(?)")) {
- ps.setString(1, accountName);
- try (ResultSet rs = ps.executeQuery()) {
- if (!rs.next()) {
- return -1;
- }
- voteTime = rs.getInt("date");
- }
- } catch (SQLException e) {
- FilePrinter.printError("hasVotedAlready.txt", e);
- return -1;
- }
- return voteTime;
- }
-
- public void resetVoteTime() {
- voteTime = -1;
+ @Override
+ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+ if (!(msg instanceof InPacket packet)) {
+ log.warn("Received invalid message: {}", msg);
+ return;
}
- public boolean hasVotedAlready(){
- Date currentDate = new Date();
- int timeNow = (int) (currentDate.getTime() / 1000);
- int difference = (timeNow - getVoteTime());
- return difference < 86400 && difference > 0;
- }
+ short opcode = packet.readShort();
+ final MaplePacketHandler handler = packetProcessor.getHandler(opcode);
- public boolean hasBannedHWID() {
- if (hwid == null) {
- return false;
- }
+ if (YamlConfig.config.server.USE_DEBUG_SHOW_RCVD_PACKET && !LoggingUtil.isIgnoredRecvPacket(opcode)) {
+ log.debug("Received packet id {}", opcode);
+ }
- boolean ret = false;
- try (Connection con = DatabaseConnection.getConnection();
- PreparedStatement ps = con.prepareStatement("SELECT COUNT(*) FROM hwidbans WHERE hwid LIKE ?")) {
- ps.setString(1, hwid);
+ if (handler != null && handler.validateState(this)) {
+ // TODO: pass InPacket directly to handler once all handlers have been ported,
+ // this is just a temporary workaround
+ final byte[] content = packet.getBytes();
+ GenericSeekableLittleEndianAccessor accessor = new GenericSeekableLittleEndianAccessor(new ByteArrayByteStream(content));
+ try {
+ MapleLogger.logRecv(this, opcode, content);
+ handler.handlePacket(accessor, this);
+ } catch (final Throwable t) {
+ FilePrinter.printError(FilePrinter.PACKET_HANDLER + handler.getClass().getName() + ".txt", t, "Error for " + (getPlayer() == null ? "" : "player ; " + getPlayer() + " on map ; " + getPlayer().getMapId() + " - ") + "account ; " + getAccountName() + "\r\n" + accessor);
+ //client.announce(MaplePacketCreator.enableActions());//bugs sometimes
+ }
+ }
- try (ResultSet rs = ps.executeQuery()) {
- if (rs != null && rs.next()) {
- if (rs.getInt(1) > 0) {
- ret = true;
- }
- }
- }
- } catch (SQLException e) {
- e.printStackTrace();
- }
+ updateLastPacket();
+ }
- return ret;
- }
+ @Override
+ public void userEventTriggered(ChannelHandlerContext ctx, Object event) {
+ if (event instanceof IdleStateEvent idleEvent) {
+ checkIfIdle(idleEvent);
+ }
+ }
- public boolean hasBannedMac() {
- if (macs.isEmpty()) {
- return false;
- }
- boolean ret = false;
- int i;
- StringBuilder sql = new StringBuilder("SELECT COUNT(*) FROM macbans WHERE mac IN (");
- for (i = 0; i < macs.size(); i++) {
- sql.append("?");
- if (i != macs.size() - 1) {
- sql.append(", ");
- }
- }
- sql.append(")");
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+ if (player != null) {
+ log.warn("Exception caught by {}", player, cause);
+ }
- try (Connection con = DatabaseConnection.getConnection();
- PreparedStatement ps = con.prepareStatement(sql.toString())) {
- i = 0;
- for (String mac : macs) {
- ps.setString(++i, mac);
- }
- try (ResultSet rs = ps.executeQuery()) {
- rs.next();
- if (rs.getInt(1) > 0) {
- ret = true;
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
+ if (cause instanceof InvalidPacketHeaderException) {
+ SessionCoordinator.getInstance().closeSession(this, true);
+ } else if (cause instanceof IOException) {
+ closeMapleSession();
+ }
+ }
- return ret;
- }
+ @Override
+ public void channelInactive(ChannelHandlerContext ctx) {
+ closeMapleSession();
+ }
- private void loadHWIDIfNescessary() throws SQLException {
- if (hwid == null) {
- try (Connection con = DatabaseConnection.getConnection();
- PreparedStatement ps = con.prepareStatement("SELECT hwid FROM accounts WHERE id = ?")) {
- ps.setInt(1, accId);
+ private void closeMapleSession() {
+ switch (type) {
+ case LOGIN -> SessionCoordinator.getInstance().closeLoginSession(this);
+ case CHANNEL -> SessionCoordinator.getInstance().closeSession(this, null);
+ }
- try (ResultSet rs = ps.executeQuery()) {
- if (rs.next()) {
- hwid = rs.getString("hwid");
- }
- }
- }
- }
- }
+ try {
+ // client freeze issues on session transition states found thanks to yolinlin, Omo Oppa, Nozphex
+ if (!inTransition) {
+ disconnect(false, false);
+ }
+ } catch (Throwable t) {
+ log.warn("Account stuck", t);
+ } finally {
+ closeSession();
+ }
+ }
- // TODO: Recode to close statements...
- private void loadMacsIfNescessary() throws SQLException {
- if (macs.isEmpty()) {
- try (Connection con = DatabaseConnection.getConnection();
- PreparedStatement ps = con.prepareStatement("SELECT macs FROM accounts WHERE id = ?")) {
- ps.setInt(1, accId);
- try (ResultSet rs = ps.executeQuery()) {
- if (rs.next()) {
- for (String mac : rs.getString("macs").split(", ")) {
- if (!mac.equals("")) {
- macs.add(mac);
- }
- }
- }
- }
- }
- }
- }
+ public void updateLastPacket() {
+ lastPacket = System.currentTimeMillis();
+ }
- public void banHWID() {
- try {
- loadHWIDIfNescessary();
+ public long getLastPacket() {
+ return lastPacket;
+ }
- try (Connection con = DatabaseConnection.getConnection();
- PreparedStatement ps = con.prepareStatement("INSERT INTO hwidbans (hwid) VALUES (?)")) {
- ps.setString(1, hwid);
- ps.executeUpdate();
- }
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
+ public void closeSession() {
+ ioChannel.close();
+ }
- public void banMacs() {
- try {
- loadMacsIfNescessary();
+ public void disconnectSession() {
+ ioChannel.disconnect();
+ }
- List filtered = new LinkedList<>();
- try (Connection con = DatabaseConnection.getConnection()) {
- try (PreparedStatement ps = con.prepareStatement("SELECT filter FROM macfilters");
- ResultSet rs = ps.executeQuery()) {
- while (rs.next()) {
- filtered.add(rs.getString("filter"));
- }
- }
+ public Hwid getHwid() {
+ return hwid;
+ }
- try (PreparedStatement ps = con.prepareStatement("INSERT INTO macbans (mac, aid) VALUES (?, ?)")) {
- for (String mac : macs) {
- boolean matched = false;
- for (String filter : filtered) {
- if (mac.matches(filter)) {
- matched = true;
- break;
- }
- }
- if (!matched) {
- ps.setString(1, mac);
- ps.setString(2, String.valueOf(getAccID()));
- ps.executeUpdate();
- }
- }
- }
- }
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
+ public void setHwid(Hwid hwid) {
+ this.hwid = hwid;
+ }
- public int finishLogin() {
- encoderLock.lock();
- try {
- if (getLoginState() > LOGIN_NOTLOGGEDIN) { // 0 = LOGIN_NOTLOGGEDIN, 1= LOGIN_SERVER_TRANSITION, 2 = LOGIN_LOGGEDIN
- loggedIn = false;
- return 7;
+ public String getRemoteAddress() {
+ return remoteAddress;
+ }
+
+ public boolean isInTransition() {
+ return inTransition;
+ }
+
+ public EventManager getEventManager(String event) {
+ return getChannelServer().getEventSM().getEventManager(event);
+ }
+
+ public MapleCharacter getPlayer() {
+ return player;
+ }
+
+ public void setPlayer(MapleCharacter player) {
+ this.player = player;
+ }
+
+ public AbstractPlayerInteraction getAbstractPlayerInteraction() {
+ return new AbstractPlayerInteraction(this);
+ }
+
+ public void sendCharList(int server) {
+ this.announce(MaplePacketCreator.getCharList(this, server, 0));
+ }
+
+ public List loadCharacters(int serverId) {
+ List chars = new ArrayList<>(15);
+ try {
+ for (CharNameAndId cni : loadCharactersInternal(serverId)) {
+ chars.add(MapleCharacter.loadCharFromDB(cni.id, this, false));
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return chars;
+ }
+
+ public List loadCharacterNames(int worldId) {
+ List chars = new ArrayList<>(15);
+ for (CharNameAndId cni : loadCharactersInternal(worldId)) {
+ chars.add(cni.name);
+ }
+ return chars;
+ }
+
+ private List loadCharactersInternal(int worldId) {
+ List chars = new ArrayList<>(15);
+ try (Connection con = DatabaseConnection.getConnection();
+ PreparedStatement ps = con.prepareStatement("SELECT id, name FROM characters WHERE accountid = ? AND world = ?")) {
+ ps.setInt(1, this.getAccID());
+ ps.setInt(2, worldId);
+
+ try (ResultSet rs = ps.executeQuery()) {
+ while (rs.next()) {
+ chars.add(new CharNameAndId(rs.getString("name"), rs.getInt("id")));
+ }
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ return chars;
+ }
+
+ public boolean isLoggedIn() {
+ return loggedIn;
+ }
+
+ public boolean hasBannedIP() {
+ boolean ret = false;
+ try (Connection con = DatabaseConnection.getConnection();
+ PreparedStatement ps = con.prepareStatement("SELECT COUNT(*) FROM ipbans WHERE ? LIKE CONCAT(ip, '%')")) {
+ ps.setString(1, remoteAddress);
+ try (ResultSet rs = ps.executeQuery()) {
+ rs.next();
+ if (rs.getInt(1) > 0) {
+ ret = true;
+ }
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ return ret;
+ }
+
+ public int getVoteTime() {
+ if (voteTime != -1) {
+ return voteTime;
+ }
+
+ try (Connection con = DatabaseConnection.getConnection();
+ PreparedStatement ps = con.prepareStatement("SELECT date FROM bit_votingrecords WHERE UPPER(account) = UPPER(?)")) {
+ ps.setString(1, accountName);
+ try (ResultSet rs = ps.executeQuery()) {
+ if (!rs.next()) {
+ return -1;
+ }
+ voteTime = rs.getInt("date");
+ }
+ } catch (SQLException e) {
+ FilePrinter.printError("hasVotedAlready.txt", e);
+ return -1;
+ }
+ return voteTime;
+ }
+
+ public void resetVoteTime() {
+ voteTime = -1;
+ }
+
+ public boolean hasVotedAlready() {
+ Date currentDate = new Date();
+ int timeNow = (int) (currentDate.getTime() / 1000);
+ int difference = (timeNow - getVoteTime());
+ return difference < 86400 && difference > 0;
+ }
+
+ public boolean hasBannedHWID() {
+ if (hwid == null) {
+ return false;
+ }
+
+ boolean ret = false;
+ try (Connection con = DatabaseConnection.getConnection();
+ PreparedStatement ps = con.prepareStatement("SELECT COUNT(*) FROM hwidbans WHERE hwid LIKE ?")) {
+ ps.setString(1, hwid.hwid());
+
+ try (ResultSet rs = ps.executeQuery()) {
+ if (rs != null && rs.next()) {
+ if (rs.getInt(1) > 0) {
+ ret = true;
}
- updateLoginState(MapleClient.LOGIN_LOGGEDIN);
- } finally {
- encoderLock.unlock();
}
-
- return 0;
- }
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
- public void setPin(String pin) {
- this.pin = pin;
- try (Connection con = DatabaseConnection.getConnection();
- PreparedStatement ps = con.prepareStatement("UPDATE accounts SET pin = ? WHERE id = ?")) {
- ps.setString(1, pin);
- ps.setInt(2, accId);
- ps.executeUpdate();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
+ return ret;
+ }
- public String getPin() {
- return pin;
- }
+ public boolean hasBannedMac() {
+ if (macs.isEmpty()) {
+ return false;
+ }
+ boolean ret = false;
+ int i;
+ StringBuilder sql = new StringBuilder("SELECT COUNT(*) FROM macbans WHERE mac IN (");
+ for (i = 0; i < macs.size(); i++) {
+ sql.append("?");
+ if (i != macs.size() - 1) {
+ sql.append(", ");
+ }
+ }
+ sql.append(")");
- public boolean checkPin(String other) {
- if (!(YamlConfig.config.server.ENABLE_PIN && !canBypassPin())) {
- return true;
+ try (Connection con = DatabaseConnection.getConnection();
+ PreparedStatement ps = con.prepareStatement(sql.toString())) {
+ i = 0;
+ for (String mac : macs) {
+ ps.setString(++i, mac);
+ }
+ try (ResultSet rs = ps.executeQuery()) {
+ rs.next();
+ if (rs.getInt(1) > 0) {
+ ret = true;
}
-
- pinattempt++;
- if (pinattempt > 5) {
- MapleSessionCoordinator.getInstance().closeSession(session, false);
- }
- if (pin.equals(other)) {
- pinattempt = 0;
- MapleLoginBypassCoordinator.getInstance().registerLoginBypassEntry(getNibbleHWID(), accId, false);
- return true;
- }
- return false;
- }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
- public void setPic(String pic) {
- this.pic = pic;
- try (Connection con = DatabaseConnection.getConnection();
- PreparedStatement ps = con.prepareStatement("UPDATE accounts SET pic = ? WHERE id = ?")) {
- ps.setString(1, pic);
- ps.setInt(2, accId);
- ps.executeUpdate();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
+ return ret;
+ }
- public String getPic() {
- return pic;
- }
+ private void loadHWIDIfNescessary() throws SQLException {
+ if (hwid == null) {
+ try (Connection con = DatabaseConnection.getConnection();
+ PreparedStatement ps = con.prepareStatement("SELECT hwid FROM accounts WHERE id = ?")) {
+ ps.setInt(1, accId);
- public boolean checkPic(String other) {
- if (!(YamlConfig.config.server.ENABLE_PIC && !canBypassPic())) {
- return true;
+ try (ResultSet rs = ps.executeQuery()) {
+ if (rs.next()) {
+ hwid = new Hwid(rs.getString("hwid"));
+ }
}
-
- picattempt++;
- if (picattempt > 5) {
- MapleSessionCoordinator.getInstance().closeSession(session, false);
- }
- if (pic.equals(other)) { // thanks ryantpayton (HeavenClient) for noticing null pics being checked here
- picattempt = 0;
- MapleLoginBypassCoordinator.getInstance().registerLoginBypassEntry(getNibbleHWID(), accId, true);
- return true;
- }
- return false;
- }
+ }
+ }
+ }
- public int login(String login, String pwd, String nibbleHwid) {
- int loginok = 5;
-
- loginattempt++;
- if (loginattempt > 4) {
- loggedIn = false;
- MapleSessionCoordinator.getInstance().closeSession(session, false);
- return 6; // thanks Survival_Project for finding out an issue with AUTOMATIC_REGISTER here
- }
-
- try (Connection con = DatabaseConnection.getConnection();
- PreparedStatement ps = con.prepareStatement("SELECT id, password, gender, banned, pin, pic, characterslots, tos, language FROM accounts WHERE name = ?")) {
- ps.setString(1, login);
-
- try (ResultSet rs = ps.executeQuery()) {
- accId = -2;
- if (rs.next()) {
- accId = rs.getInt("id");
- if (accId <= 0) {
- FilePrinter.printError(FilePrinter.LOGIN_EXCEPTION, "Tried to login with accid " + accId);
- return 15;
- }
-
- boolean banned = (rs.getByte("banned") == 1);
- gmlevel = 0;
- pin = rs.getString("pin");
- pic = rs.getString("pic");
- gender = rs.getByte("gender");
- characterSlots = rs.getByte("characterslots");
- lang = rs.getInt("language");
- String passhash = rs.getString("password");
- byte tos = rs.getByte("tos");
-
- if (banned) {
- return 3;
- }
-
- if (getLoginState() > LOGIN_NOTLOGGEDIN) { // already loggedin
- loggedIn = false;
- loginok = 7;
- } else if (passhash.charAt(0) == '$' && passhash.charAt(1) == '2' && BCrypt.checkpw(pwd, passhash)) {
- loginok = (tos == 0) ? 23 : 0;
- } else if (pwd.equals(passhash) || checkHash(passhash, "SHA-1", pwd) || checkHash(passhash, "SHA-512", pwd)) {
- // thanks GabrielSin for detecting some no-bcrypt inconsistencies here
- loginok = (tos == 0) ? (!YamlConfig.config.server.BCRYPT_MIGRATION ? 23 : -23) : (!YamlConfig.config.server.BCRYPT_MIGRATION ? 0 : -10); // migrate to bcrypt
- } else {
- loggedIn = false;
- loginok = 4;
- }
- } else {
- accId = -3;
- }
- }
- } catch (SQLException e) {
- e.printStackTrace();
- }
-
- if (loginok == 0 || loginok == 4) {
- AntiMulticlientResult res = MapleSessionCoordinator.getInstance().attemptLoginSession(session, nibbleHwid, accId, loginok == 4);
-
- switch (res) {
- case SUCCESS:
- if (loginok == 0) {
- loginattempt = 0;
- }
-
- return loginok;
-
- case REMOTE_LOGGEDIN:
- return 17;
-
- case REMOTE_REACHED_LIMIT:
- return 13;
-
- case REMOTE_PROCESSING:
- return 10;
-
- case MANY_ACCOUNT_ATTEMPTS:
- return 16;
-
- default:
- return 8;
- }
- } else {
- return loginok;
- }
- }
-
- public Calendar getTempBanCalendarFromDB() {
- final Calendar lTempban = Calendar.getInstance();
-
- try (Connection con = DatabaseConnection.getConnection();
- PreparedStatement ps = con.prepareStatement("SELECT `tempban` FROM accounts WHERE id = ?")) {
- ps.setInt(1, getAccID());
-
- final Timestamp tempban;
- try (ResultSet rs = ps.executeQuery()) {
- if (!rs.next()) {
- return null;
- }
-
- tempban = rs.getTimestamp("tempban");
- if (tempban.toLocalDateTime().equals(DefaultDates.getTempban())) {
- return null;
- }
- }
-
- lTempban.setTimeInMillis(tempban.getTime());
- tempBanCalendar = lTempban;
- return lTempban;
- } catch (SQLException e) {
- e.printStackTrace();
- }
-
- return null;//why oh why!?!
- }
-
- public Calendar getTempBanCalendar() {
- return tempBanCalendar;
- }
-
- public boolean hasBeenBanned() {
- return tempBanCalendar != null;
- }
-
- public static long dottedQuadToLong(String dottedQuad) throws RuntimeException {
- String[] quads = dottedQuad.split("\\.");
- if (quads.length != 4) {
- throw new RuntimeException("Invalid IP Address format.");
- }
- long ipAddress = 0;
- for (int i = 0; i < 4; i++) {
- int quad = Integer.parseInt(quads[i]);
- ipAddress += (long) (quad % 256) * (long) Math.pow(256, 4 - i);
- }
- return ipAddress;
- }
-
- public void updateHWID(String newHwid) {
- String[] split = newHwid.split("_");
- if (split.length > 1 && split[1].length() == 8) {
- StringBuilder hwid = new StringBuilder();
- String convert = split[1];
-
- int len = convert.length();
- for (int i = len - 2; i >= 0; i -= 2) {
- hwid.append(convert.substring(i, i + 2));
- }
- hwid.insert(4, "-");
-
- this.hwid = hwid.toString();
-
- try (Connection con = DatabaseConnection.getConnection();
- PreparedStatement ps = con.prepareStatement("UPDATE accounts SET hwid = ? WHERE id = ?")) {
- ps.setString(1, this.hwid);
- ps.setInt(2, accId);
- ps.executeUpdate();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- } else {
- this.disconnect(false, false); // Invalid HWID...
- }
- }
-
- public void updateMacs(String macData) {
- macs.addAll(Arrays.asList(macData.split(", ")));
- StringBuilder newMacData = new StringBuilder();
- Iterator iter = macs.iterator();
- while (iter.hasNext()) {
- String cur = iter.next();
- newMacData.append(cur);
- if (iter.hasNext()) {
- newMacData.append(", ");
- }
- }
-
- try (Connection con = DatabaseConnection.getConnection();
- PreparedStatement ps = con.prepareStatement("UPDATE accounts SET macs = ? WHERE id = ?")) {
- ps.setString(1, newMacData.toString());
- ps.setInt(2, accId);
- ps.executeUpdate();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
-
- public void setAccID(int id) {
- this.accId = id;
- }
-
- public int getAccID() {
- return accId;
- }
-
- public void updateLoginState(int newstate) {
- // rules out possibility of multiple account entries
- if (newstate == LOGIN_LOGGEDIN) {
- MapleSessionCoordinator.getInstance().updateOnlineSession(this.getSession());
- }
-
- try (Connection con = DatabaseConnection.getConnection();
- PreparedStatement ps = con.prepareStatement("UPDATE accounts SET loggedin = ?, lastlogin = ? WHERE id = ?")) {
- // using sql currenttime here could potentially break the login, thanks Arnah for pointing this out
-
- ps.setInt(1, newstate);
- ps.setTimestamp(2, new java.sql.Timestamp(Server.getInstance().getCurrentTime()));
- ps.setInt(3, getAccID());
- ps.executeUpdate();
- } catch (SQLException e) {
- e.printStackTrace();
- }
-
- if (newstate == LOGIN_NOTLOGGEDIN) {
- loggedIn = false;
- serverTransition = false;
- setAccID(0);
- } else {
- serverTransition = (newstate == LOGIN_SERVER_TRANSITION);
- loggedIn = !serverTransition;
- }
- }
-
- public int getLoginState() { // 0 = LOGIN_NOTLOGGEDIN, 1= LOGIN_SERVER_TRANSITION, 2 = LOGIN_LOGGEDIN
- try (Connection con = DatabaseConnection.getConnection()) {
- int state;
- try (PreparedStatement ps = con.prepareStatement("SELECT loggedin, lastlogin, birthday FROM accounts WHERE id = ?")) {
- ps.setInt(1, getAccID());
-
- try (ResultSet rs = ps.executeQuery()) {
- if (!rs.next()) {
- throw new RuntimeException("getLoginState - MapleClient AccID: " + getAccID());
- }
-
- birthday = Calendar.getInstance();
- try {
- birthday.setTime(rs.getDate("birthday"));
- } catch (SQLException e) {
- }
-
- state = rs.getInt("loggedin");
- if (state == LOGIN_SERVER_TRANSITION) {
- if (rs.getTimestamp("lastlogin").getTime() + 30000 < Server.getInstance().getCurrentTime()) {
- int accountId = accId;
- state = LOGIN_NOTLOGGEDIN;
- updateLoginState(MapleClient.LOGIN_NOTLOGGEDIN); // ACCID = 0, issue found thanks to Tochi & K u ssss o & Thora & Omo Oppa
- this.setAccID(accountId);
- }
- }
- }
- }
- if (state == LOGIN_LOGGEDIN) {
- loggedIn = true;
- } else if (state == LOGIN_SERVER_TRANSITION) {
- try (PreparedStatement ps2 = con.prepareStatement("UPDATE accounts SET loggedin = 0 WHERE id = ?")) {
- ps2.setInt(1, getAccID());
- ps2.executeUpdate();
- }
- } else {
- loggedIn = false;
- }
- return state;
- } catch (SQLException e) {
- loggedIn = false;
- e.printStackTrace();
- throw new RuntimeException("login state");
- }
- }
-
- public boolean checkBirthDate(Calendar date) {
- return date.get(Calendar.YEAR) == birthday.get(Calendar.YEAR) && date.get(Calendar.MONTH) == birthday.get(Calendar.MONTH) && date.get(Calendar.DAY_OF_MONTH) == birthday.get(Calendar.DAY_OF_MONTH);
- }
-
- private void removePartyPlayer(World wserv) {
- MapleMap map = player.getMap();
- final MapleParty party = player.getParty();
- final int idz = player.getId();
-
- if (party != null) {
- final MaplePartyCharacter chrp = new MaplePartyCharacter(player);
- chrp.setOnline(false);
- wserv.updateParty(party.getId(), PartyOperation.LOG_ONOFF, chrp);
- if (party.getLeader().getId() == idz && map != null) {
- MaplePartyCharacter lchr = null;
- for (MaplePartyCharacter pchr : party.getMembers()) {
- if (pchr != null && pchr.getId() != idz && (lchr == null || lchr.getLevel() <= pchr.getLevel()) && map.getCharacterById(pchr.getId()) != null) {
- lchr = pchr;
- }
- }
- if (lchr != null) {
- wserv.updateParty(party.getId(), PartyOperation.CHANGE_LEADER, lchr);
- }
+ // TODO: Recode to close statements...
+ private void loadMacsIfNescessary() throws SQLException {
+ if (macs.isEmpty()) {
+ try (Connection con = DatabaseConnection.getConnection();
+ PreparedStatement ps = con.prepareStatement("SELECT macs FROM accounts WHERE id = ?")) {
+ ps.setInt(1, accId);
+ try (ResultSet rs = ps.executeQuery()) {
+ if (rs.next()) {
+ for (String mac : rs.getString("macs").split(", ")) {
+ if (!mac.equals("")) {
+ macs.add(mac);
+ }
}
+ }
}
+ }
}
-
- private void removePlayer(World wserv, boolean serverTransition) {
- try {
- player.setDisconnectedFromChannelWorld();
- player.notifyMapTransferToPartner(-1);
- player.removeIncomingInvites();
- player.cancelAllBuffs(true);
-
- player.closePlayerInteractions();
- player.closePartySearchInteractions();
-
- if (!serverTransition) { // thanks MedicOP for detecting an issue with party leader change on changing channels
- removePartyPlayer(wserv);
+ }
- EventInstanceManager eim = player.getEventInstance();
- if (eim != null) {
- eim.playerDisconnected(player);
- }
-
- if (player.getMonsterCarnival() != null) {
- player.getMonsterCarnival().playerDisconnected(getPlayer().getId());
- }
-
- if (player.getAriantColiseum() != null) {
- player.getAriantColiseum().playerDisconnected(getPlayer());
- }
+ public void banHWID() {
+ try {
+ loadHWIDIfNescessary();
+
+ try (Connection con = DatabaseConnection.getConnection();
+ PreparedStatement ps = con.prepareStatement("INSERT INTO hwidbans (hwid) VALUES (?)")) {
+ ps.setString(1, hwid.hwid());
+ ps.executeUpdate();
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void banMacs() {
+ try {
+ loadMacsIfNescessary();
+
+ List filtered = new LinkedList<>();
+ try (Connection con = DatabaseConnection.getConnection()) {
+ try (PreparedStatement ps = con.prepareStatement("SELECT filter FROM macfilters");
+ ResultSet rs = ps.executeQuery()) {
+ while (rs.next()) {
+ filtered.add(rs.getString("filter"));
+ }
+ }
+
+ try (PreparedStatement ps = con.prepareStatement("INSERT INTO macbans (mac, aid) VALUES (?, ?)")) {
+ for (String mac : macs) {
+ boolean matched = false;
+ for (String filter : filtered) {
+ if (mac.matches(filter)) {
+ matched = true;
+ break;
+ }
}
-
- if (player.getMap() != null) {
- int mapId = player.getMapId();
- player.getMap().removePlayer(player);
- if(GameConstants.isDojo(mapId)) {
- this.getChannelServer().freeDojoSectionIfEmpty(mapId);
- }
- }
-
- } catch (final Throwable t) {
- FilePrinter.printError(FilePrinter.ACCOUNT_STUCK, t);
- }
- }
-
- public final void disconnect(final boolean shutdown, final boolean cashshop) {
- if (canDisconnect()) {
- ThreadManager.getInstance().newTask(() -> disconnectInternal(shutdown, cashshop));
+ if (!matched) {
+ ps.setString(1, mac);
+ ps.setString(2, String.valueOf(getAccID()));
+ ps.executeUpdate();
+ }
+ }
}
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
}
-
- public final void forceDisconnect() {
- if (canDisconnect()) {
- disconnectInternal(true, false);
+ }
+
+ public int finishLogin() {
+ encoderLock.lock();
+ try {
+ if (getLoginState() > LOGIN_NOTLOGGEDIN) { // 0 = LOGIN_NOTLOGGEDIN, 1= LOGIN_SERVER_TRANSITION, 2 = LOGIN_LOGGEDIN
+ loggedIn = false;
+ return 7;
+ }
+ updateLoginState(MapleClient.LOGIN_LOGGEDIN);
+ } finally {
+ encoderLock.unlock();
+ }
+
+ return 0;
+ }
+
+ public void setPin(String pin) {
+ this.pin = pin;
+ try (Connection con = DatabaseConnection.getConnection();
+ PreparedStatement ps = con.prepareStatement("UPDATE accounts SET pin = ? WHERE id = ?")) {
+ ps.setString(1, pin);
+ ps.setInt(2, accId);
+ ps.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public String getPin() {
+ return pin;
+ }
+
+ public boolean checkPin(String other) {
+ if (!(YamlConfig.config.server.ENABLE_PIN && !canBypassPin())) {
+ return true;
+ }
+
+ pinattempt++;
+ if (pinattempt > 5) {
+ SessionCoordinator.getInstance().closeSession(this, false);
+ }
+ if (pin.equals(other)) {
+ pinattempt = 0;
+ MapleLoginBypassCoordinator.getInstance().registerLoginBypassEntry(hwid, accId, false);
+ return true;
+ }
+ return false;
+ }
+
+ public void setPic(String pic) {
+ this.pic = pic;
+ try (Connection con = DatabaseConnection.getConnection();
+ PreparedStatement ps = con.prepareStatement("UPDATE accounts SET pic = ? WHERE id = ?")) {
+ ps.setString(1, pic);
+ ps.setInt(2, accId);
+ ps.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public String getPic() {
+ return pic;
+ }
+
+ public boolean checkPic(String other) {
+ if (!(YamlConfig.config.server.ENABLE_PIC && !canBypassPic())) {
+ return true;
+ }
+
+ picattempt++;
+ if (picattempt > 5) {
+ SessionCoordinator.getInstance().closeSession(this, false);
+ }
+ if (pic.equals(other)) { // thanks ryantpayton (HeavenClient) for noticing null pics being checked here
+ picattempt = 0;
+ MapleLoginBypassCoordinator.getInstance().registerLoginBypassEntry(hwid, accId, true);
+ return true;
+ }
+ return false;
+ }
+
+ public int login(String login, String pwd, Hwid hwid) {
+ int loginok = 5;
+
+ loginattempt++;
+ if (loginattempt > 4) {
+ loggedIn = false;
+ SessionCoordinator.getInstance().closeSession(this, false);
+ return 6; // thanks Survival_Project for finding out an issue with AUTOMATIC_REGISTER here
+ }
+
+ try (Connection con = DatabaseConnection.getConnection();
+ PreparedStatement ps = con.prepareStatement("SELECT id, password, gender, banned, pin, pic, characterslots, tos, language FROM accounts WHERE name = ?")) {
+ ps.setString(1, login);
+
+ try (ResultSet rs = ps.executeQuery()) {
+ accId = -2;
+ if (rs.next()) {
+ accId = rs.getInt("id");
+ if (accId <= 0) {
+ FilePrinter.printError(FilePrinter.LOGIN_EXCEPTION, "Tried to login with accid " + accId);
+ return 15;
+ }
+
+ boolean banned = (rs.getByte("banned") == 1);
+ gmlevel = 0;
+ pin = rs.getString("pin");
+ pic = rs.getString("pic");
+ gender = rs.getByte("gender");
+ characterSlots = rs.getByte("characterslots");
+ lang = rs.getInt("language");
+ String passhash = rs.getString("password");
+ byte tos = rs.getByte("tos");
+
+ if (banned) {
+ return 3;
+ }
+
+ if (getLoginState() > LOGIN_NOTLOGGEDIN) { // already loggedin
+ loggedIn = false;
+ loginok = 7;
+ } else if (passhash.charAt(0) == '$' && passhash.charAt(1) == '2' && BCrypt.checkpw(pwd, passhash)) {
+ loginok = (tos == 0) ? 23 : 0;
+ } else if (pwd.equals(passhash) || checkHash(passhash, "SHA-1", pwd) || checkHash(passhash, "SHA-512", pwd)) {
+ // thanks GabrielSin for detecting some no-bcrypt inconsistencies here
+ loginok = (tos == 0) ? (!YamlConfig.config.server.BCRYPT_MIGRATION ? 23 : -23) : (!YamlConfig.config.server.BCRYPT_MIGRATION ? 0 : -10); // migrate to bcrypt
+ } else {
+ loggedIn = false;
+ loginok = 4;
+ }
+ } else {
+ accId = -3;
}
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
}
-
- private synchronized boolean canDisconnect() {
- if (disconnecting) {
- return false;
- }
-
- disconnecting = true;
- return true;
+
+ if (loginok == 0 || loginok == 4) {
+ AntiMulticlientResult res = SessionCoordinator.getInstance().attemptLoginSession(this, hwid, accId, loginok == 4);
+
+ switch (res) {
+ case SUCCESS:
+ if (loginok == 0) {
+ loginattempt = 0;
+ }
+
+ return loginok;
+
+ case REMOTE_LOGGEDIN:
+ return 17;
+
+ case REMOTE_REACHED_LIMIT:
+ return 13;
+
+ case REMOTE_PROCESSING:
+ return 10;
+
+ case MANY_ACCOUNT_ATTEMPTS:
+ return 16;
+
+ default:
+ return 8;
+ }
+ } else {
+ return loginok;
}
-
- private void disconnectInternal(boolean shutdown, boolean cashshop) {//once per MapleClient instance
- if (player != null && player.isLoggedin() && player.getClient() != null) {
- final int messengerid = player.getMessenger() == null ? 0 : player.getMessenger().getId();
- //final int fid = player.getFamilyId();
- final BuddyList bl = player.getBuddylist();
- final MapleMessengerCharacter chrm = new MapleMessengerCharacter(player, 0);
- final MapleGuildCharacter chrg = player.getMGC();
- final MapleGuild guild = player.getGuild();
-
- player.cancelMagicDoor();
-
- final World wserv = getWorldServer(); // obviously wserv is NOT null if this player was online on it
- try {
- removePlayer(wserv, this.serverTransition);
-
- if (!(channel == -1 || shutdown)) {
- if (!cashshop) {
- if (!this.serverTransition) { // meaning not changing channels
- if (messengerid > 0) {
- wserv.leaveMessenger(messengerid, chrm);
- }
+ }
+
+ public Calendar getTempBanCalendarFromDB() {
+ final Calendar lTempban = Calendar.getInstance();
+
+ try (Connection con = DatabaseConnection.getConnection();
+ PreparedStatement ps = con.prepareStatement("SELECT `tempban` FROM accounts WHERE id = ?")) {
+ ps.setInt(1, getAccID());
+
+ final Timestamp tempban;
+ try (ResultSet rs = ps.executeQuery()) {
+ if (!rs.next()) {
+ return null;
+ }
+
+ tempban = rs.getTimestamp("tempban");
+ if (tempban.toLocalDateTime().equals(DefaultDates.getTempban())) {
+ return null;
+ }
+ }
+
+ lTempban.setTimeInMillis(tempban.getTime());
+ tempBanCalendar = lTempban;
+ return lTempban;
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+
+ return null;//why oh why!?!
+ }
+
+ public Calendar getTempBanCalendar() {
+ return tempBanCalendar;
+ }
+
+ public boolean hasBeenBanned() {
+ return tempBanCalendar != null;
+ }
+
+ public static long dottedQuadToLong(String dottedQuad) throws RuntimeException {
+ String[] quads = dottedQuad.split("\\.");
+ if (quads.length != 4) {
+ throw new RuntimeException("Invalid IP Address format.");
+ }
+ long ipAddress = 0;
+ for (int i = 0; i < 4; i++) {
+ int quad = Integer.parseInt(quads[i]);
+ ipAddress += (long) (quad % 256) * (long) Math.pow(256, 4 - i);
+ }
+ return ipAddress;
+ }
+
+ public void updateHwid(Hwid hwid) {
+ this.hwid = hwid;
+
+ try (Connection con = DatabaseConnection.getConnection();
+ PreparedStatement ps = con.prepareStatement("UPDATE accounts SET hwid = ? WHERE id = ?")) {
+ ps.setString(1, hwid.hwid());
+ ps.setInt(2, accId);
+ ps.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void updateMacs(String macData) {
+ macs.addAll(Arrays.asList(macData.split(", ")));
+ StringBuilder newMacData = new StringBuilder();
+ Iterator iter = macs.iterator();
+ while (iter.hasNext()) {
+ String cur = iter.next();
+ newMacData.append(cur);
+ if (iter.hasNext()) {
+ newMacData.append(", ");
+ }
+ }
+
+ try (Connection con = DatabaseConnection.getConnection();
+ PreparedStatement ps = con.prepareStatement("UPDATE accounts SET macs = ? WHERE id = ?")) {
+ ps.setString(1, newMacData.toString());
+ ps.setInt(2, accId);
+ ps.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void setAccID(int id) {
+ this.accId = id;
+ }
+
+ public int getAccID() {
+ return accId;
+ }
+
+ public void updateLoginState(int newState) {
+ // rules out possibility of multiple account entries
+ if (newState == LOGIN_LOGGEDIN) {
+ SessionCoordinator.getInstance().updateOnlineClient(this);
+ }
+
+ try (Connection con = DatabaseConnection.getConnection();
+ PreparedStatement ps = con.prepareStatement("UPDATE accounts SET loggedin = ?, lastlogin = ? WHERE id = ?")) {
+ // using sql currenttime here could potentially break the login, thanks Arnah for pointing this out
+
+ ps.setInt(1, newState);
+ ps.setTimestamp(2, new java.sql.Timestamp(Server.getInstance().getCurrentTime()));
+ ps.setInt(3, getAccID());
+ ps.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+
+ if (newState == LOGIN_NOTLOGGEDIN) {
+ loggedIn = false;
+ serverTransition = false;
+ setAccID(0);
+ } else {
+ serverTransition = (newState == LOGIN_SERVER_TRANSITION);
+ loggedIn = !serverTransition;
+ }
+ }
+
+ public int getLoginState() { // 0 = LOGIN_NOTLOGGEDIN, 1= LOGIN_SERVER_TRANSITION, 2 = LOGIN_LOGGEDIN
+ try (Connection con = DatabaseConnection.getConnection()) {
+ int state;
+ try (PreparedStatement ps = con.prepareStatement("SELECT loggedin, lastlogin, birthday FROM accounts WHERE id = ?")) {
+ ps.setInt(1, getAccID());
+
+ try (ResultSet rs = ps.executeQuery()) {
+ if (!rs.next()) {
+ throw new RuntimeException("getLoginState - MapleClient AccID: " + getAccID());
+ }
+
+ birthday = Calendar.getInstance();
+ try {
+ birthday.setTime(rs.getDate("birthday"));
+ } catch (SQLException e) {
+ }
+
+ state = rs.getInt("loggedin");
+ if (state == LOGIN_SERVER_TRANSITION) {
+ if (rs.getTimestamp("lastlogin").getTime() + 30000 < Server.getInstance().getCurrentTime()) {
+ int accountId = accId;
+ state = LOGIN_NOTLOGGEDIN;
+ updateLoginState(MapleClient.LOGIN_NOTLOGGEDIN); // ACCID = 0, issue found thanks to Tochi & K u ssss o & Thora & Omo Oppa
+ this.setAccID(accountId);
+ }
+ }
+ }
+ }
+ if (state == LOGIN_LOGGEDIN) {
+ loggedIn = true;
+ } else if (state == LOGIN_SERVER_TRANSITION) {
+ try (PreparedStatement ps2 = con.prepareStatement("UPDATE accounts SET loggedin = 0 WHERE id = ?")) {
+ ps2.setInt(1, getAccID());
+ ps2.executeUpdate();
+ }
+ } else {
+ loggedIn = false;
+ }
+ return state;
+ } catch (SQLException e) {
+ loggedIn = false;
+ e.printStackTrace();
+ throw new RuntimeException("login state");
+ }
+ }
+
+ public boolean checkBirthDate(Calendar date) {
+ return date.get(Calendar.YEAR) == birthday.get(Calendar.YEAR) && date.get(Calendar.MONTH) == birthday.get(Calendar.MONTH) && date.get(Calendar.DAY_OF_MONTH) == birthday.get(Calendar.DAY_OF_MONTH);
+ }
+
+ private void removePartyPlayer(World wserv) {
+ MapleMap map = player.getMap();
+ final MapleParty party = player.getParty();
+ final int idz = player.getId();
+
+ if (party != null) {
+ final MaplePartyCharacter chrp = new MaplePartyCharacter(player);
+ chrp.setOnline(false);
+ wserv.updateParty(party.getId(), PartyOperation.LOG_ONOFF, chrp);
+ if (party.getLeader().getId() == idz && map != null) {
+ MaplePartyCharacter lchr = null;
+ for (MaplePartyCharacter pchr : party.getMembers()) {
+ if (pchr != null && pchr.getId() != idz && (lchr == null || lchr.getLevel() <= pchr.getLevel()) && map.getCharacterById(pchr.getId()) != null) {
+ lchr = pchr;
+ }
+ }
+ if (lchr != null) {
+ wserv.updateParty(party.getId(), PartyOperation.CHANGE_LEADER, lchr);
+ }
+ }
+ }
+ }
+
+ private void removePlayer(World wserv, boolean serverTransition) {
+ try {
+ player.setDisconnectedFromChannelWorld();
+ player.notifyMapTransferToPartner(-1);
+ player.removeIncomingInvites();
+ player.cancelAllBuffs(true);
+
+ player.closePlayerInteractions();
+ player.closePartySearchInteractions();
+
+ if (!serverTransition) { // thanks MedicOP for detecting an issue with party leader change on changing channels
+ removePartyPlayer(wserv);
+
+ EventInstanceManager eim = player.getEventInstance();
+ if (eim != null) {
+ eim.playerDisconnected(player);
+ }
+
+ if (player.getMonsterCarnival() != null) {
+ player.getMonsterCarnival().playerDisconnected(getPlayer().getId());
+ }
+
+ if (player.getAriantColiseum() != null) {
+ player.getAriantColiseum().playerDisconnected(getPlayer());
+ }
+ }
+
+ if (player.getMap() != null) {
+ int mapId = player.getMapId();
+ player.getMap().removePlayer(player);
+ if (GameConstants.isDojo(mapId)) {
+ this.getChannelServer().freeDojoSectionIfEmpty(mapId);
+ }
+ }
+
+ } catch (final Throwable t) {
+ FilePrinter.printError(FilePrinter.ACCOUNT_STUCK, t);
+ }
+ }
+
+ public final void disconnect(final boolean shutdown, final boolean cashshop) {
+ if (canDisconnect()) {
+ ThreadManager.getInstance().newTask(() -> disconnectInternal(shutdown, cashshop));
+ }
+ }
+
+ public final void forceDisconnect() {
+ if (canDisconnect()) {
+ disconnectInternal(true, false);
+ }
+ }
+
+ private synchronized boolean canDisconnect() {
+ if (disconnecting) {
+ return false;
+ }
+
+ disconnecting = true;
+ return true;
+ }
+
+ private void disconnectInternal(boolean shutdown, boolean cashshop) {//once per MapleClient instance
+ if (player != null && player.isLoggedin() && player.getClient() != null) {
+ final int messengerid = player.getMessenger() == null ? 0 : player.getMessenger().getId();
+ //final int fid = player.getFamilyId();
+ final BuddyList bl = player.getBuddylist();
+ final MapleMessengerCharacter chrm = new MapleMessengerCharacter(player, 0);
+ final MapleGuildCharacter chrg = player.getMGC();
+ final MapleGuild guild = player.getGuild();
+
+ player.cancelMagicDoor();
+
+ final World wserv = getWorldServer(); // obviously wserv is NOT null if this player was online on it
+ try {
+ removePlayer(wserv, this.serverTransition);
+
+ if (!(channel == -1 || shutdown)) {
+ if (!cashshop) {
+ if (!this.serverTransition) { // meaning not changing channels
+ if (messengerid > 0) {
+ wserv.leaveMessenger(messengerid, chrm);
+ }
/*
if (fid > 0) {
final MapleFamily family = worlda.getFamily(fid);
family.
}
*/
-
- player.forfeitExpirableQuests(); //This is for those quests that you have to stay logged in for a certain amount of time
-
- if (guild != null) {
- final Server server = Server.getInstance();
- server.setGuildMemberOnline(player, false, player.getClient().getChannel());
- player.getClient().announce(MaplePacketCreator.showGuildInfo(player));
- }
- if (bl != null) {
- wserv.loggedOff(player.getName(), player.getId(), channel, player.getBuddylist().getBuddyIds());
- }
- }
- } else {
- if (!this.serverTransition) { // if dc inside of cash shop.
- if (bl != null) {
- wserv.loggedOff(player.getName(), player.getId(), channel, player.getBuddylist().getBuddyIds());
- }
- }
- }
- }
- } catch (final Exception e) {
- FilePrinter.printError(FilePrinter.ACCOUNT_STUCK, e);
- } finally {
- if (!this.serverTransition) {
- if(chrg != null) {
- chrg.setCharacter(null);
- }
- wserv.removePlayer(player);
- //getChannelServer().removePlayer(player); already being done
-
- player.saveCooldowns();
- player.cancelAllDebuffs();
- player.saveCharToDB(true);
-
- player.logOff();
- if(YamlConfig.config.server.INSTANT_NAME_CHANGE) player.doPendingNameChange();
- clear();
- } else {
- getChannelServer().removePlayer(player);
- player.saveCooldowns();
- player.cancelAllDebuffs();
- player.saveCharToDB();
- }
- }
- }
- if (!serverTransition && isLoggedIn()) {
- MapleSessionCoordinator.getInstance().closeSession(session, false);
- updateLoginState(MapleClient.LOGIN_NOTLOGGEDIN);
- session.removeAttribute(MapleClient.CLIENT_KEY); // prevents double dcing during login
-
- clear();
- } else {
- if (session.containsAttribute(MapleClient.CLIENT_KEY)) {
- MapleSessionCoordinator.getInstance().closeSession(session, false);
- session.removeAttribute(MapleClient.CLIENT_KEY);
+ player.forfeitExpirableQuests(); //This is for those quests that you have to stay logged in for a certain amount of time
+
+ if (guild != null) {
+ final Server server = Server.getInstance();
+ server.setGuildMemberOnline(player, false, player.getClient().getChannel());
+ player.getClient().announce(MaplePacketCreator.showGuildInfo(player));
+ }
+ if (bl != null) {
+ wserv.loggedOff(player.getName(), player.getId(), channel, player.getBuddylist().getBuddyIds());
+ }
}
-
- if (!Server.getInstance().hasCharacteridInTransition(this)) {
- updateLoginState(MapleClient.LOGIN_NOTLOGGEDIN);
+ } else {
+ if (!this.serverTransition) { // if dc inside of cash shop.
+ if (bl != null) {
+ wserv.loggedOff(player.getName(), player.getId(), channel, player.getBuddylist().getBuddyIds());
+ }
}
-
- engines = null; // thanks Tochi for pointing out a NPE here
+ }
}
- }
+ } catch (final Exception e) {
+ FilePrinter.printError(FilePrinter.ACCOUNT_STUCK, e);
+ } finally {
+ if (!this.serverTransition) {
+ if (chrg != null) {
+ chrg.setCharacter(null);
+ }
+ wserv.removePlayer(player);
+ //getChannelServer().removePlayer(player); already being done
- private void clear() {
- // player hard reference removal thanks to Steve (kaito1410)
- if (this.player != null) {
- this.player.empty(true); // clears schedules and stuff
+ player.saveCooldowns();
+ player.cancelAllDebuffs();
+ player.saveCharToDB(true);
+
+ player.logOff();
+ if (YamlConfig.config.server.INSTANT_NAME_CHANGE) {
+ player.doPendingNameChange();
+ }
+ clear();
+ } else {
+ getChannelServer().removePlayer(player);
+
+ player.saveCooldowns();
+ player.cancelAllDebuffs();
+ player.saveCharToDB();
}
-
- Server.getInstance().unregisterLoginState(this);
-
- this.accountName = null;
- this.macs = null;
- this.hwid = null;
- this.birthday = null;
- this.engines = null;
- this.player = null;
- this.receive = null;
- this.send = null;
- //this.session = null;
- }
-
- public void setCharacterOnSessionTransitionState(int cid) {
- this.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
- session.setAttribute(MapleClient.CLIENT_TRANSITION);
- Server.getInstance().setCharacteridInTransition(this, cid);
- }
-
- public int getChannel() {
- return channel;
- }
-
- public Channel getChannelServer() {
- return Server.getInstance().getChannel(world, channel);
- }
-
- public World getWorldServer() {
- return Server.getInstance().getWorld(world);
- }
-
- public Channel getChannelServer(byte channel) {
- return Server.getInstance().getChannel(world, channel);
- }
-
- public boolean deleteCharacter(int cid, int senderAccId) {
- try {
- MapleCharacter chr = MapleCharacter.loadCharFromDB(cid, this, false);
-
- Integer partyid = chr.getWorldServer().getCharacterPartyid(cid);
- if (partyid != null) {
- this.setPlayer(chr);
-
- MapleParty party = chr.getWorldServer().getParty(partyid);
- chr.setParty(party);
- chr.getMPC();
- chr.leaveParty(); // thanks Vcoc for pointing out deleted characters would still stay in a party
-
- this.setPlayer(null);
- }
-
- return MapleCharacter.deleteCharFromDB(chr, senderAccId);
- } catch(SQLException ex) {
- ex.printStackTrace();
- return false;
- }
- }
-
- public String getAccountName() {
- return accountName;
- }
-
- public void setAccountName(String a) {
- this.accountName = a;
- }
-
- public void setChannel(int channel) {
- this.channel = channel;
- }
-
- public int getWorld() {
- return world;
- }
-
- public void setWorld(int world) {
- this.world = world;
- }
-
- public void pongReceived() {
- lastPong = Server.getInstance().getCurrentTime();
- }
-
- public void testPing(long timeThen) {
- try {
- if (lastPong < timeThen) {
- if (session != null && session.isConnected()) {
- MapleSessionCoordinator.getInstance().closeSession(session, false);
- updateLoginState(MapleClient.LOGIN_NOTLOGGEDIN);
- session.removeAttribute(MapleClient.CLIENT_KEY);
- }
- }
- } catch (NullPointerException e) {
- e.printStackTrace();
- }
- }
-
- public String getHWID() {
- return hwid;
- }
-
- public void setHWID(String hwid) {
- this.hwid = hwid;
- }
-
- public Set getMacs() {
- return Collections.unmodifiableSet(macs);
- }
-
- public int getGMLevel() {
- return gmlevel;
- }
-
- public void setGMLevel(int level) {
- gmlevel = level;
- }
-
- public void setScriptEngine(String name, ScriptEngine e) {
- engines.put(name, e);
- }
-
- public ScriptEngine getScriptEngine(String name) {
- return engines.get(name);
- }
-
- public void removeScriptEngine(String name) {
- engines.remove(name);
- }
-
- public NPCConversationManager getCM() {
- return NPCScriptManager.getInstance().getCM(this);
- }
-
- public QuestActionManager getQM() {
- return QuestScriptManager.getInstance().getQM(this);
- }
-
- public boolean acceptToS() {
- if (accountName == null) {
- return true;
- }
-
- boolean disconnect = false;
- try (Connection con = DatabaseConnection.getConnection()) {
- try (PreparedStatement ps = con.prepareStatement("SELECT `tos` FROM accounts WHERE id = ?")) {
- ps.setInt(1, accId);
-
- try (ResultSet rs = ps.executeQuery()) {
- if (rs.next()) {
- if (rs.getByte("tos") == 1) {
- disconnect = true;
- }
- }
- }
- }
-
- try (PreparedStatement ps = con.prepareStatement("UPDATE accounts SET tos = 1 WHERE id = ?")) {
- ps.setInt(1, accId);
- ps.executeUpdate();
- }
- } catch (SQLException e) {
- e.printStackTrace();
- }
- return disconnect;
- }
-
- public void checkChar(int accid) { /// issue with multiple chars from same account login found by shavit, resinate
- if (!YamlConfig.config.server.USE_CHARACTER_ACCOUNT_CHECK) {
- return;
}
-
- for (World w : Server.getInstance().getWorlds()) {
- for (MapleCharacter chr : w.getPlayerStorage().getAllCharacters()) {
- if (accid == chr.getAccountID()) {
- FilePrinter.print(FilePrinter.EXPLOITS, "Player: " + chr.getName() + " has been removed from " + GameConstants.WORLD_NAMES[w.getId()] + ". Possible Dupe attempt.");
- chr.getClient().forceDisconnect();
- w.getPlayerStorage().removePlayer(chr.getId());
+ }
+
+ SessionCoordinator.getInstance().closeSession(this, false);
+
+ if (!serverTransition && isLoggedIn()) {
+ updateLoginState(MapleClient.LOGIN_NOTLOGGEDIN);
+
+ clear();
+ } else {
+ if (!Server.getInstance().hasCharacteridInTransition(this)) {
+ updateLoginState(MapleClient.LOGIN_NOTLOGGEDIN);
+ }
+
+ engines = null; // thanks Tochi for pointing out a NPE here
+ }
+ }
+
+ private void clear() {
+ // player hard reference removal thanks to Steve (kaito1410)
+ if (this.player != null) {
+ this.player.empty(true); // clears schedules and stuff
+ }
+
+ Server.getInstance().unregisterLoginState(this);
+
+ this.accountName = null;
+ this.macs = null;
+ this.hwid = null;
+ this.birthday = null;
+ this.engines = null;
+ this.player = null;
+ }
+
+ public void setCharacterOnSessionTransitionState(int cid) {
+ this.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
+ this.inTransition = true;
+ Server.getInstance().setCharacteridInTransition(this, cid);
+ }
+
+ public int getChannel() {
+ return channel;
+ }
+
+ public Channel getChannelServer() {
+ return Server.getInstance().getChannel(world, channel);
+ }
+
+ public World getWorldServer() {
+ return Server.getInstance().getWorld(world);
+ }
+
+ public Channel getChannelServer(byte channel) {
+ return Server.getInstance().getChannel(world, channel);
+ }
+
+ public boolean deleteCharacter(int cid, int senderAccId) {
+ try {
+ MapleCharacter chr = MapleCharacter.loadCharFromDB(cid, this, false);
+
+ Integer partyid = chr.getWorldServer().getCharacterPartyid(cid);
+ if (partyid != null) {
+ this.setPlayer(chr);
+
+ MapleParty party = chr.getWorldServer().getParty(partyid);
+ chr.setParty(party);
+ chr.getMPC();
+ chr.leaveParty(); // thanks Vcoc for pointing out deleted characters would still stay in a party
+
+ this.setPlayer(null);
+ }
+
+ return MapleCharacter.deleteCharFromDB(chr, senderAccId);
+ } catch (SQLException ex) {
+ ex.printStackTrace();
+ return false;
+ }
+ }
+
+ public String getAccountName() {
+ return accountName;
+ }
+
+ public void setAccountName(String a) {
+ this.accountName = a;
+ }
+
+ public void setChannel(int channel) {
+ this.channel = channel;
+ }
+
+ public int getWorld() {
+ return world;
+ }
+
+ public void setWorld(int world) {
+ this.world = world;
+ }
+
+ public void pongReceived() {
+ lastPong = System.currentTimeMillis();
+ }
+
+ public void checkIfIdle(final IdleStateEvent event) {
+ final long pingedAt = System.currentTimeMillis();
+ announce(MaplePacketCreator.getPing());
+ TimerManager.getInstance().schedule(() -> {
+ try {
+ if (lastPong < pingedAt) {
+ if (ioChannel.isActive()) {
+ log.info("Disconnected {} due to idling. Reason: {}", remoteAddress, event.state());
+ updateLoginState(MapleClient.LOGIN_NOTLOGGEDIN);
+ disconnectSession();
+ }
+ }
+ } catch (NullPointerException e) {
+ e.printStackTrace();
+ }
+ }, TimeUnit.SECONDS.toMillis(15));
+ }
+
+ public Set getMacs() {
+ return Collections.unmodifiableSet(macs);
+ }
+
+ public int getGMLevel() {
+ return gmlevel;
+ }
+
+ public void setGMLevel(int level) {
+ gmlevel = level;
+ }
+
+ public void setScriptEngine(String name, ScriptEngine e) {
+ engines.put(name, e);
+ }
+
+ public ScriptEngine getScriptEngine(String name) {
+ return engines.get(name);
+ }
+
+ public void removeScriptEngine(String name) {
+ engines.remove(name);
+ }
+
+ public NPCConversationManager getCM() {
+ return NPCScriptManager.getInstance().getCM(this);
+ }
+
+ public QuestActionManager getQM() {
+ return QuestScriptManager.getInstance().getQM(this);
+ }
+
+ public boolean acceptToS() {
+ if (accountName == null) {
+ return true;
+ }
+
+ boolean disconnect = false;
+ try (Connection con = DatabaseConnection.getConnection()) {
+ try (PreparedStatement ps = con.prepareStatement("SELECT `tos` FROM accounts WHERE id = ?")) {
+ ps.setInt(1, accId);
+
+ try (ResultSet rs = ps.executeQuery()) {
+ if (rs.next()) {
+ if (rs.getByte("tos") == 1) {
+ disconnect = true;
+ }
}
}
}
+
+ try (PreparedStatement ps = con.prepareStatement("UPDATE accounts SET tos = 1 WHERE id = ?")) {
+ ps.setInt(1, accId);
+ ps.executeUpdate();
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ return disconnect;
+ }
+
+ public void checkChar(int accid) { /// issue with multiple chars from same account login found by shavit, resinate
+ if (!YamlConfig.config.server.USE_CHARACTER_ACCOUNT_CHECK) {
+ return;
}
- public int getVotePoints() {
- int points = 0;
- try (Connection con = DatabaseConnection.getConnection();
- PreparedStatement ps = con.prepareStatement("SELECT `votepoints` FROM accounts WHERE id = ?")) {
- ps.setInt(1, accId);
-
- try (ResultSet rs = ps.executeQuery()) {
- if (rs.next()) {
- points = rs.getInt("votepoints");
- }
- }
- } catch (SQLException e) {
- e.printStackTrace();
- }
- votePoints = points;
- return votePoints;
- }
-
- public void addVotePoints(int points) {
- votePoints += points;
- saveVotePoints();
- }
-
- public void useVotePoints(int points){
- if (points > votePoints){
- //Should not happen, should probably log this
- return;
- }
- votePoints -= points;
- saveVotePoints();
- LogHelper.logLeaf(player, false, Integer.toString(points));
- }
-
- private void saveVotePoints() {
- try (Connection con = DatabaseConnection.getConnection();
- PreparedStatement ps = con.prepareStatement("UPDATE accounts SET votepoints = ? WHERE id = ?")) {
- ps.setInt(1, votePoints);
- ps.setInt(2, accId);
- ps.executeUpdate();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
-
- public void lockClient() {
- lock.lock();
- }
-
- public void unlockClient() {
- lock.unlock();
- }
-
- public boolean tryacquireClient() {
- if (actionsSemaphore.tryAcquire()) {
- lockClient();
- return true;
- } else {
- return false;
+ for (World w : Server.getInstance().getWorlds()) {
+ for (MapleCharacter chr : w.getPlayerStorage().getAllCharacters()) {
+ if (accid == chr.getAccountID()) {
+ FilePrinter.print(FilePrinter.EXPLOITS, "Player: " + chr.getName() + " has been removed from " + GameConstants.WORLD_NAMES[w.getId()] + ". Possible Dupe attempt.");
+ chr.getClient().forceDisconnect();
+ w.getPlayerStorage().removePlayer(chr.getId());
}
- }
-
- public void releaseClient() {
- unlockClient();
- actionsSemaphore.release();
+ }
}
-
- public boolean tryacquireEncoder() {
- if (actionsSemaphore.tryAcquire()) {
- encoderLock.lock();
- return true;
- } else {
- return false;
+ }
+
+ public int getVotePoints() {
+ int points = 0;
+ try (Connection con = DatabaseConnection.getConnection();
+ PreparedStatement ps = con.prepareStatement("SELECT `votepoints` FROM accounts WHERE id = ?")) {
+ ps.setInt(1, accId);
+
+ try (ResultSet rs = ps.executeQuery()) {
+ if (rs.next()) {
+ points = rs.getInt("votepoints");
}
- }
-
- public void unlockEncoder() {
- encoderLock.unlock();
- actionsSemaphore.release();
- }
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ votePoints = points;
+ return votePoints;
+ }
- private static class CharNameAndId {
+ public void addVotePoints(int points) {
+ votePoints += points;
+ saveVotePoints();
+ }
- public String name;
- public int id;
+ public void useVotePoints(int points) {
+ if (points > votePoints) {
+ //Should not happen, should probably log this
+ return;
+ }
+ votePoints -= points;
+ saveVotePoints();
+ LogHelper.logLeaf(player, false, Integer.toString(points));
+ }
- public CharNameAndId(String name, int id) {
- super();
- this.name = name;
- this.id = id;
- }
- }
+ private void saveVotePoints() {
+ try (Connection con = DatabaseConnection.getConnection();
+ PreparedStatement ps = con.prepareStatement("UPDATE accounts SET votepoints = ? WHERE id = ?")) {
+ ps.setInt(1, votePoints);
+ ps.setInt(2, accId);
+ ps.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
- private static boolean checkHash(String hash, String type, String password) {
- try {
- MessageDigest digester = MessageDigest.getInstance(type);
- digester.update(password.getBytes("UTF-8"), 0, password.length());
- return HexTool.toString(digester.digest()).replace(" ", "").toLowerCase().equals(hash);
- } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
- throw new RuntimeException("Encoding the string failed", e);
- }
- }
+ public void lockClient() {
+ lock.lock();
+ }
+
+ public void unlockClient() {
+ lock.unlock();
+ }
+
+ public boolean tryacquireClient() {
+ if (actionsSemaphore.tryAcquire()) {
+ lockClient();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public void releaseClient() {
+ unlockClient();
+ actionsSemaphore.release();
+ }
+
+ public boolean tryacquireEncoder() {
+ if (actionsSemaphore.tryAcquire()) {
+ encoderLock.lock();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public void unlockEncoder() {
+ encoderLock.unlock();
+ actionsSemaphore.release();
+ }
+
+ private static class CharNameAndId {
+
+ public String name;
+ public int id;
+
+ public CharNameAndId(String name, int id) {
+ super();
+ this.name = name;
+ this.id = id;
+ }
+ }
+
+ private static boolean checkHash(String hash, String type, String password) {
+ try {
+ MessageDigest digester = MessageDigest.getInstance(type);
+ digester.update(password.getBytes(StandardCharsets.UTF_8), 0, password.length());
+ return HexTool.toString(digester.digest()).replace(" ", "").toLowerCase().equals(hash);
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("Encoding the string failed", e);
+ }
+ }
+
+ public short getAvailableCharacterSlots() {
+ return (short) Math.max(0, characterSlots - Server.getInstance().getAccountCharacterCount(accId));
+ }
+
+ public short getAvailableCharacterWorldSlots() {
+ return (short) Math.max(0, characterSlots - Server.getInstance().getAccountWorldCharacterCount(accId, world));
+ }
- public short getAvailableCharacterSlots() {
- return (short) Math.max(0, characterSlots - Server.getInstance().getAccountCharacterCount(accId));
- }
-
- public short getAvailableCharacterWorldSlots() {
- return (short) Math.max(0, characterSlots - Server.getInstance().getAccountWorldCharacterCount(accId, world));
- }
-
public short getAvailableCharacterWorldSlots(int world) {
return (short) Math.max(0, characterSlots - Server.getInstance().getAccountWorldCharacterCount(accId, world));
}
-
- public short getCharacterSlots() {
- return characterSlots;
- }
-
- public void setCharacterSlots(byte slots) {
- characterSlots = slots;
- }
-
- public boolean canGainCharacterSlot() {
- return characterSlots < 15;
- }
- public synchronized boolean gainCharacterSlot() {
- if (canGainCharacterSlot()) {
- try (Connection con = DatabaseConnection.getConnection();
- PreparedStatement ps = con.prepareStatement("UPDATE accounts SET characterslots = ? WHERE id = ?")) {
- ps.setInt(1, this.characterSlots += 1);
- ps.setInt(2, accId);
- ps.executeUpdate();
+ public short getCharacterSlots() {
+ return characterSlots;
+ }
- } catch (SQLException e) {
- e.printStackTrace();
- }
- return true;
- }
- return false;
- }
+ public void setCharacterSlots(byte slots) {
+ characterSlots = slots;
+ }
- public final byte getGReason() {
- try (Connection con = DatabaseConnection.getConnection();
- PreparedStatement ps = con.prepareStatement("SELECT `greason` FROM `accounts` WHERE id = ?")) {
- ps.setInt(1, accId);
+ public boolean canGainCharacterSlot() {
+ return characterSlots < 15;
+ }
- try (ResultSet rs = ps.executeQuery()) {
- if (rs.next()) {
- return rs.getByte("greason");
- }
- }
- } catch (SQLException e) {
- e.printStackTrace();
- }
- return 0;
- }
+ public synchronized boolean gainCharacterSlot() {
+ if (canGainCharacterSlot()) {
+ try (Connection con = DatabaseConnection.getConnection();
+ PreparedStatement ps = con.prepareStatement("UPDATE accounts SET characterslots = ? WHERE id = ?")) {
+ ps.setInt(1, this.characterSlots += 1);
+ ps.setInt(2, accId);
+ ps.executeUpdate();
- public byte getGender() {
- return gender;
- }
-
- public void setGender(byte m) {
- this.gender = m;
-
- try (Connection con = DatabaseConnection.getConnection();
- PreparedStatement ps = con.prepareStatement("UPDATE accounts SET gender = ? WHERE id = ?")) {
- ps.setByte(1, gender);
- ps.setInt(2, accId);
- ps.executeUpdate();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
-
- private void announceDisableServerMessage() {
- if(!this.getWorldServer().registerDisabledServerMessage(player.getId())) {
- announce(MaplePacketCreator.serverMessage(""));
+ } catch (SQLException e) {
+ e.printStackTrace();
}
+ return true;
}
-
- public void announceServerMessage() {
- announce(MaplePacketCreator.serverMessage(this.getChannelServer().getServerMessage()));
- }
-
- public synchronized void announceBossHpBar(MapleMonster mm, final int mobHash, final byte[] packet) {
- long timeNow = System.currentTimeMillis();
- int targetHash = player.getTargetHpBarHash();
-
- if(mobHash != targetHash) {
- if(timeNow - player.getTargetHpBarTime() >= 5 * 1000) {
- // is there a way to INTERRUPT this annoying thread running on the client that drops the boss bar after some time at every attack?
- announceDisableServerMessage();
- announce(packet);
-
- player.setTargetHpBarHash(mobHash);
- player.setTargetHpBarTime(timeNow);
- }
- } else {
- announceDisableServerMessage();
- announce(packet);
-
- player.setTargetHpBarTime(timeNow);
+ return false;
+ }
+
+ public final byte getGReason() {
+ try (Connection con = DatabaseConnection.getConnection();
+ PreparedStatement ps = con.prepareStatement("SELECT `greason` FROM `accounts` WHERE id = ?")) {
+ ps.setInt(1, accId);
+
+ try (ResultSet rs = ps.executeQuery()) {
+ if (rs.next()) {
+ return rs.getByte("greason");
}
- }
-
- public void announce(final byte[] packet) { // thanks GitGud for noticing an opportunity for improvement by overcoming "synchronized announce"
- announcerLock.lock();
- try {
- session.write(packet);
- } finally {
- announcerLock.unlock();
- }
- }
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ return 0;
+ }
- public void announceHint(String msg, int length) {
- announce(MaplePacketCreator.sendHint(msg, length, 10));
- announce(MaplePacketCreator.enableActions());
+ public byte getGender() {
+ return gender;
+ }
+
+ public void setGender(byte m) {
+ this.gender = m;
+
+ try (Connection con = DatabaseConnection.getConnection();
+ PreparedStatement ps = con.prepareStatement("UPDATE accounts SET gender = ? WHERE id = ?")) {
+ ps.setByte(1, gender);
+ ps.setInt(2, accId);
+ ps.executeUpdate();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void announceDisableServerMessage() {
+ if (!this.getWorldServer().registerDisabledServerMessage(player.getId())) {
+ announce(MaplePacketCreator.serverMessage(""));
+ }
+ }
+
+ public void announceServerMessage() {
+ announce(MaplePacketCreator.serverMessage(this.getChannelServer().getServerMessage()));
+ }
+
+ public synchronized void announceBossHpBar(MapleMonster mm, final int mobHash, final byte[] packet) {
+ long timeNow = System.currentTimeMillis();
+ int targetHash = player.getTargetHpBarHash();
+
+ if (mobHash != targetHash) {
+ if (timeNow - player.getTargetHpBarTime() >= 5 * 1000) {
+ // is there a way to INTERRUPT this annoying thread running on the client that drops the boss bar after some time at every attack?
+ announceDisableServerMessage();
+ announce(packet);
+
+ player.setTargetHpBarHash(mobHash);
+ player.setTargetHpBarTime(timeNow);
+ }
+ } else {
+ announceDisableServerMessage();
+ announce(packet);
+
+ player.setTargetHpBarTime(timeNow);
+ }
+ }
+
+ @Deprecated(forRemoval = true, since = "Netty migration")
+ public void announce(final byte[] packet) { // thanks GitGud for noticing an opportunity for improvement by overcoming "synchronized announce"
+ announcerLock.lock();
+ try {
+ // session.write(packet);
+ sendPacket(packet);
+ } finally {
+ announcerLock.unlock();
+ }
+ }
+
+ // Workaround for old packets. All uses of Client#announce(byte[]) should be migrated to Client#sendPacket(OutPacket)
+ private void sendPacket(final byte[] packet) {
+ announcerLock.lock();
+ try {
+ OutPacket outPacket = new ByteBufOutPacket();
+ outPacket.writeBytes(packet);
+
+ ioChannel.writeAndFlush(outPacket);
+ } finally {
+ announcerLock.unlock();
+ }
+ }
+
+ public void sendPacket(OutPacket outPacket) {
+ announcerLock.lock();
+ try {
+ ioChannel.writeAndFlush(outPacket.getBytes());
+ } finally {
+ announcerLock.unlock();
+ }
+ }
+
+ public void announceHint(String msg, int length) {
+ announce(MaplePacketCreator.sendHint(msg, length, 10));
+ announce(MaplePacketCreator.enableActions());
+ }
+
+ public void changeChannel(int channel) {
+ Server server = Server.getInstance();
+ if (player.isBanned()) {
+ disconnect(false, false);
+ return;
+ }
+ if (!player.isAlive() || FieldLimit.CANNOTMIGRATE.check(player.getMap().getFieldLimit())) {
+ announce(MaplePacketCreator.enableActions());
+ return;
+ } else if (MapleMiniDungeonInfo.isDungeonMap(player.getMapId())) {
+ announce(MaplePacketCreator.serverNotice(5, "Changing channels or entering Cash Shop or MTS are disabled when inside a Mini-Dungeon."));
+ announce(MaplePacketCreator.enableActions());
+ return;
}
- public void changeChannel(int channel) {
- Server server = Server.getInstance();
- if (player.isBanned()) {
- disconnect(false, false);
- return;
- }
- if (!player.isAlive() || FieldLimit.CANNOTMIGRATE.check(player.getMap().getFieldLimit())) {
- announce(MaplePacketCreator.enableActions());
- return;
- } else if(MapleMiniDungeonInfo.isDungeonMap(player.getMapId())) {
- announce(MaplePacketCreator.serverNotice(5, "Changing channels or entering Cash Shop or MTS are disabled when inside a Mini-Dungeon."));
- announce(MaplePacketCreator.enableActions());
- return;
- }
-
- String[] socket = Server.getInstance().getInetSocket(this.getSession(), getWorld(), channel);
- if(socket == null) {
- announce(MaplePacketCreator.serverNotice(1, "Channel " + channel + " is currently disabled. Try another channel."));
- announce(MaplePacketCreator.enableActions());
- return;
- }
-
- player.closePlayerInteractions();
- player.closePartySearchInteractions();
-
- player.unregisterChairBuff();
- server.getPlayerBuffStorage().addBuffsToStorage(player.getId(), player.getAllBuffs());
- server.getPlayerBuffStorage().addDiseasesToStorage(player.getId(), player.getAllDiseases());
- player.setDisconnectedFromChannelWorld();
- player.notifyMapTransferToPartner(-1);
- player.removeIncomingInvites();
- player.cancelAllBuffs(true);
- player.cancelAllDebuffs();
- player.cancelBuffExpireTask();
- player.cancelDiseaseExpireTask();
- player.cancelSkillCooldownTask();
- player.cancelQuestExpirationTask();
- //Cancelling magicdoor? Nope
- //Cancelling mounts? Noty
-
- player.getInventory(MapleInventoryType.EQUIPPED).checked(false); //test
- player.getMap().removePlayer(player);
- player.clearBanishPlayerData();
- player.getClient().getChannelServer().removePlayer(player);
-
- player.saveCharToDB();
-
- player.setSessionTransitionState();
- try {
- announce(MaplePacketCreator.getChannelChange(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1])));
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- public long getSessionId() {
- return this.sessionId;
- }
-
- public void setSessionId(long sessionId) {
- this.sessionId = sessionId;
- }
-
- public boolean canRequestCharlist(){
- return lastNpcClick + 877 < Server.getInstance().getCurrentTime();
- }
-
- public boolean canClickNPC(){
- return lastNpcClick + 500 < Server.getInstance().getCurrentTime();
- }
-
- public void setClickedNPC(){
- lastNpcClick = Server.getInstance().getCurrentTime();
- }
-
- public void removeClickedNPC(){
- lastNpcClick = 0;
- }
-
- public int getVisibleWorlds(){
- return visibleWorlds;
- }
-
- public void requestedServerlist(int worlds) {
- visibleWorlds = worlds;
- setClickedNPC();
- }
-
- public void closePlayerScriptInteractions() {
- this.removeClickedNPC();
- NPCScriptManager.getInstance().dispose(this);
- QuestScriptManager.getInstance().dispose(this);
- }
-
- public boolean attemptCsCoupon() {
- if (csattempt > 2) {
- resetCsCoupon();
- return false;
- }
-
- csattempt++;
- return true;
- }
-
- public void resetCsCoupon() {
- csattempt = 0;
- }
-
- public void enableCSActions() {
- announce(MaplePacketCreator.enableCSUse(player));
- }
-
- public String getNibbleHWID() {
- return (String) session.getAttribute(MapleClient.CLIENT_NIBBLEHWID);
- }
-
- public boolean canBypassPin() {
- return MapleLoginBypassCoordinator.getInstance().canLoginBypass(getNibbleHWID(), accId, false);
- }
-
- public boolean canBypassPic() {
- return MapleLoginBypassCoordinator.getInstance().canLoginBypass(getNibbleHWID(), accId, true);
- }
-
- public int getLanguage() {
- return lang;
+ String[] socket = Server.getInstance().getInetSocket(this, getWorld(), channel);
+ if (socket == null) {
+ announce(MaplePacketCreator.serverNotice(1, "Channel " + channel + " is currently disabled. Try another channel."));
+ announce(MaplePacketCreator.enableActions());
+ return;
}
- public void setLanguage(int lingua) {
- this.lang = lingua;
+ player.closePlayerInteractions();
+ player.closePartySearchInteractions();
+
+ player.unregisterChairBuff();
+ server.getPlayerBuffStorage().addBuffsToStorage(player.getId(), player.getAllBuffs());
+ server.getPlayerBuffStorage().addDiseasesToStorage(player.getId(), player.getAllDiseases());
+ player.setDisconnectedFromChannelWorld();
+ player.notifyMapTransferToPartner(-1);
+ player.removeIncomingInvites();
+ player.cancelAllBuffs(true);
+ player.cancelAllDebuffs();
+ player.cancelBuffExpireTask();
+ player.cancelDiseaseExpireTask();
+ player.cancelSkillCooldownTask();
+ player.cancelQuestExpirationTask();
+ //Cancelling magicdoor? Nope
+ //Cancelling mounts? Noty
+
+ player.getInventory(MapleInventoryType.EQUIPPED).checked(false); //test
+ player.getMap().removePlayer(player);
+ player.clearBanishPlayerData();
+ player.getClient().getChannelServer().removePlayer(player);
+
+ player.saveCharToDB();
+
+ player.setSessionTransitionState();
+ try {
+ announce(MaplePacketCreator.getChannelChange(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1])));
+ } catch (IOException e) {
+ e.printStackTrace();
}
+ }
+
+ public long getSessionId() {
+ return this.sessionId;
+ }
+
+ public boolean canRequestCharlist() {
+ return lastNpcClick + 877 < Server.getInstance().getCurrentTime();
+ }
+
+ public boolean canClickNPC() {
+ return lastNpcClick + 500 < Server.getInstance().getCurrentTime();
+ }
+
+ public void setClickedNPC() {
+ lastNpcClick = Server.getInstance().getCurrentTime();
+ }
+
+ public void removeClickedNPC() {
+ lastNpcClick = 0;
+ }
+
+ public int getVisibleWorlds() {
+ return visibleWorlds;
+ }
+
+ public void requestedServerlist(int worlds) {
+ visibleWorlds = worlds;
+ setClickedNPC();
+ }
+
+ public void closePlayerScriptInteractions() {
+ this.removeClickedNPC();
+ NPCScriptManager.getInstance().dispose(this);
+ QuestScriptManager.getInstance().dispose(this);
+ }
+
+ public boolean attemptCsCoupon() {
+ if (csattempt > 2) {
+ resetCsCoupon();
+ return false;
+ }
+
+ csattempt++;
+ return true;
+ }
+
+ public void resetCsCoupon() {
+ csattempt = 0;
+ }
+
+ public void enableCSActions() {
+ announce(MaplePacketCreator.enableCSUse(player));
+ }
+
+ public boolean canBypassPin() {
+ return MapleLoginBypassCoordinator.getInstance().canLoginBypass(hwid, accId, false);
+ }
+
+ public boolean canBypassPic() {
+ return MapleLoginBypassCoordinator.getInstance().canLoginBypass(hwid, accId, true);
+ }
+
+ public int getLanguage() {
+ return lang;
+ }
+
+ public void setLanguage(int lingua) {
+ this.lang = lingua;
+ }
}
\ No newline at end of file
diff --git a/src/main/java/client/autoban/AutobanFactory.java b/src/main/java/client/autoban/AutobanFactory.java
index dbca257ea4..8f65f5463e 100644
--- a/src/main/java/client/autoban/AutobanFactory.java
+++ b/src/main/java/client/autoban/AutobanFactory.java
@@ -26,7 +26,7 @@ import client.MapleCharacter;
import config.YamlConfig;
import net.server.Server;
import tools.FilePrinter;
-import tools.MapleLogger;
+import net.packet.logging.MapleLogger;
import tools.MaplePacketCreator;
/**
diff --git a/src/main/java/client/command/commands/gm0/EnableAuthCommand.java b/src/main/java/client/command/commands/gm0/EnableAuthCommand.java
index 000c6fe54d..97f6ffd366 100644
--- a/src/main/java/client/command/commands/gm0/EnableAuthCommand.java
+++ b/src/main/java/client/command/commands/gm0/EnableAuthCommand.java
@@ -36,7 +36,7 @@ public class EnableAuthCommand extends Command {
public void execute(MapleClient c, String[] params) {
if (c.tryacquireClient()) {
try {
- MapleLoginBypassCoordinator.getInstance().unregisterLoginBypassEntry(c.getNibbleHWID(), c.getAccID());
+ MapleLoginBypassCoordinator.getInstance().unregisterLoginBypassEntry(c.getHwid(), c.getAccID());
} finally {
c.releaseClient();
}
diff --git a/src/main/java/client/command/commands/gm3/BanCommand.java b/src/main/java/client/command/commands/gm3/BanCommand.java
index 21080eb3a8..38a773852b 100644
--- a/src/main/java/client/command/commands/gm3/BanCommand.java
+++ b/src/main/java/client/command/commands/gm3/BanCommand.java
@@ -52,7 +52,7 @@ public class BanCommand extends Command {
MapleCharacter target = c.getChannelServer().getPlayerStorage().getCharacterByName(ign);
if (target != null) {
String readableTargetName = MapleCharacter.makeMapleReadable(target.getName());
- String ip = target.getClient().getSession().getRemoteAddress().toString().split(":")[0];
+ String ip = target.getClient().getRemoteAddress();
//Ban ip
try (Connection con = DatabaseConnection.getConnection()) {
if (ip.matches("/[0-9]{1,3}\\..*")) {
diff --git a/src/main/java/client/command/commands/gm3/IgnoreCommand.java b/src/main/java/client/command/commands/gm3/IgnoreCommand.java
index 4fc0ceb168..226e63c323 100644
--- a/src/main/java/client/command/commands/gm3/IgnoreCommand.java
+++ b/src/main/java/client/command/commands/gm3/IgnoreCommand.java
@@ -27,7 +27,7 @@ import client.MapleCharacter;
import client.MapleClient;
import client.command.Command;
import net.server.Server;
-import tools.MapleLogger;
+import net.packet.logging.MapleLogger;
import tools.MaplePacketCreator;
public class IgnoreCommand extends Command {
diff --git a/src/main/java/client/command/commands/gm3/IgnoredCommand.java b/src/main/java/client/command/commands/gm3/IgnoredCommand.java
index f15617e6dc..daf704699d 100644
--- a/src/main/java/client/command/commands/gm3/IgnoredCommand.java
+++ b/src/main/java/client/command/commands/gm3/IgnoredCommand.java
@@ -26,7 +26,7 @@ package client.command.commands.gm3;
import client.MapleCharacter;
import client.MapleClient;
import client.command.Command;
-import tools.MapleLogger;
+import net.packet.logging.MapleLogger;
public class IgnoredCommand extends Command {
{
diff --git a/src/main/java/client/command/commands/gm3/MonitorCommand.java b/src/main/java/client/command/commands/gm3/MonitorCommand.java
index 89aa250421..0a82ce454b 100644
--- a/src/main/java/client/command/commands/gm3/MonitorCommand.java
+++ b/src/main/java/client/command/commands/gm3/MonitorCommand.java
@@ -27,7 +27,7 @@ import client.MapleCharacter;
import client.MapleClient;
import client.command.Command;
import net.server.Server;
-import tools.MapleLogger;
+import net.packet.logging.MapleLogger;
import tools.MaplePacketCreator;
public class MonitorCommand extends Command {
diff --git a/src/main/java/client/command/commands/gm3/MonitorsCommand.java b/src/main/java/client/command/commands/gm3/MonitorsCommand.java
index 2a72da5ed5..97fd37a9d4 100644
--- a/src/main/java/client/command/commands/gm3/MonitorsCommand.java
+++ b/src/main/java/client/command/commands/gm3/MonitorsCommand.java
@@ -26,7 +26,7 @@ package client.command.commands.gm3;
import client.MapleCharacter;
import client.MapleClient;
import client.command.Command;
-import tools.MapleLogger;
+import net.packet.logging.MapleLogger;
public class MonitorsCommand extends Command {
{
diff --git a/src/main/java/client/command/commands/gm5/IpListCommand.java b/src/main/java/client/command/commands/gm5/IpListCommand.java
index 1a832916b7..c7ae291fbd 100644
--- a/src/main/java/client/command/commands/gm5/IpListCommand.java
+++ b/src/main/java/client/command/commands/gm5/IpListCommand.java
@@ -50,7 +50,7 @@ public class IpListCommand extends Command {
str += "\r\n" + GameConstants.WORLD_NAMES[w.getId()] + "\r\n";
for (MapleCharacter chr : chars) {
- str += " " + chr.getName() + " - " + chr.getClient().getSession().getRemoteAddress() + "\r\n";
+ str += " " + chr.getName() + " - " + chr.getClient().getRemoteAddress() + "\r\n";
}
}
}
diff --git a/src/main/java/client/command/commands/gm5/ShowSessionsCommand.java b/src/main/java/client/command/commands/gm5/ShowSessionsCommand.java
index 40ed9ed114..71d31c9982 100644
--- a/src/main/java/client/command/commands/gm5/ShowSessionsCommand.java
+++ b/src/main/java/client/command/commands/gm5/ShowSessionsCommand.java
@@ -21,7 +21,7 @@ package client.command.commands.gm5;
import client.MapleClient;
import client.command.Command;
-import net.server.coordinator.session.MapleSessionCoordinator;
+import net.server.coordinator.session.SessionCoordinator;
/**
*
@@ -34,6 +34,6 @@ public class ShowSessionsCommand extends Command {
@Override
public void execute(MapleClient c, String[] params) {
- MapleSessionCoordinator.getInstance().printSessionTrace(c);
+ SessionCoordinator.getInstance().printSessionTrace(c);
}
}
diff --git a/src/main/java/client/command/commands/gm6/WarpWorldCommand.java b/src/main/java/client/command/commands/gm6/WarpWorldCommand.java
index 9670f16a87..0512f1f4fc 100644
--- a/src/main/java/client/command/commands/gm6/WarpWorldCommand.java
+++ b/src/main/java/client/command/commands/gm6/WarpWorldCommand.java
@@ -49,7 +49,7 @@ public class WarpWorldCommand extends Command {
byte worldb = Byte.parseByte(params[0]);
if (worldb <= (server.getWorldsSize() - 1)) {
try {
- String[] socket = server.getInetSocket(c.getSession(), worldb, c.getChannel());
+ String[] socket = server.getInetSocket(c, worldb, c.getChannel());
c.getWorldServer().removePlayer(player);
player.getMap().removePlayer(player);//LOL FORGOT THIS ><
player.setSessionTransitionState();
diff --git a/src/main/java/constants/net/ServerConstants.java b/src/main/java/constants/net/ServerConstants.java
index 2905adbccd..9b5f6b1d8b 100644
--- a/src/main/java/constants/net/ServerConstants.java
+++ b/src/main/java/constants/net/ServerConstants.java
@@ -3,7 +3,7 @@ package constants.net;
public class ServerConstants {
//Server Version
- public static short VERSION = 83;
+ public static final short VERSION = 83;
//Debug Variables
public static int[] DEBUG_VALUES = new int[10]; // Field designed for packet testing purposes
diff --git a/src/main/java/net/MapleServerHandler.java b/src/main/java/net/MapleServerHandler.java
deleted file mode 100644
index edca4bfda8..0000000000
--- a/src/main/java/net/MapleServerHandler.java
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
-This file is part of the OdinMS Maple Story Server
-Copyright (C) 2008 Patrick Huy
-Matthias Butz
-Jan Christian Meyer
-
-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 .
- */
-package net;
-
-import client.MapleClient;
-import config.YamlConfig;
-import constants.net.ServerConstants;
-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.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 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 idleSessions = new HashMap<>(100);
- private Map 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 = MapleSessionCoordinator.fetchRemoteAddress(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(session, true);
- return;
- }
-
- if (!isLoginServerHandler()) {
- if (Server.getInstance().getChannel(world, channel) == null) {
- MapleSessionCoordinator.getInstance().closeSession(session, true);
- return;
- }
- } else {
- if (!MapleSessionCoordinator.getInstance().canStartLoginSession(session)) {
- return;
- }
-
- FilePrinter.print(FilePrinter.SESSION, "IoSession with " + session.getRemoteAddress() + " opened on " + sdf.format(Calendar.getInstance().getTime()), false);
- }
-
- byte[] ivRecv = {70, 114, 122, 82};
- byte[] ivSend = {82, 48, 120, 115};
- ivRecv[3] = (byte) (Math.random() * 255);
- ivSend[3] = (byte) (Math.random() * 255);
- MapleAESOFB sendCypher = new MapleAESOFB(ivSend, (short) (0xFFFF - ServerConstants.VERSION));
- MapleAESOFB recvCypher = new MapleAESOFB(ivRecv, ServerConstants.VERSION);
- MapleClient client = new MapleClient(sendCypher, recvCypher, session);
- 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(session);
- } else {
- MapleSessionCoordinator.getInstance().closeSession(session, 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 (!session.containsAttribute(MapleClient.CLIENT_TRANSITION)) {
- 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 pingClients = new HashSet<>();
- idleLock.lock();
- try {
- for(Entry mc : idleSessions.entrySet()) {
- if(timeNow - mc.getValue() >= 15000) {
- pingClients.add(mc.getKey());
- }
- }
- idleSessions.clear();
-
- if(!tempIdleSessions.isEmpty()) {
- tempLock.lock();
- try {
- for(Entry 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();
- }
-}
diff --git a/src/main/java/net/PacketProcessor.java b/src/main/java/net/PacketProcessor.java
index 94e07b5441..487a5c2985 100644
--- a/src/main/java/net/PacketProcessor.java
+++ b/src/main/java/net/PacketProcessor.java
@@ -21,34 +21,16 @@
*/
package net;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
+import net.netty.LoginServer;
import net.opcodes.RecvOpcode;
import net.server.channel.handlers.*;
import net.server.handlers.CustomPacketHandler;
import net.server.handlers.KeepAliveHandler;
import net.server.handlers.LoginRequiringNoOpHandler;
-import net.server.handlers.login.AcceptToSHandler;
-import net.server.handlers.login.AfterLoginHandler;
-import net.server.handlers.login.CharSelectedHandler;
-import net.server.handlers.login.CharSelectedWithPicHandler;
-import net.server.handlers.login.CharlistRequestHandler;
-import net.server.handlers.login.CheckCharNameHandler;
-import net.server.handlers.login.CreateCharHandler;
-import net.server.handlers.login.DeleteCharHandler;
-import net.server.handlers.login.GuestLoginHandler;
-import net.server.handlers.login.LoginPasswordHandler;
-import net.server.handlers.login.RegisterPicHandler;
-import net.server.handlers.login.RegisterPinHandler;
-import net.server.handlers.login.RelogRequestHandler;
-import net.server.handlers.login.ServerStatusRequestHandler;
-import net.server.handlers.login.ServerlistRequestHandler;
-import net.server.handlers.login.SetGenderHandler;
-import net.server.handlers.login.ViewAllCharHandler;
-import net.server.handlers.login.ViewAllCharRegisterPicHandler;
-import net.server.handlers.login.ViewAllCharSelectedHandler;
-import net.server.handlers.login.ViewAllCharSelectedWithPicHandler;
+import net.server.handlers.login.*;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
public final class PacketProcessor {
@@ -65,6 +47,14 @@ public final class PacketProcessor {
handlers = new MaplePacketHandler[maxRecvOp + 1];
}
+ public static PacketProcessor getLoginServerProcessor() {
+ return getProcessor(LoginServer.WORLD_ID, LoginServer.CHANNEL_ID);
+ }
+
+ public static PacketProcessor getChannelServerProcessor(int world, int channel) {
+ return getProcessor(world, channel);
+ }
+
public MaplePacketHandler getHandler(short packetId) {
if (packetId > handlers.length) {
return null;
@@ -86,12 +76,12 @@ public final class PacketProcessor {
}
public synchronized static PacketProcessor getProcessor(int world, int channel) {
- final String lolpair = world + " " + channel;
- PacketProcessor processor = instances.get(lolpair);
+ final String processorId = world + " " + channel;
+ PacketProcessor processor = instances.get(processorId);
if (processor == null) {
processor = new PacketProcessor();
processor.reset(channel);
- instances.put(lolpair, processor);
+ instances.put(processorId, processor);
}
return processor;
}
@@ -99,181 +89,192 @@ public final class PacketProcessor {
public void reset(int channel) {
handlers = new MaplePacketHandler[handlers.length];
- registerHandler(RecvOpcode.PONG, new KeepAliveHandler());
- registerHandler(RecvOpcode.CUSTOM_PACKET, new CustomPacketHandler());
+ registerCommonHandlers();
+
if (channel < 0) {
- //LOGIN HANDLERS
- registerHandler(RecvOpcode.ACCEPT_TOS, new AcceptToSHandler());
- registerHandler(RecvOpcode.AFTER_LOGIN, new AfterLoginHandler());
- registerHandler(RecvOpcode.SERVERLIST_REREQUEST, new ServerlistRequestHandler());
- registerHandler(RecvOpcode.CHARLIST_REQUEST, new CharlistRequestHandler());
- registerHandler(RecvOpcode.CHAR_SELECT, new CharSelectedHandler());
- registerHandler(RecvOpcode.LOGIN_PASSWORD, new LoginPasswordHandler());
- registerHandler(RecvOpcode.RELOG, new RelogRequestHandler());
- registerHandler(RecvOpcode.SERVERLIST_REQUEST, new ServerlistRequestHandler());
- registerHandler(RecvOpcode.SERVERSTATUS_REQUEST, new ServerStatusRequestHandler());
- registerHandler(RecvOpcode.CHECK_CHAR_NAME, new CheckCharNameHandler());
- registerHandler(RecvOpcode.CREATE_CHAR, new CreateCharHandler());
- registerHandler(RecvOpcode.DELETE_CHAR, new DeleteCharHandler());
- registerHandler(RecvOpcode.VIEW_ALL_CHAR, new ViewAllCharHandler());
- registerHandler(RecvOpcode.PICK_ALL_CHAR, new ViewAllCharSelectedHandler());
- registerHandler(RecvOpcode.REGISTER_PIN, new RegisterPinHandler());
- registerHandler(RecvOpcode.GUEST_LOGIN, new GuestLoginHandler());
- registerHandler(RecvOpcode.REGISTER_PIC, new RegisterPicHandler());
- registerHandler(RecvOpcode.CHAR_SELECT_WITH_PIC, new CharSelectedWithPicHandler());
- registerHandler(RecvOpcode.SET_GENDER, new SetGenderHandler());
- registerHandler(RecvOpcode.VIEW_ALL_WITH_PIC, new ViewAllCharSelectedWithPicHandler());
- registerHandler(RecvOpcode.VIEW_ALL_PIC_REGISTER, new ViewAllCharRegisterPicHandler());
+ registerLoginHandlers();
} else {
- //CHANNEL HANDLERS
- registerHandler(RecvOpcode.NAME_TRANSFER, new TransferNameHandler());
- registerHandler(RecvOpcode.CHECK_CHAR_NAME, new TransferNameResultHandler());
- registerHandler(RecvOpcode.WORLD_TRANSFER, new TransferWorldHandler());
- registerHandler(RecvOpcode.CHANGE_CHANNEL, new ChangeChannelHandler());
- registerHandler(RecvOpcode.STRANGE_DATA, LoginRequiringNoOpHandler.getInstance());
- registerHandler(RecvOpcode.GENERAL_CHAT, new GeneralChatHandler());
- registerHandler(RecvOpcode.WHISPER, new WhisperHandler());
- registerHandler(RecvOpcode.NPC_TALK, new NPCTalkHandler());
- registerHandler(RecvOpcode.NPC_TALK_MORE, new NPCMoreTalkHandler());
- registerHandler(RecvOpcode.QUEST_ACTION, new QuestActionHandler());
- registerHandler(RecvOpcode.GRENADE_EFFECT, new GrenadeEffectHandler());
- registerHandler(RecvOpcode.NPC_SHOP, new NPCShopHandler());
- registerHandler(RecvOpcode.ITEM_SORT, new InventoryMergeHandler());
- registerHandler(RecvOpcode.ITEM_MOVE, new ItemMoveHandler());
- registerHandler(RecvOpcode.MESO_DROP, new MesoDropHandler());
- registerHandler(RecvOpcode.PLAYER_LOGGEDIN, new PlayerLoggedinHandler());
- registerHandler(RecvOpcode.CHANGE_MAP, new ChangeMapHandler());
- registerHandler(RecvOpcode.MOVE_LIFE, new MoveLifeHandler());
- registerHandler(RecvOpcode.CLOSE_RANGE_ATTACK, new CloseRangeDamageHandler());
- registerHandler(RecvOpcode.RANGED_ATTACK, new RangedAttackHandler());
- registerHandler(RecvOpcode.MAGIC_ATTACK, new MagicDamageHandler());
- registerHandler(RecvOpcode.TAKE_DAMAGE, new TakeDamageHandler());
- registerHandler(RecvOpcode.MOVE_PLAYER, new MovePlayerHandler());
- registerHandler(RecvOpcode.USE_CASH_ITEM, new UseCashItemHandler());
- registerHandler(RecvOpcode.USE_ITEM, new UseItemHandler());
- registerHandler(RecvOpcode.USE_RETURN_SCROLL, new UseItemHandler());
- registerHandler(RecvOpcode.USE_UPGRADE_SCROLL, new ScrollHandler());
- registerHandler(RecvOpcode.USE_SUMMON_BAG, new UseSummonBagHandler());
- registerHandler(RecvOpcode.FACE_EXPRESSION, new FaceExpressionHandler());
- registerHandler(RecvOpcode.HEAL_OVER_TIME, new HealOvertimeHandler());
- registerHandler(RecvOpcode.ITEM_PICKUP, new ItemPickupHandler());
- registerHandler(RecvOpcode.CHAR_INFO_REQUEST, new CharInfoRequestHandler());
- registerHandler(RecvOpcode.SPECIAL_MOVE, new SpecialMoveHandler());
- registerHandler(RecvOpcode.USE_INNER_PORTAL, new InnerPortalHandler());
- registerHandler(RecvOpcode.CANCEL_BUFF, new CancelBuffHandler());
- registerHandler(RecvOpcode.CANCEL_ITEM_EFFECT, new CancelItemEffectHandler());
- registerHandler(RecvOpcode.PLAYER_INTERACTION, new PlayerInteractionHandler());
- registerHandler(RecvOpcode.RPS_ACTION, new RPSActionHandler());
- registerHandler(RecvOpcode.DISTRIBUTE_AP, new DistributeAPHandler());
- registerHandler(RecvOpcode.DISTRIBUTE_SP, new DistributeSPHandler());
- registerHandler(RecvOpcode.CHANGE_KEYMAP, new KeymapChangeHandler());
- registerHandler(RecvOpcode.CHANGE_MAP_SPECIAL, new ChangeMapSpecialHandler());
- registerHandler(RecvOpcode.STORAGE, new StorageHandler());
- registerHandler(RecvOpcode.GIVE_FAME, new GiveFameHandler());
- registerHandler(RecvOpcode.PARTY_OPERATION, new PartyOperationHandler());
- registerHandler(RecvOpcode.DENY_PARTY_REQUEST, new DenyPartyRequestHandler());
- registerHandler(RecvOpcode.MULTI_CHAT, new MultiChatHandler());
- registerHandler(RecvOpcode.USE_DOOR, new DoorHandler());
- registerHandler(RecvOpcode.ENTER_MTS, new EnterMTSHandler());
- registerHandler(RecvOpcode.ENTER_CASHSHOP, new EnterCashShopHandler());
- registerHandler(RecvOpcode.DAMAGE_SUMMON, new DamageSummonHandler());
- registerHandler(RecvOpcode.MOVE_SUMMON, new MoveSummonHandler());
- registerHandler(RecvOpcode.SUMMON_ATTACK, new SummonDamageHandler());
- registerHandler(RecvOpcode.BUDDYLIST_MODIFY, new BuddylistModifyHandler());
- registerHandler(RecvOpcode.USE_ITEMEFFECT, new UseItemEffectHandler());
- registerHandler(RecvOpcode.USE_CHAIR, new UseChairHandler());
- registerHandler(RecvOpcode.CANCEL_CHAIR, new CancelChairHandler());
- registerHandler(RecvOpcode.DAMAGE_REACTOR, new ReactorHitHandler());
- registerHandler(RecvOpcode.GUILD_OPERATION, new GuildOperationHandler());
- registerHandler(RecvOpcode.DENY_GUILD_REQUEST, new DenyGuildRequestHandler());
- registerHandler(RecvOpcode.BBS_OPERATION, new BBSOperationHandler());
- registerHandler(RecvOpcode.SKILL_EFFECT, new SkillEffectHandler());
- registerHandler(RecvOpcode.MESSENGER, new MessengerHandler());
- registerHandler(RecvOpcode.NPC_ACTION, new NPCAnimationHandler());
- registerHandler(RecvOpcode.CHECK_CASH, new TouchingCashShopHandler());
- registerHandler(RecvOpcode.CASHSHOP_OPERATION, new CashOperationHandler());
- registerHandler(RecvOpcode.COUPON_CODE, new CouponCodeHandler());
- registerHandler(RecvOpcode.SPAWN_PET, new SpawnPetHandler());
- registerHandler(RecvOpcode.MOVE_PET, new MovePetHandler());
- registerHandler(RecvOpcode.PET_CHAT, new PetChatHandler());
- registerHandler(RecvOpcode.PET_COMMAND, new PetCommandHandler());
- registerHandler(RecvOpcode.PET_FOOD, new PetFoodHandler());
- registerHandler(RecvOpcode.PET_LOOT, new PetLootHandler());
- registerHandler(RecvOpcode.AUTO_AGGRO, new AutoAggroHandler());
- registerHandler(RecvOpcode.MONSTER_BOMB, new MonsterBombHandler());
- registerHandler(RecvOpcode.CANCEL_DEBUFF, new CancelDebuffHandler());
- registerHandler(RecvOpcode.USE_SKILL_BOOK, new SkillBookHandler());
- registerHandler(RecvOpcode.SKILL_MACRO, new SkillMacroHandler());
- registerHandler(RecvOpcode.NOTE_ACTION, new NoteActionHandler());
- registerHandler(RecvOpcode.CLOSE_CHALKBOARD, new CloseChalkboardHandler());
- registerHandler(RecvOpcode.USE_MOUNT_FOOD, new UseMountFoodHandler());
- registerHandler(RecvOpcode.MTS_OPERATION, new MTSHandler());
- registerHandler(RecvOpcode.RING_ACTION, new RingActionHandler());
- registerHandler(RecvOpcode.SPOUSE_CHAT, new SpouseChatHandler());
- registerHandler(RecvOpcode.PET_AUTO_POT, new PetAutoPotHandler());
- registerHandler(RecvOpcode.PET_EXCLUDE_ITEMS, new PetExcludeItemsHandler());
- registerHandler(RecvOpcode.OWL_ACTION, new UseOwlOfMinervaHandler());
- registerHandler(RecvOpcode.OWL_WARP, new OwlWarpHandler());
- registerHandler(RecvOpcode.TOUCH_MONSTER_ATTACK, new TouchMonsterDamageHandler());
- registerHandler(RecvOpcode.TROCK_ADD_MAP, new TrockAddMapHandler());
- registerHandler(RecvOpcode.HIRED_MERCHANT_REQUEST, new HiredMerchantRequest());
- registerHandler(RecvOpcode.MOB_BANISH_PLAYER, new MobBanishPlayerHandler());
- registerHandler(RecvOpcode.MOB_DAMAGE_MOB, new MobDamageMobHandler());
- registerHandler(RecvOpcode.REPORT, new ReportHandler());
- registerHandler(RecvOpcode.MONSTER_BOOK_COVER, new MonsterBookCoverHandler());
- registerHandler(RecvOpcode.AUTO_DISTRIBUTE_AP, new AutoAssignHandler());
- registerHandler(RecvOpcode.MAKER_SKILL, new MakerSkillHandler());
- registerHandler(RecvOpcode.OPEN_FAMILY_PEDIGREE, new OpenFamilyPedigreeHandler());
- registerHandler(RecvOpcode.OPEN_FAMILY, new OpenFamilyHandler());
- registerHandler(RecvOpcode.ADD_FAMILY, new FamilyAddHandler());
- registerHandler(RecvOpcode.SEPARATE_FAMILY_BY_SENIOR, new FamilySeparateHandler());
- registerHandler(RecvOpcode.SEPARATE_FAMILY_BY_JUNIOR, new FamilySeparateHandler());
- registerHandler(RecvOpcode.USE_FAMILY, new FamilyUseHandler());
- registerHandler(RecvOpcode.CHANGE_FAMILY_MESSAGE, new FamilyPreceptsHandler());
- registerHandler(RecvOpcode.FAMILY_SUMMON_RESPONSE, new FamilySummonResponseHandler());
- registerHandler(RecvOpcode.USE_HAMMER, new UseHammerHandler());
- registerHandler(RecvOpcode.SCRIPTED_ITEM, new ScriptedItemHandler());
- registerHandler(RecvOpcode.TOUCHING_REACTOR, new TouchReactorHandler());
- registerHandler(RecvOpcode.BEHOLDER, new BeholderHandler());
- registerHandler(RecvOpcode.ADMIN_COMMAND, new AdminCommandHandler());
- registerHandler(RecvOpcode.ADMIN_LOG, new AdminLogHandler());
- registerHandler(RecvOpcode.ALLIANCE_OPERATION, new AllianceOperationHandler());
- registerHandler(RecvOpcode.DENY_ALLIANCE_REQUEST, new DenyAllianceRequestHandler());
- registerHandler(RecvOpcode.USE_SOLOMON_ITEM, new UseSolomonHandler());
- registerHandler(RecvOpcode.USE_GACHA_EXP, new UseGachaExpHandler());
- registerHandler(RecvOpcode.NEW_YEAR_CARD_REQUEST, new NewYearCardHandler());
- registerHandler(RecvOpcode.CASHSHOP_SURPRISE, new CashShopSurpriseHandler());
- registerHandler(RecvOpcode.USE_ITEM_REWARD, new ItemRewardHandler());
- registerHandler(RecvOpcode.USE_REMOTE, new RemoteGachaponHandler());
- registerHandler(RecvOpcode.ACCEPT_FAMILY, new AcceptFamilyHandler());
- registerHandler(RecvOpcode.DUEY_ACTION, new DueyHandler());
- registerHandler(RecvOpcode.USE_DEATHITEM, new UseDeathItemHandler());
- registerHandler(RecvOpcode.PLAYER_MAP_TRANSFER, new PlayerMapTransitionHandler());
- registerHandler(RecvOpcode.USE_MAPLELIFE, new UseMapleLifeHandler());
- registerHandler(RecvOpcode.USE_CATCH_ITEM, new UseCatchItemHandler());
- registerHandler(RecvOpcode.FIELD_DAMAGE_MOB, new FieldDamageMobHandler());
- registerHandler(RecvOpcode.MOB_DAMAGE_MOB_FRIENDLY, new MobDamageMobFriendlyHandler());
- registerHandler(RecvOpcode.PARTY_SEARCH_REGISTER, new PartySearchRegisterHandler());
- registerHandler(RecvOpcode.PARTY_SEARCH_START, new PartySearchStartHandler());
- registerHandler(RecvOpcode.PARTY_SEARCH_UPDATE, new PartySearchUpdateHandler());
- registerHandler(RecvOpcode.ITEM_SORT2, new InventorySortHandler());
- registerHandler(RecvOpcode.LEFT_KNOCKBACK, new LeftKnockbackHandler());
- registerHandler(RecvOpcode.SNOWBALL, new SnowballHandler());
- registerHandler(RecvOpcode.COCONUT, new CoconutHandler());
- registerHandler(RecvOpcode.ARAN_COMBO_COUNTER, new AranComboHandler());
- registerHandler(RecvOpcode.CLICK_GUIDE, new ClickGuideHandler());
- registerHandler(RecvOpcode.FREDRICK_ACTION, new FredrickHandler());
- registerHandler(RecvOpcode.MONSTER_CARNIVAL, new MonsterCarnivalHandler());
- registerHandler(RecvOpcode.REMOTE_STORE, new RemoteStoreHandler());
- registerHandler(RecvOpcode.WEDDING_ACTION, new WeddingHandler());
- registerHandler(RecvOpcode.WEDDING_TALK, new WeddingTalkHandler());
- registerHandler(RecvOpcode.WEDDING_TALK_MORE, new WeddingTalkMoreHandler());
- registerHandler(RecvOpcode.WATER_OF_LIFE, new UseWaterOfLifeHandler());
- registerHandler(RecvOpcode.ADMIN_CHAT, new AdminChatHandler());
- registerHandler(RecvOpcode.MOVE_DRAGON, new MoveDragonHandler());
- registerHandler(RecvOpcode.OPEN_ITEMUI, new RaiseUIStateHandler());
- registerHandler(RecvOpcode.USE_ITEMUI, new RaiseIncExpHandler());
- registerHandler(RecvOpcode.CHANGE_QUICKSLOT, new QuickslotKeyMappedModifiedHandler());
+ registerChannelHandlers();
}
}
+
+ private void registerCommonHandlers() {
+ registerHandler(RecvOpcode.PONG, new KeepAliveHandler());
+ registerHandler(RecvOpcode.CUSTOM_PACKET, new CustomPacketHandler());
+ }
+
+ private void registerLoginHandlers() {
+ registerHandler(RecvOpcode.ACCEPT_TOS, new AcceptToSHandler());
+ registerHandler(RecvOpcode.AFTER_LOGIN, new AfterLoginHandler());
+ registerHandler(RecvOpcode.SERVERLIST_REREQUEST, new ServerlistRequestHandler());
+ registerHandler(RecvOpcode.CHARLIST_REQUEST, new CharlistRequestHandler());
+ registerHandler(RecvOpcode.CHAR_SELECT, new CharSelectedHandler());
+ registerHandler(RecvOpcode.LOGIN_PASSWORD, new LoginPasswordHandler());
+ registerHandler(RecvOpcode.RELOG, new RelogRequestHandler());
+ registerHandler(RecvOpcode.SERVERLIST_REQUEST, new ServerlistRequestHandler());
+ registerHandler(RecvOpcode.SERVERSTATUS_REQUEST, new ServerStatusRequestHandler());
+ registerHandler(RecvOpcode.CHECK_CHAR_NAME, new CheckCharNameHandler());
+ registerHandler(RecvOpcode.CREATE_CHAR, new CreateCharHandler());
+ registerHandler(RecvOpcode.DELETE_CHAR, new DeleteCharHandler());
+ registerHandler(RecvOpcode.VIEW_ALL_CHAR, new ViewAllCharHandler());
+ registerHandler(RecvOpcode.PICK_ALL_CHAR, new ViewAllCharSelectedHandler());
+ registerHandler(RecvOpcode.REGISTER_PIN, new RegisterPinHandler());
+ registerHandler(RecvOpcode.GUEST_LOGIN, new GuestLoginHandler());
+ registerHandler(RecvOpcode.REGISTER_PIC, new RegisterPicHandler());
+ registerHandler(RecvOpcode.CHAR_SELECT_WITH_PIC, new CharSelectedWithPicHandler());
+ registerHandler(RecvOpcode.SET_GENDER, new SetGenderHandler());
+ registerHandler(RecvOpcode.VIEW_ALL_WITH_PIC, new ViewAllCharSelectedWithPicHandler());
+ registerHandler(RecvOpcode.VIEW_ALL_PIC_REGISTER, new ViewAllCharRegisterPicHandler());
+ }
+
+ private void registerChannelHandlers() {
+ registerHandler(RecvOpcode.NAME_TRANSFER, new TransferNameHandler());
+ registerHandler(RecvOpcode.CHECK_CHAR_NAME, new TransferNameResultHandler());
+ registerHandler(RecvOpcode.WORLD_TRANSFER, new TransferWorldHandler());
+ registerHandler(RecvOpcode.CHANGE_CHANNEL, new ChangeChannelHandler());
+ registerHandler(RecvOpcode.STRANGE_DATA, LoginRequiringNoOpHandler.getInstance());
+ registerHandler(RecvOpcode.GENERAL_CHAT, new GeneralChatHandler());
+ registerHandler(RecvOpcode.WHISPER, new WhisperHandler());
+ registerHandler(RecvOpcode.NPC_TALK, new NPCTalkHandler());
+ registerHandler(RecvOpcode.NPC_TALK_MORE, new NPCMoreTalkHandler());
+ registerHandler(RecvOpcode.QUEST_ACTION, new QuestActionHandler());
+ registerHandler(RecvOpcode.GRENADE_EFFECT, new GrenadeEffectHandler());
+ registerHandler(RecvOpcode.NPC_SHOP, new NPCShopHandler());
+ registerHandler(RecvOpcode.ITEM_SORT, new InventoryMergeHandler());
+ registerHandler(RecvOpcode.ITEM_MOVE, new ItemMoveHandler());
+ registerHandler(RecvOpcode.MESO_DROP, new MesoDropHandler());
+ registerHandler(RecvOpcode.PLAYER_LOGGEDIN, new PlayerLoggedinHandler());
+ registerHandler(RecvOpcode.CHANGE_MAP, new ChangeMapHandler());
+ registerHandler(RecvOpcode.MOVE_LIFE, new MoveLifeHandler());
+ registerHandler(RecvOpcode.CLOSE_RANGE_ATTACK, new CloseRangeDamageHandler());
+ registerHandler(RecvOpcode.RANGED_ATTACK, new RangedAttackHandler());
+ registerHandler(RecvOpcode.MAGIC_ATTACK, new MagicDamageHandler());
+ registerHandler(RecvOpcode.TAKE_DAMAGE, new TakeDamageHandler());
+ registerHandler(RecvOpcode.MOVE_PLAYER, new MovePlayerHandler());
+ registerHandler(RecvOpcode.USE_CASH_ITEM, new UseCashItemHandler());
+ registerHandler(RecvOpcode.USE_ITEM, new UseItemHandler());
+ registerHandler(RecvOpcode.USE_RETURN_SCROLL, new UseItemHandler());
+ registerHandler(RecvOpcode.USE_UPGRADE_SCROLL, new ScrollHandler());
+ registerHandler(RecvOpcode.USE_SUMMON_BAG, new UseSummonBagHandler());
+ registerHandler(RecvOpcode.FACE_EXPRESSION, new FaceExpressionHandler());
+ registerHandler(RecvOpcode.HEAL_OVER_TIME, new HealOvertimeHandler());
+ registerHandler(RecvOpcode.ITEM_PICKUP, new ItemPickupHandler());
+ registerHandler(RecvOpcode.CHAR_INFO_REQUEST, new CharInfoRequestHandler());
+ registerHandler(RecvOpcode.SPECIAL_MOVE, new SpecialMoveHandler());
+ registerHandler(RecvOpcode.USE_INNER_PORTAL, new InnerPortalHandler());
+ registerHandler(RecvOpcode.CANCEL_BUFF, new CancelBuffHandler());
+ registerHandler(RecvOpcode.CANCEL_ITEM_EFFECT, new CancelItemEffectHandler());
+ registerHandler(RecvOpcode.PLAYER_INTERACTION, new PlayerInteractionHandler());
+ registerHandler(RecvOpcode.RPS_ACTION, new RPSActionHandler());
+ registerHandler(RecvOpcode.DISTRIBUTE_AP, new DistributeAPHandler());
+ registerHandler(RecvOpcode.DISTRIBUTE_SP, new DistributeSPHandler());
+ registerHandler(RecvOpcode.CHANGE_KEYMAP, new KeymapChangeHandler());
+ registerHandler(RecvOpcode.CHANGE_MAP_SPECIAL, new ChangeMapSpecialHandler());
+ registerHandler(RecvOpcode.STORAGE, new StorageHandler());
+ registerHandler(RecvOpcode.GIVE_FAME, new GiveFameHandler());
+ registerHandler(RecvOpcode.PARTY_OPERATION, new PartyOperationHandler());
+ registerHandler(RecvOpcode.DENY_PARTY_REQUEST, new DenyPartyRequestHandler());
+ registerHandler(RecvOpcode.MULTI_CHAT, new MultiChatHandler());
+ registerHandler(RecvOpcode.USE_DOOR, new DoorHandler());
+ registerHandler(RecvOpcode.ENTER_MTS, new EnterMTSHandler());
+ registerHandler(RecvOpcode.ENTER_CASHSHOP, new EnterCashShopHandler());
+ registerHandler(RecvOpcode.DAMAGE_SUMMON, new DamageSummonHandler());
+ registerHandler(RecvOpcode.MOVE_SUMMON, new MoveSummonHandler());
+ registerHandler(RecvOpcode.SUMMON_ATTACK, new SummonDamageHandler());
+ registerHandler(RecvOpcode.BUDDYLIST_MODIFY, new BuddylistModifyHandler());
+ registerHandler(RecvOpcode.USE_ITEMEFFECT, new UseItemEffectHandler());
+ registerHandler(RecvOpcode.USE_CHAIR, new UseChairHandler());
+ registerHandler(RecvOpcode.CANCEL_CHAIR, new CancelChairHandler());
+ registerHandler(RecvOpcode.DAMAGE_REACTOR, new ReactorHitHandler());
+ registerHandler(RecvOpcode.GUILD_OPERATION, new GuildOperationHandler());
+ registerHandler(RecvOpcode.DENY_GUILD_REQUEST, new DenyGuildRequestHandler());
+ registerHandler(RecvOpcode.BBS_OPERATION, new BBSOperationHandler());
+ registerHandler(RecvOpcode.SKILL_EFFECT, new SkillEffectHandler());
+ registerHandler(RecvOpcode.MESSENGER, new MessengerHandler());
+ registerHandler(RecvOpcode.NPC_ACTION, new NPCAnimationHandler());
+ registerHandler(RecvOpcode.CHECK_CASH, new TouchingCashShopHandler());
+ registerHandler(RecvOpcode.CASHSHOP_OPERATION, new CashOperationHandler());
+ registerHandler(RecvOpcode.COUPON_CODE, new CouponCodeHandler());
+ registerHandler(RecvOpcode.SPAWN_PET, new SpawnPetHandler());
+ registerHandler(RecvOpcode.MOVE_PET, new MovePetHandler());
+ registerHandler(RecvOpcode.PET_CHAT, new PetChatHandler());
+ registerHandler(RecvOpcode.PET_COMMAND, new PetCommandHandler());
+ registerHandler(RecvOpcode.PET_FOOD, new PetFoodHandler());
+ registerHandler(RecvOpcode.PET_LOOT, new PetLootHandler());
+ registerHandler(RecvOpcode.AUTO_AGGRO, new AutoAggroHandler());
+ registerHandler(RecvOpcode.MONSTER_BOMB, new MonsterBombHandler());
+ registerHandler(RecvOpcode.CANCEL_DEBUFF, new CancelDebuffHandler());
+ registerHandler(RecvOpcode.USE_SKILL_BOOK, new SkillBookHandler());
+ registerHandler(RecvOpcode.SKILL_MACRO, new SkillMacroHandler());
+ registerHandler(RecvOpcode.NOTE_ACTION, new NoteActionHandler());
+ registerHandler(RecvOpcode.CLOSE_CHALKBOARD, new CloseChalkboardHandler());
+ registerHandler(RecvOpcode.USE_MOUNT_FOOD, new UseMountFoodHandler());
+ registerHandler(RecvOpcode.MTS_OPERATION, new MTSHandler());
+ registerHandler(RecvOpcode.RING_ACTION, new RingActionHandler());
+ registerHandler(RecvOpcode.SPOUSE_CHAT, new SpouseChatHandler());
+ registerHandler(RecvOpcode.PET_AUTO_POT, new PetAutoPotHandler());
+ registerHandler(RecvOpcode.PET_EXCLUDE_ITEMS, new PetExcludeItemsHandler());
+ registerHandler(RecvOpcode.OWL_ACTION, new UseOwlOfMinervaHandler());
+ registerHandler(RecvOpcode.OWL_WARP, new OwlWarpHandler());
+ registerHandler(RecvOpcode.TOUCH_MONSTER_ATTACK, new TouchMonsterDamageHandler());
+ registerHandler(RecvOpcode.TROCK_ADD_MAP, new TrockAddMapHandler());
+ registerHandler(RecvOpcode.HIRED_MERCHANT_REQUEST, new HiredMerchantRequest());
+ registerHandler(RecvOpcode.MOB_BANISH_PLAYER, new MobBanishPlayerHandler());
+ registerHandler(RecvOpcode.MOB_DAMAGE_MOB, new MobDamageMobHandler());
+ registerHandler(RecvOpcode.REPORT, new ReportHandler());
+ registerHandler(RecvOpcode.MONSTER_BOOK_COVER, new MonsterBookCoverHandler());
+ registerHandler(RecvOpcode.AUTO_DISTRIBUTE_AP, new AutoAssignHandler());
+ registerHandler(RecvOpcode.MAKER_SKILL, new MakerSkillHandler());
+ registerHandler(RecvOpcode.OPEN_FAMILY_PEDIGREE, new OpenFamilyPedigreeHandler());
+ registerHandler(RecvOpcode.OPEN_FAMILY, new OpenFamilyHandler());
+ registerHandler(RecvOpcode.ADD_FAMILY, new FamilyAddHandler());
+ registerHandler(RecvOpcode.SEPARATE_FAMILY_BY_SENIOR, new FamilySeparateHandler());
+ registerHandler(RecvOpcode.SEPARATE_FAMILY_BY_JUNIOR, new FamilySeparateHandler());
+ registerHandler(RecvOpcode.USE_FAMILY, new FamilyUseHandler());
+ registerHandler(RecvOpcode.CHANGE_FAMILY_MESSAGE, new FamilyPreceptsHandler());
+ registerHandler(RecvOpcode.FAMILY_SUMMON_RESPONSE, new FamilySummonResponseHandler());
+ registerHandler(RecvOpcode.USE_HAMMER, new UseHammerHandler());
+ registerHandler(RecvOpcode.SCRIPTED_ITEM, new ScriptedItemHandler());
+ registerHandler(RecvOpcode.TOUCHING_REACTOR, new TouchReactorHandler());
+ registerHandler(RecvOpcode.BEHOLDER, new BeholderHandler());
+ registerHandler(RecvOpcode.ADMIN_COMMAND, new AdminCommandHandler());
+ registerHandler(RecvOpcode.ADMIN_LOG, new AdminLogHandler());
+ registerHandler(RecvOpcode.ALLIANCE_OPERATION, new AllianceOperationHandler());
+ registerHandler(RecvOpcode.DENY_ALLIANCE_REQUEST, new DenyAllianceRequestHandler());
+ registerHandler(RecvOpcode.USE_SOLOMON_ITEM, new UseSolomonHandler());
+ registerHandler(RecvOpcode.USE_GACHA_EXP, new UseGachaExpHandler());
+ registerHandler(RecvOpcode.NEW_YEAR_CARD_REQUEST, new NewYearCardHandler());
+ registerHandler(RecvOpcode.CASHSHOP_SURPRISE, new CashShopSurpriseHandler());
+ registerHandler(RecvOpcode.USE_ITEM_REWARD, new ItemRewardHandler());
+ registerHandler(RecvOpcode.USE_REMOTE, new RemoteGachaponHandler());
+ registerHandler(RecvOpcode.ACCEPT_FAMILY, new AcceptFamilyHandler());
+ registerHandler(RecvOpcode.DUEY_ACTION, new DueyHandler());
+ registerHandler(RecvOpcode.USE_DEATHITEM, new UseDeathItemHandler());
+ registerHandler(RecvOpcode.PLAYER_MAP_TRANSFER, new PlayerMapTransitionHandler());
+ registerHandler(RecvOpcode.USE_MAPLELIFE, new UseMapleLifeHandler());
+ registerHandler(RecvOpcode.USE_CATCH_ITEM, new UseCatchItemHandler());
+ registerHandler(RecvOpcode.FIELD_DAMAGE_MOB, new FieldDamageMobHandler());
+ registerHandler(RecvOpcode.MOB_DAMAGE_MOB_FRIENDLY, new MobDamageMobFriendlyHandler());
+ registerHandler(RecvOpcode.PARTY_SEARCH_REGISTER, new PartySearchRegisterHandler());
+ registerHandler(RecvOpcode.PARTY_SEARCH_START, new PartySearchStartHandler());
+ registerHandler(RecvOpcode.PARTY_SEARCH_UPDATE, new PartySearchUpdateHandler());
+ registerHandler(RecvOpcode.ITEM_SORT2, new InventorySortHandler());
+ registerHandler(RecvOpcode.LEFT_KNOCKBACK, new LeftKnockbackHandler());
+ registerHandler(RecvOpcode.SNOWBALL, new SnowballHandler());
+ registerHandler(RecvOpcode.COCONUT, new CoconutHandler());
+ registerHandler(RecvOpcode.ARAN_COMBO_COUNTER, new AranComboHandler());
+ registerHandler(RecvOpcode.CLICK_GUIDE, new ClickGuideHandler());
+ registerHandler(RecvOpcode.FREDRICK_ACTION, new FredrickHandler());
+ registerHandler(RecvOpcode.MONSTER_CARNIVAL, new MonsterCarnivalHandler());
+ registerHandler(RecvOpcode.REMOTE_STORE, new RemoteStoreHandler());
+ registerHandler(RecvOpcode.WEDDING_ACTION, new WeddingHandler());
+ registerHandler(RecvOpcode.WEDDING_TALK, new WeddingTalkHandler());
+ registerHandler(RecvOpcode.WEDDING_TALK_MORE, new WeddingTalkMoreHandler());
+ registerHandler(RecvOpcode.WATER_OF_LIFE, new UseWaterOfLifeHandler());
+ registerHandler(RecvOpcode.ADMIN_CHAT, new AdminChatHandler());
+ registerHandler(RecvOpcode.MOVE_DRAGON, new MoveDragonHandler());
+ registerHandler(RecvOpcode.OPEN_ITEMUI, new RaiseUIStateHandler());
+ registerHandler(RecvOpcode.USE_ITEMUI, new RaiseIncExpHandler());
+ registerHandler(RecvOpcode.CHANGE_QUICKSLOT, new QuickslotKeyMappedModifiedHandler());
+ }
}
\ No newline at end of file
diff --git a/src/main/java/net/encryption/ClientCyphers.java b/src/main/java/net/encryption/ClientCyphers.java
new file mode 100644
index 0000000000..13c09292dd
--- /dev/null
+++ b/src/main/java/net/encryption/ClientCyphers.java
@@ -0,0 +1,27 @@
+package net.encryption;
+
+import constants.net.ServerConstants;
+
+public class ClientCyphers {
+ private final MapleAESOFB send;
+ private final MapleAESOFB receive;
+
+ private ClientCyphers(MapleAESOFB send, MapleAESOFB receive) {
+ this.send = send;
+ this.receive = receive;
+ }
+
+ public static ClientCyphers of(InitializationVector sendIv, InitializationVector receiveIv) {
+ MapleAESOFB send = new MapleAESOFB(sendIv, (short) (0xFFFF - ServerConstants.VERSION));
+ MapleAESOFB receive = new MapleAESOFB(receiveIv, ServerConstants.VERSION);
+ return new ClientCyphers(send, receive);
+ }
+
+ public MapleAESOFB getSendCypher() {
+ return send;
+ }
+
+ public MapleAESOFB getReceiveCypher() {
+ return receive;
+ }
+}
diff --git a/src/main/java/net/encryption/InitializationVector.java b/src/main/java/net/encryption/InitializationVector.java
new file mode 100644
index 0000000000..fb5edaa7b5
--- /dev/null
+++ b/src/main/java/net/encryption/InitializationVector.java
@@ -0,0 +1,27 @@
+package net.encryption;
+
+public class InitializationVector {
+ private final byte[] bytes;
+
+ private InitializationVector(byte[] bytes) {
+ this.bytes = bytes;
+ }
+
+ public byte[] getBytes() {
+ return bytes;
+ }
+
+ public static InitializationVector generateSend() {
+ byte[] ivSend = {82, 48, 120, getRandomByte()};
+ return new InitializationVector(ivSend);
+ }
+
+ public static InitializationVector generateReceive() {
+ byte[] ivRecv = {70, 114, 122, getRandomByte()};
+ return new InitializationVector(ivRecv);
+ }
+
+ private static byte getRandomByte() {
+ return (byte) (Math.random() * 255);
+ }
+}
diff --git a/src/main/java/tools/MapleAESOFB.java b/src/main/java/net/encryption/MapleAESOFB.java
similarity index 50%
rename from src/main/java/tools/MapleAESOFB.java
rename to src/main/java/net/encryption/MapleAESOFB.java
index 7ccfc16ac2..96ab7d52bb 100644
--- a/src/main/java/tools/MapleAESOFB.java
+++ b/src/main/java/net/encryption/MapleAESOFB.java
@@ -19,7 +19,11 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
-package tools;
+package net.encryption;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import tools.HexTool;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
@@ -30,52 +34,73 @@ import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
public class MapleAESOFB {
- private byte[] iv;
- private Cipher cipher;
- private short mapleVersion;
+ private static final Logger log = LoggerFactory.getLogger(MapleAESOFB.class);
private final static SecretKeySpec skey = new SecretKeySpec(
- new byte[]{0x13, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, (byte) 0xB4, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00}, "AES");
+ new byte[]{
+ 0x13, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00,
+ (byte) 0xB4, 0x00, 0x00, 0x00,
+ 0x1B, 0x00, 0x00, 0x00,
+ 0x0F, 0x00, 0x00, 0x00,
+ 0x33, 0x00, 0x00, 0x00,
+ 0x52, 0x00, 0x00, 0x00}, "AES");
- private static final byte[] funnyBytes = new byte[]{(byte) 0xEC, (byte) 0x3F, (byte) 0x77, (byte) 0xA4, (byte) 0x45, (byte) 0xD0, (byte) 0x71, (byte) 0xBF, (byte) 0xB7, (byte) 0x98, (byte) 0x20, (byte) 0xFC,
- (byte) 0x4B, (byte) 0xE9, (byte) 0xB3, (byte) 0xE1, (byte) 0x5C, (byte) 0x22, (byte) 0xF7, (byte) 0x0C, (byte) 0x44, (byte) 0x1B, (byte) 0x81, (byte) 0xBD, (byte) 0x63, (byte) 0x8D, (byte) 0xD4, (byte) 0xC3,
- (byte) 0xF2, (byte) 0x10, (byte) 0x19, (byte) 0xE0, (byte) 0xFB, (byte) 0xA1, (byte) 0x6E, (byte) 0x66, (byte) 0xEA, (byte) 0xAE, (byte) 0xD6, (byte) 0xCE, (byte) 0x06, (byte) 0x18, (byte) 0x4E, (byte) 0xEB,
- (byte) 0x78, (byte) 0x95, (byte) 0xDB, (byte) 0xBA, (byte) 0xB6, (byte) 0x42, (byte) 0x7A, (byte) 0x2A, (byte) 0x83, (byte) 0x0B, (byte) 0x54, (byte) 0x67, (byte) 0x6D, (byte) 0xE8, (byte) 0x65, (byte) 0xE7,
- (byte) 0x2F, (byte) 0x07, (byte) 0xF3, (byte) 0xAA, (byte) 0x27, (byte) 0x7B, (byte) 0x85, (byte) 0xB0, (byte) 0x26, (byte) 0xFD, (byte) 0x8B, (byte) 0xA9, (byte) 0xFA, (byte) 0xBE, (byte) 0xA8, (byte) 0xD7,
- (byte) 0xCB, (byte) 0xCC, (byte) 0x92, (byte) 0xDA, (byte) 0xF9, (byte) 0x93, (byte) 0x60, (byte) 0x2D, (byte) 0xDD, (byte) 0xD2, (byte) 0xA2, (byte) 0x9B, (byte) 0x39, (byte) 0x5F, (byte) 0x82, (byte) 0x21,
- (byte) 0x4C, (byte) 0x69, (byte) 0xF8, (byte) 0x31, (byte) 0x87, (byte) 0xEE, (byte) 0x8E, (byte) 0xAD, (byte) 0x8C, (byte) 0x6A, (byte) 0xBC, (byte) 0xB5, (byte) 0x6B, (byte) 0x59, (byte) 0x13, (byte) 0xF1,
- (byte) 0x04, (byte) 0x00, (byte) 0xF6, (byte) 0x5A, (byte) 0x35, (byte) 0x79, (byte) 0x48, (byte) 0x8F, (byte) 0x15, (byte) 0xCD, (byte) 0x97, (byte) 0x57, (byte) 0x12, (byte) 0x3E, (byte) 0x37, (byte) 0xFF,
- (byte) 0x9D, (byte) 0x4F, (byte) 0x51, (byte) 0xF5, (byte) 0xA3, (byte) 0x70, (byte) 0xBB, (byte) 0x14, (byte) 0x75, (byte) 0xC2, (byte) 0xB8, (byte) 0x72, (byte) 0xC0, (byte) 0xED, (byte) 0x7D, (byte) 0x68,
- (byte) 0xC9, (byte) 0x2E, (byte) 0x0D, (byte) 0x62, (byte) 0x46, (byte) 0x17, (byte) 0x11, (byte) 0x4D, (byte) 0x6C, (byte) 0xC4, (byte) 0x7E, (byte) 0x53, (byte) 0xC1, (byte) 0x25, (byte) 0xC7, (byte) 0x9A,
- (byte) 0x1C, (byte) 0x88, (byte) 0x58, (byte) 0x2C, (byte) 0x89, (byte) 0xDC, (byte) 0x02, (byte) 0x64, (byte) 0x40, (byte) 0x01, (byte) 0x5D, (byte) 0x38, (byte) 0xA5, (byte) 0xE2, (byte) 0xAF, (byte) 0x55,
- (byte) 0xD5, (byte) 0xEF, (byte) 0x1A, (byte) 0x7C, (byte) 0xA7, (byte) 0x5B, (byte) 0xA6, (byte) 0x6F, (byte) 0x86, (byte) 0x9F, (byte) 0x73, (byte) 0xE6, (byte) 0x0A, (byte) 0xDE, (byte) 0x2B, (byte) 0x99,
- (byte) 0x4A, (byte) 0x47, (byte) 0x9C, (byte) 0xDF, (byte) 0x09, (byte) 0x76, (byte) 0x9E, (byte) 0x30, (byte) 0x0E, (byte) 0xE4, (byte) 0xB2, (byte) 0x94, (byte) 0xA0, (byte) 0x3B, (byte) 0x34, (byte) 0x1D,
- (byte) 0x28, (byte) 0x0F, (byte) 0x36, (byte) 0xE3, (byte) 0x23, (byte) 0xB4, (byte) 0x03, (byte) 0xD8, (byte) 0x90, (byte) 0xC8, (byte) 0x3C, (byte) 0xFE, (byte) 0x5E, (byte) 0x32, (byte) 0x24, (byte) 0x50,
- (byte) 0x1F, (byte) 0x3A, (byte) 0x43, (byte) 0x8A, (byte) 0x96, (byte) 0x41, (byte) 0x74, (byte) 0xAC, (byte) 0x52, (byte) 0x33, (byte) 0xF0, (byte) 0xD9, (byte) 0x29, (byte) 0x80, (byte) 0xB1, (byte) 0x16,
- (byte) 0xD3, (byte) 0xAB, (byte) 0x91, (byte) 0xB9, (byte) 0x84, (byte) 0x7F, (byte) 0x61, (byte) 0x1E, (byte) 0xCF, (byte) 0xC5, (byte) 0xD1, (byte) 0x56, (byte) 0x3D, (byte) 0xCA, (byte) 0xF4, (byte) 0x05,
- (byte) 0xC6, (byte) 0xE5, (byte) 0x08, (byte) 0x49};
+ private static final byte[] funnyBytes = new byte[]{
+ (byte) 0xEC, (byte) 0x3F, (byte) 0x77, (byte) 0xA4, (byte) 0x45, (byte) 0xD0, (byte) 0x71, (byte) 0xBF,
+ (byte) 0xB7, (byte) 0x98, (byte) 0x20, (byte) 0xFC, (byte) 0x4B, (byte) 0xE9, (byte) 0xB3, (byte) 0xE1,
+ (byte) 0x5C, (byte) 0x22, (byte) 0xF7, (byte) 0x0C, (byte) 0x44, (byte) 0x1B, (byte) 0x81, (byte) 0xBD,
+ (byte) 0x63, (byte) 0x8D, (byte) 0xD4, (byte) 0xC3, (byte) 0xF2, (byte) 0x10, (byte) 0x19, (byte) 0xE0,
+ (byte) 0xFB, (byte) 0xA1, (byte) 0x6E, (byte) 0x66, (byte) 0xEA, (byte) 0xAE, (byte) 0xD6, (byte) 0xCE,
+ (byte) 0x06, (byte) 0x18, (byte) 0x4E, (byte) 0xEB, (byte) 0x78, (byte) 0x95, (byte) 0xDB, (byte) 0xBA,
+ (byte) 0xB6, (byte) 0x42, (byte) 0x7A, (byte) 0x2A, (byte) 0x83, (byte) 0x0B, (byte) 0x54, (byte) 0x67,
+ (byte) 0x6D, (byte) 0xE8, (byte) 0x65, (byte) 0xE7, (byte) 0x2F, (byte) 0x07, (byte) 0xF3, (byte) 0xAA,
+ (byte) 0x27, (byte) 0x7B, (byte) 0x85, (byte) 0xB0, (byte) 0x26, (byte) 0xFD, (byte) 0x8B, (byte) 0xA9,
+ (byte) 0xFA, (byte) 0xBE, (byte) 0xA8, (byte) 0xD7, (byte) 0xCB, (byte) 0xCC, (byte) 0x92, (byte) 0xDA,
+ (byte) 0xF9, (byte) 0x93, (byte) 0x60, (byte) 0x2D, (byte) 0xDD, (byte) 0xD2, (byte) 0xA2, (byte) 0x9B,
+ (byte) 0x39, (byte) 0x5F, (byte) 0x82, (byte) 0x21, (byte) 0x4C, (byte) 0x69, (byte) 0xF8, (byte) 0x31,
+ (byte) 0x87, (byte) 0xEE, (byte) 0x8E, (byte) 0xAD, (byte) 0x8C, (byte) 0x6A, (byte) 0xBC, (byte) 0xB5,
+ (byte) 0x6B, (byte) 0x59, (byte) 0x13, (byte) 0xF1, (byte) 0x04, (byte) 0x00, (byte) 0xF6, (byte) 0x5A,
+ (byte) 0x35, (byte) 0x79, (byte) 0x48, (byte) 0x8F, (byte) 0x15, (byte) 0xCD, (byte) 0x97, (byte) 0x57,
+ (byte) 0x12, (byte) 0x3E, (byte) 0x37, (byte) 0xFF, (byte) 0x9D, (byte) 0x4F, (byte) 0x51, (byte) 0xF5,
+ (byte) 0xA3, (byte) 0x70, (byte) 0xBB, (byte) 0x14, (byte) 0x75, (byte) 0xC2, (byte) 0xB8, (byte) 0x72,
+ (byte) 0xC0, (byte) 0xED, (byte) 0x7D, (byte) 0x68, (byte) 0xC9, (byte) 0x2E, (byte) 0x0D, (byte) 0x62,
+ (byte) 0x46, (byte) 0x17, (byte) 0x11, (byte) 0x4D, (byte) 0x6C, (byte) 0xC4, (byte) 0x7E, (byte) 0x53,
+ (byte) 0xC1, (byte) 0x25, (byte) 0xC7, (byte) 0x9A, (byte) 0x1C, (byte) 0x88, (byte) 0x58, (byte) 0x2C,
+ (byte) 0x89, (byte) 0xDC, (byte) 0x02, (byte) 0x64, (byte) 0x40, (byte) 0x01, (byte) 0x5D, (byte) 0x38,
+ (byte) 0xA5, (byte) 0xE2, (byte) 0xAF, (byte) 0x55, (byte) 0xD5, (byte) 0xEF, (byte) 0x1A, (byte) 0x7C,
+ (byte) 0xA7, (byte) 0x5B, (byte) 0xA6, (byte) 0x6F, (byte) 0x86, (byte) 0x9F, (byte) 0x73, (byte) 0xE6,
+ (byte) 0x0A, (byte) 0xDE, (byte) 0x2B, (byte) 0x99, (byte) 0x4A, (byte) 0x47, (byte) 0x9C, (byte) 0xDF,
+ (byte) 0x09, (byte) 0x76, (byte) 0x9E, (byte) 0x30, (byte) 0x0E, (byte) 0xE4, (byte) 0xB2, (byte) 0x94,
+ (byte) 0xA0, (byte) 0x3B, (byte) 0x34, (byte) 0x1D, (byte) 0x28, (byte) 0x0F, (byte) 0x36, (byte) 0xE3,
+ (byte) 0x23, (byte) 0xB4, (byte) 0x03, (byte) 0xD8, (byte) 0x90, (byte) 0xC8, (byte) 0x3C, (byte) 0xFE,
+ (byte) 0x5E, (byte) 0x32, (byte) 0x24, (byte) 0x50, (byte) 0x1F, (byte) 0x3A, (byte) 0x43, (byte) 0x8A,
+ (byte) 0x96, (byte) 0x41, (byte) 0x74, (byte) 0xAC, (byte) 0x52, (byte) 0x33, (byte) 0xF0, (byte) 0xD9,
+ (byte) 0x29, (byte) 0x80, (byte) 0xB1, (byte) 0x16, (byte) 0xD3, (byte) 0xAB, (byte) 0x91, (byte) 0xB9,
+ (byte) 0x84, (byte) 0x7F, (byte) 0x61, (byte) 0x1E, (byte) 0xCF, (byte) 0xC5, (byte) 0xD1, (byte) 0x56,
+ (byte) 0x3D, (byte) 0xCA, (byte) 0xF4, (byte) 0x05, (byte) 0xC6, (byte) 0xE5, (byte) 0x08, (byte) 0x49};
- public MapleAESOFB(byte[] iv, short mapleVersion) {
+ private final short mapleVersion;
+ private final Cipher cipher;
+ private byte[] iv;
+
+ public MapleAESOFB(InitializationVector iv, short mapleVersion) {
try {
cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skey);
- } catch (NoSuchAlgorithmException e) {
- System.out.println("ERROR " + e);
- } catch (NoSuchPaddingException e) {
- System.out.println("ERROR " + e);
- } catch (InvalidKeyException e) {
- System.out.println("Error initializing the encryption cipher. Make sure you're using the Unlimited Strength cryptography jar files.");
+ } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException e) {
+ log.warn("Cypher initialization error with skey: {}", skey, e);
+ throw new RuntimeException(e);
}
- this.setIv(iv);
+
+ this.iv = iv.getBytes();
this.mapleVersion = (short) (((mapleVersion >> 8) & 0xFF) | ((mapleVersion << 8) & 0xFF00));
}
- private void setIv(byte[] iv) {
- this.iv = iv;
- }
-
private static byte[] multiplyBytes(byte[] in, int count, int mul) {
- byte[] ret = new byte[count * mul];
- for (int x = 0; x < count * mul; x++) {
+ final int size = count * mul;
+ byte[] ret = new byte[size];
+ for (int x = 0; x < size; x++) {
ret[x] = in[x % count];
}
return ret;
@@ -94,12 +119,8 @@ public class MapleAESOFB {
if ((x - start) % myIv.length == 0) {
try {
byte[] newIv = cipher.doFinal(myIv);
- for (int j = 0; j < myIv.length; j++) {
- myIv[j] = newIv[j];
- }
- } catch (IllegalBlockSizeException e) {
- e.printStackTrace();
- } catch (BadPaddingException e) {
+ System.arraycopy(newIv, 0, myIv, 0, myIv.length);
+ } catch (IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
}
}
@@ -137,11 +158,12 @@ public class MapleAESOFB {
return packetLength;
}
- public boolean checkPacket(byte[] packet) {
- return ((((packet[0] ^ iv[2]) & 0xFF) == ((mapleVersion >> 8) & 0xFF)) && (((packet[1] ^ iv[3]) & 0xFF) == (mapleVersion & 0xFF)));
+ private boolean checkPacket(byte[] packet) {
+ return ((((packet[0] ^ iv[2]) & 0xFF) == ((mapleVersion >> 8) & 0xFF)) &&
+ (((packet[1] ^ iv[3]) & 0xFF) == (mapleVersion & 0xFF)));
}
- public boolean checkPacket(int packetHeader) {
+ public boolean isValidHeader(int packetHeader) {
byte[] packetHeaderBuf = new byte[2];
packetHeaderBuf[0] = (byte) ((packetHeader >> 24) & 0xFF);
packetHeaderBuf[1] = (byte) ((packetHeader >> 16) & 0xFF);
diff --git a/src/main/java/net/mina/MapleCustomEncryption.java b/src/main/java/net/encryption/MapleCustomEncryption.java
similarity index 99%
rename from src/main/java/net/mina/MapleCustomEncryption.java
rename to src/main/java/net/encryption/MapleCustomEncryption.java
index 93f0a1b121..67e94844c3 100644
--- a/src/main/java/net/mina/MapleCustomEncryption.java
+++ b/src/main/java/net/encryption/MapleCustomEncryption.java
@@ -19,7 +19,7 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
-package net.mina;
+package net.encryption;
public class MapleCustomEncryption {
private static byte rollLeft(byte in, int count) {
diff --git a/src/main/java/net/encryption/PacketCodec.java b/src/main/java/net/encryption/PacketCodec.java
new file mode 100644
index 0000000000..e3541cc734
--- /dev/null
+++ b/src/main/java/net/encryption/PacketCodec.java
@@ -0,0 +1,9 @@
+package net.encryption;
+
+import io.netty.channel.CombinedChannelDuplexHandler;
+
+public class PacketCodec extends CombinedChannelDuplexHandler {
+ public PacketCodec(ClientCyphers clientCyphers) {
+ super(new PacketDecoder(clientCyphers.getReceiveCypher()), new PacketEncoder(clientCyphers.getSendCypher()));
+ }
+}
diff --git a/src/main/java/net/encryption/PacketDecoder.java b/src/main/java/net/encryption/PacketDecoder.java
new file mode 100644
index 0000000000..896d565d0f
--- /dev/null
+++ b/src/main/java/net/encryption/PacketDecoder.java
@@ -0,0 +1,48 @@
+package net.encryption;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.ReplayingDecoder;
+import net.netty.InvalidPacketHeaderException;
+import net.packet.ByteBufInPacket;
+
+import java.util.List;
+
+public class PacketDecoder extends ReplayingDecoder {
+ private final MapleAESOFB receiveCypher;
+
+ public PacketDecoder(MapleAESOFB receiveCypher) {
+ this.receiveCypher = receiveCypher;
+ }
+
+ @Override
+ protected void decode(ChannelHandlerContext context, ByteBuf in, List