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 committed 2017-11-09 20:20:21 -02:00
1 parent 9677e6f3f5
commit c46ff82929
35 files changed
+394 -168

No files matched your search

+3 -2
View File
@@ -69,7 +69,8 @@ Hamachi is optional, though. You don't have to install Hamachi if you want to ma
Set the "MapleSolaxia" folder on a place of your preference. It is recommended for use "C:\Nexon\MapleSolaxia". Set the "MapleSolaxia" folder on a place of your preference. It is recommended for use "C:\Nexon\MapleSolaxia".
Setting up the SQL: open MySQL Query Browser, and define these parameters at startup and click OK: Setting up the SQL: open MySQL Query Browser, define these parameters at startup and click OK.
Server Host: localhost Port: 3306 Username: root Server Host: localhost Port: 3306 Username: root
Now it must be done CAREFULLY: Now it must be done CAREFULLY:
@@ -80,7 +81,7 @@ Now it is OPTIONAL, you don't need to run it if you don't want, as it will simpl
3. File -> Open Script... -> Browse for "C:\Nexon\MapleSolaxia\sql" -> db_shopupdate.sql, and execute it. 3. File -> Open Script... -> Browse for "C:\Nexon\MapleSolaxia\sql" -> db_shopupdate.sql, and execute it.
At the end of the execution of these SQLs, you should have installed a database schema named "maplesolaxia". REGISTER YOUR FIRST ACCOUNT to be used in-game by creating manually a entry on the table "accounts" at that database with a login and a password. At the end of the execution of these SQLs, you should have installed a database schema named "maplesolaxia". REGISTER YOUR FIRST ACCOUNT to be used in-game by creating manually an entry on the table "accounts" at that database with a login and a password.
Configure the IP you want to use for your MapleStory server in "configuration.ini" file, or set it as "localhost" if you want to run it only on your machine. Alternatively, you can use the IP given by Hamachi to use on a Hamachi network, or you can use a non-Hamachi method of port-forwarding. Neither will be approached here. Configure the IP you want to use for your MapleStory server in "configuration.ini" file, or set it as "localhost" if you want to run it only on your machine. Alternatively, you can use the IP given by Hamachi to use on a Hamachi network, or you can use a non-Hamachi method of port-forwarding. Neither will be approached here.
BIN
View File
Binary file not shown.
+12 -2
View File
@@ -1,6 +1,6 @@
========== MapleSolaxiaV2 ========== ========== MapleSolaxiaV2 ==========
Credits: Credits:
Ronan - Freelance Developer Ronan - Developer
Vcoc - Freelance Developer Vcoc - Freelance Developer
--------------------------- ---------------------------
@@ -81,17 +81,27 @@ Server potentials:
* Custom jail system (needs provided custom wz). * Custom jail system (needs provided custom wz).
* Delete Character 100% (requires ENABLE_PIC activated). * Delete Character 100% (requires ENABLE_PIC activated).
* Autosaver (periodically saves on DB current state of every player in-game). * Autosaver (periodically saves on DB current state of every player in-game).
* Both fixed and randomized versions of HP/MP growth rate abailable, regarding player job (enable one at ServerConstants). Placeholder for HP/MP washing feature. * Both fixed and randomized versions of HP/MP growth rate available, regarding player job (enable one at ServerConstants). Placeholder for HP/MP washing feature.
Admin/GM commands: Admin/GM commands:
* Server commands layered by GM levels. * Server commands layered by GM levels.
* Spawn Zakum/Horntail/Pinkbean 100%. * Spawn Zakum/Horntail/Pinkbean 100%.
* New commands. * New commands.
External tools:
* MapleArrowFetcher - Updates min/max quantity dropped on all arrows drop data, calculations based on mob level and whether it's a boss or not.
* MapleCouponInstaller - Retrieves coupon info from the WZ and makes a SQL table with it. The server will use that table to gather info regarding rates and intervals.
* MapleIdRetriever - Two behaviors: generates a SQL table with relation (id, name) of the handbook given as input. Given a file with names, outputs a file with ids.
* MapleMesoFetcher - Creates meso drop data for mobs with more than 4 items (thus overworld mobs), calculations based on mob level and whether it's a boss or not.
* MapleQuestItemFetcher - Searches the SQL tables and project files and reports in all relevant data regarding missing/erroneous quest items.
* MobBookIndexer - Generates a SQL table with all relations of cardid and mobid present in the mob book.
* MobBookUpdate - Generates a wz.xml that is a copy of the original MonsterBook.wz.xml, except it updates the drop data info in the book with those currently on DB.
Project: Project:
* Organized project code. * Organized project code.
* Highly configurable server (see all server flags at ServerConstants). * Highly configurable server (see all server flags at ServerConstants).
* Fixed/added some missing packets for MoveEnvironment, summons and others. * Fixed/added some missing packets for MoveEnvironment, summons and others.
* Reviewed many Java object aspects that needed concurrency protection. * Reviewed many Java object aspects that needed concurrency protection.
* Heavily reviewed future task management inside the project. Way less trivial schedules are spawned now, relieving task overload on the TimerManager.
--------------------------- ---------------------------
+9
View File
@@ -651,3 +651,12 @@ Implementado nova ferramenta: MapleQuestItemFetcher. Ela vasculha a DB e os XMLs
05 Novembro 2017, 05 Novembro 2017,
Adicionado sistema de level cap para jobs correntes. Adicionado sistema de level cap para jobs correntes.
Revisto acesso concorrente sobre o componente EM da classe EIM. Revisto acesso concorrente sobre o componente EM da classe EIM.
07 Novembro 2017,
Refatorado esquema de schedules por toda a source, diminuindo drasticamente as chamadas ao TimerManager.
Refatorado algumas chamadas à DB, busca somente aquilo que é necessário.
08 - 09 Novembro 2017,
Adicionado packet para extra slot pendant.
Corrigido possível bug em MapleMapFactory.
Modificado todas as DB tables agora utilizando InnoDB (ganhos do MyISAM em contraste se tornou ínfimo, para casos críticos).
+10 -10
View File
@@ -206,7 +206,7 @@ CREATE TABLE IF NOT EXISTS `temp_data` (
`chance` int(11) NOT NULL DEFAULT '0', `chance` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`dropperid`, `itemid`), PRIMARY KEY (`dropperid`, `itemid`),
KEY `mobid` (`dropperid`) KEY `mobid` (`dropperid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=0 ; ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=0 ;
INSERT IGNORE INTO `temp_data` (`id`, `dropperid`, `itemid`, `minimum_quantity`, `maximum_quantity`, `questid`, `chance`) VALUES INSERT IGNORE INTO `temp_data` (`id`, `dropperid`, `itemid`, `minimum_quantity`, `maximum_quantity`, `questid`, `chance`) VALUES
(1, 9400121, 4000138, 1, 1, 0, 600000), (1, 9400121, 4000138, 1, 1, 0, 600000),
@@ -15929,7 +15929,7 @@ CREATE TABLE IF NOT EXISTS `monsterbook` (
`charid` int(11) unsigned NOT NULL, `charid` int(11) unsigned NOT NULL,
`cardid` int(11) NOT NULL, `cardid` int(11) NOT NULL,
`level` int(1) DEFAULT '1' `level` int(1) DEFAULT '1'
) ENGINE=MyISAM DEFAULT CHARSET=latin1; ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `monstercarddata` ( CREATE TABLE IF NOT EXISTS `monstercarddata` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
@@ -15937,7 +15937,7 @@ CREATE TABLE IF NOT EXISTS `monstercarddata` (
`mobid` int(11) NOT NULL DEFAULT '0', `mobid` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `id` (`id`) UNIQUE KEY `id` (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=309 ; ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=309 ;
INSERT INTO `monstercarddata` (`id`, `cardid`, `mobid`) VALUES INSERT INTO `monstercarddata` (`id`, `cardid`, `mobid`) VALUES
(1, 2380000, 100100), (1, 2380000, 100100),
@@ -16313,7 +16313,7 @@ CREATE TABLE IF NOT EXISTS `nxcode` (
`type` int(11) NOT NULL DEFAULT '0', `type` int(11) NOT NULL DEFAULT '0',
`item` int(11) NOT NULL DEFAULT '10000', `item` int(11) NOT NULL DEFAULT '10000',
PRIMARY KEY (`code`) PRIMARY KEY (`code`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1; ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `nxcoupons` ( CREATE TABLE IF NOT EXISTS `nxcoupons` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
@@ -16418,7 +16418,7 @@ CREATE TABLE IF NOT EXISTS `questactions` (
`status` int(11) NOT NULL DEFAULT '0', `status` int(11) NOT NULL DEFAULT '0',
`data` blob NOT NULL, `data` blob NOT NULL,
PRIMARY KEY (`questactionid`) PRIMARY KEY (`questactionid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `questprogress` ( CREATE TABLE IF NOT EXISTS `questprogress` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT, `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
@@ -16434,7 +16434,7 @@ CREATE TABLE IF NOT EXISTS `questrequirements` (
`status` int(11) NOT NULL DEFAULT '0', `status` int(11) NOT NULL DEFAULT '0',
`data` blob NOT NULL, `data` blob NOT NULL,
PRIMARY KEY (`questrequirementid`) PRIMARY KEY (`questrequirementid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `queststatus` ( CREATE TABLE IF NOT EXISTS `queststatus` (
`queststatusid` int(10) unsigned NOT NULL AUTO_INCREMENT, `queststatusid` int(10) unsigned NOT NULL AUTO_INCREMENT,
@@ -16456,7 +16456,7 @@ CREATE TABLE IF NOT EXISTS `reactordrops` (
`questid` int(5) NOT NULL DEFAULT '-1', `questid` int(5) NOT NULL DEFAULT '-1',
PRIMARY KEY (`reactordropid`), PRIMARY KEY (`reactordropid`),
KEY `reactorid` (`reactorid`) KEY `reactorid` (`reactorid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 PACK_KEYS=1 AUTO_INCREMENT=841 ; ) ENGINE=InnoDB DEFAULT CHARSET=latin1 PACK_KEYS=1 AUTO_INCREMENT=841 ;
INSERT INTO `reactordrops` (`reactordropid`, `reactorid`, `itemid`, `chance`, `questid`) VALUES INSERT INTO `reactordrops` (`reactordropid`, `reactorid`, `itemid`, `chance`, `questid`) VALUES
(1, 2001, 4031161, 1, 1008), (1, 2001, 4031161, 1, 1008),
@@ -17339,7 +17339,7 @@ CREATE TABLE IF NOT EXISTS `shopitems` (
`pitch` int(11) NOT NULL DEFAULT '0', `pitch` int(11) NOT NULL DEFAULT '0',
`position` int(11) NOT NULL COMMENT 'sort is an arbitrary field designed to give leeway when modifying shops. The lowest number is 104 and it increments by 4 for each item to allow decent space for swapping/inserting/removing items.', `position` int(11) NOT NULL COMMENT 'sort is an arbitrary field designed to give leeway when modifying shops. The lowest number is 104 and it increments by 4 for each item to allow decent space for swapping/inserting/removing items.',
PRIMARY KEY (`shopitemid`) PRIMARY KEY (`shopitemid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=20047 ; ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=20047 ;
INSERT INTO `shopitems` (`shopitemid`, `shopid`, `itemid`, `price`, `pitch`, `position`) VALUES INSERT INTO `shopitems` (`shopitemid`, `shopid`, `itemid`, `price`, `pitch`, `position`) VALUES
(1, 11000, 1332005, 500, 0, 104), (1, 11000, 1332005, 500, 0, 104),
@@ -20967,7 +20967,7 @@ CREATE TABLE IF NOT EXISTS `shops` (
`shopid` int(10) unsigned NOT NULL AUTO_INCREMENT, `shopid` int(10) unsigned NOT NULL AUTO_INCREMENT,
`npcid` int(11) NOT NULL DEFAULT '0', `npcid` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`shopid`) PRIMARY KEY (`shopid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=10000000 ; ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=10000000 ;
INSERT INTO `shops` (`shopid`, `npcid`) VALUES INSERT INTO `shops` (`shopid`, `npcid`) VALUES
(11000, 11000), (11000, 11000),
@@ -21256,7 +21256,7 @@ CREATE TABLE IF NOT EXISTS `skillmacros` (
`name` varchar(13) DEFAULT NULL, `name` varchar(13) DEFAULT NULL,
`shout` tinyint(1) NOT NULL DEFAULT '0', `shout` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `skills` ( CREATE TABLE IF NOT EXISTS `skills` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
+2 -2
View File
@@ -19885,7 +19885,7 @@ USE `maplesolaxia`;
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
UNIQUE KEY (`dropperid`, `itemid`), UNIQUE KEY (`dropperid`, `itemid`),
KEY `mobid` (`dropperid`) KEY `mobid` (`dropperid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
#pass (sorted) data from one table to another #pass (sorted) data from one table to another
INSERT INTO drop_data (dropperid, itemid, minimum_quantity, maximum_quantity, questid, chance) INSERT INTO drop_data (dropperid, itemid, minimum_quantity, maximum_quantity, questid, chance)
@@ -21223,7 +21223,7 @@ USE `maplesolaxia`;
`mobid` int(11) NOT NULL DEFAULT '0', `mobid` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`) USING BTREE, PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `id` (`id`) UNIQUE KEY `id` (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
INSERT INTO `monstercarddata` (`cardid`, `mobid`) (SELECT itemid, min(dropperid) FROM drop_data where itemid>=2380000 and itemid<2390000 group by itemid); INSERT INTO `monstercarddata` (`cardid`, `mobid`) (SELECT itemid, min(dropperid) FROM drop_data where itemid>=2380000 and itemid<2390000 group by itemid);
+94 -35
View File
@@ -257,6 +257,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
private Map<Integer, MapleCoolDownValueHolder> coolDowns = new LinkedHashMap<>(); private Map<Integer, MapleCoolDownValueHolder> coolDowns = new LinkedHashMap<>();
private EnumMap<MapleDisease, MapleDiseaseValueHolder> diseases = new EnumMap<>(MapleDisease.class); private EnumMap<MapleDisease, MapleDiseaseValueHolder> diseases = new EnumMap<>(MapleDisease.class);
private Map<Integer, MapleDoor> doors = new LinkedHashMap<>(); private Map<Integer, MapleDoor> doors = new LinkedHashMap<>();
private Map<MapleQuest, Long> questExpirations = new LinkedHashMap<>();
private ScheduledFuture<?> dragonBloodSchedule; private ScheduledFuture<?> dragonBloodSchedule;
private ScheduledFuture<?> hpDecreaseTask; private ScheduledFuture<?> hpDecreaseTask;
private ScheduledFuture<?> beholderHealingSchedule, beholderBuffSchedule, berserkSchedule; private ScheduledFuture<?> beholderHealingSchedule, beholderBuffSchedule, berserkSchedule;
@@ -264,14 +265,14 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
private ScheduledFuture<?> buffExpireTask = null; private ScheduledFuture<?> buffExpireTask = null;
private ScheduledFuture<?> itemExpireTask = null; private ScheduledFuture<?> itemExpireTask = null;
private ScheduledFuture<?> diseaseExpireTask = null; private ScheduledFuture<?> diseaseExpireTask = null;
private ScheduledFuture<?> questExpireTask = null;
private ScheduledFuture<?> recoveryTask = null; private ScheduledFuture<?> recoveryTask = null;
private ScheduledFuture<?> extraRecoveryTask = null; private ScheduledFuture<?> extraRecoveryTask = null;
private ScheduledFuture<?> chairRecoveryTask = null; private ScheduledFuture<?> chairRecoveryTask = null;
private ScheduledFuture<?> pendantOfSpirit = null; //1122017 private ScheduledFuture<?> pendantOfSpirit = null; //1122017
private List<ScheduledFuture<?>> timers = new ArrayList<>();
private Lock chrLock = new ReentrantLock(true); private Lock chrLock = new ReentrantLock(true);
private Lock effLock = new ReentrantLock(true); private Lock effLock = new ReentrantLock(true);
private Lock petLock = new ReentrantLock(true); private Lock petLock = new ReentrantLock(true); // for quest tasks as well
private Lock prtLock = new ReentrantLock(); private Lock prtLock = new ReentrantLock();
private Map<Integer, Set<Integer>> excluded = new LinkedHashMap<>(); private Map<Integer, Set<Integer>> excluded = new LinkedHashMap<>();
private Set<Integer> excludedItems = new LinkedHashSet<>(); private Set<Integer> excludedItems = new LinkedHashSet<>();
@@ -2088,13 +2089,15 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
addHP(-getMap().getHPDec()); addHP(-getMap().getHPDec());
lastHpDec = System.currentTimeMillis(); lastHpDec = System.currentTimeMillis();
} }
}
hpDecreaseTask = TimerManager.getInstance().schedule(new Runnable() { private void startHpDecreaseTask(long lastHpTask) {
hpDecreaseTask = TimerManager.getInstance().register(new Runnable() {
@Override @Override
public void run() { public void run() {
doHurtHp(); doHurtHp();
} }
}, 10000); }, 10000, 10000 - lastHpTask);
} }
public void resetHpDecreaseTask() { public void resetHpDecreaseTask() {
@@ -2103,16 +2106,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
} }
long lastHpTask = System.currentTimeMillis() - lastHpDec; long lastHpTask = System.currentTimeMillis() - lastHpDec;
if(lastHpTask >= 10000) { startHpDecreaseTask((lastHpTask > 10000) ? 10000 : lastHpTask);
doHurtHp();
} else {
hpDecreaseTask = TimerManager.getInstance().schedule(new Runnable() {
@Override
public void run() {
doHurtHp();
}
}, 10000 - lastHpTask);
}
} }
public void dropMessage(String message) { public void dropMessage(String message) {
@@ -2127,10 +2121,6 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
return nf.format(MapleGuild.CHANGE_EMBLEM_COST); return nf.format(MapleGuild.CHANGE_EMBLEM_COST);
} }
public List<ScheduledFuture<?>> getTimers() {
return timers;
}
private void enforceMaxHpMp() { private void enforceMaxHpMp() {
List<Pair<MapleStat, Integer>> stats = new ArrayList<>(2); List<Pair<MapleStat, Integer>> stats = new ArrayList<>(2);
if (getMp() > getCurrentMaxMp()) { if (getMp() > getCurrentMaxMp()) {
@@ -7466,15 +7456,83 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
updateQuest(newStatus); updateQuest(newStatus);
} }
public void questTimeLimit(final MapleQuest quest, int seconds) { public void cancelQuestExpirationTask() {
ScheduledFuture<?> sf = TimerManager.getInstance().schedule(new Runnable() { petLock.lock();
try {
if (questExpireTask != null) {
questExpireTask.cancel(false);
questExpireTask = null;
}
} finally {
petLock.unlock();
}
}
public void questExpirationTask() {
petLock.lock();
try {
if(!questExpirations.isEmpty()) {
if(questExpireTask == null) {
questExpireTask = TimerManager.getInstance().register(new Runnable() {
@Override @Override
public void run() { public void run() {
expireQuest(quest); runQuestExpireTask();
} }
}, seconds * 1000); }, 10 * 1000);
}
}
} finally {
petLock.unlock();
}
}
private void runQuestExpireTask() {
petLock.lock();
try {
long timeNow = System.currentTimeMillis();
List<MapleQuest> expireList = new LinkedList<>();
for(Entry<MapleQuest, Long> qe : questExpirations.entrySet()) {
if(qe.getValue() <= timeNow) expireList.add(qe.getKey());
}
if(!expireList.isEmpty()) {
for(MapleQuest quest : expireList) {
expireQuest(quest);
questExpirations.remove(quest);
}
if(questExpirations.isEmpty()) {
questExpireTask.cancel(false);
questExpireTask = null;
}
}
} finally {
petLock.unlock();
}
}
private void registerQuestExpire(MapleQuest quest, long time) {
petLock.lock();
try {
if(questExpireTask == null) {
questExpireTask = TimerManager.getInstance().register(new Runnable() {
@Override
public void run() {
runQuestExpireTask();
}
}, 10 * 1000);
}
questExpirations.put(quest, System.currentTimeMillis() + time);
} finally {
petLock.unlock();
}
}
public void questTimeLimit(final MapleQuest quest, int seconds) {
registerQuestExpire(quest, seconds * 1000);
announce(MaplePacketCreator.addQuestTimeLimit(quest.getId(), seconds * 1000)); announce(MaplePacketCreator.addQuestTimeLimit(quest.getId(), seconds * 1000));
timers.add(sf);
} }
public void questTimeLimit2(final MapleQuest quest, long expires) { public void questTimeLimit2(final MapleQuest quest, long expires) {
@@ -7483,14 +7541,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
if(timeLeft <= 0) { if(timeLeft <= 0) {
expireQuest(quest); expireQuest(quest);
} else { } else {
ScheduledFuture<?> sf = TimerManager.getInstance().schedule(new Runnable() { registerQuestExpire(quest, timeLeft);
@Override
public void run() {
expireQuest(quest);
}
}, timeLeft);
timers.add(sf);
} }
} }
@@ -7903,10 +7954,19 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
cancelSkillCooldownTask(); cancelSkillCooldownTask();
cancelExpirationTask(); cancelExpirationTask();
for (ScheduledFuture<?> sf : timers) { petLock.lock();
sf.cancel(false); try {
if (questExpireTask != null) {
questExpireTask.cancel(false);
questExpireTask = null;
questExpirations.clear();
questExpirations = null;
} }
timers.clear(); } finally {
petLock.unlock();
}
if (maplemount != null) { if (maplemount != null) {
maplemount.empty(); maplemount.empty();
maplemount = null; maplemount = null;
@@ -7921,7 +7981,6 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
family = null; family = null;
client = null; client = null;
map = null; map = null;
timers = null;
} }
} }
+5 -25
View File
@@ -41,7 +41,6 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
@@ -70,7 +69,6 @@ import scripting.quest.QuestActionManager;
import scripting.quest.QuestScriptManager; import scripting.quest.QuestScriptManager;
import server.life.MapleMonster; import server.life.MapleMonster;
import server.MapleTrade; import server.MapleTrade;
import server.TimerManager;
import server.maps.*; import server.maps.*;
import server.quest.MapleQuest; import server.quest.MapleQuest;
import tools.LogHelper; import tools.LogHelper;
@@ -101,7 +99,6 @@ public class MapleClient {
private int gmlevel; private int gmlevel;
private Set<String> macs = new HashSet<>(); private Set<String> macs = new HashSet<>();
private Map<String, ScriptEngine> engines = new HashMap<>(); private Map<String, ScriptEngine> engines = new HashMap<>();
private ScheduledFuture<?> idleTask = null;
private byte characterSlots = 3; private byte characterSlots = 3;
private byte loginattempt = 0; private byte loginattempt = 0;
private String pin = null; private String pin = null;
@@ -941,15 +938,13 @@ public class MapleClient {
} }
private void clear() { //usable when defining client = null shortly after private void clear() { //usable when defining client = null shortly after
Server.getInstance().unregisterLoginState(this);
this.accountName = null; this.accountName = null;
this.macs = null; this.macs = null;
this.hwid = null; this.hwid = null;
this.birthday = null; this.birthday = null;
//this.engines = null; //this.engines = null;
if (this.idleTask != null) {
this.idleTask.cancel(true);
this.idleTask = null;
}
this.player = null; this.player = null;
this.receive = null; this.receive = null;
this.send = null; this.send = null;
@@ -1005,15 +1000,9 @@ public class MapleClient {
lastPong = System.currentTimeMillis(); lastPong = System.currentTimeMillis();
} }
public void sendPing() { public void testPing(long timeThen) {
final long then = System.currentTimeMillis();
announce(MaplePacketCreator.getPing());
TimerManager.getInstance().schedule(new Runnable() {
@Override
public void run() {
try { try {
if (lastPong < then) { if (lastPong < timeThen) {
if (session != null && session.isConnected()) { if (session != null && session.isConnected()) {
session.close(false); session.close(false);
} }
@@ -1022,8 +1011,6 @@ public class MapleClient {
e.printStackTrace(); e.printStackTrace();
} }
} }
}, 15000);
}
public String getHWID() { public String getHWID() {
return hwid; return hwid;
@@ -1053,14 +1040,6 @@ public class MapleClient {
engines.remove(name); engines.remove(name);
} }
public ScheduledFuture<?> getIdleTask() {
return idleTask;
}
public void setIdleTask(ScheduledFuture<?> idleTask) {
this.idleTask = idleTask;
}
public NPCConversationManager getCM() { public NPCConversationManager getCM() {
return NPCScriptManager.getInstance().getCM(this); return NPCScriptManager.getInstance().getCM(this);
} }
@@ -1321,6 +1300,7 @@ public class MapleClient {
player.cancelBuffExpireTask(); player.cancelBuffExpireTask();
player.cancelDiseaseExpireTask(); player.cancelDiseaseExpireTask();
player.cancelSkillCooldownTask(); player.cancelSkillCooldownTask();
player.cancelQuestExpirationTask();
//Cancelling magicdoor? Nope //Cancelling magicdoor? Nope
//Cancelling mounts? Noty //Cancelling mounts? Noty
if (player.getBuffedValue(MapleBuffStat.PUPPET) != null) { if (player.getBuffedValue(MapleBuffStat.PUPPET) != null) {
+9 -6
View File
@@ -349,6 +349,10 @@ public class Commands {
break; break;
case "staff": case "staff":
player.yellowMessage("MapleSolaxiaV2 Staff");
player.yellowMessage("Ronan - Developer");
player.yellowMessage("Vcoc - Freelance Developer");
player.yellowMessage("");
player.yellowMessage("MapleSolaxia Staff"); player.yellowMessage("MapleSolaxia Staff");
player.yellowMessage("Aria - Administrator"); player.yellowMessage("Aria - Administrator");
player.yellowMessage("Twdtwd - Administrator"); player.yellowMessage("Twdtwd - Administrator");
@@ -358,9 +362,6 @@ public class Commands {
player.yellowMessage("SourMjolk - Game Master"); player.yellowMessage("SourMjolk - Game Master");
player.yellowMessage("Kanade - Game Master"); player.yellowMessage("Kanade - Game Master");
player.yellowMessage("Kitsune - Game Master"); player.yellowMessage("Kitsune - Game Master");
player.yellowMessage("MapleSolaxiaV2 Staff");
player.yellowMessage("Ronan - Freelance Developer");
player.yellowMessage("Vcoc - Freelance Developer");
break; break;
case "lastrestart": case "lastrestart":
@@ -451,7 +452,7 @@ public class Commands {
output += "#b" + data.getRight() + "#k is dropped by:\r\n"; output += "#b" + data.getRight() + "#k is dropped by:\r\n";
try { try {
Connection con = DatabaseConnection.getConnection(); Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT * FROM drop_data WHERE itemid = ? LIMIT 50"); PreparedStatement ps = con.prepareStatement("SELECT dropperid FROM drop_data WHERE itemid = ? LIMIT 50");
ps.setInt(1, data.getLeft()); ps.setInt(1, data.getLeft());
ResultSet rs = ps.executeQuery(); ResultSet rs = ps.executeQuery();
while(rs.next()) { while(rs.next()) {
@@ -1513,11 +1514,13 @@ public class Commands {
case "reloadmap": case "reloadmap":
MapleMap oldMap = c.getPlayer().getMap(); MapleMap oldMap = c.getPlayer().getMap();
MapleMap newMap = c.getChannelServer().getMapFactory().getMap(player.getMapId()); MapleMap newMap = c.getChannelServer().getMapFactory().resetMap(player.getMapId());
int callerid = c.getPlayer().getId();
for (MapleCharacter ch : oldMap.getCharacters()) { for (MapleCharacter ch : oldMap.getCharacters()) {
ch.changeMap(newMap); ch.changeMap(newMap);
if(ch.getId() != callerid) ch.dropMessage("You have been relocated due to map reloading. Sorry for the inconvenience.");
} }
oldMap = null;
newMap.respawn(); newMap.respawn();
break; break;
+1
View File
@@ -85,6 +85,7 @@ public class ServerConstants {
//Dangling Items Configuration //Dangling Items Configuration
public static final int ITEM_EXPIRE_TIME = 3 * 60 * 1000; //Time before items start disappearing. Recommended to be set up to 3 minutes. public static final int ITEM_EXPIRE_TIME = 3 * 60 * 1000; //Time before items start disappearing. Recommended to be set up to 3 minutes.
public static final int ITEM_MONITOR_TIME = 5 * 60 * 1000; //Interval between item monitoring tasks on maps, which checks for dangling (null) item objects on the map item history. public static final int ITEM_MONITOR_TIME = 5 * 60 * 1000; //Interval between item monitoring tasks on maps, which checks for dangling (null) item objects on the map item history.
public static final int ITEM_EXPIRE_CHECK = 10 * 1000; //Interval between item expiring tasks on maps, which checks and makes disappear expired items.
public static final int ITEM_LIMIT_ON_MAP = 200; //Max number of items allowed on a map. public static final int ITEM_LIMIT_ON_MAP = 200; //Max number of items allowed on a map.
//Some Gameplay Enhancing Configurations //Some Gameplay Enhancing Configurations
+82 -1
View File
@@ -42,6 +42,15 @@ import tools.data.input.SeekableLittleEndianAccessor;
import client.MapleClient; import client.MapleClient;
import constants.ServerConstants; 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 { public class MapleServerHandler extends IoHandlerAdapter {
private PacketProcessor processor; private PacketProcessor processor;
@@ -49,14 +58,24 @@ public class MapleServerHandler extends IoHandlerAdapter {
private static final SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy HH:mm"); private static final SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy HH:mm");
private static AtomicLong sessionId = new AtomicLong(7777); 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() { public MapleServerHandler() {
this.processor = PacketProcessor.getProcessor(-1, -1); this.processor = PacketProcessor.getProcessor(-1, -1);
idleManagerTask();
} }
public MapleServerHandler(int world, int channel) { public MapleServerHandler(int world, int channel) {
this.processor = PacketProcessor.getProcessor(world, channel); this.processor = PacketProcessor.getProcessor(world, channel);
this.world = world; this.world = world;
this.channel = channel; this.channel = channel;
idleManagerTask();
} }
@Override @Override
@@ -155,8 +174,70 @@ public class MapleServerHandler extends IoHandlerAdapter {
public void sessionIdle(final IoSession session, final IdleStatus status) throws Exception { public void sessionIdle(final IoSession session, final IdleStatus status) throws Exception {
MapleClient client = (MapleClient) session.getAttribute(MapleClient.CLIENT_KEY); MapleClient client = (MapleClient) session.getAttribute(MapleClient.CLIENT_KEY);
if (client != null) { if (client != null) {
client.sendPing(); registerIdleSession(client);
} }
super.sessionIdle(session, status); 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;
}
} }
+2 -2
View File
@@ -132,7 +132,7 @@ public enum SendOpcode {
NOTIFY_LEVELUP(0x69), NOTIFY_LEVELUP(0x69),
NOTIFY_MARRIAGE(0x6A), NOTIFY_MARRIAGE(0x6A),
NOTIFY_JOB_CHANGE(0x6B), 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 MAPLE_TV_USE_RES(0x6D), //It's not blank, It's a popup nibs
AVATAR_MEGAPHONE_RESULT(0x6E),//bot useless.. AVATAR_MEGAPHONE_RESULT(0x6E),//bot useless..
SET_AVATAR_MEGAPHONE(0x6F), SET_AVATAR_MEGAPHONE(0x6F),
@@ -145,7 +145,7 @@ public enum SendOpcode {
NEW_YEAR_CARD_RES(0x76), NEW_YEAR_CARD_RES(0x76),
RANDOM_MORPH_RES(0x77), RANDOM_MORPH_RES(0x77),
CANCEL_NAME_CHANGE_BY_OTHER(0x78), CANCEL_NAME_CHANGE_BY_OTHER(0x78),
SET_BUY_EQUIP_EXT(0x79), SET_EXTRA_PENDANT_SLOT(0x79),
SCRIPT_PROGRESS_MESSAGE(0x7A), SCRIPT_PROGRESS_MESSAGE(0x7A),
DATA_CRC_CHECK_FAILED(0x7B), DATA_CRC_CHECK_FAILED(0x7B),
MACRO_SYS_DATA_INIT(0x7C), MACRO_SYS_DATA_INIT(0x7C),
+60 -3
View File
@@ -37,6 +37,7 @@ import java.util.LinkedHashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
@@ -63,6 +64,7 @@ import server.TimerManager;
import tools.DatabaseConnection; import tools.DatabaseConnection;
import tools.FilePrinter; import tools.FilePrinter;
import tools.Pair; import tools.Pair;
import client.MapleClient;
import client.MapleCharacter; import client.MapleCharacter;
import client.SkillFactory; import client.SkillFactory;
import constants.ItemConstants; import constants.ItemConstants;
@@ -82,7 +84,8 @@ public class Server implements Runnable {
private static Server instance = null; private static Server instance = null;
private List<Pair<Integer, String>> worldRecommendedList = new LinkedList<>(); private List<Pair<Integer, String>> worldRecommendedList = new LinkedList<>();
private final Map<Integer, MapleGuild> guilds = new LinkedHashMap<>(); 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 PlayerBuffStorage buffStorage = new PlayerBuffStorage();
private final Map<Integer, MapleAlliance> alliances = new LinkedHashMap<>(); private final Map<Integer, MapleAlliance> alliances = new LinkedHashMap<>();
private boolean online = false; private boolean online = false;
@@ -279,6 +282,7 @@ public class Server implements Runnable {
TimerManager tMan = TimerManager.getInstance(); TimerManager tMan = TimerManager.getInstance();
tMan.start(); tMan.start();
tMan.register(tMan.purge(), ServerConstants.PURGING_INTERVAL);//Purging ftw... tMan.register(tMan.purge(), ServerConstants.PURGING_INTERVAL);//Purging ftw...
disconnectIdlesOnLoginTask();
long timeLeft = getTimeLeftForNextHour(); long timeLeft = getTimeLeftForNextHour();
tMan.register(new CouponWorker(), ServerConstants.COUPON_INTERVAL, timeLeft); tMan.register(new CouponWorker(), ServerConstants.COUPON_INTERVAL, timeLeft);
@@ -720,11 +724,64 @@ public class Server implements Runnable {
return worlds; 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! public final Runnable shutdown(final boolean restart) {//no player should be online when trying to shutdown!
return new Runnable() { return new Runnable() {
@Override @Override
public void run() { public void run() {
shutdownLock.lock(); srvLock.lock();
try { try {
System.out.println((restart ? "Restarting" : "Shutting down") + " the server!\r\n"); 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: getInstance().run();//DID I DO EVERYTHING?! D:
} }
} finally { } finally {
shutdownLock.unlock(); srvLock.unlock();
} }
} }
}; };
@@ -297,7 +297,7 @@ public final class BBSOperationHandler extends AbstractMaplePacketHandler {
if (mc.getGuildId() <= 0) { if (mc.getGuildId() <= 0) {
return; return;
} }
Connection con = null; Connection con;
try { try {
con = DatabaseConnection.getConnection(); con = DatabaseConnection.getConnection();
PreparedStatement ps2; PreparedStatement ps2;
@@ -65,6 +65,7 @@ public class EnterCashShopHandler extends AbstractMaplePacketHandler {
mc.cancelDiseaseExpireTask(); mc.cancelDiseaseExpireTask();
mc.cancelSkillCooldownTask(); mc.cancelSkillCooldownTask();
mc.cancelExpirationTask(); mc.cancelExpirationTask();
mc.cancelQuestExpirationTask();
c.announce(MaplePacketCreator.openCashShop(c, false)); c.announce(MaplePacketCreator.openCashShop(c, false));
c.announce(MaplePacketCreator.showCashInventory(c)); c.announce(MaplePacketCreator.showCashInventory(c));
@@ -74,6 +74,7 @@ public final class EnterMTSHandler extends AbstractMaplePacketHandler {
chr.cancelDiseaseExpireTask(); chr.cancelDiseaseExpireTask();
chr.cancelSkillCooldownTask(); chr.cancelSkillCooldownTask();
chr.cancelExpirationTask(); chr.cancelExpirationTask();
chr.cancelQuestExpirationTask();
chr.saveToDB(); chr.saveToDB();
chr.getMap().removePlayer(c.getPlayer()); chr.getMap().removePlayer(c.getPlayer());
@@ -343,15 +343,15 @@ public final class MTSHandler extends AbstractMaplePacketHandler {
} }
} else if (op == 9) { //add to cart } else if (op == 9) { //add to cart
int id = slea.readInt(); //id of the item int id = slea.readInt(); //id of the item
Connection con = null; Connection con;
try { try {
con = DatabaseConnection.getConnection(); con = DatabaseConnection.getConnection();
try (PreparedStatement ps1 = con.prepareStatement("SELECT * FROM mts_items WHERE id = ? AND seller <> ?")) { try (PreparedStatement ps1 = con.prepareStatement("SELECT id FROM mts_items WHERE id = ? AND seller <> ?")) {
ps1.setInt(1, id);//Previene que agregues al cart tus propios items ps1.setInt(1, id); //Dummy query, prevents adding to cart self owned items
ps1.setInt(2, c.getPlayer().getId()); ps1.setInt(2, c.getPlayer().getId());
try (ResultSet rs1 = ps1.executeQuery()) { try (ResultSet rs1 = ps1.executeQuery()) {
if (rs1.next()) { 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(1, c.getPlayer().getId());
ps.setInt(2, id); ps.setInt(2, id);
try (ResultSet rs = ps.executeQuery()) { try (ResultSet rs = ps.executeQuery()) {
@@ -267,6 +267,7 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
player.diseaseExpireTask(); player.diseaseExpireTask();
player.skillCooldownTask(); player.skillCooldownTask();
player.expirationTask(); player.expirationTask();
player.questExpirationTask();
if (GameConstants.hasSPTable(player.getJob()) && player.getJob().getId() != 2001) { if (GameConstants.hasSPTable(player.getJob()) && player.getJob().getId() != 2001) {
player.createDragon(); player.createDragon();
} }
+1 -1
View File
@@ -208,7 +208,7 @@ public class MapleAlliance {
ps.close(); ps.close();
rs.close(); rs.close();
ps = con.prepareStatement("SELECT * FROM allianceguilds WHERE allianceid = ?"); ps = con.prepareStatement("SELECT guildid FROM allianceguilds WHERE allianceid = ?");
ps.setInt(1, id); ps.setInt(1, id);
rs = ps.executeQuery(); rs = ps.executeQuery();
@@ -26,10 +26,12 @@ import net.MaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor; import tools.data.input.SeekableLittleEndianAccessor;
public class KeepAliveHandler implements MaplePacketHandler { public class KeepAliveHandler implements MaplePacketHandler {
@Override
public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) { public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
c.pongReceived(); c.pongReceived();
} }
@Override
public boolean validateState(MapleClient c) { public boolean validateState(MapleClient c) {
return true; return true;
} }
@@ -41,9 +41,7 @@ public final class CharSelectedHandler extends AbstractMaplePacketHandler {
return; return;
} }
if (c.getIdleTask() != null) { Server.getInstance().unregisterLoginState(c);
c.getIdleTask().cancel(true);
}
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION); c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
String[] socket = Server.getInstance().getIP(c.getWorld(), c.getChannel()).split(":"); String[] socket = Server.getInstance().getIP(c.getWorld(), c.getChannel()).split(":");
try { try {
@@ -26,9 +26,7 @@ public class CharSelectedWithPicHandler extends AbstractMaplePacketHandler {
return; return;
} }
if (c.checkPic(pic)) { if (c.checkPic(pic)) {
if (c.getIdleTask() != null) { Server.getInstance().unregisterLoginState(c);
c.getIdleTask().cancel(true);
}
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION); c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
String[] socket = Server.getInstance().getIP(c.getWorld(), c.getChannel()).split(":"); String[] socket = Server.getInstance().getIP(c.getWorld(), c.getChannel()).split(":");
@@ -24,6 +24,7 @@ package net.server.handlers.login;
import java.util.Calendar; import java.util.Calendar;
import net.MaplePacketHandler; import net.MaplePacketHandler;
import net.server.Server;
import server.TimerManager; import server.TimerManager;
import tools.MaplePacketCreator; import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor; import tools.data.input.SeekableLittleEndianAccessor;
@@ -73,12 +74,7 @@ public final class LoginPasswordHandler implements MaplePacketHandler {
private static void login(MapleClient c){ private static void login(MapleClient c){
c.announce(MaplePacketCreator.getAuthSuccess(c));//why the fk did I do c.getAccountName()? c.announce(MaplePacketCreator.getAuthSuccess(c));//why the fk did I do c.getAccountName()?
final MapleClient client = c;
c.setIdleTask(TimerManager.getInstance().schedule(new Runnable() { Server.getInstance().registerLoginState(c);
@Override
public void run() {
client.disconnect(false, false);
}
}, 600000));
} }
} }
@@ -49,9 +49,7 @@ public final class PickCharHandler extends AbstractMaplePacketHandler {
e.printStackTrace(); e.printStackTrace();
c.setChannel(1); c.setChannel(1);
} }
if (c.getIdleTask() != null) { Server.getInstance().unregisterLoginState(c);
c.getIdleTask().cancel(true);
}
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION); c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
String[] socket = Server.getInstance().getIP(c.getWorld(), c.getChannel()).split(":"); String[] socket = Server.getInstance().getIP(c.getWorld(), c.getChannel()).split(":");
try { try {
@@ -29,9 +29,7 @@ public final class RegisterPicHandler extends AbstractMaplePacketHandler {
String pic = slea.readMapleAsciiString(); String pic = slea.readMapleAsciiString();
if (c.getPic() == null || c.getPic().equals("")) { if (c.getPic() == null || c.getPic().equals("")) {
c.setPic(pic); c.setPic(pic);
if (c.getIdleTask() != null) { Server.getInstance().unregisterLoginState(c);
c.getIdleTask().cancel(true);
}
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION); c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
String[] socket = Server.getInstance().getIP(c.getWorld(), c.getChannel()).split(":"); String[] socket = Server.getInstance().getIP(c.getWorld(), c.getChannel()).split(":");
try { try {
@@ -24,7 +24,7 @@ package net.server.handlers.login;
import client.MapleClient; import client.MapleClient;
import net.AbstractMaplePacketHandler; import net.AbstractMaplePacketHandler;
import server.TimerManager; import net.server.Server;
import tools.MaplePacketCreator; import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor; import tools.data.input.SeekableLittleEndianAccessor;
@@ -40,12 +40,8 @@ public class SetGenderHandler extends AbstractMaplePacketHandler {
c.setGender(slea.readByte()); c.setGender(slea.readByte());
c.announce(MaplePacketCreator.getAuthSuccess(c)); c.announce(MaplePacketCreator.getAuthSuccess(c));
final MapleClient client = c; final MapleClient client = c;
c.setIdleTask(TimerManager.getInstance().schedule(new Runnable() {
@Override Server.getInstance().registerLoginState(c);
public void run() {
client.getSession().close(true);
}
}, 600000));
} }
} }
@@ -29,9 +29,7 @@ public class ViewAllCharSelectedWithPicHandler extends AbstractMaplePacketHandle
return; return;
} }
if (c.checkPic(pic)) { if (c.checkPic(pic)) {
if (c.getIdleTask() != null) { Server.getInstance().unregisterLoginState(c);
c.getIdleTask().cancel(true);
}
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION); c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
String[] socket = Server.getInstance().getIP(c.getWorld(), c.getChannel()).split(":"); String[] socket = Server.getInstance().getIP(c.getWorld(), c.getChannel()).split(":");
@@ -28,9 +28,7 @@ public final class ViewAllPicRegisterHandler extends AbstractMaplePacketHandler
slea.readMapleAsciiString(); slea.readMapleAsciiString();
String pic = slea.readMapleAsciiString(); String pic = slea.readMapleAsciiString();
c.setPic(pic); c.setPic(pic);
if (c.getIdleTask() != null) { Server.getInstance().unregisterLoginState(c);
c.getIdleTask().cancel(true);
}
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION); c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
String[] socket = Server.getInstance().getIP(c.getWorld(), channel).split(":"); String[] socket = Server.getInstance().getIP(c.getWorld(), channel).split(":");
try { try {
+1 -1
View File
@@ -1508,7 +1508,7 @@ public class MapleItemInformationProvider {
Connection con = null; Connection con = null;
try { try {
con = DatabaseConnection.getConnection(); con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT * FROM drop_data WHERE itemid = ? LIMIT 50"); PreparedStatement ps = con.prepareStatement("SELECT dropperid FROM drop_data WHERE itemid = ? LIMIT 50");
ps.setInt(1, itemId); ps.setInt(1, itemId);
ResultSet rs = ps.executeQuery(); ResultSet rs = ps.executeQuery();
while(rs.next()) { while(rs.next()) {
+1 -1
View File
@@ -236,7 +236,7 @@ public class MapleShop {
con.close(); con.close();
return null; return null;
} }
ps = con.prepareStatement("SELECT * FROM shopitems WHERE shopid = ? ORDER BY position DESC"); ps = con.prepareStatement("SELECT itemid, price, pitch FROM shopitems WHERE shopid = ? ORDER BY position DESC");
ps.setInt(1, shopId); ps.setInt(1, shopId);
rs = ps.executeQuery(); rs = ps.executeQuery();
List<Integer> recharges = new ArrayList<>(rechargeableItems); List<Integer> recharges = new ArrayList<>(rechargeableItems);
@@ -111,7 +111,7 @@ public class MapleMonsterInformationProvider {
Connection con = null; Connection con = null;
try { try {
con = DatabaseConnection.getConnection(); con = DatabaseConnection.getConnection();
ps = con.prepareStatement("SELECT * FROM drop_data WHERE dropperid = ?"); ps = con.prepareStatement("SELECT itemid, chance, minimum_quantity, maximum_quantity, questid FROM drop_data WHERE dropperid = ?");
ps.setInt(1, monsterId); ps.setInt(1, monsterId);
rs = ps.executeQuery(); rs = ps.executeQuery();
+42 -21
View File
@@ -98,6 +98,7 @@ public class MapleMap {
private Map<Integer, MaplePortal> portals = new HashMap<>(); private Map<Integer, MaplePortal> portals = new HashMap<>();
private Map<Integer, Integer> backgroundTypes = new HashMap<>(); private Map<Integer, Integer> backgroundTypes = new HashMap<>();
private Map<String, Integer> environment = new LinkedHashMap<>(); private Map<String, Integer> environment = new LinkedHashMap<>();
private Map<MapleMapItem, Long> droppedItems = new LinkedHashMap<>();
private LinkedList<WeakReference<MapleMapObject>> registeredDrops = new LinkedList<>(); private LinkedList<WeakReference<MapleMapObject>> registeredDrops = new LinkedList<>();
private List<Rectangle> areas = new ArrayList<>(); private List<Rectangle> areas = new ArrayList<>();
private MapleFootholdTree footholds = null; private MapleFootholdTree footholds = null;
@@ -130,6 +131,7 @@ public class MapleMap {
private int mobCapacity = -1; private int mobCapacity = -1;
private ScheduledFuture<?> mapMonitor = null; private ScheduledFuture<?> mapMonitor = null;
private ScheduledFuture<?> itemMonitor = null; private ScheduledFuture<?> itemMonitor = null;
private ScheduledFuture<?> expireItemsTask = null;
private short itemMonitorTimeout; private short itemMonitorTimeout;
private Pair<Integer, String> timeMob = null; private Pair<Integer, String> timeMob = null;
private short mobInterval = 5000; private short mobInterval = 5000;
@@ -368,7 +370,6 @@ public class MapleMap {
private void spawnRangedMapObject(MapleMapObject mapobject, DelayedPacketCreation packetbakery, SpawnCondition condition) { private void spawnRangedMapObject(MapleMapObject mapobject, DelayedPacketCreation packetbakery, SpawnCondition condition) {
chrRLock.lock(); chrRLock.lock();
try { try {
int curOID = getUsableOID(); int curOID = getUsableOID();
mapobject.setObjectId(curOID); mapobject.setObjectId(curOID);
@@ -585,6 +586,9 @@ public class MapleMap {
try { try {
itemMonitor.cancel(false); itemMonitor.cancel(false);
itemMonitor = null; itemMonitor = null;
expireItemsTask.cancel(false);
expireItemsTask = null;
} finally { } finally {
chrWLock.unlock(); chrWLock.unlock();
} }
@@ -622,6 +626,13 @@ public class MapleMap {
} }
}, ServerConstants.ITEM_MONITOR_TIME, ServerConstants.ITEM_MONITOR_TIME); }, ServerConstants.ITEM_MONITOR_TIME, ServerConstants.ITEM_MONITOR_TIME);
expireItemsTask = TimerManager.getInstance().register(new Runnable() {
@Override
public void run() {
makeDisappearExpiredItemDrops();
}
}, ServerConstants.ITEM_EXPIRE_CHECK, ServerConstants.ITEM_EXPIRE_CHECK);
itemMonitorTimeout = 1; itemMonitorTimeout = 1;
} finally { } finally {
chrWLock.unlock(); chrWLock.unlock();
@@ -637,7 +648,7 @@ public class MapleMap {
} }
} }
private void registerItemDrop(MapleMapItem mdrop) { private void instantiateItemDrop(MapleMapItem mdrop) {
if(droppedItemCount.get() >= ServerConstants.ITEM_LIMIT_ON_MAP) { if(droppedItemCount.get() >= ServerConstants.ITEM_LIMIT_ON_MAP) {
MapleMapObject mapobj; MapleMapObject mapobj;
@@ -654,10 +665,9 @@ public class MapleMap {
makeDisappearItemFromMap(mapobj); makeDisappearItemFromMap(mapobj);
} }
if(!everlast) TimerManager.getInstance().schedule(new ExpireMapItemJob(mdrop), ServerConstants.ITEM_EXPIRE_TIME);
objectWLock.lock(); objectWLock.lock();
try { try {
if(!everlast) registerItemDrop(mdrop);
registeredDrops.add(new WeakReference<>((MapleMapObject) mdrop)); registeredDrops.add(new WeakReference<>((MapleMapObject) mdrop));
} finally { } finally {
objectWLock.unlock(); objectWLock.unlock();
@@ -666,6 +676,31 @@ public class MapleMap {
droppedItemCount.incrementAndGet(); droppedItemCount.incrementAndGet();
} }
private void registerItemDrop(MapleMapItem mdrop) {
droppedItems.put(mdrop, System.currentTimeMillis() + ServerConstants.ITEM_EXPIRE_TIME);
}
private void makeDisappearExpiredItemDrops() {
objectWLock.lock();
try {
List<MapleMapItem> toDisappear = new LinkedList<>();
long timeNow = System.currentTimeMillis();
for(Entry<MapleMapItem, Long> it : droppedItems.entrySet()) {
if(it.getValue() < timeNow) {
toDisappear.add(it.getKey());
}
}
for(MapleMapItem mmi : toDisappear) {
makeDisappearItemFromMap(mmi);
droppedItems.remove(mmi);
}
} finally {
objectWLock.unlock();
}
}
public void pickItemDrop(byte[] pickupPacket, MapleMapItem mdrop) { public void pickItemDrop(byte[] pickupPacket, MapleMapItem mdrop) {
broadcastMessage(pickupPacket, mdrop.getPosition()); broadcastMessage(pickupPacket, mdrop.getPosition());
@@ -686,7 +721,7 @@ public class MapleMap {
} }
}, null); }, null);
registerItemDrop(mdrop); instantiateItemDrop(mdrop);
activateItemReactors(mdrop, chr.getClient()); activateItemReactors(mdrop, chr.getClient());
} }
@@ -702,7 +737,7 @@ public class MapleMap {
} }
}, null); }, null);
registerItemDrop(mdrop); instantiateItemDrop(mdrop);
} }
public final void disappearingItemDrop(final MapleMapObject dropper, final MapleCharacter owner, final Item item, final Point pos) { public final void disappearingItemDrop(final MapleMapObject dropper, final MapleCharacter owner, final Item item, final Point pos) {
@@ -1719,7 +1754,7 @@ public class MapleMap {
}, null); }, null);
broadcastMessage(MaplePacketCreator.dropItemFromMapObject(mdrop, dropper.getPosition(), droppos, (byte) 0)); broadcastMessage(MaplePacketCreator.dropItemFromMapObject(mdrop, dropper.getPosition(), droppos, (byte) 0));
registerItemDrop(mdrop); instantiateItemDrop(mdrop);
activateItemReactors(mdrop, owner.getClient()); activateItemReactors(mdrop, owner.getClient());
} }
@@ -2694,20 +2729,6 @@ public class MapleMap {
} }
} }
private class ExpireMapItemJob implements Runnable {
private MapleMapItem mapitem;
public ExpireMapItemJob(MapleMapItem mapitem) {
this.mapitem = mapitem;
}
@Override
public void run() {
makeDisappearItemFromMap(mapitem);
}
}
private class ActivateItemReactor implements Runnable { private class ActivateItemReactor implements Runnable {
private MapleMapItem mapitem; private MapleMapItem mapitem;
+26 -14
View File
@@ -69,19 +69,20 @@ public class MapleMapFactory {
this.mapsWLock = rrwl.writeLock(); this.mapsWLock = rrwl.writeLock();
} }
public MapleMap getMap(int mapid) { public MapleMap resetMap(int mapid) {
Integer omapid = Integer.valueOf(mapid); mapsWLock.lock();
MapleMap map;
mapsRLock.lock();
try { try {
map = maps.get(omapid); maps.remove(Integer.valueOf(mapid));
} finally { } finally {
mapsRLock.unlock(); mapsWLock.unlock();
} }
if (map == null) { return getMap(mapid);
synchronized (this) { }
private synchronized MapleMap loadMapFromWz(int mapid, Integer omapid) {
MapleMap map;
mapsRLock.lock(); mapsRLock.lock();
try { try {
map = maps.get(omapid); map = maps.get(omapid);
@@ -92,6 +93,7 @@ public class MapleMapFactory {
if (map != null) { if (map != null) {
return map; return map;
} }
String mapName = getMapName(mapid); String mapName = getMapName(mapid);
MapleData mapData = source.getData(mapName); MapleData mapData = source.getData(mapName);
MapleData infoData = mapData.getChildByPath("info"); MapleData infoData = mapData.getChildByPath("info");
@@ -210,9 +212,6 @@ public class MapleMapFactory {
for (MapleData life : mapData.getChildByPath("life")) { for (MapleData life : mapData.getChildByPath("life")) {
String id = MapleDataTool.getString(life.getChildByPath("id")); String id = MapleDataTool.getString(life.getChildByPath("id"));
String type = MapleDataTool.getString(life.getChildByPath("type")); String type = MapleDataTool.getString(life.getChildByPath("type"));
if (id.equals("9001105")) {
id = "9001108";//soz
}
AbstractLoadedMapleLife myLife = loadLife(life, id, type); AbstractLoadedMapleLife myLife = loadLife(life, id, type);
if (myLife instanceof MapleMonster) { if (myLife instanceof MapleMonster) {
MapleMonster monster = (MapleMonster) myLife; MapleMonster monster = (MapleMonster) myLife;
@@ -282,11 +281,24 @@ public class MapleMapFactory {
} finally { } finally {
mapsWLock.unlock(); mapsWLock.unlock();
} }
}
}
return map; return map;
} }
public MapleMap getMap(int mapid) {
Integer omapid = Integer.valueOf(mapid);
MapleMap map;
mapsRLock.lock();
try {
map = maps.get(omapid);
} finally {
mapsRLock.unlock();
}
return (map != null) ? map : loadMapFromWz(mapid, omapid);
}
public boolean isMapLoaded(int mapId) { public boolean isMapLoaded(int mapId) {
mapsRLock.lock(); mapsRLock.lock();
try { try {
+4 -4
View File
@@ -26,16 +26,16 @@ public class DatabaseConnection {
} }
int denies = 0; int denies = 0;
while(true) { // There is no way it can pass with a null out of here while(true) { // There is no way it can pass with a null out of here?
try { try {
return DriverManager.getConnection(ServerConstants.DB_URL, ServerConstants.DB_USER, ServerConstants.DB_PASS); return DriverManager.getConnection(ServerConstants.DB_URL, ServerConstants.DB_USER, ServerConstants.DB_PASS);
} catch (SQLException sqle) { } catch (SQLException sqle) {
denies++; denies++;
if(denies == 3) { if(denies == 3) {
// Give up, return null :3 // Give up, throw exception. Nothing good will come from this.
FilePrinter.printError(FilePrinter.SQL_EXCEPTION, "SQL Driver refused to give a connection after " + denies + " tries."); FilePrinter.printError(FilePrinter.SQL_EXCEPTION, "SQL Driver refused to give a connection after " + denies + " tries. Problem: " + sqle.getMessage());
return null; throw sqle;
} }
} }
} }
+7
View File
@@ -314,6 +314,13 @@ public class MaplePacketCreator {
} }
} }
public static byte[] setExtraPendantSlot(boolean toggleExtraSlot) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.SET_EXTRA_PENDANT_SLOT.getValue());
mplew.writeBool(toggleExtraSlot);
return mplew.getPacket();
}
private static void addCharEntry(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr, boolean viewall) { private static void addCharEntry(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr, boolean viewall) {
addCharStats(mplew, chr); addCharStats(mplew, chr);
addCharLook(mplew, chr, false); addCharLook(mplew, chr, false);