Heal GMS + Improved chnl workers & Pshop tooltip + Equips on party HP
Slightly improved channel and disease announce workers performance. Completion of repeatable quests no longer generates fame to players. Equipment drop rates of Leprechaun were slightly decreased. Fixed Pet Item Ignore not checking certain exploit cases correctly. Optimized Pet Item Ignore server handler performance. Fixed some exploits and improved performance on PetLootHandler. Improved concurrency protection on MapleInventoryManipulator. Heal skill effect on players now works GMS-intended, as description says. Also removed the delayed Heal cast effect to others. Fixed party player HPBar not accounting the player's HP stat gained on equips towards the effective MaxHP. The duration of mists generated by mobs has been rescaled to 10x longer than what has been displayed until now (wz duration property is supposed to actually be in 100ms). Optimized timer management for mob skill cooldown and elemental effectiveness. Implemented an additional inventory check system, to be used in cases where it's expected to remove a set group for items (with quantity) to then add a new group of items. Fixed Player Shop/Hired Merchant "vacancy" tooltip, now properly showing whether the store has a visitor room or is already full at that time. Fixed Player Shops only using the standard stand type. Fixed cash pet food ignoring certain pet itemids when reading data from WZ.
This commit is contained in:
@@ -28,6 +28,8 @@ import java.util.HashSet;
|
||||
import java.util.Calendar;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import net.server.Server;
|
||||
|
||||
import org.apache.mina.core.service.IoHandlerAdapter;
|
||||
@@ -46,14 +48,12 @@ import constants.ServerConstants;
|
||||
import java.util.Arrays;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import server.TimerManager;
|
||||
import tools.locks.MonitoredLockType;
|
||||
|
||||
public class MapleServerHandler extends IoHandlerAdapter {
|
||||
private final static Set<Short> ignoredDebugRecvPackets = new HashSet<>(Arrays.asList((short) 167, (short) 197, (short) 89, (short) 91, (short) 41, (short) 188, (short) 107));
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
package net.server;
|
||||
|
||||
import java.io.Console;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author kevintjuh93
|
||||
*/
|
||||
public class CreateINI {
|
||||
|
||||
public static void main(String args[]) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String nextline = "\r\n";//Because I can, and it's free.
|
||||
byte worlds;
|
||||
Console con = System.console();
|
||||
|
||||
System.out.println("Welcome to MoopleDEV's .ini creator\r\n\r\n");
|
||||
|
||||
sb.append("#MoopleDEV's INI file. Do NOT modify it if you are an idiot (:\r\n");
|
||||
sb.append("#Flag types: 0 = nothing, 1 = event, 2 = new, 3 = hot\r\n\r\n");
|
||||
|
||||
System.out.println("Flag types: 0 = nothing, 1 = event, 2 = new, 3 = hot\r\n\r\n");
|
||||
|
||||
worlds = Byte.parseByte(con.readLine("Number of worlds: "));
|
||||
sb.append("worlds=").append(worlds).append("\r\n\r\n");
|
||||
|
||||
System.out.println("\r\n");
|
||||
|
||||
|
||||
for (byte b = 0; b < worlds; b++) {
|
||||
sb.append("#Properties for world ").append(b).append("\r\n");
|
||||
|
||||
System.out.println("Properties for world " + b);
|
||||
if (b > 1) {
|
||||
System.out.println("Make sure you create a npc folder for this world!");
|
||||
}
|
||||
sb.append("flag").append(b).append("=").append(
|
||||
Integer.parseInt(con.readLine(" Flag: "))).append("\r\n");
|
||||
|
||||
sb.append("servermessage").append(b).append("=").append(
|
||||
con.readLine(" Server message: ")).append("\r\n");
|
||||
|
||||
sb.append("eventmessage").append(b).append("=").append(
|
||||
con.readLine(" Event message: ")).append("\r\n");
|
||||
|
||||
sb.append("whyamirecommended").append(b).append("=").append(
|
||||
con.readLine(" Recommend message: ")).append("\r\n");
|
||||
|
||||
sb.append("channels").append(b).append("=").append(
|
||||
Byte.parseByte(con.readLine(" Number of channels: "))).append("\r\n");
|
||||
|
||||
sb.append("exprate").append(b).append("=").append(
|
||||
Integer.parseInt(con.readLine(" Exp rate: "))).append("\r\n");
|
||||
|
||||
sb.append("droprate").append(b).append("=").append(
|
||||
Integer.parseInt(con.readLine(" Drop rate: "))).append("\r\n");
|
||||
|
||||
sb.append("mesorate").append(b).append("=").append(
|
||||
Integer.parseInt(con.readLine(" Meso rate: "))).append("\r\n");
|
||||
|
||||
sb.append("questrate").append(b).append("=").append(
|
||||
Integer.parseInt(con.readLine(" Quest rate: "))).append("\r\n");
|
||||
|
||||
System.out.println(nextline);
|
||||
sb.append("\r\n");
|
||||
}
|
||||
|
||||
sb.append("\r\n").append("gmserver=").append(Boolean.parseBoolean(con.readLine("Do you want a GM Server? (true/false)")));
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
out = new FileOutputStream("moople.ini", false);
|
||||
out.write(sb.toString().getBytes());
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (out != null) {
|
||||
out.close();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
sb = new StringBuilder();
|
||||
try {
|
||||
System.out.println("\r\nYou are about to set the Java Heap Size, if you don't know what it is, type '?'.");
|
||||
String heapsize = con.readLine("Java Heap Size (in MB): ");
|
||||
while (heapsize.equals("?")) {
|
||||
System.out.println("\r\n");
|
||||
System.out.println("WikiAnswers: Java heap is the heap size allocated to JVM applications which takes care of the new objects being created. If the objects being created exceed the heap size, it will throw an error saying memoryOutof Bound\r\n");
|
||||
System.out.println("I recommend using 64 bit with the heap size around 4000, if you have 4 gb RAM.");
|
||||
heapsize = con.readLine("Java Heap Size (in MB): ");
|
||||
}
|
||||
String linux = con.readLine("\r\nAre you using a Linux platform or not? (y/n):");
|
||||
while (!linux.equals("y") && !linux.equals("n")) {
|
||||
System.out.println("Type 'y' if you use linux else type 'n'.");
|
||||
linux = con.readLine("Are you using a Linux platform or not? (y/n):");
|
||||
}
|
||||
if (linux.equals("n")) {
|
||||
out = new FileOutputStream("launch_server.bat", false);
|
||||
sb.append("@echo off").append("\r\n").append("@title MoopleDEV Server v83").append("\r\n");
|
||||
sb.append("set CLASSPATH=.;dist\\*\r\n");
|
||||
sb.append("java -Xmx").append(heapsize).append("m -Dwzpath=wz\\ net.server.Server\r\n");
|
||||
sb.append("pause");
|
||||
} else {//test
|
||||
out = new FileOutputStream("launch_server.sh", false);
|
||||
sb.append("#!/bin/sh").append("\r\n\r\n");
|
||||
sb.append("export CLASSPATH=\".:dist/*\" \r\n\r\n");
|
||||
sb.append("java -Dwzpath=wz/ \\\r\n");
|
||||
sb.append("-Xmx").append(heapsize).append("m ").append("net.server.Server");
|
||||
System.out.println("Use DOS2UNIX command to convert the .sh file once again.");
|
||||
}
|
||||
out.write(sb.toString().getBytes());
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (out != null) {
|
||||
out.close();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
System.out.println("\r\nMake sure that ServerConstants in modified too, and clean+compiled before you start the server.");
|
||||
System.out.println("If you want other settings; restart this .bat or modify the moople.ini");
|
||||
}
|
||||
}
|
||||
@@ -28,8 +28,8 @@ import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import server.life.MobSkill;
|
||||
import tools.Pair;
|
||||
import tools.locks.MonitoredLockType;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
@@ -27,11 +27,11 @@ import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import tools.locks.MonitoredReentrantReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
||||
import tools.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
|
||||
|
||||
public class PlayerStorage {
|
||||
private final ReentrantReadWriteLock locks = new MonitoredReentrantReadWriteLock(MonitoredLockType.PLAYER_STORAGE, true);
|
||||
|
||||
@@ -41,12 +41,16 @@ import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
import tools.locks.MonitoredReentrantReadWriteLock;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
||||
|
||||
import net.server.audit.ThreadTracker;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
|
||||
|
||||
import net.MapleServerHandler;
|
||||
import net.mina.MapleCodecFactory;
|
||||
import net.server.channel.Channel;
|
||||
@@ -75,7 +79,6 @@ import client.newyear.NewYearCardRecord;
|
||||
import constants.ItemConstants;
|
||||
import constants.GameConstants;
|
||||
import constants.ServerConstants;
|
||||
import net.server.audit.ThreadTracker;
|
||||
import server.CashShop.CashItemFactory;
|
||||
import server.TimerManager;
|
||||
import server.life.MaplePlayerNPCFactory;
|
||||
@@ -84,7 +87,6 @@ import tools.AutoJCE;
|
||||
import tools.DatabaseConnection;
|
||||
import tools.FilePrinter;
|
||||
import tools.Pair;
|
||||
import tools.locks.MonitoredLockType;
|
||||
|
||||
public class Server {
|
||||
private static final Set<Integer> activeFly = new HashSet<>();
|
||||
@@ -325,18 +327,27 @@ public class Server {
|
||||
}
|
||||
|
||||
public void runAnnouncePlayerDiseasesSchedule() {
|
||||
List<MapleClient> processDiseaseAnnounceClients;
|
||||
disLock.lock();
|
||||
try {
|
||||
while(!processDiseaseAnnouncePlayers.isEmpty()) {
|
||||
MapleClient c = processDiseaseAnnouncePlayers.remove(0);
|
||||
MapleCharacter player = c.getPlayer();
|
||||
if(player != null && player.isLoggedinWorld()) {
|
||||
for(MapleCharacter chr : player.getMap().getCharacters()) {
|
||||
chr.announceDiseases(c);
|
||||
}
|
||||
processDiseaseAnnounceClients = new LinkedList<>(processDiseaseAnnouncePlayers);
|
||||
processDiseaseAnnouncePlayers.clear();
|
||||
} finally {
|
||||
disLock.unlock();
|
||||
}
|
||||
|
||||
while(!processDiseaseAnnounceClients.isEmpty()) {
|
||||
MapleClient c = processDiseaseAnnounceClients.remove(0);
|
||||
MapleCharacter player = c.getPlayer();
|
||||
if(player != null && player.isLoggedinWorld()) {
|
||||
for(MapleCharacter chr : player.getMap().getCharacters()) {
|
||||
chr.announceDiseases(c);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
disLock.lock();
|
||||
try {
|
||||
// this is to force the system to wait for at least one complete tick before releasing disease info for the registered clients
|
||||
while(!registeredDiseaseAnnouncePlayers.isEmpty()) {
|
||||
MapleClient c = registeredDiseaseAnnouncePlayers.remove(0);
|
||||
@@ -362,7 +373,7 @@ public class Server {
|
||||
p.load(new FileInputStream("world.ini"));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.out.println("Please start create_server.bat");
|
||||
System.out.println("[SEVERE] Could not find/open 'world.ini'.");
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
@@ -453,7 +464,7 @@ public class Server {
|
||||
loadPlayerNpcMapStepFromDb();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();//For those who get errors
|
||||
System.out.println("Error in moople.ini, start CreateINI.bat to re-make the file.");
|
||||
System.out.println("[SEVERE] Syntax error in 'world.ini'.");
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,10 +34,11 @@ import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import constants.ServerConstants;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import server.TimerManager;
|
||||
import tools.FilePrinter;
|
||||
import tools.locks.MonitoredLockType;
|
||||
import constants.ServerConstants;
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
90
src/net/server/audit/locks/MonitoredLockType.java
Normal file
90
src/net/server/audit/locks/MonitoredLockType.java
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft 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.locks;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author RonanLana
|
||||
*/
|
||||
|
||||
public enum MonitoredLockType {
|
||||
UNDEFINED,
|
||||
CHARACTER_CHR,
|
||||
CHARACTER_EFF,
|
||||
CHARACTER_PET,
|
||||
CHARACTER_PRT,
|
||||
CLIENT,
|
||||
CLIENT_ENCODER,
|
||||
CLIENT_LOGIN,
|
||||
BOOK,
|
||||
ITEM,
|
||||
INVENTORY,
|
||||
SRVHANDLER_IDLE,
|
||||
SRVHANDLER_TEMP,
|
||||
BUFF_STORAGE,
|
||||
PLAYER_STORAGE,
|
||||
SERVER,
|
||||
SERVER_LOGIN,
|
||||
SERVER_DISEASES,
|
||||
MERCHANT,
|
||||
CHANNEL,
|
||||
CHANNEL_FACEEXPRS,
|
||||
CHANNEL_FACESCHDL,
|
||||
CHANNEL_MOBACTION,
|
||||
CHANNEL_MOBANIMAT,
|
||||
CHANNEL_MOBMIST,
|
||||
CHANNEL_MOBSKILL,
|
||||
CHANNEL_MOBSTATUS,
|
||||
CHANNEL_OVTSTATUS,
|
||||
CHANNEL_OVERALL,
|
||||
GUILD,
|
||||
PARTY,
|
||||
WORLD_PARTY,
|
||||
WORLD_OWL,
|
||||
WORLD_PETS,
|
||||
WORLD_CHARS,
|
||||
WORLD_MOUNTS,
|
||||
WORLD_PSHOPS,
|
||||
WORLD_MERCHS,
|
||||
WORLD_MAPOBJS,
|
||||
EIM,
|
||||
EIM_PARTY,
|
||||
EIM_SCRIPT,
|
||||
EM_LOBBY,
|
||||
EM_QUEUE,
|
||||
CASHSHOP,
|
||||
VISITOR_PSHOP,
|
||||
STORAGE,
|
||||
MOB,
|
||||
MOB_ANI,
|
||||
MOB_EXT,
|
||||
MOB_STATI,
|
||||
MOBSKILL_FACTORY,
|
||||
PORTAL,
|
||||
VISITOR_MERCH,
|
||||
MAP_CHRS,
|
||||
MAP_OBJS,
|
||||
MAP_FACTORY,
|
||||
MAP_ITEM,
|
||||
MAP_BOUNDS,
|
||||
MINIDUNGEON,
|
||||
REACTOR,
|
||||
REACTOR_HIT;
|
||||
}
|
||||
149
src/net/server/audit/locks/MonitoredReadLock.java
Normal file
149
src/net/server/audit/locks/MonitoredReadLock.java
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
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.locks;
|
||||
|
||||
import constants.ServerConstants;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import server.TimerManager;
|
||||
import net.server.Server;
|
||||
import net.server.audit.ThreadTracker;
|
||||
|
||||
import tools.FilePrinter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author RonanLana
|
||||
*/
|
||||
public class MonitoredReadLock extends ReentrantReadWriteLock.ReadLock {
|
||||
private ScheduledFuture<?> timeoutSchedule = null;
|
||||
private StackTraceElement[] deadlockedState = null;
|
||||
private final MonitoredLockType id;
|
||||
private final int hashcode;
|
||||
private final Lock state = new ReentrantLock(true);
|
||||
private final AtomicInteger reentrantCount = new AtomicInteger(0);
|
||||
|
||||
public MonitoredReadLock(MonitoredReentrantReadWriteLock lock) {
|
||||
super(lock);
|
||||
this.id = lock.id;
|
||||
hashcode = this.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lock() {
|
||||
if(ServerConstants.USE_THREAD_TRACKER) {
|
||||
if(deadlockedState != null) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||
|
||||
//FilePrinter.printError(FilePrinter.DEADLOCK_ERROR, "[CRITICAL] " + dateFormat.format(new Date()) + " Deadlock occurred when trying to use the '" + id.name() + "' lock resources:\r\n" + printStackTrace(deadlockedState) + "\r\n\r\n");
|
||||
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
|
||||
deadlockedState = null;
|
||||
}
|
||||
|
||||
registerLocking();
|
||||
}
|
||||
|
||||
super.lock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlock() {
|
||||
if(ServerConstants.USE_THREAD_TRACKER) {
|
||||
unregisterLocking();
|
||||
}
|
||||
|
||||
super.unlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryLock() {
|
||||
if(super.tryLock()) {
|
||||
if(ServerConstants.USE_THREAD_TRACKER) {
|
||||
if(deadlockedState != null) {
|
||||
//FilePrinter.printError(FilePrinter.DEADLOCK_ERROR, "Deadlock occurred when trying to use the '" + id.name() + "' lock resources:\r\n" + printStackTrace(deadlockedState) + "\r\n\r\n");
|
||||
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
|
||||
deadlockedState = null;
|
||||
}
|
||||
|
||||
registerLocking();
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void registerLocking() {
|
||||
state.lock();
|
||||
try {
|
||||
ThreadTracker.getInstance().accessThreadTracker(false, true, id, hashcode);
|
||||
|
||||
if(reentrantCount.incrementAndGet() == 1) {
|
||||
final Thread t = Thread.currentThread();
|
||||
timeoutSchedule = TimerManager.getInstance().schedule(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
issueDeadlock(t);
|
||||
}
|
||||
}, ServerConstants.LOCK_MONITOR_TIME);
|
||||
}
|
||||
} finally {
|
||||
state.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void unregisterLocking() {
|
||||
state.lock();
|
||||
try {
|
||||
if(reentrantCount.decrementAndGet() == 0) {
|
||||
if(timeoutSchedule != null) {
|
||||
timeoutSchedule.cancel(false);
|
||||
timeoutSchedule = null;
|
||||
}
|
||||
}
|
||||
|
||||
ThreadTracker.getInstance().accessThreadTracker(false, false, id, hashcode);
|
||||
} finally {
|
||||
state.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void issueDeadlock(Thread t) {
|
||||
deadlockedState = t.getStackTrace();
|
||||
//super.unlock();
|
||||
}
|
||||
|
||||
private static String printStackTrace(StackTraceElement[] list) {
|
||||
String s = "";
|
||||
for(int i = 0; i < list.length; i++) {
|
||||
s += (" " + list[i].toString() + "\r\n");
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
||||
153
src/net/server/audit/locks/MonitoredReentrantLock.java
Normal file
153
src/net/server/audit/locks/MonitoredReentrantLock.java
Normal file
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
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.locks;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import constants.ServerConstants;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
import server.TimerManager;
|
||||
import net.server.Server;
|
||||
import net.server.audit.ThreadTracker;
|
||||
import tools.FilePrinter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author RonanLana
|
||||
*/
|
||||
public class MonitoredReentrantLock extends ReentrantLock {
|
||||
private ScheduledFuture<?> timeoutSchedule = null;
|
||||
private StackTraceElement[] deadlockedState = null;
|
||||
private final MonitoredLockType id;
|
||||
private final int hashcode;
|
||||
private final Lock state = new ReentrantLock(true);
|
||||
private final AtomicInteger reentrantCount = new AtomicInteger(0);
|
||||
|
||||
public MonitoredReentrantLock(MonitoredLockType id) {
|
||||
super();
|
||||
this.id = id;
|
||||
hashcode = this.hashCode();
|
||||
}
|
||||
|
||||
public MonitoredReentrantLock(MonitoredLockType id, boolean fair) {
|
||||
super(fair);
|
||||
this.id = id;
|
||||
hashcode = this.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lock() {
|
||||
if(ServerConstants.USE_THREAD_TRACKER) {
|
||||
if(deadlockedState != null) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||
|
||||
//FilePrinter.printError(FilePrinter.DEADLOCK_ERROR, "[CRITICAL] " + dateFormat.format(new Date()) + " Deadlock occurred when trying to use the '" + id.name() + "' lock resources:\r\n" + printStackTrace(deadlockedState) + "\r\n\r\n");
|
||||
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
|
||||
deadlockedState = null;
|
||||
}
|
||||
|
||||
registerLocking();
|
||||
}
|
||||
|
||||
super.lock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlock() {
|
||||
if(ServerConstants.USE_THREAD_TRACKER) {
|
||||
unregisterLocking();
|
||||
}
|
||||
|
||||
super.unlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryLock() {
|
||||
if(super.tryLock()) {
|
||||
if(ServerConstants.USE_THREAD_TRACKER) {
|
||||
if(deadlockedState != null) {
|
||||
//FilePrinter.printError(FilePrinter.DEADLOCK_ERROR, "Deadlock occurred when trying to use the '" + id.name() + "' lock resources:\r\n" + printStackTrace(deadlockedState) + "\r\n\r\n");
|
||||
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
|
||||
deadlockedState = null;
|
||||
}
|
||||
|
||||
registerLocking();
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void registerLocking() {
|
||||
state.lock();
|
||||
try {
|
||||
ThreadTracker.getInstance().accessThreadTracker(false, true, id, hashcode);
|
||||
|
||||
if(reentrantCount.incrementAndGet() == 1) {
|
||||
final Thread t = Thread.currentThread();
|
||||
timeoutSchedule = TimerManager.getInstance().schedule(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
issueDeadlock(t);
|
||||
}
|
||||
}, ServerConstants.LOCK_MONITOR_TIME);
|
||||
}
|
||||
} finally {
|
||||
state.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void unregisterLocking() {
|
||||
state.lock();
|
||||
try {
|
||||
if(reentrantCount.decrementAndGet() == 0) {
|
||||
if(timeoutSchedule != null) {
|
||||
timeoutSchedule.cancel(false);
|
||||
timeoutSchedule = null;
|
||||
}
|
||||
}
|
||||
|
||||
ThreadTracker.getInstance().accessThreadTracker(false, false, id, hashcode);
|
||||
} finally {
|
||||
state.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void issueDeadlock(Thread t) {
|
||||
deadlockedState = t.getStackTrace();
|
||||
//super.unlock();
|
||||
}
|
||||
|
||||
private static String printStackTrace(StackTraceElement[] list) {
|
||||
String s = "";
|
||||
for(int i = 0; i < list.length; i++) {
|
||||
s += (" " + list[i].toString() + "\r\n");
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
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.locks;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author RonanLana
|
||||
*/
|
||||
public class MonitoredReentrantReadWriteLock extends ReentrantReadWriteLock {
|
||||
public final MonitoredLockType id;
|
||||
|
||||
public MonitoredReentrantReadWriteLock(MonitoredLockType id) {
|
||||
super();
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public MonitoredReentrantReadWriteLock(MonitoredLockType id, boolean fair) {
|
||||
super(fair);
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadLock readLock() {
|
||||
return super.readLock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WriteLock writeLock() {
|
||||
return super.writeLock();
|
||||
}
|
||||
}
|
||||
148
src/net/server/audit/locks/MonitoredWriteLock.java
Normal file
148
src/net/server/audit/locks/MonitoredWriteLock.java
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
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.locks;
|
||||
|
||||
import constants.ServerConstants;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import server.TimerManager;
|
||||
import net.server.Server;
|
||||
import net.server.audit.ThreadTracker;
|
||||
import tools.FilePrinter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author RonanLana
|
||||
*/
|
||||
public class MonitoredWriteLock extends ReentrantReadWriteLock.WriteLock {
|
||||
private ScheduledFuture<?> timeoutSchedule = null;
|
||||
private StackTraceElement[] deadlockedState = null;
|
||||
private final MonitoredLockType id;
|
||||
private final int hashcode;
|
||||
private final Lock state = new ReentrantLock(true);
|
||||
private final AtomicInteger reentrantCount = new AtomicInteger(0);
|
||||
|
||||
public MonitoredWriteLock(MonitoredReentrantReadWriteLock lock) {
|
||||
super(lock);
|
||||
this.id = lock.id;
|
||||
hashcode = this.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lock() {
|
||||
if(ServerConstants.USE_THREAD_TRACKER) {
|
||||
if(deadlockedState != null) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||
|
||||
//FilePrinter.printError(FilePrinter.DEADLOCK_ERROR, "[CRITICAL] " + dateFormat.format(new Date()) + " Deadlock occurred when trying to use the '" + id.name() + "' lock resources:\r\n" + printStackTrace(deadlockedState) + "\r\n\r\n");
|
||||
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
|
||||
deadlockedState = null;
|
||||
}
|
||||
|
||||
registerLocking();
|
||||
}
|
||||
|
||||
super.lock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlock() {
|
||||
if(ServerConstants.USE_THREAD_TRACKER) {
|
||||
unregisterLocking();
|
||||
}
|
||||
|
||||
super.unlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryLock() {
|
||||
if(super.tryLock()) {
|
||||
if(ServerConstants.USE_THREAD_TRACKER) {
|
||||
if(deadlockedState != null) {
|
||||
//FilePrinter.printError(FilePrinter.DEADLOCK_ERROR, "Deadlock occurred when trying to use the '" + id.name() + "' lock resources:\r\n" + printStackTrace(deadlockedState) + "\r\n\r\n");
|
||||
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
|
||||
deadlockedState = null;
|
||||
}
|
||||
|
||||
registerLocking();
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void registerLocking() {
|
||||
state.lock();
|
||||
try {
|
||||
ThreadTracker.getInstance().accessThreadTracker(false, true, id, hashcode);
|
||||
|
||||
if(reentrantCount.incrementAndGet() == 1) {
|
||||
final Thread t = Thread.currentThread();
|
||||
timeoutSchedule = TimerManager.getInstance().schedule(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
issueDeadlock(t);
|
||||
}
|
||||
}, ServerConstants.LOCK_MONITOR_TIME);
|
||||
}
|
||||
} finally {
|
||||
state.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void unregisterLocking() {
|
||||
state.lock();
|
||||
try {
|
||||
if(reentrantCount.decrementAndGet() == 0) {
|
||||
if(timeoutSchedule != null) {
|
||||
timeoutSchedule.cancel(false);
|
||||
timeoutSchedule = null;
|
||||
}
|
||||
}
|
||||
|
||||
ThreadTracker.getInstance().accessThreadTracker(false, false, id, hashcode);
|
||||
} finally {
|
||||
state.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void issueDeadlock(Thread t) {
|
||||
deadlockedState = t.getStackTrace();
|
||||
//super.unlock();
|
||||
}
|
||||
|
||||
private static String printStackTrace(StackTraceElement[] list) {
|
||||
String s = "";
|
||||
for(int i = 0; i < list.length; i++) {
|
||||
s += (" " + list[i].toString() + "\r\n");
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
||||
@@ -34,11 +34,12 @@ import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
import tools.locks.MonitoredReentrantReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
|
||||
|
||||
import net.MapleServerHandler;
|
||||
import net.mina.MapleCodecFactory;
|
||||
@@ -76,7 +77,6 @@ import client.MapleCharacter;
|
||||
import client.status.MonsterStatusEffect;
|
||||
import constants.ServerConstants;
|
||||
import server.maps.MapleMiniDungeonInfo;
|
||||
import tools.locks.MonitoredLockType;
|
||||
|
||||
public final class Channel {
|
||||
|
||||
@@ -89,6 +89,8 @@ public final class Channel {
|
||||
private EventScriptManager eventSM;
|
||||
private MobStatusScheduler mobStatusSchedulers[] = new MobStatusScheduler[4];
|
||||
private MobAnimationScheduler mobAnimationSchedulers[] = new MobAnimationScheduler[4];
|
||||
private MobClearSkillScheduler mobClearSkillSchedulers[] = new MobClearSkillScheduler[4];
|
||||
private MobMistScheduler mobMistSchedulers[] = new MobMistScheduler[4];
|
||||
private FaceExpressionScheduler faceExpressionSchedulers[] = new FaceExpressionScheduler[4];
|
||||
private OverallScheduler channelSchedulers[] = new OverallScheduler[4];
|
||||
private Map<Integer, MapleHiredMerchant> hiredMerchants = new HashMap<>();
|
||||
@@ -164,6 +166,8 @@ public final class Channel {
|
||||
|
||||
mobStatusSchedulers[i] = new MobStatusScheduler();
|
||||
mobAnimationSchedulers[i] = new MobAnimationScheduler();
|
||||
mobClearSkillSchedulers[i] = new MobClearSkillScheduler();
|
||||
mobMistSchedulers[i] = new MobMistScheduler();
|
||||
faceExpressionSchedulers[i] = new FaceExpressionScheduler(faceLock[i]);
|
||||
channelSchedulers[i] = new OverallScheduler();
|
||||
}
|
||||
@@ -868,6 +872,14 @@ public final class Channel {
|
||||
return mobAnimationSchedulers[getChannelSchedulerIndex(mapid)].registerAnimationMode(mobHash, delay);
|
||||
}
|
||||
|
||||
public void registerMobClearSkillAction(int mapid, Runnable runAction, long delay) {
|
||||
mobClearSkillSchedulers[getChannelSchedulerIndex(mapid)].registerClearSkillAction(runAction, delay);
|
||||
}
|
||||
|
||||
public void registerMobMistCancelAction(int mapid, Runnable runAction, long delay) {
|
||||
mobMistSchedulers[getChannelSchedulerIndex(mapid)].registerMistCancelAction(runAction, delay);
|
||||
}
|
||||
|
||||
public void registerOverallAction(int mapid, Runnable runAction, long delay) {
|
||||
channelSchedulers[getChannelSchedulerIndex(mapid)].registerDelayedAction(runAction, delay);
|
||||
}
|
||||
|
||||
@@ -674,6 +674,8 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
|
||||
// This formula is still a bit wonky, but it is fairly accurate.
|
||||
calcDmgMax = (int) Math.round((chr.getTotalInt() * 4.8 + chr.getTotalLuk() * 4) * chr.getTotalMagic() / 1000);
|
||||
calcDmgMax = calcDmgMax * effect.getHp() / 100;
|
||||
|
||||
ret.speed = 7;
|
||||
}
|
||||
} else if(ret.skill == Hermit.SHADOW_MESO) {
|
||||
// Shadow Meso also has its own formula
|
||||
|
||||
@@ -230,7 +230,14 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
|
||||
} else if (action == 0x0E) { // Put into Cash Inventory
|
||||
int cashId = slea.readInt();
|
||||
slea.skip(4);
|
||||
MapleInventory mi = chr.getInventory(MapleInventoryType.getByType(slea.readByte()));
|
||||
|
||||
byte invType = slea.readByte();
|
||||
if (invType < 1 || invType > 5) {
|
||||
c.disconnect(false, false);
|
||||
return;
|
||||
}
|
||||
|
||||
MapleInventory mi = chr.getInventory(MapleInventoryType.getByType(invType));
|
||||
Item item = mi.findByCashId(cashId);
|
||||
if (item == null) {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
|
||||
@@ -39,13 +39,19 @@ public final class InventoryMergeHandler extends AbstractMaplePacketHandler {
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
MapleCharacter chr = c.getPlayer();
|
||||
chr.getAutobanManager().setTimestamp(2, slea.readInt(), 3);
|
||||
MapleInventoryType inventoryType = MapleInventoryType.getByType(slea.readByte());
|
||||
|
||||
if(!ServerConstants.USE_ITEM_SORT) {
|
||||
|
||||
if(!ServerConstants.USE_ITEM_SORT) {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
byte invType = slea.readByte();
|
||||
if (invType < 1 || invType > 5) {
|
||||
c.disconnect(false, false);
|
||||
return;
|
||||
}
|
||||
|
||||
MapleInventoryType inventoryType = MapleInventoryType.getByType(invType);
|
||||
MapleInventory inventory = c.getPlayer().getInventory(inventoryType);
|
||||
inventory.lockInventory();
|
||||
try {
|
||||
|
||||
@@ -188,14 +188,14 @@ public final class InventorySortHandler extends AbstractMaplePacketHandler {
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
MapleCharacter chr = c.getPlayer();
|
||||
chr.getAutobanManager().setTimestamp(3, slea.readInt(), 3);
|
||||
byte inventoryType = slea.readByte();
|
||||
|
||||
if(!ServerConstants.USE_ITEM_SORT) {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
|
||||
if (inventoryType < 1 || inventoryType > 5) {
|
||||
|
||||
byte invType = slea.readByte();
|
||||
if (invType < 1 || invType > 5) {
|
||||
c.disconnect(false, false);
|
||||
return;
|
||||
}
|
||||
@@ -203,7 +203,7 @@ public final class InventorySortHandler extends AbstractMaplePacketHandler {
|
||||
ArrayList<Item> itemarray = new ArrayList<>();
|
||||
List<ModifyInventory> mods = new ArrayList<>();
|
||||
|
||||
MapleInventory inventory = chr.getInventory(MapleInventoryType.getByType(inventoryType));
|
||||
MapleInventory inventory = chr.getInventory(MapleInventoryType.getByType(invType));
|
||||
inventory.lockInventory();
|
||||
try {
|
||||
for (short i = 1; i <= inventory.getSlotLimit(); i++) {
|
||||
@@ -218,7 +218,7 @@ public final class InventorySortHandler extends AbstractMaplePacketHandler {
|
||||
mods.add(new ModifyInventory(3, item));
|
||||
}
|
||||
|
||||
int invTypeCriteria = (MapleInventoryType.getByType(inventoryType) == MapleInventoryType.EQUIP) ? 3 : 1;
|
||||
int invTypeCriteria = (MapleInventoryType.getByType(invType) == MapleInventoryType.EQUIP) ? 3 : 1;
|
||||
int sortCriteria = (ServerConstants.USE_ITEM_SORT_BY_NAME == true) ? 2 : 0;
|
||||
PairedQuicksort pq = new PairedQuicksort(itemarray, sortCriteria, invTypeCriteria);
|
||||
|
||||
@@ -232,7 +232,7 @@ public final class InventorySortHandler extends AbstractMaplePacketHandler {
|
||||
}
|
||||
|
||||
c.announce(MaplePacketCreator.modifyInventory(true, mods));
|
||||
c.announce(MaplePacketCreator.finishedSort2(inventoryType));
|
||||
c.announce(MaplePacketCreator.finishedSort2(invType));
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import tools.data.input.SeekableLittleEndianAccessor;
|
||||
import tools.data.output.MaplePacketLittleEndianWriter;
|
||||
|
||||
public final class NPCAnimationHandler extends AbstractMaplePacketHandler {
|
||||
@Override
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
||||
int length = (int) slea.available();
|
||||
|
||||
@@ -161,22 +161,8 @@ public final class PetAutoPotHandler extends AbstractMaplePacketHandler {
|
||||
return false;
|
||||
}
|
||||
|
||||
private Pair<Short, Short> calcEffectivePool(MapleCharacter chr) {
|
||||
short hp = 0, mp = 0;
|
||||
|
||||
if(ServerConstants.USE_EQUIPS_ON_AUTOPOT) {
|
||||
for(Item i : chr.getInventory(MapleInventoryType.EQUIPPED).list()) {
|
||||
Equip e = (Equip) i;
|
||||
|
||||
hp += e.getHp();
|
||||
mp += e.getMp();
|
||||
}
|
||||
}
|
||||
|
||||
hp = (short) Math.min(chr.getMaxHp() + hp, 30000);
|
||||
mp = (short) Math.min(chr.getMaxMp() + mp, 30000);
|
||||
|
||||
return new Pair<>(hp, mp);
|
||||
private static Pair<Short, Short> calcEffectivePool(MapleCharacter chr) {
|
||||
return new Pair<>((short) chr.getMaxHpEquipped(), (short) chr.getMaxMpEquipped());
|
||||
}
|
||||
|
||||
private boolean shouldReusePot() {
|
||||
|
||||
@@ -25,7 +25,6 @@ import java.util.Set;
|
||||
|
||||
import client.MapleCharacter;
|
||||
import client.MapleClient;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import client.inventory.MaplePet;
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import server.maps.MapleMapItem;
|
||||
@@ -58,25 +57,35 @@ public final class PetLootHandler extends AbstractMaplePacketHandler {
|
||||
int oid = slea.readInt();
|
||||
MapleMapObject ob = chr.getMap().getMapObject(oid);
|
||||
if(ob == null) {
|
||||
c.getSession().write(MaplePacketCreator.enableActions());
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
|
||||
if (chr.getInventory(MapleInventoryType.EQUIPPED).findById(1812007) != null) {
|
||||
final Set<Integer> petIgnore = chr.getExcludedItems();
|
||||
MapleMapItem mapitem = (MapleMapItem) ob;
|
||||
MapleMapItem mapitem = (MapleMapItem) ob;
|
||||
if (mapitem.getMeso() > 0) {
|
||||
if (!chr.isEquippedMesoMagnet()) {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
|
||||
if(!petIgnore.isEmpty()) {
|
||||
if (chr.getInventory(MapleInventoryType.EQUIPPED).findById(1812000) != null) { // Meso magnet
|
||||
if (mapitem.getMeso() > 0 && petIgnore.contains(Integer.MAX_VALUE)) {
|
||||
c.getSession().write(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
} else if (chr.getInventory(MapleInventoryType.EQUIPPED).findById(1812001) != null) { // Item Pouch
|
||||
if (petIgnore.contains(mapitem.getItem().getItemId())) {
|
||||
c.getSession().write(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
if (chr.isEquippedPetItemIgnore()) {
|
||||
final Set<Integer> petIgnore = chr.getExcludedItems();
|
||||
if(!petIgnore.isEmpty() && petIgnore.contains(Integer.MAX_VALUE)) {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!chr.isEquippedItemPouch()) {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
|
||||
if (chr.isEquippedPetItemIgnore()) {
|
||||
final Set<Integer> petIgnore = chr.getExcludedItems();
|
||||
if(!petIgnore.isEmpty() && petIgnore.contains(mapitem.getItem().getItemId())) {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,14 +203,14 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
|
||||
}
|
||||
|
||||
if (ItemConstants.isPlayerShop(itemId)) {
|
||||
MaplePlayerShop shop = new MaplePlayerShop(chr, desc);
|
||||
MaplePlayerShop shop = new MaplePlayerShop(chr, desc, itemId);
|
||||
chr.setPlayerShop(shop);
|
||||
chr.getMap().addMapObject(shop);
|
||||
shop.sendShop(c);
|
||||
c.getWorldServer().registerPlayerShop(shop);
|
||||
//c.announce(MaplePacketCreator.getPlayerShopRemoveVisitor(1));
|
||||
} else if (ItemConstants.isHiredMerchant(itemId)) {
|
||||
MapleHiredMerchant merchant = new MapleHiredMerchant(chr, itemId, desc);
|
||||
MapleHiredMerchant merchant = new MapleHiredMerchant(chr, desc, itemId);
|
||||
chr.setHiredMerchant(merchant);
|
||||
c.getWorldServer().registerHiredMerchant(merchant);
|
||||
chr.getClient().getChannelServer().addHiredMerchant(chr.getId(), merchant);
|
||||
@@ -304,18 +304,18 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
if(ServerConstants.USE_ERASE_PERMIT_ON_OPENSHOP) {
|
||||
try {
|
||||
MapleInventoryManipulator.removeById(c, MapleInventoryType.CASH, 5140000, 1, true, false);
|
||||
MapleInventoryManipulator.removeById(c, MapleInventoryType.CASH, shop.getItemId(), 1, true, false);
|
||||
} catch(RuntimeException re) {} // fella does not have a player shop permit...
|
||||
}
|
||||
|
||||
chr.getMap().broadcastMessage(MaplePacketCreator.addCharBox(chr, 4));
|
||||
chr.getMap().broadcastMessage(MaplePacketCreator.updatePlayerShopBox(shop));
|
||||
shop.setOpen(true);
|
||||
} else if (merchant != null && merchant.isOwner(chr)) {
|
||||
chr.setHasMerchant(true);
|
||||
merchant.setOpen(true);
|
||||
chr.getMap().addMapObject(merchant);
|
||||
chr.setHiredMerchant(null);
|
||||
chr.getMap().broadcastMessage(MaplePacketCreator.spawnHiredMerchant(merchant));
|
||||
chr.getMap().broadcastMessage(MaplePacketCreator.spawnHiredMerchantBox(merchant));
|
||||
slea.readByte();
|
||||
}
|
||||
} else if (mode == Action.READY.getCode()) {
|
||||
|
||||
@@ -49,6 +49,9 @@ import client.MapleClient;
|
||||
import client.MapleDisease;
|
||||
import client.MapleFamily;
|
||||
import client.SkillFactory;
|
||||
import client.inventory.Equip;
|
||||
import client.inventory.Item;
|
||||
import client.inventory.MapleInventory;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import client.inventory.MaplePet;
|
||||
import constants.GameConstants;
|
||||
@@ -223,9 +226,18 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
|
||||
player.updatePartyMemberHP();
|
||||
}
|
||||
|
||||
if (player.getInventory(MapleInventoryType.EQUIPPED).findById(1122017) != null) {
|
||||
player.equipPendantOfSpirit();
|
||||
MapleInventory eqpInv = player.getInventory(MapleInventoryType.EQUIPPED);
|
||||
eqpInv.lockInventory();
|
||||
try {
|
||||
player.resetEquippedHpMp();
|
||||
|
||||
for(Item it : eqpInv.list()) {
|
||||
player.equippedItem((Equip) it);
|
||||
}
|
||||
} finally {
|
||||
eqpInv.unlockInventory();
|
||||
}
|
||||
|
||||
c.announce(MaplePacketCreator.updateBuddylist(player.getBuddylist().getBuddies()));
|
||||
|
||||
CharacterNameAndId pendingBuddyRequest = c.getPlayer().getBuddylist().pollPendingRequest();
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
package net.server.channel.handlers;
|
||||
|
||||
import client.MapleClient;
|
||||
import client.MapleCharacter;
|
||||
import client.Skill;
|
||||
import client.SkillFactory;
|
||||
import client.inventory.Equip;
|
||||
@@ -35,7 +36,6 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import client.inventory.manipulator.MapleInventoryManipulator;
|
||||
import constants.ServerConstants;
|
||||
import server.MapleItemInformationProvider;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
@@ -57,16 +57,18 @@ public final class ScrollHandler extends AbstractMaplePacketHandler {
|
||||
if ((ws & 2) == 2) {
|
||||
whiteScroll = true;
|
||||
}
|
||||
|
||||
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
|
||||
Equip toScroll = (Equip) c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).getItem(dst);
|
||||
MapleCharacter chr = c.getPlayer();
|
||||
Equip toScroll = (Equip) chr.getInventory(MapleInventoryType.EQUIPPED).getItem(dst);
|
||||
Skill LegendarySpirit = SkillFactory.getSkill(1003);
|
||||
if (c.getPlayer().getSkillLevel(LegendarySpirit) > 0 && dst >= 0) {
|
||||
if (chr.getSkillLevel(LegendarySpirit) > 0 && dst >= 0) {
|
||||
legendarySpirit = true;
|
||||
toScroll = (Equip) c.getPlayer().getInventory(MapleInventoryType.EQUIP).getItem(dst);
|
||||
toScroll = (Equip) chr.getInventory(MapleInventoryType.EQUIP).getItem(dst);
|
||||
}
|
||||
byte oldLevel = toScroll.getLevel();
|
||||
byte oldSlots = toScroll.getUpgradeSlots();
|
||||
MapleInventory useInventory = c.getPlayer().getInventory(MapleInventoryType.USE);
|
||||
MapleInventory useInventory = chr.getInventory(MapleInventoryType.USE);
|
||||
Item scroll = useInventory.getItem(slot);
|
||||
Item wscroll = null;
|
||||
|
||||
@@ -81,7 +83,7 @@ public final class ScrollHandler extends AbstractMaplePacketHandler {
|
||||
}
|
||||
if (whiteScroll) {
|
||||
wscroll = useInventory.findById(2340000);
|
||||
if (wscroll == null || wscroll.getItemId() != 2340000) {
|
||||
if (wscroll == null) {
|
||||
whiteScroll = false;
|
||||
}
|
||||
}
|
||||
@@ -96,7 +98,7 @@ public final class ScrollHandler extends AbstractMaplePacketHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
Equip scrolled = (Equip) ii.scrollEquipWithId(toScroll, scroll.getItemId(), whiteScroll, 0, c.getPlayer().isGM());
|
||||
Equip scrolled = (Equip) ii.scrollEquipWithId(toScroll, scroll.getItemId(), whiteScroll, 0, chr.isGM());
|
||||
ScrollResult scrollSuccess = Equip.ScrollResult.FAIL; // fail
|
||||
if (scrolled == null) {
|
||||
scrollSuccess = Equip.ScrollResult.CURSE;
|
||||
@@ -112,9 +114,17 @@ public final class ScrollHandler extends AbstractMaplePacketHandler {
|
||||
if(!ItemConstants.isWeddingRing(toScroll.getItemId())) {
|
||||
mods.add(new ModifyInventory(3, toScroll));
|
||||
if (dst < 0) {
|
||||
c.getPlayer().getInventory(MapleInventoryType.EQUIPPED).removeItem(toScroll.getPosition());
|
||||
MapleInventory inv = chr.getInventory(MapleInventoryType.EQUIPPED);
|
||||
|
||||
inv.lockInventory();
|
||||
try {
|
||||
chr.unequippedItem(toScroll);
|
||||
inv.removeItem(toScroll.getPosition());
|
||||
} finally {
|
||||
inv.unlockInventory();
|
||||
}
|
||||
} else {
|
||||
c.getPlayer().getInventory(MapleInventoryType.EQUIP).removeItem(toScroll.getPosition());
|
||||
chr.getInventory(MapleInventoryType.EQUIP).removeItem(toScroll.getPosition());
|
||||
}
|
||||
} else {
|
||||
scrolled = toScroll;
|
||||
@@ -128,13 +138,13 @@ public final class ScrollHandler extends AbstractMaplePacketHandler {
|
||||
mods.add(new ModifyInventory(0, scrolled));
|
||||
}
|
||||
c.announce(MaplePacketCreator.modifyInventory(true, mods));
|
||||
c.getPlayer().getMap().broadcastMessage(MaplePacketCreator.getScrollEffect(c.getPlayer().getId(), scrollSuccess, legendarySpirit));
|
||||
chr.getMap().broadcastMessage(MaplePacketCreator.getScrollEffect(chr.getId(), scrollSuccess, legendarySpirit));
|
||||
if (dst < 0 && (scrollSuccess == Equip.ScrollResult.SUCCESS || scrollSuccess == Equip.ScrollResult.CURSE)) {
|
||||
c.getPlayer().equipChanged();
|
||||
chr.equipChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canScroll(int scrollid, int itemid) {
|
||||
private static boolean canScroll(int scrollid, int itemid) {
|
||||
int sid = scrollid / 100;
|
||||
|
||||
switch(sid) {
|
||||
|
||||
@@ -26,16 +26,13 @@ import java.awt.Point;
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import server.MapleStatEffect;
|
||||
import server.life.MapleMonster;
|
||||
import tools.FilePrinter;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
import client.MapleCharacter;
|
||||
import client.autoban.AutobanFactory;
|
||||
import client.MapleClient;
|
||||
import client.MapleStat;
|
||||
import client.Skill;
|
||||
import client.SkillFactory;
|
||||
import constants.GameConstants;
|
||||
import constants.ServerConstants;
|
||||
import constants.skills.Brawler;
|
||||
import constants.skills.Corsair;
|
||||
|
||||
@@ -484,8 +484,10 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
|
||||
for (byte i = 0; i < 3; i++) {
|
||||
MaplePet pet = player.getPet(i);
|
||||
if (pet != null) {
|
||||
if (pet.canConsume(itemId)) {
|
||||
pet.gainClosenessFullness(player, 100, 100, 1);
|
||||
Pair<Integer, Boolean> p = pet.canConsume(itemId);
|
||||
|
||||
if (p.getRight()) {
|
||||
pet.gainClosenessFullness(player, p.getLeft(), 100, 1);
|
||||
remove(c, itemId);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@ import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import server.TimerManager;
|
||||
import tools.Pair;
|
||||
import tools.locks.MonitoredLockType;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -89,6 +89,7 @@ public abstract class BaseScheduler {
|
||||
|
||||
private void runBaseSchedule() {
|
||||
List<Object> toRemove;
|
||||
Map<Object, Pair<Runnable, Long>> registeredEntriesCopy;
|
||||
|
||||
lockScheduler();
|
||||
try {
|
||||
@@ -104,26 +105,35 @@ public abstract class BaseScheduler {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
idleProcs = 0;
|
||||
|
||||
long timeNow = System.currentTimeMillis();
|
||||
toRemove = new LinkedList<>();
|
||||
for(Entry<Object, Pair<Runnable, Long>> rmd : registeredEntries.entrySet()) {
|
||||
Pair<Runnable, Long> r = rmd.getValue();
|
||||
|
||||
if(r.getRight() < timeNow) {
|
||||
r.getLeft().run(); // runs the cancel action
|
||||
toRemove.add(rmd.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
for(Object mse : toRemove) {
|
||||
registeredEntries.remove(mse);
|
||||
}
|
||||
registeredEntriesCopy = new HashMap<>(registeredEntries);
|
||||
} finally {
|
||||
unlockScheduler();
|
||||
}
|
||||
|
||||
long timeNow = System.currentTimeMillis();
|
||||
toRemove = new LinkedList<>();
|
||||
for(Entry<Object, Pair<Runnable, Long>> rmd : registeredEntriesCopy.entrySet()) {
|
||||
Pair<Runnable, Long> r = rmd.getValue();
|
||||
|
||||
if(r.getRight() < timeNow) {
|
||||
r.getLeft().run(); // runs the cancel action
|
||||
toRemove.add(rmd.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
if(!toRemove.isEmpty()) {
|
||||
lockScheduler();
|
||||
try {
|
||||
for(Object o : toRemove) {
|
||||
registeredEntries.remove(o);
|
||||
}
|
||||
} finally {
|
||||
unlockScheduler();
|
||||
}
|
||||
}
|
||||
|
||||
dispatchRemovedEntries(toRemove, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ package net.server.channel.worker;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import tools.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
@@ -19,13 +19,13 @@
|
||||
*/
|
||||
package net.server.channel.worker;
|
||||
|
||||
import tools.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
36
src/net/server/channel/worker/MobClearSkillScheduler.java
Normal file
36
src/net/server/channel/worker/MobClearSkillScheduler.java
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft 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.channel.worker;
|
||||
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Ronan
|
||||
*/
|
||||
public class MobClearSkillScheduler extends BaseScheduler {
|
||||
public MobClearSkillScheduler() {
|
||||
super(MonitoredLockType.CHANNEL_MOBSKILL);
|
||||
}
|
||||
|
||||
public void registerClearSkillAction(Runnable runAction, long delay) {
|
||||
registerEntry(runAction, runAction, delay);
|
||||
}
|
||||
}
|
||||
36
src/net/server/channel/worker/MobMistScheduler.java
Normal file
36
src/net/server/channel/worker/MobMistScheduler.java
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft 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.channel.worker;
|
||||
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Ronan
|
||||
*/
|
||||
public class MobMistScheduler extends BaseScheduler {
|
||||
public MobMistScheduler() {
|
||||
super(MonitoredLockType.CHANNEL_MOBMIST);
|
||||
}
|
||||
|
||||
public void registerMistCancelAction(Runnable runAction, long delay) {
|
||||
registerEntry(runAction, runAction, delay);
|
||||
}
|
||||
}
|
||||
@@ -26,8 +26,8 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import tools.locks.MonitoredLockType;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
*/
|
||||
package net.server.channel.worker;
|
||||
|
||||
import tools.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
@@ -36,13 +36,13 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
|
||||
import net.server.Server;
|
||||
import net.server.channel.Channel;
|
||||
import tools.DatabaseConnection;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
|
||||
public class MapleGuild {
|
||||
|
||||
|
||||
@@ -30,9 +30,9 @@ import java.util.HashMap;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Map;
|
||||
import java.util.Comparator;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import tools.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
|
||||
public class MapleParty {
|
||||
private int id;
|
||||
|
||||
@@ -48,7 +48,7 @@ import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
@@ -75,7 +75,7 @@ import net.server.guild.MapleGuildSummary;
|
||||
import tools.DatabaseConnection;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Pair;
|
||||
import tools.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user