Mystic Doors review + Togglable SrvMessage-BossHP + Map-Event patch
Reviewed Mystic Doors. Fixed several issues showing up on Duey in uncommon scenarios. Fixed a concurrency issue with XMLDomMapleData. Scheduled forward the "lock disposal" action within the source. Now, it's expected that, after a set while, no method should require usage of a disposed lock and, during that while, a supposed "disposed lock" is still available to run (although no new processes is expected to require use of these locks). Fixed concurrency issues with player's current event instance, generating several inconsistencies when swiftly registering/unregistering from events. Implemented a mutually exclusive approach for server message - Boss HPbar. Fixed item-making Kage requiring lv71~80 ETC instead of the expected 81~90. Removed the possibility to buy cosmetic coupons with mesos through the NPCs. Sleepywood JQ's no longer gives cash items when they finish the quest repeatedly. Added Duey trucks in several maps lacking it. Added NPC Duey in New Leaf City. Fixed scripted quests not calculating QUEST_RATE (if applied) when rewarding experience and meso.
This commit is contained in:
@@ -60,6 +60,7 @@ import net.server.guild.MapleGuildCharacter;
|
||||
import net.server.worker.CharacterDiseaseWorker;
|
||||
import net.server.worker.CouponWorker;
|
||||
import net.server.worker.RankingWorker;
|
||||
import net.server.worker.ReleaseLockWorker;
|
||||
import net.server.world.World;
|
||||
|
||||
import org.apache.mina.core.buffer.IoBuffer;
|
||||
@@ -206,7 +207,11 @@ public class Server {
|
||||
public World getWorld(int id) {
|
||||
wldRLock.lock();
|
||||
try {
|
||||
return worlds.get(id);
|
||||
try {
|
||||
return worlds.get(id);
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
return null;
|
||||
}
|
||||
} finally {
|
||||
wldRLock.unlock();
|
||||
}
|
||||
@@ -231,21 +236,33 @@ public class Server {
|
||||
}
|
||||
|
||||
public Channel getChannel(int world, int channel) {
|
||||
return this.getWorld(world).getChannel(channel);
|
||||
try {
|
||||
return this.getWorld(world).getChannel(channel);
|
||||
} catch(NullPointerException npe) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public List<Channel> getChannelsFromWorld(int world) {
|
||||
return this.getWorld(world).getChannels();
|
||||
try {
|
||||
return this.getWorld(world).getChannels();
|
||||
} catch(NullPointerException npe) {
|
||||
return new ArrayList<>(0);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Channel> getAllChannels() {
|
||||
List<Channel> channelz = new ArrayList<>();
|
||||
for (World world : this.getWorlds()) {
|
||||
for (Channel ch : world.getChannels()) {
|
||||
channelz.add(ch);
|
||||
try {
|
||||
List<Channel> channelz = new ArrayList<>();
|
||||
for (World world : this.getWorlds()) {
|
||||
for (Channel ch : world.getChannels()) {
|
||||
channelz.add(ch);
|
||||
}
|
||||
}
|
||||
return channelz;
|
||||
} catch(NullPointerException npe) {
|
||||
return new ArrayList<>(0);
|
||||
}
|
||||
return channelz;
|
||||
}
|
||||
|
||||
public Set<Integer> getOpenChannels(int world) {
|
||||
@@ -257,7 +274,7 @@ public class Server {
|
||||
}
|
||||
}
|
||||
|
||||
public String getIP(int world, int channel) {
|
||||
private String getIP(int world, int channel) {
|
||||
wldRLock.lock();
|
||||
try {
|
||||
return channels.get(world).get(channel);
|
||||
@@ -266,6 +283,15 @@ public class Server {
|
||||
}
|
||||
}
|
||||
|
||||
public String[] getInetSocket(int world, int channel) {
|
||||
try {
|
||||
return getIP(world, channel).split(":");
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void dumpData() {
|
||||
wldWLock.lock();
|
||||
try {
|
||||
@@ -643,6 +669,7 @@ public class Server {
|
||||
|
||||
long timeLeft = getTimeLeftForNextHour();
|
||||
tMan.register(new CharacterDiseaseWorker(), ServerConstants.UPDATE_INTERVAL, ServerConstants.UPDATE_INTERVAL);
|
||||
tMan.register(new ReleaseLockWorker(), 2 * 60 * 1000, 2 * 60 * 1000);
|
||||
tMan.register(new CouponWorker(), ServerConstants.COUPON_INTERVAL, timeLeft);
|
||||
tMan.register(new RankingWorker(), ServerConstants.RANKING_INTERVAL, timeLeft);
|
||||
|
||||
@@ -1149,8 +1176,10 @@ public class Server {
|
||||
}
|
||||
*/
|
||||
|
||||
public Pair<Pair<Integer, List<MapleCharacter>>, List<Pair<Integer, List<MapleCharacter>>>> loadAccountCharlist(Integer accountId) {
|
||||
public Pair<Pair<Integer, List<MapleCharacter>>, List<Pair<Integer, List<MapleCharacter>>>> loadAccountCharlist(Integer accountId, int visibleWorlds) {
|
||||
List<World> wlist = this.getWorlds();
|
||||
if(wlist.size() > visibleWorlds) wlist = wlist.subList(0, visibleWorlds);
|
||||
|
||||
List<Pair<Integer, List<MapleCharacter>>> accChars = new ArrayList<>(wlist.size() + 1);
|
||||
int chrTotal = 0;
|
||||
List<MapleCharacter> lastwchars = null;
|
||||
|
||||
75
src/net/server/audit/LockCollector.java
Normal file
75
src/net/server/audit/LockCollector.java
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2018 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.audit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Ronan
|
||||
*/
|
||||
public class LockCollector {
|
||||
|
||||
private static final LockCollector instance = new LockCollector();
|
||||
|
||||
private Map<Runnable, Integer> disposableLocks = new HashMap<>(200);
|
||||
private final Lock lock = new ReentrantLock(true);
|
||||
|
||||
public static LockCollector getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void registerDisposeAction(Runnable r) {
|
||||
lock.lock();
|
||||
try {
|
||||
disposableLocks.put(r, 0);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void runLockCollector() {
|
||||
List<Runnable> toDispose = new ArrayList<>();
|
||||
|
||||
lock.lock();
|
||||
try {
|
||||
for(Entry<Runnable, Integer> e : disposableLocks.entrySet()) {
|
||||
Integer eVal = e.getValue();
|
||||
if(eVal > 5) { // updates each 2min
|
||||
toDispose.add(e.getKey());
|
||||
} else {
|
||||
disposableLocks.put(e.getKey(), ++eVal);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
for(Runnable r : toDispose) {
|
||||
r.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -57,7 +57,7 @@ public class ThreadTracker {
|
||||
private final Map<Long, AtomicInteger> lockCount = new HashMap<>();
|
||||
private final Map<Long, MonitoredLockType> lockIds = new HashMap<>();
|
||||
private final Map<Long, Long> lockThreads = new HashMap<>();
|
||||
private final Map<Long, Byte> lockUpdate = new HashMap<>();
|
||||
private final Map<Long, Integer> lockUpdate = new HashMap<>();
|
||||
|
||||
private final Map<MonitoredLockType, Map<Long, Integer>> locks = new HashMap<>();
|
||||
ScheduledFuture<?> threadTrackerSchedule;
|
||||
@@ -169,8 +169,8 @@ public class ThreadTracker {
|
||||
|
||||
toRemove.clear();
|
||||
|
||||
for(Entry<Long, Byte> it : lockUpdate.entrySet()) {
|
||||
byte val = (byte)(it.getValue() + 1);
|
||||
for(Entry<Long, Integer> it : lockUpdate.entrySet()) {
|
||||
int val = it.getValue() + 1;
|
||||
|
||||
if(val < 60) {
|
||||
lockUpdate.put(it.getKey(), val);
|
||||
@@ -202,7 +202,7 @@ public class ThreadTracker {
|
||||
lockCount.put(lockOid, c);
|
||||
lockIds.put(lockOid, lockId);
|
||||
lockThreads.put(lockOid, tid);
|
||||
lockUpdate.put(lockOid, (byte) 0);
|
||||
lockUpdate.put(lockOid, 0);
|
||||
}
|
||||
c.incrementAndGet();
|
||||
|
||||
@@ -233,7 +233,7 @@ public class ThreadTracker {
|
||||
else {
|
||||
AtomicInteger c = lockCount.get(lockOid);
|
||||
c.decrementAndGet();
|
||||
lockUpdate.put(lockOid, (byte) 0);
|
||||
lockUpdate.put(lockOid, 0);
|
||||
|
||||
List<MonitoredLockType> list = threadTracker.get(tid);
|
||||
for(int i = list.size() - 1; i >= 0; i--) {
|
||||
|
||||
@@ -30,6 +30,7 @@ public enum MonitoredLockType {
|
||||
CHARACTER_EFF,
|
||||
CHARACTER_PET,
|
||||
CHARACTER_PRT,
|
||||
CHARACTER_EVT,
|
||||
CLIENT,
|
||||
CLIENT_ENCODER,
|
||||
CLIENT_LOGIN,
|
||||
@@ -40,6 +41,7 @@ public enum MonitoredLockType {
|
||||
SRVHANDLER_TEMP,
|
||||
BUFF_STORAGE,
|
||||
PLAYER_STORAGE,
|
||||
PLAYER_DOOR,
|
||||
SERVER,
|
||||
SERVER_DISEASES,
|
||||
SERVER_LOGIN,
|
||||
@@ -59,7 +61,7 @@ public enum MonitoredLockType {
|
||||
GUILD,
|
||||
PARTY,
|
||||
WORLD_PARTY,
|
||||
WORLD_OWL,
|
||||
WORLD_SRVMESSAGES,
|
||||
WORLD_PETS,
|
||||
WORLD_CHARS,
|
||||
WORLD_CHANNELS,
|
||||
|
||||
@@ -159,11 +159,13 @@ public class TrackerReadLock extends ReentrantReadWriteLock.ReadLock implements
|
||||
timeoutSchedule.cancel(false);
|
||||
timeoutSchedule = null;
|
||||
}
|
||||
|
||||
reentrantCount.set(Integer.MAX_VALUE);
|
||||
} finally {
|
||||
state.unlock();
|
||||
}
|
||||
|
||||
//unlock();
|
||||
return new EmptyReadLock();
|
||||
return new EmptyReadLock(id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ public class TrackerReentrantLock extends ReentrantLock implements MonitoredReen
|
||||
private final int hashcode;
|
||||
private final Lock state = new ReentrantLock(true);
|
||||
private final AtomicInteger reentrantCount = new AtomicInteger(0);
|
||||
|
||||
|
||||
public TrackerReentrantLock(MonitoredLockType id) {
|
||||
super();
|
||||
this.id = id;
|
||||
@@ -161,11 +161,13 @@ public class TrackerReentrantLock extends ReentrantLock implements MonitoredReen
|
||||
timeoutSchedule.cancel(false);
|
||||
timeoutSchedule = null;
|
||||
}
|
||||
|
||||
reentrantCount.set(Integer.MAX_VALUE);
|
||||
} finally {
|
||||
state.unlock();
|
||||
}
|
||||
|
||||
//unlock();
|
||||
return new EmptyReentrantLock();
|
||||
return new EmptyReentrantLock(id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,11 +157,13 @@ public class TrackerWriteLock extends ReentrantReadWriteLock.WriteLock implement
|
||||
timeoutSchedule.cancel(false);
|
||||
timeoutSchedule = null;
|
||||
}
|
||||
|
||||
reentrantCount.set(Integer.MAX_VALUE);
|
||||
} finally {
|
||||
state.unlock();
|
||||
}
|
||||
|
||||
//unlock();
|
||||
return new EmptyWriteLock();
|
||||
return new EmptyWriteLock(id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,26 +19,56 @@
|
||||
*/
|
||||
package net.server.audit.locks.empty;
|
||||
|
||||
import constants.ServerConstants;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReadLock;
|
||||
import tools.FilePrinter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author RonanLana
|
||||
*/
|
||||
public class EmptyReadLock implements MonitoredReadLock {
|
||||
private final MonitoredLockType id;
|
||||
|
||||
public EmptyReadLock(MonitoredLockType type) {
|
||||
this.id = type;
|
||||
}
|
||||
|
||||
private static String printThreadStack(StackTraceElement[] list) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||
String df = dateFormat.format(new Date());
|
||||
|
||||
String s = "\r\n" + df + "\r\n";
|
||||
for(int i = 0; i < list.length; i++) {
|
||||
s += (" " + list[i].toString() + "\r\n");
|
||||
}
|
||||
s += "----------------------------";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lock() {}
|
||||
public void lock() {
|
||||
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlock() {}
|
||||
|
||||
@Override
|
||||
public boolean tryLock() {
|
||||
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured try-locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MonitoredReadLock dispose() {
|
||||
return null;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,26 +19,56 @@
|
||||
*/
|
||||
package net.server.audit.locks.empty;
|
||||
|
||||
import constants.ServerConstants;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import tools.FilePrinter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author RonanLana
|
||||
*/
|
||||
public class EmptyReentrantLock implements MonitoredReentrantLock {
|
||||
private final MonitoredLockType id;
|
||||
|
||||
public EmptyReentrantLock(MonitoredLockType type) {
|
||||
this.id = type;
|
||||
}
|
||||
|
||||
private static String printThreadStack(StackTraceElement[] list) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||
String df = dateFormat.format(new Date());
|
||||
|
||||
String s = "\r\n" + df + "\r\n";
|
||||
for(int i = 0; i < list.length; i++) {
|
||||
s += (" " + list[i].toString() + "\r\n");
|
||||
}
|
||||
s += "----------------------------";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lock() {}
|
||||
public void lock() {
|
||||
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlock() {}
|
||||
|
||||
@Override
|
||||
public boolean tryLock() {
|
||||
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured try-locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MonitoredReentrantLock dispose() {
|
||||
return null;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,26 +19,56 @@
|
||||
*/
|
||||
package net.server.audit.locks.empty;
|
||||
|
||||
import constants.ServerConstants;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredWriteLock;
|
||||
import tools.FilePrinter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author RonanLana
|
||||
*/
|
||||
public class EmptyWriteLock implements MonitoredWriteLock {
|
||||
private final MonitoredLockType id;
|
||||
|
||||
public EmptyWriteLock(MonitoredLockType type) {
|
||||
this.id = type;
|
||||
}
|
||||
|
||||
private static String printThreadStack(StackTraceElement[] list) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||
String df = dateFormat.format(new Date());
|
||||
|
||||
String s = "\r\n" + df + "\r\n";
|
||||
for(int i = 0; i < list.length; i++) {
|
||||
s += (" " + list[i].toString() + "\r\n");
|
||||
}
|
||||
s += "----------------------------";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lock() {}
|
||||
public void lock() {
|
||||
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlock() {}
|
||||
|
||||
@Override
|
||||
public boolean tryLock() {
|
||||
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured try-locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MonitoredWriteLock dispose() {
|
||||
return null;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
||||
import net.server.audit.LockCollector;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
|
||||
@@ -266,7 +267,22 @@ public final class Channel {
|
||||
channelSchedulers[i].dispose();
|
||||
channelSchedulers[i] = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
disposeLocks();
|
||||
}
|
||||
|
||||
private void disposeLocks() {
|
||||
LockCollector.getInstance().registerDisposeAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
emptyLocks();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void emptyLocks() {
|
||||
for(int i = 0; i < 4; i++) {
|
||||
faceLock[i] = faceLock[i].dispose();
|
||||
}
|
||||
|
||||
@@ -300,6 +316,10 @@ public final class Channel {
|
||||
players.addPlayer(chr);
|
||||
chr.announce(MaplePacketCreator.serverMessage(serverMessage));
|
||||
}
|
||||
|
||||
public String getServerMessage() {
|
||||
return serverMessage;
|
||||
}
|
||||
|
||||
public PlayerStorage getPlayerStorage() {
|
||||
return players;
|
||||
@@ -443,6 +463,7 @@ public final class Channel {
|
||||
public void setServerMessage(String message) {
|
||||
this.serverMessage = message;
|
||||
broadcastPacket(MaplePacketCreator.serverMessage(message));
|
||||
Server.getInstance().getWorld(world).resetDisabledServerMessages();
|
||||
}
|
||||
|
||||
private static String [] getEvents(){
|
||||
@@ -540,7 +561,7 @@ public final class Channel {
|
||||
resetDojo(dojoMapId, 0);
|
||||
}
|
||||
|
||||
private void resetDojo(int dojoMapId, int thisStg) {
|
||||
public void resetDojo(int dojoMapId, int thisStg) {
|
||||
int slot = getDojoSlot(dojoMapId);
|
||||
this.dojoStage[slot] = thisStg;
|
||||
|
||||
|
||||
@@ -21,13 +21,11 @@
|
||||
*/
|
||||
package net.server.channel.handlers;
|
||||
|
||||
import java.util.Calendar;
|
||||
import client.MapleCharacter;
|
||||
import client.MapleClient;
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import server.maps.MapleDoorObject;
|
||||
import server.maps.MapleMapObject;
|
||||
import tools.FilePrinter;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
|
||||
@@ -43,10 +41,6 @@ public final class DoorHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
MapleCharacter chr = c.getPlayer();
|
||||
if (chr.isChangingMaps() || chr.isBanned()) {
|
||||
if(chr.isChangingMaps()) {
|
||||
FilePrinter.printError(FilePrinter.PORTAL_STUCK + chr.getName() + ".txt", "Player " + chr.getName() + " got stuck when changing maps (using Mystic Door). Timestamp: " + Calendar.getInstance().getTime().toString() + " Last visited mapids: " + chr.getLastVisitedMapids());
|
||||
}
|
||||
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,13 @@ public class EnterCashShopHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
}
|
||||
|
||||
if(MapleMiniDungeonInfo.isDungeonMap(c.getPlayer().getMapId())) {
|
||||
if(mc.getEventInstance() != null) {
|
||||
c.announce(MaplePacketCreator.serverNotice(5, "Entering Cash Shop or MTS are disabled when registered on an event."));
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
|
||||
if(MapleMiniDungeonInfo.isDungeonMap(mc.getMapId())) {
|
||||
c.announce(MaplePacketCreator.serverNotice(5, "Changing channels or entering Cash Shop or MTS are disabled when inside a Mini-Dungeon."));
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
|
||||
@@ -58,7 +58,13 @@ public final class EnterMTSHandler extends AbstractMaplePacketHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
if(MapleMiniDungeonInfo.isDungeonMap(c.getPlayer().getMapId())) {
|
||||
if(chr.getEventInstance() != null) {
|
||||
c.announce(MaplePacketCreator.serverNotice(5, "Entering Cash Shop or MTS are disabled when registered on an event."));
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
|
||||
if(MapleMiniDungeonInfo.isDungeonMap(chr.getMapId())) {
|
||||
c.announce(MaplePacketCreator.serverNotice(5, "Changing channels or entering Cash Shop or MTS are disabled when inside a Mini-Dungeon."));
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
|
||||
@@ -82,9 +82,9 @@ public final class PartyOperationHandler extends AbstractMaplePacketHandler {
|
||||
player.setMPC(partyplayer);
|
||||
player.getMap().addPartyMember(player);
|
||||
player.silentPartyUpdate();
|
||||
c.announce(MaplePacketCreator.partyCreated(partyplayer, party.getId()));
|
||||
|
||||
player.updateMapDropsUponPartyOperation(null);
|
||||
player.partyOperationUpdate(party, null);
|
||||
c.announce(MaplePacketCreator.partyCreated(party, partyplayer.getId()));
|
||||
} else {
|
||||
c.announce(MaplePacketCreator.serverNotice(5, "You can't create a party as you are already in one."));
|
||||
}
|
||||
@@ -94,7 +94,7 @@ public final class PartyOperationHandler extends AbstractMaplePacketHandler {
|
||||
List<MapleCharacter> partymembers = player.getPartyMembers();
|
||||
|
||||
leaveParty(party, partyplayer, c);
|
||||
player.updateMapDropsUponPartyOperation(partymembers);
|
||||
player.partyOperationUpdate(party, partymembers);
|
||||
break;
|
||||
}
|
||||
case 3: { // join
|
||||
@@ -110,7 +110,7 @@ public final class PartyOperationHandler extends AbstractMaplePacketHandler {
|
||||
player.receivePartyMemberHP();
|
||||
player.updatePartyMemberHP();
|
||||
|
||||
player.updateMapDropsUponPartyOperation(null);
|
||||
player.partyOperationUpdate(party, null);
|
||||
} else {
|
||||
c.announce(MaplePacketCreator.partyStatusMessage(17));
|
||||
}
|
||||
@@ -147,9 +147,9 @@ public final class PartyOperationHandler extends AbstractMaplePacketHandler {
|
||||
player.setParty(party);
|
||||
player.setMPC(partyplayer);
|
||||
player.getMap().addPartyMember(player);
|
||||
c.announce(MaplePacketCreator.partyCreated(partyplayer, party.getId()));
|
||||
|
||||
player.updateMapDropsUponPartyOperation(null);
|
||||
player.partyOperationUpdate(party, null);
|
||||
c.announce(MaplePacketCreator.partyCreated(party, partyplayer.getId()));
|
||||
}
|
||||
if (party.getMembers().size() < 6) {
|
||||
invited.getClient().announce(MaplePacketCreator.partyInvite(player));
|
||||
@@ -184,7 +184,7 @@ public final class PartyOperationHandler extends AbstractMaplePacketHandler {
|
||||
emc.setParty(null);
|
||||
world.updateParty(party.getId(), PartyOperation.EXPEL, expelled);
|
||||
|
||||
emc.updateMapDropsUponPartyOperation(partyMembers);
|
||||
emc.partyOperationUpdate(party, partyMembers);
|
||||
} else {
|
||||
world.updateParty(party.getId(), PartyOperation.EXPEL, expelled);
|
||||
}
|
||||
|
||||
@@ -54,10 +54,8 @@ public final class PetCommandHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
if (Randomizer.nextInt(101) <= petCommand.getProbability()) {
|
||||
pet.gainClosenessFullness(chr, petCommand.getIncrease(), 0, command);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
chr.getMap().broadcastMessage(MaplePacketCreator.commandResponse(chr.getId(), petIndex, command, false));
|
||||
if(chr.getMount() != null) chr.getMap().broadcastMessage(MaplePacketCreator.updateMount(chr.getId(), chr.getMount(), false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,12 +103,18 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
|
||||
int state = c.getLoginState();
|
||||
boolean allowLogin = true;
|
||||
|
||||
Channel cserv = c.getChannelServer();
|
||||
World world = server.getWorld(c.getWorld());
|
||||
if(world == null) {
|
||||
c.disconnect(true, false);
|
||||
return;
|
||||
}
|
||||
|
||||
Channel cserv = world.getChannel(c.getChannel());
|
||||
if(cserv == null) {
|
||||
c.setChannel(1);
|
||||
cserv = c.getChannelServer();
|
||||
cserv = world.getChannel(c.getChannel());
|
||||
|
||||
if(cserv == null) { // world server is out
|
||||
if(cserv == null) {
|
||||
c.disconnect(true, false);
|
||||
return;
|
||||
}
|
||||
@@ -136,8 +142,6 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
|
||||
return;
|
||||
}
|
||||
c.updateLoginState(MapleClient.LOGIN_LOGGEDIN);
|
||||
|
||||
World world = server.getWorld(c.getWorld());
|
||||
|
||||
cserv.addPlayer(player);
|
||||
world.addPlayer(player);
|
||||
|
||||
@@ -29,6 +29,7 @@ import java.util.Map.Entry;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
|
||||
import net.server.Server;
|
||||
import net.server.audit.LockCollector;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
@@ -196,6 +197,19 @@ public abstract class BaseScheduler {
|
||||
externalLocks.clear();
|
||||
}
|
||||
|
||||
disposeLocks();
|
||||
}
|
||||
|
||||
private void disposeLocks() {
|
||||
LockCollector.getInstance().registerDisposeAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
emptyLocks();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void emptyLocks() {
|
||||
schedulerLock = schedulerLock.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import net.server.audit.locks.MonitoredLockType;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import net.server.audit.LockCollector;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
|
||||
@@ -76,7 +77,20 @@ public class MobAnimationScheduler extends BaseScheduler {
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
animationLock = animationLock.dispose();
|
||||
disposeLocks();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private void disposeLocks() {
|
||||
LockCollector.getInstance().registerDisposeAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
emptyLocks();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void emptyLocks() {
|
||||
animationLock = animationLock.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import net.server.audit.LockCollector;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
@@ -111,7 +112,20 @@ public class MobStatusScheduler extends BaseScheduler {
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
overtimeStatusLock = overtimeStatusLock.dispose();
|
||||
disposeLocks();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private void disposeLocks() {
|
||||
LockCollector.getInstance().registerDisposeAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
emptyLocks();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void emptyLocks() {
|
||||
overtimeStatusLock = overtimeStatusLock.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import net.server.Server;
|
||||
import net.server.world.World;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
|
||||
@@ -52,7 +53,14 @@ public final class CharSelectedHandler extends AbstractMaplePacketHandler {
|
||||
}
|
||||
|
||||
c.setWorld(server.getCharacterWorld(charId));
|
||||
if(c.getWorldServer().isWorldCapacityFull()) {
|
||||
World wserv = c.getWorldServer();
|
||||
if(wserv == null || wserv.isWorldCapacityFull()) {
|
||||
c.announce(MaplePacketCreator.getAfterLoginError(10));
|
||||
return;
|
||||
}
|
||||
|
||||
String[] socket = server.getInetSocket(c.getWorld(), c.getChannel());
|
||||
if(socket == null) {
|
||||
c.announce(MaplePacketCreator.getAfterLoginError(10));
|
||||
return;
|
||||
}
|
||||
@@ -61,7 +69,6 @@ public final class CharSelectedHandler extends AbstractMaplePacketHandler {
|
||||
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
|
||||
server.setCharacteridInTransition((InetSocketAddress) c.getSession().getRemoteAddress(), charId);
|
||||
|
||||
String[] socket = server.getIP(c.getWorld(), c.getChannel()).split(":");
|
||||
try {
|
||||
c.announce(MaplePacketCreator.getServerIP(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]), charId));
|
||||
} catch (UnknownHostException | NumberFormatException e) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import java.net.UnknownHostException;
|
||||
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import net.server.Server;
|
||||
import net.server.world.World;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
import client.MapleClient;
|
||||
@@ -34,7 +35,14 @@ public class CharSelectedWithPicHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
if (c.checkPic(pic)) {
|
||||
c.setWorld(server.getCharacterWorld(charId));
|
||||
if(c.getWorldServer().isWorldCapacityFull()) {
|
||||
World wserv = c.getWorldServer();
|
||||
if(wserv == null || wserv.isWorldCapacityFull()) {
|
||||
c.announce(MaplePacketCreator.getAfterLoginError(10));
|
||||
return;
|
||||
}
|
||||
|
||||
String[] socket = server.getInetSocket(c.getWorld(), c.getChannel());
|
||||
if(socket == null) {
|
||||
c.announce(MaplePacketCreator.getAfterLoginError(10));
|
||||
return;
|
||||
}
|
||||
@@ -42,8 +50,7 @@ public class CharSelectedWithPicHandler extends AbstractMaplePacketHandler {
|
||||
server.unregisterLoginState(c);
|
||||
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
|
||||
server.setCharacteridInTransition((InetSocketAddress) c.getSession().getRemoteAddress(), charId);
|
||||
|
||||
String[] socket = server.getIP(c.getWorld(), c.getChannel()).split(":");
|
||||
|
||||
try {
|
||||
c.announce(MaplePacketCreator.getServerIP(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]), charId));
|
||||
} catch (UnknownHostException | NumberFormatException e) {
|
||||
|
||||
@@ -24,6 +24,7 @@ package net.server.handlers.login;
|
||||
import client.MapleClient;
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import net.server.Server;
|
||||
import net.server.world.World;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
|
||||
@@ -33,14 +34,21 @@ public final class CharlistRequestHandler extends AbstractMaplePacketHandler {
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
slea.readByte();
|
||||
int world = slea.readByte();
|
||||
c.setWorld(world);
|
||||
|
||||
if(Server.getInstance().getWorld(world).isWorldCapacityFull()) {
|
||||
World wserv = Server.getInstance().getWorld(world);
|
||||
if(wserv == null || wserv.isWorldCapacityFull()) {
|
||||
c.announce(MaplePacketCreator.getServerStatus(2));
|
||||
return;
|
||||
}
|
||||
|
||||
c.setChannel(slea.readByte() + 1);
|
||||
int channel = slea.readByte() + 1;
|
||||
if(wserv.getChannel(channel) == null) {
|
||||
c.announce(MaplePacketCreator.getServerStatus(2));
|
||||
return;
|
||||
}
|
||||
|
||||
c.setWorld(world);
|
||||
c.setChannel(channel);
|
||||
c.sendCharList(world);
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import java.net.UnknownHostException;
|
||||
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import net.server.Server;
|
||||
import net.server.world.World;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
import client.MapleClient;
|
||||
@@ -37,7 +38,14 @@ public final class RegisterPicHandler extends AbstractMaplePacketHandler {
|
||||
c.setPic(pic);
|
||||
|
||||
c.setWorld(server.getCharacterWorld(charId));
|
||||
if(c.getWorldServer().isWorldCapacityFull()) {
|
||||
World wserv = c.getWorldServer();
|
||||
if(wserv == null || wserv.isWorldCapacityFull()) {
|
||||
c.announce(MaplePacketCreator.getAfterLoginError(10));
|
||||
return;
|
||||
}
|
||||
|
||||
String[] socket = server.getInetSocket(c.getWorld(), c.getChannel());
|
||||
if(socket == null) {
|
||||
c.announce(MaplePacketCreator.getAfterLoginError(10));
|
||||
return;
|
||||
}
|
||||
@@ -46,7 +54,6 @@ public final class RegisterPicHandler extends AbstractMaplePacketHandler {
|
||||
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
|
||||
server.setCharacteridInTransition((InetSocketAddress) c.getSession().getRemoteAddress(), charId);
|
||||
|
||||
String[] socket = server.getIP(c.getWorld(), c.getChannel()).split(":");
|
||||
try {
|
||||
c.announce(MaplePacketCreator.getServerIP(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]), charId));
|
||||
} catch (UnknownHostException e) {
|
||||
|
||||
@@ -23,6 +23,7 @@ package net.server.handlers.login;
|
||||
|
||||
import client.MapleClient;
|
||||
import constants.GameConstants;
|
||||
import java.util.List;
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import net.server.Server;
|
||||
import net.server.world.World;
|
||||
@@ -34,10 +35,10 @@ public final class ServerlistRequestHandler extends AbstractMaplePacketHandler {
|
||||
@Override
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
Server server = Server.getInstance();
|
||||
server.loadAccountCharacters(c); // locks the login session until data is recovered from the cache or the DB.
|
||||
c.setClickedNPC();
|
||||
List<World> worlds = server.getWorlds();
|
||||
c.requestedServerlist(worlds.size());
|
||||
|
||||
for (World world : server.getWorlds()) {
|
||||
for (World world : worlds) {
|
||||
c.announce(MaplePacketCreator.getServerList(world.getId(), GameConstants.WORLD_NAMES[world.getId()], world.getFlag(), world.getEventMessage(), world.getChannels()));
|
||||
}
|
||||
c.announce(MaplePacketCreator.getEndOfServerList());
|
||||
|
||||
@@ -41,7 +41,7 @@ public final class ViewAllCharHandler extends AbstractMaplePacketHandler {
|
||||
}
|
||||
|
||||
int accountId = c.getAccID();
|
||||
Pair<Pair<Integer, List<MapleCharacter>>, List<Pair<Integer, List<MapleCharacter>>>> loginBlob = Server.getInstance().loadAccountCharlist(accountId);
|
||||
Pair<Pair<Integer, List<MapleCharacter>>, List<Pair<Integer, List<MapleCharacter>>>> loginBlob = Server.getInstance().loadAccountCharlist(accountId, c.getVisibleWorlds());
|
||||
|
||||
List<Pair<Integer, List<MapleCharacter>>> worldChars = loginBlob.getRight();
|
||||
int chrTotal = loginBlob.getLeft().getLeft();
|
||||
|
||||
@@ -6,12 +6,12 @@ import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import net.server.Server;
|
||||
import net.server.world.World;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Randomizer;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
|
||||
public final class ViewAllCharRegisterPicHandler extends AbstractMaplePacketHandler { //Gey class name lol
|
||||
|
||||
public final class ViewAllCharRegisterPicHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
@Override
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
@@ -26,7 +26,8 @@ public final class ViewAllCharRegisterPicHandler extends AbstractMaplePacketHand
|
||||
}
|
||||
|
||||
c.setWorld(server.getCharacterWorld(charId));
|
||||
if(c.getWorldServer().isWorldCapacityFull()) {
|
||||
World wserv = c.getWorldServer();
|
||||
if(wserv == null || wserv.isWorldCapacityFull()) {
|
||||
c.announce(MaplePacketCreator.getAfterLoginError(10));
|
||||
return;
|
||||
}
|
||||
@@ -45,11 +46,16 @@ public final class ViewAllCharRegisterPicHandler extends AbstractMaplePacketHand
|
||||
String pic = slea.readMapleAsciiString();
|
||||
c.setPic(pic);
|
||||
|
||||
String[] socket = server.getInetSocket(c.getWorld(), channel);
|
||||
if (socket == null) {
|
||||
c.announce(MaplePacketCreator.getAfterLoginError(10));
|
||||
return;
|
||||
}
|
||||
|
||||
server.unregisterLoginState(c);
|
||||
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
|
||||
server.setCharacteridInTransition((InetSocketAddress) c.getSession().getRemoteAddress(), charId);
|
||||
|
||||
String[] socket = server.getIP(c.getWorld(), channel).split(":");
|
||||
try {
|
||||
c.announce(MaplePacketCreator.getServerIP(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]), charId));
|
||||
} catch (UnknownHostException e) {
|
||||
|
||||
@@ -27,6 +27,7 @@ import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import net.server.Server;
|
||||
import net.server.world.World;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Randomizer;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
@@ -45,7 +46,9 @@ public final class ViewAllCharSelectedHandler extends AbstractMaplePacketHandler
|
||||
}
|
||||
|
||||
c.setWorld(server.getCharacterWorld(charId));
|
||||
if(c.getWorldServer().isWorldCapacityFull()) {
|
||||
|
||||
World wserv = c.getWorldServer();
|
||||
if(wserv == null || wserv.isWorldCapacityFull()) {
|
||||
c.announce(MaplePacketCreator.getAfterLoginError(10));
|
||||
return;
|
||||
}
|
||||
@@ -58,18 +61,23 @@ public final class ViewAllCharSelectedHandler extends AbstractMaplePacketHandler
|
||||
}
|
||||
|
||||
try {
|
||||
int channel = Randomizer.rand(1, c.getWorldServer().getChannelsSize());
|
||||
int channel = Randomizer.rand(1, wserv.getChannelsSize());
|
||||
c.setChannel(channel);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
c.setChannel(1);
|
||||
}
|
||||
|
||||
String[] socket = server.getInetSocket(c.getWorld(), c.getChannel());
|
||||
if(socket == null) {
|
||||
c.announce(MaplePacketCreator.getAfterLoginError(10));
|
||||
return;
|
||||
}
|
||||
|
||||
server.unregisterLoginState(c);
|
||||
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
|
||||
server.setCharacteridInTransition((InetSocketAddress) c.getSession().getRemoteAddress(), charId);
|
||||
|
||||
String[] socket = server.getIP(c.getWorld(), c.getChannel()).split(":");
|
||||
try {
|
||||
c.announce(MaplePacketCreator.getServerIP(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]), charId));
|
||||
} catch (UnknownHostException e) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.net.UnknownHostException;
|
||||
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import net.server.Server;
|
||||
import net.server.world.World;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Randomizer;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
@@ -27,7 +28,13 @@ public class ViewAllCharSelectedWithPicHandler extends AbstractMaplePacketHandle
|
||||
}
|
||||
|
||||
c.setWorld(server.getCharacterWorld(charId));
|
||||
int channel = Randomizer.rand(1, c.getWorldServer().getChannelsSize());
|
||||
World wserv = c.getWorldServer();
|
||||
if(wserv == null || wserv.isWorldCapacityFull()) {
|
||||
c.announce(MaplePacketCreator.getAfterLoginError(10));
|
||||
return;
|
||||
}
|
||||
|
||||
int channel = Randomizer.rand(1, wserv.getChannelsSize());
|
||||
c.setChannel(channel);
|
||||
|
||||
String macs = slea.readMapleAsciiString();
|
||||
@@ -38,7 +45,8 @@ public class ViewAllCharSelectedWithPicHandler extends AbstractMaplePacketHandle
|
||||
}
|
||||
|
||||
if (c.checkPic(pic)) {
|
||||
if(c.getWorldServer().isWorldCapacityFull()) {
|
||||
String[] socket = server.getInetSocket(c.getWorld(), c.getChannel());
|
||||
if(socket == null) {
|
||||
c.announce(MaplePacketCreator.getAfterLoginError(10));
|
||||
return;
|
||||
}
|
||||
@@ -46,8 +54,7 @@ public class ViewAllCharSelectedWithPicHandler extends AbstractMaplePacketHandle
|
||||
server.unregisterLoginState(c);
|
||||
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
|
||||
server.setCharacteridInTransition((InetSocketAddress) c.getSession().getRemoteAddress(), charId);
|
||||
|
||||
String[] socket = server.getIP(c.getWorld(), c.getChannel()).split(":");
|
||||
|
||||
try {
|
||||
c.announce(MaplePacketCreator.getServerIP(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]), charId));
|
||||
} catch (UnknownHostException e) {
|
||||
|
||||
33
src/net/server/worker/ReleaseLockWorker.java
Normal file
33
src/net/server/worker/ReleaseLockWorker.java
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2018 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.worker;
|
||||
|
||||
import net.server.audit.LockCollector;
|
||||
|
||||
/**
|
||||
* @author Ronan
|
||||
* @info Thread responsible for expiring locks signalized for dispose.
|
||||
*/
|
||||
public class ReleaseLockWorker implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
LockCollector.getInstance().runLockCollector();
|
||||
}
|
||||
}
|
||||
40
src/net/server/worker/ServerMessageWorker.java
Normal file
40
src/net/server/worker/ServerMessageWorker.java
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2018 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.worker;
|
||||
|
||||
import net.server.world.World;
|
||||
|
||||
/**
|
||||
* @author Ronan
|
||||
*/
|
||||
public class ServerMessageWorker extends BaseWorker implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
// It's purpose is for tracking whether the player client currently displays a boss HPBar and, if so,
|
||||
// temporarily disable the server message for that player.
|
||||
|
||||
wserv.runDisabledServerMessagesSchedule();
|
||||
}
|
||||
|
||||
public ServerMessageWorker(World world) {
|
||||
super(world);
|
||||
}
|
||||
}
|
||||
@@ -30,9 +30,11 @@ import java.util.HashMap;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Map;
|
||||
import java.util.Comparator;
|
||||
import net.server.audit.LockCollector;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import server.maps.MapleDoor;
|
||||
|
||||
public class MapleParty {
|
||||
private int id;
|
||||
@@ -44,11 +46,12 @@ public class MapleParty {
|
||||
private Map<Integer, Integer> histMembers = new HashMap<>();
|
||||
private int nextEntry = 0;
|
||||
|
||||
private Map<Integer, MapleDoor> doors = new HashMap<>();
|
||||
|
||||
private MonitoredReentrantLock lock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.PARTY, true);
|
||||
|
||||
public MapleParty(int id, MaplePartyCharacter chrfor) {
|
||||
this.leaderId = chrfor.getId();
|
||||
this.members.add(chrfor);
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@@ -169,7 +172,7 @@ public class MapleParty {
|
||||
}
|
||||
}
|
||||
|
||||
public byte getPartyDoor(int cid) {
|
||||
public List<Integer> getMembersSortedByHistory() {
|
||||
List<Entry<Integer, Integer>> histList;
|
||||
|
||||
lock.lock();
|
||||
@@ -187,16 +190,53 @@ public class MapleParty {
|
||||
return ( o1.getValue() ).compareTo( o2.getValue() );
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
List<Integer> histSort = new LinkedList<>();
|
||||
for(Entry<Integer, Integer> e : histList) {
|
||||
histSort.add(e.getKey());
|
||||
}
|
||||
|
||||
return histSort;
|
||||
}
|
||||
|
||||
public byte getPartyDoor(int cid) {
|
||||
List<Integer> histList = getMembersSortedByHistory();
|
||||
byte slot = 0;
|
||||
for(Entry<Integer, Integer> e: histList) {
|
||||
if(e.getKey() == cid) break;
|
||||
for(Integer e: histList) {
|
||||
if(e == cid) break;
|
||||
slot++;
|
||||
}
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
public void addDoor(Integer owner, MapleDoor door) {
|
||||
lock.lock();
|
||||
try {
|
||||
this.doors.put(owner, door);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeDoor(Integer owner) {
|
||||
lock.lock();
|
||||
try {
|
||||
this.doors.remove(owner);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Map<Integer, MapleDoor> getDoors() {
|
||||
lock.lock();
|
||||
try {
|
||||
return Collections.unmodifiableMap(doors);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void assignNewLeader(MapleClient c) {
|
||||
World world = c.getWorldServer();
|
||||
MaplePartyCharacter newLeadr = null;
|
||||
@@ -216,6 +256,15 @@ public class MapleParty {
|
||||
}
|
||||
|
||||
public void disposeLocks() {
|
||||
LockCollector.getInstance().registerDisposeAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
emptyLocks();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void emptyLocks() {
|
||||
lock = lock.dispose();
|
||||
}
|
||||
|
||||
|
||||
@@ -21,15 +21,8 @@
|
||||
*/
|
||||
package net.server.world;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Collection;
|
||||
|
||||
import server.maps.MapleDoor;
|
||||
import client.MapleCharacter;
|
||||
import client.MapleJob;
|
||||
import java.util.Collections;
|
||||
|
||||
public class MaplePartyCharacter {
|
||||
private String name;
|
||||
@@ -38,7 +31,6 @@ public class MaplePartyCharacter {
|
||||
private int channel, world;
|
||||
private int jobid;
|
||||
private int mapid;
|
||||
private Map<Integer, MapleDoor> doors = new LinkedHashMap<>();
|
||||
private boolean online;
|
||||
private MapleJob job;
|
||||
private MapleCharacter character;
|
||||
@@ -54,9 +46,6 @@ public class MaplePartyCharacter {
|
||||
this.mapid = maplechar.getMapId();
|
||||
this.online = true;
|
||||
this.job = maplechar.getJob();
|
||||
for (Entry<Integer, MapleDoor> entry : maplechar.getDoors().entrySet()) {
|
||||
doors.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
public MaplePartyCharacter() {
|
||||
@@ -118,18 +107,6 @@ public class MaplePartyCharacter {
|
||||
public int getGuildId() {
|
||||
return character.getGuildId();
|
||||
}
|
||||
|
||||
public void addDoor(Integer owner, MapleDoor door) {
|
||||
this.doors.put(owner, door);
|
||||
}
|
||||
|
||||
public void removeDoor(Integer owner) {
|
||||
this.doors.remove(owner);
|
||||
}
|
||||
|
||||
public Collection<MapleDoor> getDoors() {
|
||||
return Collections.unmodifiableCollection(doors.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
@@ -63,12 +63,15 @@ import server.maps.MaplePlayerShop;
|
||||
import server.maps.MaplePlayerShopItem;
|
||||
import server.maps.AbstractMapleMapObject;
|
||||
import net.server.worker.CharacterAutosaverWorker;
|
||||
import net.server.worker.HiredMerchantWorker;
|
||||
import net.server.worker.MountTirednessWorker;
|
||||
import net.server.worker.PetFullnessWorker;
|
||||
import net.server.worker.ServerMessageWorker;
|
||||
import net.server.worker.TimedMapObjectWorker;
|
||||
import net.server.worker.WeddingReservationWorker;
|
||||
import net.server.PlayerStorage;
|
||||
import net.server.Server;
|
||||
import net.server.audit.LockCollector;
|
||||
import net.server.channel.Channel;
|
||||
import net.server.channel.CharacterIdChannelPair;
|
||||
import net.server.guild.MapleGuild;
|
||||
@@ -119,15 +122,17 @@ public class World {
|
||||
private MonitoredReentrantLock partyLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_PARTY, true);
|
||||
|
||||
private Map<Integer, Integer> owlSearched = new LinkedHashMap<>();
|
||||
private MonitoredReentrantLock owlLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_OWL);
|
||||
private Map<Integer, Integer> disabledServerMessages = new HashMap<>(); // reuse owl lock
|
||||
private MonitoredReentrantLock srvMessagesLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_SRVMESSAGES);
|
||||
private ScheduledFuture<?> srvMessagesSchedule;
|
||||
|
||||
private MonitoredReentrantLock activePetsLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_PETS, true);
|
||||
private Map<Integer, Byte> activePets = new LinkedHashMap<>();
|
||||
private Map<Integer, Integer> activePets = new LinkedHashMap<>();
|
||||
private ScheduledFuture<?> petsSchedule;
|
||||
private long petUpdate;
|
||||
|
||||
private MonitoredReentrantLock activeMountsLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_MOUNTS, true);
|
||||
private Map<Integer, Byte> activeMounts = new LinkedHashMap<>();
|
||||
private Map<Integer, Integer> activeMounts = new LinkedHashMap<>();
|
||||
private ScheduledFuture<?> mountsSchedule;
|
||||
private long mountUpdate;
|
||||
|
||||
@@ -135,7 +140,8 @@ public class World {
|
||||
private Map<Integer, MaplePlayerShop> activePlayerShops = new LinkedHashMap<>();
|
||||
|
||||
private MonitoredReentrantLock activeMerchantsLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_MERCHS, true);
|
||||
private Map<Integer, Pair<MapleHiredMerchant, Byte>> activeMerchants = new LinkedHashMap<>();
|
||||
private Map<Integer, Pair<MapleHiredMerchant, Integer>> activeMerchants = new LinkedHashMap<>();
|
||||
private ScheduledFuture<?> merchantSchedule;
|
||||
private long merchantUpdate;
|
||||
|
||||
private Map<Runnable, Long> registeredTimedMapObjects = new LinkedHashMap<>();
|
||||
@@ -161,7 +167,9 @@ public class World {
|
||||
|
||||
TimerManager tman = TimerManager.getInstance();
|
||||
petsSchedule = tman.register(new PetFullnessWorker(this), 60 * 1000, 60 * 1000);
|
||||
srvMessagesSchedule = tman.register(new ServerMessageWorker(this), 10 * 1000, 10 * 1000);
|
||||
mountsSchedule = tman.register(new MountTirednessWorker(this), 60 * 1000, 60 * 1000);
|
||||
merchantSchedule = tman.register(new HiredMerchantWorker(this), 10 * 60 * 1000, 10 * 60 * 1000);
|
||||
timedMapObjectsSchedule = tman.register(new TimedMapObjectWorker(this), 60 * 1000, 60 * 1000);
|
||||
charactersSchedule = tman.register(new CharacterAutosaverWorker(this), 60 * 60 * 1000, 60 * 60 * 1000);
|
||||
marriagesSchedule = tman.register(new WeddingReservationWorker(this), ServerConstants.WEDDING_RESERVATION_INTERVAL * 60 * 1000, ServerConstants.WEDDING_RESERVATION_INTERVAL * 60 * 1000);
|
||||
@@ -189,7 +197,11 @@ public class World {
|
||||
public Channel getChannel(int channel) {
|
||||
chnRLock.lock();
|
||||
try {
|
||||
return channels.get(channel - 1);
|
||||
try {
|
||||
return channels.get(channel - 1);
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
return null;
|
||||
}
|
||||
} finally {
|
||||
chnRLock.unlock();
|
||||
}
|
||||
@@ -731,6 +743,7 @@ public class World {
|
||||
partyLock.unlock();
|
||||
}
|
||||
|
||||
party.addMember(chrfor);
|
||||
return party;
|
||||
}
|
||||
|
||||
@@ -784,7 +797,7 @@ public class World {
|
||||
updateCharacterParty(party, operation, target, partyMembers);
|
||||
|
||||
for (MaplePartyCharacter partychar : partyMembers) {
|
||||
MapleCharacter chr = getPlayerStorage().getCharacterByName(partychar.getName());
|
||||
MapleCharacter chr = getPlayerStorage().getCharacterById(partychar.getId());
|
||||
if (chr != null) {
|
||||
if (operation == PartyOperation.DISBAND) {
|
||||
chr.setParty(null);
|
||||
@@ -799,7 +812,7 @@ public class World {
|
||||
switch (operation) {
|
||||
case LEAVE:
|
||||
case EXPEL:
|
||||
MapleCharacter chr = getPlayerStorage().getCharacterByName(target.getName());
|
||||
MapleCharacter chr = getPlayerStorage().getCharacterById(target.getId());
|
||||
if (chr != null) {
|
||||
chr.getClient().announce(MaplePacketCreator.updateParty(chr.getClient().getChannel(), party, operation, target));
|
||||
chr.setParty(null);
|
||||
@@ -1126,7 +1139,7 @@ public class World {
|
||||
}
|
||||
|
||||
public void addOwlItemSearch(Integer itemid) {
|
||||
owlLock.lock();
|
||||
srvMessagesLock.lock();
|
||||
try {
|
||||
Integer cur = owlSearched.get(itemid);
|
||||
if(cur != null) {
|
||||
@@ -1135,7 +1148,7 @@ public class World {
|
||||
owlSearched.put(itemid, 1);
|
||||
}
|
||||
} finally {
|
||||
owlLock.unlock();
|
||||
srvMessagesLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1144,7 +1157,7 @@ public class World {
|
||||
return new ArrayList<>(0);
|
||||
}
|
||||
|
||||
owlLock.lock();
|
||||
srvMessagesLock.lock();
|
||||
try {
|
||||
List<Pair<Integer, Integer>> searchCounts = new ArrayList<>(owlSearched.size());
|
||||
|
||||
@@ -1154,7 +1167,7 @@ public class World {
|
||||
|
||||
return searchCounts;
|
||||
} finally {
|
||||
owlLock.unlock();
|
||||
srvMessagesLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1167,7 +1180,7 @@ public class World {
|
||||
|
||||
activePetsLock.lock();
|
||||
try {
|
||||
byte initProc;
|
||||
int initProc;
|
||||
if(System.currentTimeMillis() - petUpdate > 55000) initProc = ServerConstants.PET_EXHAUST_COUNT - 2;
|
||||
else initProc = ServerConstants.PET_EXHAUST_COUNT - 1;
|
||||
|
||||
@@ -1189,7 +1202,7 @@ public class World {
|
||||
}
|
||||
|
||||
public void runPetSchedule() {
|
||||
Map<Integer, Byte> deployedPets;
|
||||
Map<Integer, Integer> deployedPets;
|
||||
|
||||
activePetsLock.lock();
|
||||
try {
|
||||
@@ -1199,11 +1212,11 @@ public class World {
|
||||
activePetsLock.unlock();
|
||||
}
|
||||
|
||||
for(Map.Entry<Integer, Byte> dp: deployedPets.entrySet()) {
|
||||
for(Map.Entry<Integer, Integer> dp: deployedPets.entrySet()) {
|
||||
MapleCharacter chr = this.getPlayerStorage().getCharacterById(dp.getKey() / 4);
|
||||
if(chr == null || !chr.isLoggedinWorld()) continue;
|
||||
|
||||
Byte dpVal = (byte)(dp.getValue() + 1);
|
||||
Integer dpVal = dp.getValue() + 1;
|
||||
if(dpVal == ServerConstants.PET_EXHAUST_COUNT) {
|
||||
chr.runFullnessSchedule(dp.getKey() % 4);
|
||||
dpVal = 0;
|
||||
@@ -1226,7 +1239,7 @@ public class World {
|
||||
Integer key = chr.getId();
|
||||
activeMountsLock.lock();
|
||||
try {
|
||||
byte initProc;
|
||||
int initProc;
|
||||
if(System.currentTimeMillis() - mountUpdate > 45000) initProc = ServerConstants.MOUNT_EXHAUST_COUNT - 2;
|
||||
else initProc = ServerConstants.MOUNT_EXHAUST_COUNT - 1;
|
||||
|
||||
@@ -1248,7 +1261,7 @@ public class World {
|
||||
}
|
||||
|
||||
public void runMountSchedule() {
|
||||
Map<Integer, Byte> deployedMounts;
|
||||
Map<Integer, Integer> deployedMounts;
|
||||
activeMountsLock.lock();
|
||||
try {
|
||||
mountUpdate = System.currentTimeMillis();
|
||||
@@ -1257,11 +1270,11 @@ public class World {
|
||||
activeMountsLock.unlock();
|
||||
}
|
||||
|
||||
for(Map.Entry<Integer, Byte> dp: deployedMounts.entrySet()) {
|
||||
for(Map.Entry<Integer, Integer> dp: deployedMounts.entrySet()) {
|
||||
MapleCharacter chr = this.getPlayerStorage().getCharacterById(dp.getKey());
|
||||
if(chr == null || !chr.isLoggedinWorld()) continue;
|
||||
|
||||
Byte dpVal = (byte)(dp.getValue() + 1);
|
||||
int dpVal = dp.getValue() + 1;
|
||||
if(dpVal == ServerConstants.MOUNT_EXHAUST_COUNT) {
|
||||
chr.runTirednessSchedule();
|
||||
dpVal = 0;
|
||||
@@ -1320,8 +1333,8 @@ public class World {
|
||||
public void registerHiredMerchant(MapleHiredMerchant hm) {
|
||||
activeMerchantsLock.lock();
|
||||
try {
|
||||
byte initProc;
|
||||
if(System.currentTimeMillis() - merchantUpdate > 5 * 60 * 1000) initProc = 1;
|
||||
int initProc;
|
||||
if(Server.getInstance().getCurrentTime() - merchantUpdate > 5 * 60 * 1000) initProc = 1;
|
||||
else initProc = 0;
|
||||
|
||||
activeMerchants.put(hm.getOwnerId(), new Pair<>(hm, initProc));
|
||||
@@ -1340,18 +1353,18 @@ public class World {
|
||||
}
|
||||
|
||||
public void runHiredMerchantSchedule() {
|
||||
Map<Integer, Pair<MapleHiredMerchant, Byte>> deployedMerchants;
|
||||
Map<Integer, Pair<MapleHiredMerchant, Integer>> deployedMerchants;
|
||||
activeMerchantsLock.lock();
|
||||
try {
|
||||
merchantUpdate = System.currentTimeMillis();
|
||||
merchantUpdate = Server.getInstance().getCurrentTime();
|
||||
deployedMerchants = new LinkedHashMap<>(activeMerchants);
|
||||
|
||||
for(Map.Entry<Integer, Pair<MapleHiredMerchant, Byte>> dm: deployedMerchants.entrySet()) {
|
||||
byte timeOn = dm.getValue().getRight();
|
||||
for(Map.Entry<Integer, Pair<MapleHiredMerchant, Integer>> dm: deployedMerchants.entrySet()) {
|
||||
int timeOn = dm.getValue().getRight();
|
||||
MapleHiredMerchant hm = dm.getValue().getLeft();
|
||||
|
||||
if(timeOn <= 144) { // 1440 minutes == 24hrs
|
||||
activeMerchants.put(hm.getOwnerId(), new Pair<>(dm.getValue().getLeft(), (byte)(timeOn + 1)));
|
||||
activeMerchants.put(hm.getOwnerId(), new Pair<>(dm.getValue().getLeft(), timeOn + 1));
|
||||
} else {
|
||||
hm.forceClose();
|
||||
this.getChannel(hm.getChannel()).removeHiredMerchant(hm.getOwnerId());
|
||||
@@ -1368,7 +1381,7 @@ public class World {
|
||||
List<MapleHiredMerchant> hmList = new ArrayList<>();
|
||||
activeMerchantsLock.lock();
|
||||
try {
|
||||
for(Pair<MapleHiredMerchant, Byte> hmp : activeMerchants.values()) {
|
||||
for(Pair<MapleHiredMerchant, Integer> hmp : activeMerchants.values()) {
|
||||
MapleHiredMerchant hm = hmp.getLeft();
|
||||
if(hm.isOpen()) {
|
||||
hmList.add(hm);
|
||||
@@ -1397,7 +1410,7 @@ public class World {
|
||||
public void registerTimedMapObject(Runnable r, long duration) {
|
||||
timedMapObjectLock.lock();
|
||||
try {
|
||||
long expirationTime = System.currentTimeMillis() + duration;
|
||||
long expirationTime = Server.getInstance().getCurrentTime() + duration;
|
||||
registeredTimedMapObjects.put(r, expirationTime);
|
||||
} finally {
|
||||
timedMapObjectLock.unlock();
|
||||
@@ -1409,7 +1422,7 @@ public class World {
|
||||
|
||||
timedMapObjectLock.lock();
|
||||
try {
|
||||
long timeNow = System.currentTimeMillis();
|
||||
long timeNow = Server.getInstance().getCurrentTime();
|
||||
|
||||
for(Entry<Runnable, Long> rtmo : registeredTimedMapObjects.entrySet()) {
|
||||
if(rtmo.getValue() <= timeNow) {
|
||||
@@ -1429,6 +1442,68 @@ public class World {
|
||||
}
|
||||
}
|
||||
|
||||
public void resetDisabledServerMessages() {
|
||||
srvMessagesLock.lock();
|
||||
try {
|
||||
disabledServerMessages.clear();
|
||||
} finally {
|
||||
srvMessagesLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean registerDisabledServerMessage(int chrid) {
|
||||
srvMessagesLock.lock();
|
||||
try {
|
||||
boolean alreadyDisabled = disabledServerMessages.containsKey(chrid);
|
||||
disabledServerMessages.put(chrid, 0);
|
||||
|
||||
return alreadyDisabled;
|
||||
} finally {
|
||||
srvMessagesLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean unregisterDisabledServerMessage(int chrid) {
|
||||
srvMessagesLock.lock();
|
||||
try {
|
||||
return disabledServerMessages.remove(chrid) != null;
|
||||
} finally {
|
||||
srvMessagesLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void runDisabledServerMessagesSchedule() {
|
||||
List<Integer> toRemove = new LinkedList<>();
|
||||
|
||||
srvMessagesLock.lock();
|
||||
try {
|
||||
for(Entry<Integer, Integer> dsm : disabledServerMessages.entrySet()) {
|
||||
int b = dsm.getValue();
|
||||
if(b >= 4) { // ~35sec duration, 10sec update
|
||||
toRemove.add(dsm.getKey());
|
||||
} else {
|
||||
disabledServerMessages.put(dsm.getKey(), ++b);
|
||||
}
|
||||
}
|
||||
|
||||
for(Integer chrid : toRemove) {
|
||||
disabledServerMessages.remove(chrid);
|
||||
}
|
||||
} finally {
|
||||
srvMessagesLock.unlock();
|
||||
}
|
||||
|
||||
if(!toRemove.isEmpty()) {
|
||||
for(Integer chrid : toRemove) {
|
||||
MapleCharacter chr = players.getCharacterById(chrid);
|
||||
|
||||
if(chr != null && chr.isLoggedinWorld()) {
|
||||
chr.announce(MaplePacketCreator.serverMessage(chr.getClient().getChannelServer().getServerMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setPlayerNpcMapStep(int mapid, int step) {
|
||||
setPlayerNpcMapData(mapid, step, -1, false);
|
||||
}
|
||||
@@ -1670,7 +1745,7 @@ public class World {
|
||||
}
|
||||
}
|
||||
|
||||
private void disposeLocks() {
|
||||
private void clearWorldData() {
|
||||
List<MapleParty> pList;
|
||||
partyLock.lock();
|
||||
try {
|
||||
@@ -1683,9 +1758,22 @@ public class World {
|
||||
p.disposeLocks();
|
||||
}
|
||||
|
||||
disposeLocks();
|
||||
}
|
||||
|
||||
private void disposeLocks() {
|
||||
LockCollector.getInstance().registerDisposeAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
emptyLocks();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void emptyLocks() {
|
||||
accountCharsLock = accountCharsLock.dispose();
|
||||
partyLock = partyLock.dispose();
|
||||
owlLock = owlLock.dispose();
|
||||
srvMessagesLock = srvMessagesLock.dispose();
|
||||
activePetsLock = activePetsLock.dispose();
|
||||
activeMountsLock = activeMountsLock.dispose();
|
||||
activePlayerShopsLock = activePlayerShopsLock.dispose();
|
||||
@@ -1703,11 +1791,21 @@ public class World {
|
||||
petsSchedule = null;
|
||||
}
|
||||
|
||||
if(srvMessagesSchedule != null) {
|
||||
srvMessagesSchedule.cancel(false);
|
||||
srvMessagesSchedule = null;
|
||||
}
|
||||
|
||||
if(mountsSchedule != null) {
|
||||
mountsSchedule.cancel(false);
|
||||
mountsSchedule = null;
|
||||
}
|
||||
|
||||
if(merchantSchedule != null) {
|
||||
merchantSchedule.cancel(false);
|
||||
merchantSchedule = null;
|
||||
}
|
||||
|
||||
if(timedMapObjectsSchedule != null) {
|
||||
timedMapObjectsSchedule.cancel(false);
|
||||
timedMapObjectsSchedule = null;
|
||||
@@ -1726,6 +1824,6 @@ public class World {
|
||||
players.disconnectAll();
|
||||
players = null;
|
||||
|
||||
disposeLocks();
|
||||
clearWorldData();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user