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:
@@ -257,6 +257,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
private Map<Integer, MapleCoolDownValueHolder> coolDowns = new LinkedHashMap<>();
|
||||
private EnumMap<MapleDisease, MapleDiseaseValueHolder> diseases = new EnumMap<>(MapleDisease.class);
|
||||
private Map<Integer, MapleDoor> doors = new LinkedHashMap<>();
|
||||
private Map<MapleQuest, Long> questExpirations = new LinkedHashMap<>();
|
||||
private ScheduledFuture<?> dragonBloodSchedule;
|
||||
private ScheduledFuture<?> hpDecreaseTask;
|
||||
private ScheduledFuture<?> beholderHealingSchedule, beholderBuffSchedule, berserkSchedule;
|
||||
@@ -264,14 +265,14 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
private ScheduledFuture<?> buffExpireTask = null;
|
||||
private ScheduledFuture<?> itemExpireTask = null;
|
||||
private ScheduledFuture<?> diseaseExpireTask = null;
|
||||
private ScheduledFuture<?> questExpireTask = null;
|
||||
private ScheduledFuture<?> recoveryTask = null;
|
||||
private ScheduledFuture<?> extraRecoveryTask = null;
|
||||
private ScheduledFuture<?> chairRecoveryTask = null;
|
||||
private ScheduledFuture<?> pendantOfSpirit = null; //1122017
|
||||
private List<ScheduledFuture<?>> timers = new ArrayList<>();
|
||||
private Lock chrLock = 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 Map<Integer, Set<Integer>> excluded = new LinkedHashMap<>();
|
||||
private Set<Integer> excludedItems = new LinkedHashSet<>();
|
||||
@@ -2088,13 +2089,15 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
addHP(-getMap().getHPDec());
|
||||
lastHpDec = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
hpDecreaseTask = TimerManager.getInstance().schedule(new Runnable() {
|
||||
}
|
||||
|
||||
private void startHpDecreaseTask(long lastHpTask) {
|
||||
hpDecreaseTask = TimerManager.getInstance().register(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
doHurtHp();
|
||||
}
|
||||
}, 10000);
|
||||
}, 10000, 10000 - lastHpTask);
|
||||
}
|
||||
|
||||
public void resetHpDecreaseTask() {
|
||||
@@ -2103,16 +2106,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
}
|
||||
|
||||
long lastHpTask = System.currentTimeMillis() - lastHpDec;
|
||||
if(lastHpTask >= 10000) {
|
||||
doHurtHp();
|
||||
} else {
|
||||
hpDecreaseTask = TimerManager.getInstance().schedule(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
doHurtHp();
|
||||
}
|
||||
}, 10000 - lastHpTask);
|
||||
}
|
||||
startHpDecreaseTask((lastHpTask > 10000) ? 10000 : lastHpTask);
|
||||
}
|
||||
|
||||
public void dropMessage(String message) {
|
||||
@@ -2127,10 +2121,6 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
return nf.format(MapleGuild.CHANGE_EMBLEM_COST);
|
||||
}
|
||||
|
||||
public List<ScheduledFuture<?>> getTimers() {
|
||||
return timers;
|
||||
}
|
||||
|
||||
private void enforceMaxHpMp() {
|
||||
List<Pair<MapleStat, Integer>> stats = new ArrayList<>(2);
|
||||
if (getMp() > getCurrentMaxMp()) {
|
||||
@@ -7221,7 +7211,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
public void showNote() {
|
||||
try {
|
||||
Connection con = DatabaseConnection.getConnection();
|
||||
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM notes WHERE `to`=? AND `deleted` = 0", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE)) {
|
||||
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM notes WHERE `to` = ? AND `deleted` = 0", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE)) {
|
||||
ps.setString(1, this.getName());
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
rs.last();
|
||||
@@ -7466,15 +7456,83 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
updateQuest(newStatus);
|
||||
}
|
||||
|
||||
public void questTimeLimit(final MapleQuest quest, int seconds) {
|
||||
ScheduledFuture<?> sf = TimerManager.getInstance().schedule(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
expireQuest(quest);
|
||||
public void cancelQuestExpirationTask() {
|
||||
petLock.lock();
|
||||
try {
|
||||
if (questExpireTask != null) {
|
||||
questExpireTask.cancel(false);
|
||||
questExpireTask = null;
|
||||
}
|
||||
}, seconds * 1000);
|
||||
} finally {
|
||||
petLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void questExpirationTask() {
|
||||
petLock.lock();
|
||||
try {
|
||||
if(!questExpirations.isEmpty()) {
|
||||
if(questExpireTask == null) {
|
||||
questExpireTask = TimerManager.getInstance().register(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
runQuestExpireTask();
|
||||
}
|
||||
}, 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));
|
||||
timers.add(sf);
|
||||
}
|
||||
|
||||
public void questTimeLimit2(final MapleQuest quest, long expires) {
|
||||
@@ -7483,14 +7541,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
if(timeLeft <= 0) {
|
||||
expireQuest(quest);
|
||||
} else {
|
||||
ScheduledFuture<?> sf = TimerManager.getInstance().schedule(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
expireQuest(quest);
|
||||
}
|
||||
}, timeLeft);
|
||||
|
||||
timers.add(sf);
|
||||
registerQuestExpire(quest, timeLeft);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7903,10 +7954,19 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
cancelSkillCooldownTask();
|
||||
cancelExpirationTask();
|
||||
|
||||
for (ScheduledFuture<?> sf : timers) {
|
||||
sf.cancel(false);
|
||||
petLock.lock();
|
||||
try {
|
||||
if (questExpireTask != null) {
|
||||
questExpireTask.cancel(false);
|
||||
questExpireTask = null;
|
||||
|
||||
questExpirations.clear();
|
||||
questExpirations = null;
|
||||
}
|
||||
} finally {
|
||||
petLock.unlock();
|
||||
}
|
||||
timers.clear();
|
||||
|
||||
if (maplemount != null) {
|
||||
maplemount.empty();
|
||||
maplemount = null;
|
||||
@@ -7921,7 +7981,6 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
family = null;
|
||||
client = null;
|
||||
map = null;
|
||||
timers = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
@@ -70,7 +69,6 @@ import scripting.quest.QuestActionManager;
|
||||
import scripting.quest.QuestScriptManager;
|
||||
import server.life.MapleMonster;
|
||||
import server.MapleTrade;
|
||||
import server.TimerManager;
|
||||
import server.maps.*;
|
||||
import server.quest.MapleQuest;
|
||||
import tools.LogHelper;
|
||||
@@ -101,7 +99,6 @@ public class MapleClient {
|
||||
private int gmlevel;
|
||||
private Set<String> macs = new HashSet<>();
|
||||
private Map<String, ScriptEngine> engines = new HashMap<>();
|
||||
private ScheduledFuture<?> idleTask = null;
|
||||
private byte characterSlots = 3;
|
||||
private byte loginattempt = 0;
|
||||
private String pin = null;
|
||||
@@ -941,15 +938,13 @@ public class MapleClient {
|
||||
}
|
||||
|
||||
private void clear() { //usable when defining client = null shortly after
|
||||
Server.getInstance().unregisterLoginState(this);
|
||||
|
||||
this.accountName = null;
|
||||
this.macs = null;
|
||||
this.hwid = null;
|
||||
this.birthday = null;
|
||||
//this.engines = null;
|
||||
if (this.idleTask != null) {
|
||||
this.idleTask.cancel(true);
|
||||
this.idleTask = null;
|
||||
}
|
||||
this.player = null;
|
||||
this.receive = null;
|
||||
this.send = null;
|
||||
@@ -1005,25 +1000,17 @@ public class MapleClient {
|
||||
lastPong = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public void sendPing() {
|
||||
final long then = System.currentTimeMillis();
|
||||
announce(MaplePacketCreator.getPing());
|
||||
TimerManager.getInstance().schedule(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (lastPong < then) {
|
||||
if (session != null && session.isConnected()) {
|
||||
session.close(false);
|
||||
}
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, 15000);
|
||||
}
|
||||
public void testPing(long timeThen) {
|
||||
try {
|
||||
if (lastPong < timeThen) {
|
||||
if (session != null && session.isConnected()) {
|
||||
session.close(false);
|
||||
}
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public String getHWID() {
|
||||
return hwid;
|
||||
@@ -1053,14 +1040,6 @@ public class MapleClient {
|
||||
engines.remove(name);
|
||||
}
|
||||
|
||||
public ScheduledFuture<?> getIdleTask() {
|
||||
return idleTask;
|
||||
}
|
||||
|
||||
public void setIdleTask(ScheduledFuture<?> idleTask) {
|
||||
this.idleTask = idleTask;
|
||||
}
|
||||
|
||||
public NPCConversationManager getCM() {
|
||||
return NPCScriptManager.getInstance().getCM(this);
|
||||
}
|
||||
@@ -1321,6 +1300,7 @@ public class MapleClient {
|
||||
player.cancelBuffExpireTask();
|
||||
player.cancelDiseaseExpireTask();
|
||||
player.cancelSkillCooldownTask();
|
||||
player.cancelQuestExpirationTask();
|
||||
//Cancelling magicdoor? Nope
|
||||
//Cancelling mounts? Noty
|
||||
if (player.getBuffedValue(MapleBuffStat.PUPPET) != null) {
|
||||
|
||||
@@ -349,6 +349,10 @@ public class Commands {
|
||||
break;
|
||||
|
||||
case "staff":
|
||||
player.yellowMessage("MapleSolaxiaV2 Staff");
|
||||
player.yellowMessage("Ronan - Developer");
|
||||
player.yellowMessage("Vcoc - Freelance Developer");
|
||||
player.yellowMessage("");
|
||||
player.yellowMessage("MapleSolaxia Staff");
|
||||
player.yellowMessage("Aria - Administrator");
|
||||
player.yellowMessage("Twdtwd - Administrator");
|
||||
@@ -358,9 +362,6 @@ public class Commands {
|
||||
player.yellowMessage("SourMjolk - Game Master");
|
||||
player.yellowMessage("Kanade - Game Master");
|
||||
player.yellowMessage("Kitsune - Game Master");
|
||||
player.yellowMessage("MapleSolaxiaV2 Staff");
|
||||
player.yellowMessage("Ronan - Freelance Developer");
|
||||
player.yellowMessage("Vcoc - Freelance Developer");
|
||||
break;
|
||||
|
||||
case "lastrestart":
|
||||
@@ -451,7 +452,7 @@ public class Commands {
|
||||
output += "#b" + data.getRight() + "#k is dropped by:\r\n";
|
||||
try {
|
||||
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());
|
||||
ResultSet rs = ps.executeQuery();
|
||||
while(rs.next()) {
|
||||
@@ -1513,11 +1514,13 @@ public class Commands {
|
||||
|
||||
case "reloadmap":
|
||||
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()) {
|
||||
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();
|
||||
break;
|
||||
|
||||
|
||||
@@ -85,6 +85,7 @@ public class ServerConstants {
|
||||
//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_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.
|
||||
|
||||
//Some Gameplay Enhancing Configurations
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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(":");
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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(":");
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -1508,7 +1508,7 @@ public class MapleItemInformationProvider {
|
||||
Connection con = null;
|
||||
try {
|
||||
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);
|
||||
ResultSet rs = ps.executeQuery();
|
||||
while(rs.next()) {
|
||||
|
||||
@@ -236,7 +236,7 @@ public class MapleShop {
|
||||
con.close();
|
||||
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);
|
||||
rs = ps.executeQuery();
|
||||
List<Integer> recharges = new ArrayList<>(rechargeableItems);
|
||||
|
||||
@@ -111,7 +111,7 @@ public class MapleMonsterInformationProvider {
|
||||
Connection con = null;
|
||||
try {
|
||||
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);
|
||||
rs = ps.executeQuery();
|
||||
|
||||
|
||||
@@ -98,6 +98,7 @@ public class MapleMap {
|
||||
private Map<Integer, MaplePortal> portals = new HashMap<>();
|
||||
private Map<Integer, Integer> backgroundTypes = new HashMap<>();
|
||||
private Map<String, Integer> environment = new LinkedHashMap<>();
|
||||
private Map<MapleMapItem, Long> droppedItems = new LinkedHashMap<>();
|
||||
private LinkedList<WeakReference<MapleMapObject>> registeredDrops = new LinkedList<>();
|
||||
private List<Rectangle> areas = new ArrayList<>();
|
||||
private MapleFootholdTree footholds = null;
|
||||
@@ -130,6 +131,7 @@ public class MapleMap {
|
||||
private int mobCapacity = -1;
|
||||
private ScheduledFuture<?> mapMonitor = null;
|
||||
private ScheduledFuture<?> itemMonitor = null;
|
||||
private ScheduledFuture<?> expireItemsTask = null;
|
||||
private short itemMonitorTimeout;
|
||||
private Pair<Integer, String> timeMob = null;
|
||||
private short mobInterval = 5000;
|
||||
@@ -368,7 +370,6 @@ public class MapleMap {
|
||||
|
||||
private void spawnRangedMapObject(MapleMapObject mapobject, DelayedPacketCreation packetbakery, SpawnCondition condition) {
|
||||
chrRLock.lock();
|
||||
|
||||
try {
|
||||
int curOID = getUsableOID();
|
||||
mapobject.setObjectId(curOID);
|
||||
@@ -585,6 +586,9 @@ public class MapleMap {
|
||||
try {
|
||||
itemMonitor.cancel(false);
|
||||
itemMonitor = null;
|
||||
|
||||
expireItemsTask.cancel(false);
|
||||
expireItemsTask = null;
|
||||
} finally {
|
||||
chrWLock.unlock();
|
||||
}
|
||||
@@ -621,6 +625,13 @@ public class MapleMap {
|
||||
if(!registeredDrops.isEmpty()) cleanItemMonitor();
|
||||
}
|
||||
}, 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;
|
||||
} finally {
|
||||
@@ -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) {
|
||||
MapleMapObject mapobj;
|
||||
|
||||
@@ -654,10 +665,9 @@ public class MapleMap {
|
||||
makeDisappearItemFromMap(mapobj);
|
||||
}
|
||||
|
||||
if(!everlast) TimerManager.getInstance().schedule(new ExpireMapItemJob(mdrop), ServerConstants.ITEM_EXPIRE_TIME);
|
||||
|
||||
objectWLock.lock();
|
||||
try {
|
||||
if(!everlast) registerItemDrop(mdrop);
|
||||
registeredDrops.add(new WeakReference<>((MapleMapObject) mdrop));
|
||||
} finally {
|
||||
objectWLock.unlock();
|
||||
@@ -666,6 +676,31 @@ public class MapleMap {
|
||||
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) {
|
||||
broadcastMessage(pickupPacket, mdrop.getPosition());
|
||||
|
||||
@@ -686,7 +721,7 @@ public class MapleMap {
|
||||
}
|
||||
}, null);
|
||||
|
||||
registerItemDrop(mdrop);
|
||||
instantiateItemDrop(mdrop);
|
||||
activateItemReactors(mdrop, chr.getClient());
|
||||
}
|
||||
|
||||
@@ -702,7 +737,7 @@ public class MapleMap {
|
||||
}
|
||||
}, null);
|
||||
|
||||
registerItemDrop(mdrop);
|
||||
instantiateItemDrop(mdrop);
|
||||
}
|
||||
|
||||
public final void disappearingItemDrop(final MapleMapObject dropper, final MapleCharacter owner, final Item item, final Point pos) {
|
||||
@@ -1719,7 +1754,7 @@ public class MapleMap {
|
||||
}, null);
|
||||
broadcastMessage(MaplePacketCreator.dropItemFromMapObject(mdrop, dropper.getPosition(), droppos, (byte) 0));
|
||||
|
||||
registerItemDrop(mdrop);
|
||||
instantiateItemDrop(mdrop);
|
||||
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 MapleMapItem mapitem;
|
||||
|
||||
@@ -69,6 +69,222 @@ public class MapleMapFactory {
|
||||
this.mapsWLock = rrwl.writeLock();
|
||||
}
|
||||
|
||||
public MapleMap resetMap(int mapid) {
|
||||
mapsWLock.lock();
|
||||
try {
|
||||
maps.remove(Integer.valueOf(mapid));
|
||||
} finally {
|
||||
mapsWLock.unlock();
|
||||
}
|
||||
|
||||
return getMap(mapid);
|
||||
}
|
||||
|
||||
private synchronized MapleMap loadMapFromWz(int mapid, Integer omapid) {
|
||||
MapleMap map;
|
||||
|
||||
mapsRLock.lock();
|
||||
try {
|
||||
map = maps.get(omapid);
|
||||
} finally {
|
||||
mapsRLock.unlock();
|
||||
}
|
||||
|
||||
if (map != null) {
|
||||
return map;
|
||||
}
|
||||
|
||||
String mapName = getMapName(mapid);
|
||||
MapleData mapData = source.getData(mapName);
|
||||
MapleData infoData = mapData.getChildByPath("info");
|
||||
|
||||
String link = MapleDataTool.getString(infoData.getChildByPath("link"), "");
|
||||
if (!link.equals("")) { //nexon made hundreds of dojo maps so to reduce the size they added links.
|
||||
mapName = getMapName(Integer.parseInt(link));
|
||||
mapData = source.getData(mapName);
|
||||
}
|
||||
float monsterRate = 0;
|
||||
MapleData mobRate = infoData.getChildByPath("mobRate");
|
||||
if (mobRate != null) {
|
||||
monsterRate = ((Float) mobRate.getData()).floatValue();
|
||||
}
|
||||
map = new MapleMap(mapid, world, channel, MapleDataTool.getInt("returnMap", infoData), monsterRate);
|
||||
map.setEventInstance(event);
|
||||
|
||||
String onFirstEnter = MapleDataTool.getString(infoData.getChildByPath("onFirstUserEnter"), String.valueOf(mapid));
|
||||
map.setOnFirstUserEnter(onFirstEnter.equals("") ? String.valueOf(mapid) : onFirstEnter);
|
||||
|
||||
String onEnter = MapleDataTool.getString(infoData.getChildByPath("onUserEnter"), String.valueOf(mapid));
|
||||
map.setOnUserEnter(onEnter.equals("") ? String.valueOf(mapid) : onEnter);
|
||||
|
||||
map.setFieldLimit(MapleDataTool.getInt(infoData.getChildByPath("fieldLimit"), 0));
|
||||
map.setMobInterval((short) MapleDataTool.getInt(infoData.getChildByPath("createMobInterval"), 5000));
|
||||
PortalFactory portalFactory = new PortalFactory();
|
||||
for (MapleData portal : mapData.getChildByPath("portal")) {
|
||||
map.addPortal(portalFactory.makePortal(MapleDataTool.getInt(portal.getChildByPath("pt")), portal));
|
||||
}
|
||||
MapleData timeMob = infoData.getChildByPath("timeMob");
|
||||
if (timeMob != null) {
|
||||
map.timeMob(MapleDataTool.getInt(timeMob.getChildByPath("id")),
|
||||
MapleDataTool.getString(timeMob.getChildByPath("message")));
|
||||
}
|
||||
|
||||
int bounds[] = new int[4];
|
||||
bounds[0] = MapleDataTool.getInt(infoData.getChildByPath("VRTop"));
|
||||
bounds[1] = MapleDataTool.getInt(infoData.getChildByPath("VRBottom"));
|
||||
|
||||
if(bounds[0] == bounds[1]) { // old-style baked map
|
||||
MapleData minimapData = mapData.getChildByPath("miniMap");
|
||||
if(minimapData != null) {
|
||||
bounds[0] = MapleDataTool.getInt(minimapData.getChildByPath("centerX")) * -1;
|
||||
bounds[1] = MapleDataTool.getInt(minimapData.getChildByPath("centerY")) * -1;
|
||||
bounds[2] = MapleDataTool.getInt(minimapData.getChildByPath("height"));
|
||||
bounds[3] = MapleDataTool.getInt(minimapData.getChildByPath("width"));
|
||||
|
||||
map.setMapPointBoundings(bounds[0], bounds[1], bounds[2], bounds[3]);
|
||||
}
|
||||
} else {
|
||||
bounds[2] = MapleDataTool.getInt(infoData.getChildByPath("VRLeft"));
|
||||
bounds[3] = MapleDataTool.getInt(infoData.getChildByPath("VRRight"));
|
||||
|
||||
map.setMapLineBoundings(bounds[0], bounds[1], bounds[2], bounds[3]);
|
||||
}
|
||||
|
||||
List<MapleFoothold> allFootholds = new LinkedList<>();
|
||||
Point lBound = new Point();
|
||||
Point uBound = new Point();
|
||||
for (MapleData footRoot : mapData.getChildByPath("foothold")) {
|
||||
for (MapleData footCat : footRoot) {
|
||||
for (MapleData footHold : footCat) {
|
||||
int x1 = MapleDataTool.getInt(footHold.getChildByPath("x1"));
|
||||
int y1 = MapleDataTool.getInt(footHold.getChildByPath("y1"));
|
||||
int x2 = MapleDataTool.getInt(footHold.getChildByPath("x2"));
|
||||
int y2 = MapleDataTool.getInt(footHold.getChildByPath("y2"));
|
||||
MapleFoothold fh = new MapleFoothold(new Point(x1, y1), new Point(x2, y2), Integer.parseInt(footHold.getName()));
|
||||
fh.setPrev(MapleDataTool.getInt(footHold.getChildByPath("prev")));
|
||||
fh.setNext(MapleDataTool.getInt(footHold.getChildByPath("next")));
|
||||
if (fh.getX1() < lBound.x) {
|
||||
lBound.x = fh.getX1();
|
||||
}
|
||||
if (fh.getX2() > uBound.x) {
|
||||
uBound.x = fh.getX2();
|
||||
}
|
||||
if (fh.getY1() < lBound.y) {
|
||||
lBound.y = fh.getY1();
|
||||
}
|
||||
if (fh.getY2() > uBound.y) {
|
||||
uBound.y = fh.getY2();
|
||||
}
|
||||
allFootholds.add(fh);
|
||||
}
|
||||
}
|
||||
}
|
||||
MapleFootholdTree fTree = new MapleFootholdTree(lBound, uBound);
|
||||
for (MapleFoothold fh : allFootholds) {
|
||||
fTree.insert(fh);
|
||||
}
|
||||
map.setFootholds(fTree);
|
||||
if (mapData.getChildByPath("area") != null) {
|
||||
for (MapleData area : mapData.getChildByPath("area")) {
|
||||
int x1 = MapleDataTool.getInt(area.getChildByPath("x1"));
|
||||
int y1 = MapleDataTool.getInt(area.getChildByPath("y1"));
|
||||
int x2 = MapleDataTool.getInt(area.getChildByPath("x2"));
|
||||
int y2 = MapleDataTool.getInt(area.getChildByPath("y2"));
|
||||
map.addMapleArea(new Rectangle(x1, y1, (x2 - x1), (y2 - y1)));
|
||||
}
|
||||
}
|
||||
try {
|
||||
Connection con = DatabaseConnection.getConnection();
|
||||
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM playernpcs WHERE map = ?")) {
|
||||
ps.setInt(1, omapid);
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
map.addMapObject(new PlayerNPCs(rs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
con.close();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
for (MapleData life : mapData.getChildByPath("life")) {
|
||||
String id = MapleDataTool.getString(life.getChildByPath("id"));
|
||||
String type = MapleDataTool.getString(life.getChildByPath("type"));
|
||||
AbstractLoadedMapleLife myLife = loadLife(life, id, type);
|
||||
if (myLife instanceof MapleMonster) {
|
||||
MapleMonster monster = (MapleMonster) myLife;
|
||||
int mobTime = MapleDataTool.getInt("mobTime", life, 0);
|
||||
int team = MapleDataTool.getInt("team", life, -1);
|
||||
if (mobTime == -1) { //does not respawn, force spawn once
|
||||
map.spawnMonster(monster);
|
||||
} else {
|
||||
map.addMonsterSpawn(monster, mobTime, team);
|
||||
}
|
||||
|
||||
//should the map be reseted, use allMonsterSpawn list of monsters to spawn them again
|
||||
map.addAllMonsterSpawn(monster, mobTime, team);
|
||||
} else {
|
||||
map.addMapObject(myLife);
|
||||
}
|
||||
}
|
||||
|
||||
if (mapData.getChildByPath("reactor") != null) {
|
||||
for (MapleData reactor : mapData.getChildByPath("reactor")) {
|
||||
String id = MapleDataTool.getString(reactor.getChildByPath("id"));
|
||||
if (id != null) {
|
||||
MapleReactor newReactor = loadReactor(reactor, id);
|
||||
map.spawnReactor(newReactor);
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
map.setMapName(MapleDataTool.getString("mapName", nameData.getChildByPath(getMapStringName(omapid)), ""));
|
||||
map.setStreetName(MapleDataTool.getString("streetName", nameData.getChildByPath(getMapStringName(omapid)), ""));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.err.println("Not found mapid " + omapid);
|
||||
|
||||
map.setMapName("");
|
||||
map.setStreetName("");
|
||||
}
|
||||
|
||||
map.setClock(mapData.getChildByPath("clock") != null);
|
||||
map.setEverlast(infoData.getChildByPath("everlast") != null);
|
||||
map.setTown(infoData.getChildByPath("town") != null);
|
||||
map.setHPDec(MapleDataTool.getIntConvert("decHP", infoData, 0));
|
||||
map.setHPDecProtect(MapleDataTool.getIntConvert("protectItem", infoData, 0));
|
||||
map.setForcedReturnMap(MapleDataTool.getInt(infoData.getChildByPath("forcedReturn"), 999999999));
|
||||
map.setBoat(mapData.getChildByPath("shipObj") != null);
|
||||
map.setTimeLimit(MapleDataTool.getIntConvert("timeLimit", infoData, -1));
|
||||
map.setFieldType(MapleDataTool.getIntConvert("fieldType", infoData, 0));
|
||||
map.setMobCapacity(MapleDataTool.getIntConvert("fixedMobCapacity", infoData, 500));//Is there a map that contains more than 500 mobs?
|
||||
|
||||
HashMap<Integer, Integer> backTypes = new HashMap<>();
|
||||
try {
|
||||
for (MapleData layer : mapData.getChildByPath("back")) { // yolo
|
||||
int layerNum = Integer.parseInt(layer.getName());
|
||||
int type = MapleDataTool.getInt(layer.getChildByPath("type"), 0);
|
||||
|
||||
backTypes.put(layerNum, type);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
// swallow cause I'm cool
|
||||
}
|
||||
map.setBackgroundTypes(backTypes);
|
||||
|
||||
mapsWLock.lock();
|
||||
try {
|
||||
maps.put(omapid, map);
|
||||
} finally {
|
||||
mapsWLock.unlock();
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
public MapleMap getMap(int mapid) {
|
||||
Integer omapid = Integer.valueOf(mapid);
|
||||
MapleMap map;
|
||||
@@ -80,211 +296,7 @@ public class MapleMapFactory {
|
||||
mapsRLock.unlock();
|
||||
}
|
||||
|
||||
if (map == null) {
|
||||
synchronized (this) {
|
||||
mapsRLock.lock();
|
||||
try {
|
||||
map = maps.get(omapid);
|
||||
} finally {
|
||||
mapsRLock.unlock();
|
||||
}
|
||||
|
||||
if (map != null) {
|
||||
return map;
|
||||
}
|
||||
String mapName = getMapName(mapid);
|
||||
MapleData mapData = source.getData(mapName);
|
||||
MapleData infoData = mapData.getChildByPath("info");
|
||||
|
||||
String link = MapleDataTool.getString(infoData.getChildByPath("link"), "");
|
||||
if (!link.equals("")) { //nexon made hundreds of dojo maps so to reduce the size they added links.
|
||||
mapName = getMapName(Integer.parseInt(link));
|
||||
mapData = source.getData(mapName);
|
||||
}
|
||||
float monsterRate = 0;
|
||||
MapleData mobRate = infoData.getChildByPath("mobRate");
|
||||
if (mobRate != null) {
|
||||
monsterRate = ((Float) mobRate.getData()).floatValue();
|
||||
}
|
||||
map = new MapleMap(mapid, world, channel, MapleDataTool.getInt("returnMap", infoData), monsterRate);
|
||||
map.setEventInstance(event);
|
||||
|
||||
String onFirstEnter = MapleDataTool.getString(infoData.getChildByPath("onFirstUserEnter"), String.valueOf(mapid));
|
||||
map.setOnFirstUserEnter(onFirstEnter.equals("") ? String.valueOf(mapid) : onFirstEnter);
|
||||
|
||||
String onEnter = MapleDataTool.getString(infoData.getChildByPath("onUserEnter"), String.valueOf(mapid));
|
||||
map.setOnUserEnter(onEnter.equals("") ? String.valueOf(mapid) : onEnter);
|
||||
|
||||
map.setFieldLimit(MapleDataTool.getInt(infoData.getChildByPath("fieldLimit"), 0));
|
||||
map.setMobInterval((short) MapleDataTool.getInt(infoData.getChildByPath("createMobInterval"), 5000));
|
||||
PortalFactory portalFactory = new PortalFactory();
|
||||
for (MapleData portal : mapData.getChildByPath("portal")) {
|
||||
map.addPortal(portalFactory.makePortal(MapleDataTool.getInt(portal.getChildByPath("pt")), portal));
|
||||
}
|
||||
MapleData timeMob = infoData.getChildByPath("timeMob");
|
||||
if (timeMob != null) {
|
||||
map.timeMob(MapleDataTool.getInt(timeMob.getChildByPath("id")),
|
||||
MapleDataTool.getString(timeMob.getChildByPath("message")));
|
||||
}
|
||||
|
||||
int bounds[] = new int[4];
|
||||
bounds[0] = MapleDataTool.getInt(infoData.getChildByPath("VRTop"));
|
||||
bounds[1] = MapleDataTool.getInt(infoData.getChildByPath("VRBottom"));
|
||||
|
||||
if(bounds[0] == bounds[1]) { // old-style baked map
|
||||
MapleData minimapData = mapData.getChildByPath("miniMap");
|
||||
if(minimapData != null) {
|
||||
bounds[0] = MapleDataTool.getInt(minimapData.getChildByPath("centerX")) * -1;
|
||||
bounds[1] = MapleDataTool.getInt(minimapData.getChildByPath("centerY")) * -1;
|
||||
bounds[2] = MapleDataTool.getInt(minimapData.getChildByPath("height"));
|
||||
bounds[3] = MapleDataTool.getInt(minimapData.getChildByPath("width"));
|
||||
|
||||
map.setMapPointBoundings(bounds[0], bounds[1], bounds[2], bounds[3]);
|
||||
}
|
||||
} else {
|
||||
bounds[2] = MapleDataTool.getInt(infoData.getChildByPath("VRLeft"));
|
||||
bounds[3] = MapleDataTool.getInt(infoData.getChildByPath("VRRight"));
|
||||
|
||||
map.setMapLineBoundings(bounds[0], bounds[1], bounds[2], bounds[3]);
|
||||
}
|
||||
|
||||
List<MapleFoothold> allFootholds = new LinkedList<>();
|
||||
Point lBound = new Point();
|
||||
Point uBound = new Point();
|
||||
for (MapleData footRoot : mapData.getChildByPath("foothold")) {
|
||||
for (MapleData footCat : footRoot) {
|
||||
for (MapleData footHold : footCat) {
|
||||
int x1 = MapleDataTool.getInt(footHold.getChildByPath("x1"));
|
||||
int y1 = MapleDataTool.getInt(footHold.getChildByPath("y1"));
|
||||
int x2 = MapleDataTool.getInt(footHold.getChildByPath("x2"));
|
||||
int y2 = MapleDataTool.getInt(footHold.getChildByPath("y2"));
|
||||
MapleFoothold fh = new MapleFoothold(new Point(x1, y1), new Point(x2, y2), Integer.parseInt(footHold.getName()));
|
||||
fh.setPrev(MapleDataTool.getInt(footHold.getChildByPath("prev")));
|
||||
fh.setNext(MapleDataTool.getInt(footHold.getChildByPath("next")));
|
||||
if (fh.getX1() < lBound.x) {
|
||||
lBound.x = fh.getX1();
|
||||
}
|
||||
if (fh.getX2() > uBound.x) {
|
||||
uBound.x = fh.getX2();
|
||||
}
|
||||
if (fh.getY1() < lBound.y) {
|
||||
lBound.y = fh.getY1();
|
||||
}
|
||||
if (fh.getY2() > uBound.y) {
|
||||
uBound.y = fh.getY2();
|
||||
}
|
||||
allFootholds.add(fh);
|
||||
}
|
||||
}
|
||||
}
|
||||
MapleFootholdTree fTree = new MapleFootholdTree(lBound, uBound);
|
||||
for (MapleFoothold fh : allFootholds) {
|
||||
fTree.insert(fh);
|
||||
}
|
||||
map.setFootholds(fTree);
|
||||
if (mapData.getChildByPath("area") != null) {
|
||||
for (MapleData area : mapData.getChildByPath("area")) {
|
||||
int x1 = MapleDataTool.getInt(area.getChildByPath("x1"));
|
||||
int y1 = MapleDataTool.getInt(area.getChildByPath("y1"));
|
||||
int x2 = MapleDataTool.getInt(area.getChildByPath("x2"));
|
||||
int y2 = MapleDataTool.getInt(area.getChildByPath("y2"));
|
||||
map.addMapleArea(new Rectangle(x1, y1, (x2 - x1), (y2 - y1)));
|
||||
}
|
||||
}
|
||||
try {
|
||||
Connection con = DatabaseConnection.getConnection();
|
||||
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM playernpcs WHERE map = ?")) {
|
||||
ps.setInt(1, omapid);
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
map.addMapObject(new PlayerNPCs(rs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
con.close();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
for (MapleData life : mapData.getChildByPath("life")) {
|
||||
String id = MapleDataTool.getString(life.getChildByPath("id"));
|
||||
String type = MapleDataTool.getString(life.getChildByPath("type"));
|
||||
if (id.equals("9001105")) {
|
||||
id = "9001108";//soz
|
||||
}
|
||||
AbstractLoadedMapleLife myLife = loadLife(life, id, type);
|
||||
if (myLife instanceof MapleMonster) {
|
||||
MapleMonster monster = (MapleMonster) myLife;
|
||||
int mobTime = MapleDataTool.getInt("mobTime", life, 0);
|
||||
int team = MapleDataTool.getInt("team", life, -1);
|
||||
if (mobTime == -1) { //does not respawn, force spawn once
|
||||
map.spawnMonster(monster);
|
||||
} else {
|
||||
map.addMonsterSpawn(monster, mobTime, team);
|
||||
}
|
||||
|
||||
//should the map be reseted, use allMonsterSpawn list of monsters to spawn them again
|
||||
map.addAllMonsterSpawn(monster, mobTime, team);
|
||||
} else {
|
||||
map.addMapObject(myLife);
|
||||
}
|
||||
}
|
||||
|
||||
if (mapData.getChildByPath("reactor") != null) {
|
||||
for (MapleData reactor : mapData.getChildByPath("reactor")) {
|
||||
String id = MapleDataTool.getString(reactor.getChildByPath("id"));
|
||||
if (id != null) {
|
||||
MapleReactor newReactor = loadReactor(reactor, id);
|
||||
map.spawnReactor(newReactor);
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
map.setMapName(MapleDataTool.getString("mapName", nameData.getChildByPath(getMapStringName(omapid)), ""));
|
||||
map.setStreetName(MapleDataTool.getString("streetName", nameData.getChildByPath(getMapStringName(omapid)), ""));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.err.println("Not found mapid " + omapid);
|
||||
|
||||
map.setMapName("");
|
||||
map.setStreetName("");
|
||||
}
|
||||
|
||||
map.setClock(mapData.getChildByPath("clock") != null);
|
||||
map.setEverlast(infoData.getChildByPath("everlast") != null);
|
||||
map.setTown(infoData.getChildByPath("town") != null);
|
||||
map.setHPDec(MapleDataTool.getIntConvert("decHP", infoData, 0));
|
||||
map.setHPDecProtect(MapleDataTool.getIntConvert("protectItem", infoData, 0));
|
||||
map.setForcedReturnMap(MapleDataTool.getInt(infoData.getChildByPath("forcedReturn"), 999999999));
|
||||
map.setBoat(mapData.getChildByPath("shipObj") != null);
|
||||
map.setTimeLimit(MapleDataTool.getIntConvert("timeLimit", infoData, -1));
|
||||
map.setFieldType(MapleDataTool.getIntConvert("fieldType", infoData, 0));
|
||||
map.setMobCapacity(MapleDataTool.getIntConvert("fixedMobCapacity", infoData, 500));//Is there a map that contains more than 500 mobs?
|
||||
|
||||
HashMap<Integer, Integer> backTypes = new HashMap<>();
|
||||
try {
|
||||
for (MapleData layer : mapData.getChildByPath("back")) { // yolo
|
||||
int layerNum = Integer.parseInt(layer.getName());
|
||||
int type = MapleDataTool.getInt(layer.getChildByPath("type"), 0);
|
||||
|
||||
backTypes.put(layerNum, type);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
// swallow cause I'm cool
|
||||
}
|
||||
map.setBackgroundTypes(backTypes);
|
||||
|
||||
mapsWLock.lock();
|
||||
try {
|
||||
maps.put(omapid, map);
|
||||
} finally {
|
||||
mapsWLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
return (map != null) ? map : loadMapFromWz(mapid, omapid);
|
||||
}
|
||||
|
||||
public boolean isMapLoaded(int mapId) {
|
||||
|
||||
@@ -26,16 +26,16 @@ public class DatabaseConnection {
|
||||
}
|
||||
|
||||
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 {
|
||||
return DriverManager.getConnection(ServerConstants.DB_URL, ServerConstants.DB_USER, ServerConstants.DB_PASS);
|
||||
} catch (SQLException sqle) {
|
||||
denies++;
|
||||
|
||||
if(denies == 3) {
|
||||
// Give up, return null :3
|
||||
FilePrinter.printError(FilePrinter.SQL_EXCEPTION, "SQL Driver refused to give a connection after " + denies + " tries.");
|
||||
return null;
|
||||
// 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. Problem: " + sqle.getMessage());
|
||||
throw sqle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,6 +313,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) {
|
||||
addCharStats(mplew, chr);
|
||||
|
||||
Reference in New Issue
Block a user