Major schedules & DB refactor

Refactored many calls for TimerManager's schedules throughout the source.
Switched all tables using MyISAM to InnoDB: on a multi-threaded environment such as this, table-locking is an instant no-no, and other gains MyISAM would have over InnoDB are minimal.
Altered getConnection() to properly throw an exception (good practice!) in case of no available connection instead of a mere null.
This commit is contained in:
ronancpl
2017-11-09 20:20:21 -02:00
parent 9677e6f3f5
commit c46ff82929
35 changed files with 600 additions and 374 deletions

View File

@@ -42,6 +42,15 @@ import tools.data.input.SeekableLittleEndianAccessor;
import client.MapleClient;
import constants.ServerConstants;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.ScheduledFuture;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import server.TimerManager;
public class MapleServerHandler extends IoHandlerAdapter {
private PacketProcessor processor;
@@ -49,16 +58,26 @@ public class MapleServerHandler extends IoHandlerAdapter {
private static final SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy HH:mm");
private static AtomicLong sessionId = new AtomicLong(7777);
private Lock idleLock = new ReentrantLock(true);
private Lock tempLock = new ReentrantLock(true);
private Map<MapleClient, Long> idleSessions = new HashMap<>(100);
private Map<MapleClient, Long> tempIdleSessions = new HashMap<>();
private ScheduledFuture<?> idleManager = null;
public MapleServerHandler() {
this.processor = PacketProcessor.getProcessor(-1, -1);
idleManagerTask();
}
public MapleServerHandler(int world, int channel) {
this.processor = PacketProcessor.getProcessor(world, channel);
this.world = world;
this.channel = channel;
idleManagerTask();
}
@Override
public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
System.out.println("disconnect by exception");
@@ -155,8 +174,70 @@ public class MapleServerHandler extends IoHandlerAdapter {
public void sessionIdle(final IoSession session, final IdleStatus status) throws Exception {
MapleClient client = (MapleClient) session.getAttribute(MapleClient.CLIENT_KEY);
if (client != null) {
client.sendPing();
registerIdleSession(client);
}
super.sessionIdle(session, status);
}
private void registerIdleSession(MapleClient c) {
if(idleLock.tryLock()) {
idleSessions.put(c, System.currentTimeMillis());
c.announce(MaplePacketCreator.getPing());
idleLock.unlock();
} else {
tempLock.lock();
try {
tempIdleSessions.put(c, System.currentTimeMillis());
c.announce(MaplePacketCreator.getPing());
} finally {
tempLock.unlock();
}
}
}
private void manageIdleSessions() {
long timeNow = System.currentTimeMillis();
long timeThen = timeNow - 15000;
idleLock.lock();
try {
for(Entry<MapleClient, Long> mc : idleSessions.entrySet()) {
if(timeNow - mc.getValue() >= 15000) {
mc.getKey().testPing(timeThen);
}
}
idleSessions.clear();
if(!tempIdleSessions.isEmpty()) {
tempLock.lock();
try {
for(Entry<MapleClient, Long> mc : tempIdleSessions.entrySet()) {
idleSessions.put(mc.getKey(), mc.getValue());
}
tempIdleSessions.clear();
} finally {
tempLock.unlock();
}
}
} finally {
idleLock.unlock();
}
}
private void idleManagerTask() {
this.idleManager = TimerManager.getInstance().register(new Runnable() {
@Override
public void run() {
manageIdleSessions();
}
}, 10000);
}
private void cancelIdleManagerTask() {
this.idleManager.cancel(false);
this.idleManager = null;
}
}

View File

@@ -132,7 +132,7 @@ public enum SendOpcode {
NOTIFY_LEVELUP(0x69),
NOTIFY_MARRIAGE(0x6A),
NOTIFY_JOB_CHANGE(0x6B),
//SET_BUY_EQUIP_EXT(0x6C),//lol?
//SET_BUY_EQUIP_EXT(0x6C), //probably extra pendant slot for other versions?
MAPLE_TV_USE_RES(0x6D), //It's not blank, It's a popup nibs
AVATAR_MEGAPHONE_RESULT(0x6E),//bot useless..
SET_AVATAR_MEGAPHONE(0x6F),
@@ -145,7 +145,7 @@ public enum SendOpcode {
NEW_YEAR_CARD_RES(0x76),
RANDOM_MORPH_RES(0x77),
CANCEL_NAME_CHANGE_BY_OTHER(0x78),
SET_BUY_EQUIP_EXT(0x79),
SET_EXTRA_PENDANT_SLOT(0x79),
SCRIPT_PROGRESS_MESSAGE(0x7A),
DATA_CRC_CHECK_FAILED(0x7B),
MACRO_SYS_DATA_INIT(0x7C),

View File

@@ -37,6 +37,7 @@ import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
@@ -63,6 +64,7 @@ import server.TimerManager;
import tools.DatabaseConnection;
import tools.FilePrinter;
import tools.Pair;
import client.MapleClient;
import client.MapleCharacter;
import client.SkillFactory;
import constants.ItemConstants;
@@ -82,7 +84,8 @@ public class Server implements Runnable {
private static Server instance = null;
private List<Pair<Integer, String>> worldRecommendedList = new LinkedList<>();
private final Map<Integer, MapleGuild> guilds = new LinkedHashMap<>();
private final Lock shutdownLock = new ReentrantLock();
private final Map<MapleClient, Long> inLoginState = new LinkedHashMap<>();
private final Lock srvLock = new ReentrantLock();
private final PlayerBuffStorage buffStorage = new PlayerBuffStorage();
private final Map<Integer, MapleAlliance> alliances = new LinkedHashMap<>();
private boolean online = false;
@@ -279,6 +282,7 @@ public class Server implements Runnable {
TimerManager tMan = TimerManager.getInstance();
tMan.start();
tMan.register(tMan.purge(), ServerConstants.PURGING_INTERVAL);//Purging ftw...
disconnectIdlesOnLoginTask();
long timeLeft = getTimeLeftForNextHour();
tMan.register(new CouponWorker(), ServerConstants.COUPON_INTERVAL, timeLeft);
@@ -720,11 +724,64 @@ public class Server implements Runnable {
return worlds;
}
public void registerLoginState(MapleClient c) {
srvLock.lock();
try {
inLoginState.put(c, System.currentTimeMillis() + 600000);
} finally {
srvLock.unlock();
}
}
public void unregisterLoginState(MapleClient c) {
srvLock.lock();
try {
inLoginState.remove(c);
} finally {
srvLock.unlock();
}
}
private void disconnectIdlesOnLoginState() {
srvLock.lock();
try {
List<MapleClient> toDisconnect = new LinkedList<>();
long timeNow = System.currentTimeMillis();
for(Entry<MapleClient, Long> mc : inLoginState.entrySet()) {
if(timeNow > mc.getValue()) {
toDisconnect.add(mc.getKey());
}
}
for(MapleClient c : toDisconnect) {
if(c.isLoggedIn()) {
c.disconnect(false, false);
} else {
c.getSession().close(true);
}
inLoginState.remove(c);
}
} finally {
srvLock.unlock();
}
}
private void disconnectIdlesOnLoginTask() {
TimerManager.getInstance().register(new Runnable() {
@Override
public void run() {
disconnectIdlesOnLoginState();
}
}, 300000);
}
public final Runnable shutdown(final boolean restart) {//no player should be online when trying to shutdown!
return new Runnable() {
@Override
public void run() {
shutdownLock.lock();
srvLock.lock();
try {
System.out.println((restart ? "Restarting" : "Shutting down") + " the server!\r\n");
@@ -788,7 +845,7 @@ public class Server implements Runnable {
getInstance().run();//DID I DO EVERYTHING?! D:
}
} finally {
shutdownLock.unlock();
srvLock.unlock();
}
}
};

View File

@@ -297,7 +297,7 @@ public final class BBSOperationHandler extends AbstractMaplePacketHandler {
if (mc.getGuildId() <= 0) {
return;
}
Connection con = null;
Connection con;
try {
con = DatabaseConnection.getConnection();
PreparedStatement ps2;

View File

@@ -65,6 +65,7 @@ public class EnterCashShopHandler extends AbstractMaplePacketHandler {
mc.cancelDiseaseExpireTask();
mc.cancelSkillCooldownTask();
mc.cancelExpirationTask();
mc.cancelQuestExpirationTask();
c.announce(MaplePacketCreator.openCashShop(c, false));
c.announce(MaplePacketCreator.showCashInventory(c));

View File

@@ -74,6 +74,7 @@ public final class EnterMTSHandler extends AbstractMaplePacketHandler {
chr.cancelDiseaseExpireTask();
chr.cancelSkillCooldownTask();
chr.cancelExpirationTask();
chr.cancelQuestExpirationTask();
chr.saveToDB();
chr.getMap().removePlayer(c.getPlayer());

View File

@@ -343,15 +343,15 @@ public final class MTSHandler extends AbstractMaplePacketHandler {
}
} else if (op == 9) { //add to cart
int id = slea.readInt(); //id of the item
Connection con = null;
Connection con;
try {
con = DatabaseConnection.getConnection();
try (PreparedStatement ps1 = con.prepareStatement("SELECT * FROM mts_items WHERE id = ? AND seller <> ?")) {
ps1.setInt(1, id);//Previene que agregues al cart tus propios items
try (PreparedStatement ps1 = con.prepareStatement("SELECT id FROM mts_items WHERE id = ? AND seller <> ?")) {
ps1.setInt(1, id); //Dummy query, prevents adding to cart self owned items
ps1.setInt(2, c.getPlayer().getId());
try (ResultSet rs1 = ps1.executeQuery()) {
if (rs1.next()) {
PreparedStatement ps = con.prepareStatement("SELECT * FROM mts_cart WHERE cid = ? AND itemid = ?");
PreparedStatement ps = con.prepareStatement("SELECT cid FROM mts_cart WHERE cid = ? AND itemid = ?");
ps.setInt(1, c.getPlayer().getId());
ps.setInt(2, id);
try (ResultSet rs = ps.executeQuery()) {

View File

@@ -267,6 +267,7 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
player.diseaseExpireTask();
player.skillCooldownTask();
player.expirationTask();
player.questExpirationTask();
if (GameConstants.hasSPTable(player.getJob()) && player.getJob().getId() != 2001) {
player.createDragon();
}

View File

@@ -208,7 +208,7 @@ public class MapleAlliance {
ps.close();
rs.close();
ps = con.prepareStatement("SELECT * FROM allianceguilds WHERE allianceid = ?");
ps = con.prepareStatement("SELECT guildid FROM allianceguilds WHERE allianceid = ?");
ps.setInt(1, id);
rs = ps.executeQuery();

View File

@@ -26,10 +26,12 @@ import net.MaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor;
public class KeepAliveHandler implements MaplePacketHandler {
@Override
public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
c.pongReceived();
}
@Override
public boolean validateState(MapleClient c) {
return true;
}

View File

@@ -41,9 +41,7 @@ public final class CharSelectedHandler extends AbstractMaplePacketHandler {
return;
}
if (c.getIdleTask() != null) {
c.getIdleTask().cancel(true);
}
Server.getInstance().unregisterLoginState(c);
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
String[] socket = Server.getInstance().getIP(c.getWorld(), c.getChannel()).split(":");
try {

View File

@@ -26,9 +26,7 @@ public class CharSelectedWithPicHandler extends AbstractMaplePacketHandler {
return;
}
if (c.checkPic(pic)) {
if (c.getIdleTask() != null) {
c.getIdleTask().cancel(true);
}
Server.getInstance().unregisterLoginState(c);
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
String[] socket = Server.getInstance().getIP(c.getWorld(), c.getChannel()).split(":");

View File

@@ -24,6 +24,7 @@ package net.server.handlers.login;
import java.util.Calendar;
import net.MaplePacketHandler;
import net.server.Server;
import server.TimerManager;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
@@ -73,12 +74,7 @@ public final class LoginPasswordHandler implements MaplePacketHandler {
private static void login(MapleClient c){
c.announce(MaplePacketCreator.getAuthSuccess(c));//why the fk did I do c.getAccountName()?
final MapleClient client = c;
c.setIdleTask(TimerManager.getInstance().schedule(new Runnable() {
@Override
public void run() {
client.disconnect(false, false);
}
}, 600000));
Server.getInstance().registerLoginState(c);
}
}

View File

@@ -49,9 +49,7 @@ public final class PickCharHandler extends AbstractMaplePacketHandler {
e.printStackTrace();
c.setChannel(1);
}
if (c.getIdleTask() != null) {
c.getIdleTask().cancel(true);
}
Server.getInstance().unregisterLoginState(c);
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
String[] socket = Server.getInstance().getIP(c.getWorld(), c.getChannel()).split(":");
try {

View File

@@ -29,9 +29,7 @@ public final class RegisterPicHandler extends AbstractMaplePacketHandler {
String pic = slea.readMapleAsciiString();
if (c.getPic() == null || c.getPic().equals("")) {
c.setPic(pic);
if (c.getIdleTask() != null) {
c.getIdleTask().cancel(true);
}
Server.getInstance().unregisterLoginState(c);
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
String[] socket = Server.getInstance().getIP(c.getWorld(), c.getChannel()).split(":");
try {

View File

@@ -24,7 +24,7 @@ package net.server.handlers.login;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import server.TimerManager;
import net.server.Server;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
@@ -40,12 +40,8 @@ public class SetGenderHandler extends AbstractMaplePacketHandler {
c.setGender(slea.readByte());
c.announce(MaplePacketCreator.getAuthSuccess(c));
final MapleClient client = c;
c.setIdleTask(TimerManager.getInstance().schedule(new Runnable() {
@Override
public void run() {
client.getSession().close(true);
}
}, 600000));
Server.getInstance().registerLoginState(c);
}
}

View File

@@ -29,9 +29,7 @@ public class ViewAllCharSelectedWithPicHandler extends AbstractMaplePacketHandle
return;
}
if (c.checkPic(pic)) {
if (c.getIdleTask() != null) {
c.getIdleTask().cancel(true);
}
Server.getInstance().unregisterLoginState(c);
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
String[] socket = Server.getInstance().getIP(c.getWorld(), c.getChannel()).split(":");

View File

@@ -28,9 +28,7 @@ public final class ViewAllPicRegisterHandler extends AbstractMaplePacketHandler
slea.readMapleAsciiString();
String pic = slea.readMapleAsciiString();
c.setPic(pic);
if (c.getIdleTask() != null) {
c.getIdleTask().cancel(true);
}
Server.getInstance().unregisterLoginState(c);
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
String[] socket = Server.getInstance().getIP(c.getWorld(), channel).split(":");
try {