ThreadTracker + Attempt on NPC Disappearing fix
Engineered the ThreadTracker: server-embedded deadlock auditing tool, which will print error messages in case of found deadlocks (also showing all in-use locks on the time of the issue). Changed the player's id on DB now starting from 20mil, thus preventing players from overwriting NPC/mobs with same oid in-game. Requires proper testing to see if the issue has been cleared.
This commit is contained in:
@@ -43,13 +43,14 @@ import client.MapleClient;
|
||||
import constants.ServerConstants;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
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.MonitoredEnums;
|
||||
|
||||
public class MapleServerHandler extends IoHandlerAdapter {
|
||||
|
||||
@@ -58,8 +59,8 @@ public class MapleServerHandler extends IoHandlerAdapter {
|
||||
private static final SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy HH:mm");
|
||||
private static AtomicLong sessionId = new AtomicLong(7777);
|
||||
|
||||
private Lock idleLock = new ReentrantLock(true);
|
||||
private Lock tempLock = new ReentrantLock(true);
|
||||
private Lock idleLock = new MonitoredReentrantLock(MonitoredEnums.SHANDLER_IDLE, true);
|
||||
private Lock tempLock = new MonitoredReentrantLock(MonitoredEnums.SHANDLER_TEMP, true);
|
||||
private Map<MapleClient, Long> idleSessions = new HashMap<>(100);
|
||||
private Map<MapleClient, Long> tempIdleSessions = new HashMap<>();
|
||||
private ScheduledFuture<?> idleManager = null;
|
||||
|
||||
@@ -35,27 +35,28 @@ public class MaplePacketEncoder implements ProtocolEncoder {
|
||||
public void encode(final IoSession session, final Object message, final ProtocolEncoderOutput out) throws Exception {
|
||||
final MapleClient client = (MapleClient) session.getAttribute(MapleClient.CLIENT_KEY);
|
||||
|
||||
if (client != null) {
|
||||
final MapleAESOFB send_crypto = client.getSendCrypto();
|
||||
final byte[] input = (byte[]) message;
|
||||
final byte[] unencrypted = new byte[input.length];
|
||||
System.arraycopy(input, 0, unencrypted, 0, input.length);
|
||||
final byte[] ret = new byte[unencrypted.length + 4];
|
||||
final byte[] header = send_crypto.getPacketHeader(unencrypted.length);
|
||||
MapleCustomEncryption.encryptData(unencrypted);
|
||||
|
||||
try {
|
||||
client.lockClient();
|
||||
try {
|
||||
final MapleAESOFB send_crypto = client.getSendCrypto();
|
||||
final byte[] input = (byte[]) message;
|
||||
final byte[] unencrypted = new byte[input.length];
|
||||
System.arraycopy(input, 0, unencrypted, 0, input.length);
|
||||
final byte[] ret = new byte[unencrypted.length + 4];
|
||||
final byte[] header = send_crypto.getPacketHeader(unencrypted.length);
|
||||
MapleCustomEncryption.encryptData(unencrypted);
|
||||
|
||||
send_crypto.crypt(unencrypted);
|
||||
System.arraycopy(header, 0, ret, 0, 4);
|
||||
System.arraycopy(unencrypted, 0, ret, 4, unencrypted.length);
|
||||
|
||||
out.write(IoBuffer.wrap(ret));
|
||||
} finally {
|
||||
client.unlockClient();
|
||||
}
|
||||
// System.arraycopy(unencrypted, 0, ret, 4, unencrypted.length);
|
||||
// out.write(ByteBuffer.wrap(ret));
|
||||
} else {
|
||||
} catch (NullPointerException npe) {
|
||||
out.write(IoBuffer.wrap(((byte[]) message)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,8 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import tools.locks.MonitoredEnums;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -33,7 +34,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
*/
|
||||
public class PlayerBuffStorage {
|
||||
private int id = (int) (Math.random() * 100);
|
||||
private final Lock lock = new ReentrantLock(true);
|
||||
private final Lock lock = new MonitoredReentrantLock(MonitoredEnums.BUFF_STORAGE, true);
|
||||
private Map<Integer, List<PlayerBuffValueHolder>> buffs = new HashMap<>();
|
||||
|
||||
public void addBuffsToStorage(int chrid, List<PlayerBuffValueHolder> toStore) {
|
||||
|
||||
@@ -26,12 +26,14 @@ 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.MonitoredEnums;
|
||||
|
||||
public class PlayerStorage {
|
||||
private final ReentrantReadWriteLock locks = new ReentrantReadWriteLock(true);
|
||||
private final ReentrantReadWriteLock locks = new MonitoredReentrantReadWriteLock(MonitoredEnums.PLAYER_STORAGE, true);
|
||||
private final ReadLock rlock = locks.readLock();
|
||||
private final WriteLock wlock = locks.writeLock();
|
||||
private final Map<Integer, MapleCharacter> storage = new LinkedHashMap<>();
|
||||
|
||||
@@ -33,15 +33,16 @@ import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
|
||||
import net.MapleServerHandler;
|
||||
import net.mina.MapleCodecFactory;
|
||||
@@ -70,11 +71,13 @@ import client.SkillFactory;
|
||||
import constants.ItemConstants;
|
||||
import constants.ServerConstants;
|
||||
import java.util.Calendar;
|
||||
import net.server.audit.ThreadTracker;
|
||||
import server.quest.MapleQuest;
|
||||
import tools.locks.MonitoredEnums;
|
||||
|
||||
public class Server implements Runnable {
|
||||
private static final Set<Integer> activeFly = new HashSet<>();
|
||||
private static final Map<Integer, Integer> couponRates = new LinkedHashMap<>();
|
||||
private static final Map<Integer, Integer> couponRates = new HashMap<>(30);
|
||||
private static final List<Integer> activeCoupons = new LinkedList<>();
|
||||
|
||||
private IoAcceptor acceptor;
|
||||
@@ -83,11 +86,12 @@ public class Server implements Runnable {
|
||||
private final Properties subnetInfo = new Properties();
|
||||
private static Server instance = null;
|
||||
private List<Pair<Integer, String>> worldRecommendedList = new LinkedList<>();
|
||||
private final Map<Integer, MapleGuild> guilds = new LinkedHashMap<>();
|
||||
private final Map<MapleClient, Long> inLoginState = new LinkedHashMap<>();
|
||||
private final Lock srvLock = new ReentrantLock();
|
||||
private final Map<Integer, MapleGuild> guilds = new HashMap<>(100);
|
||||
private final Map<MapleClient, Long> inLoginState = new HashMap<>(100);
|
||||
private final Lock srvLock = new MonitoredReentrantLock(MonitoredEnums.SERVER);
|
||||
private final PlayerBuffStorage buffStorage = new PlayerBuffStorage();
|
||||
private final Map<Integer, MapleAlliance> alliances = new LinkedHashMap<>();
|
||||
private final Map<Integer, MapleAlliance> alliances = new HashMap<>(100);
|
||||
|
||||
private boolean online = false;
|
||||
public static long uptime = System.currentTimeMillis();
|
||||
|
||||
@@ -301,7 +305,9 @@ public class Server implements Runnable {
|
||||
timeToTake = System.currentTimeMillis();
|
||||
MapleQuest.loadAllQuest();
|
||||
System.out.println("Quest loaded in " + ((System.currentTimeMillis() - timeToTake) / 1000.0) + " seconds\r\n");
|
||||
|
||||
|
||||
if(ServerConstants.USE_THREAD_TRACKER) ThreadTracker.getInstance().registerThreadTrackerTask();
|
||||
|
||||
try {
|
||||
Integer worldCount = Math.min(ServerConstants.WORLD_NAMES.length, Integer.parseInt(p.getProperty("worlds")));
|
||||
|
||||
@@ -317,7 +323,7 @@ public class Server implements Runnable {
|
||||
|
||||
worldRecommendedList.add(new Pair<>(i, p.getProperty("whyamirecommended" + i)));
|
||||
worlds.add(world);
|
||||
channels.add(new LinkedHashMap<Integer, String>());
|
||||
channels.add(new HashMap<Integer, String>());
|
||||
for (int j = 0; j < Integer.parseInt(p.getProperty("channels" + i)); j++) {
|
||||
int channelid = j + 1;
|
||||
Channel channel = new Channel(i, channelid);
|
||||
@@ -807,6 +813,8 @@ public class Server implements Runnable {
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
if(ServerConstants.USE_THREAD_TRACKER) ThreadTracker.getInstance().cancelThreadTrackerTask();
|
||||
|
||||
TimerManager.getInstance().purge();
|
||||
TimerManager.getInstance().stop();
|
||||
|
||||
281
src/net/server/audit/ThreadTracker.java
Normal file
281
src/net/server/audit/ThreadTracker.java
Normal file
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* This file is part of the MapleSolaxiaV2 Maple Story Server
|
||||
*
|
||||
* Copyright (C) 2017 RonanLana
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.audit;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import server.TimerManager;
|
||||
import tools.FilePrinter;
|
||||
import tools.locks.MonitoredEnums;
|
||||
import constants.ServerConstants;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author RonanLana
|
||||
*
|
||||
* This tool has the main purpose of auditing deadlocks throughout the server and must be used only for debugging. The flag is USE_THREAD_TRACKER.
|
||||
*/
|
||||
public class ThreadTracker {
|
||||
private static ThreadTracker instance = null;
|
||||
private final Lock ttLock = new ReentrantLock(true);
|
||||
|
||||
private final Map<Long, List<MonitoredEnums>> threadTracker = new HashMap<>();
|
||||
private final Map<Long, Integer> threadUpdate = new HashMap<>();
|
||||
private final Map<Long, Thread> threads = new HashMap<>();
|
||||
|
||||
private final Map<Long, AtomicInteger> lockCount = new HashMap<>();
|
||||
private final Map<Long, MonitoredEnums> lockIds = new HashMap<>();
|
||||
private final Map<Long, Long> lockThreads = new HashMap<>();
|
||||
private final Map<Long, Byte> lockUpdate = new HashMap<>();
|
||||
|
||||
private final Map<MonitoredEnums, Map<Long, Integer>> locks = new HashMap<>();
|
||||
ScheduledFuture<?> threadTrackerSchedule;
|
||||
|
||||
private String printThreadTrackerState(String dateFormat) {
|
||||
|
||||
Map<MonitoredEnums, List<Integer>> lockValues = new HashMap<>();
|
||||
Set<Long> executingThreads = new HashSet<>();
|
||||
|
||||
for(Map.Entry<Long, AtomicInteger> lock : lockCount.entrySet()) {
|
||||
if(lock.getValue().get() != 0) {
|
||||
executingThreads.add(lockThreads.get(lock.getKey()));
|
||||
|
||||
MonitoredEnums lockId = lockIds.get(lock.getKey());
|
||||
List<Integer> list = lockValues.get(lockId);
|
||||
|
||||
if(list == null) {
|
||||
list = new ArrayList<>();
|
||||
lockValues.put(lockId, list);
|
||||
}
|
||||
|
||||
list.add(lock.getValue().get());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String s = "----------------------------\r\n" + dateFormat + "\r\n ";
|
||||
s += "Lock-thread usage count:";
|
||||
for(Map.Entry<MonitoredEnums, List<Integer>> lock : lockValues.entrySet()) {
|
||||
s += ("\r\n " + lock.getKey().name() + ": ");
|
||||
|
||||
for(Integer i : lock.getValue()) {
|
||||
s += (i + " ");
|
||||
}
|
||||
}
|
||||
s += "\r\n\r\nThread opened lock path:";
|
||||
|
||||
for(Long tid : executingThreads) {
|
||||
s += "\r\n";
|
||||
for(MonitoredEnums lockid : threadTracker.get(tid)) {
|
||||
s += (lockid.name() + " ");
|
||||
}
|
||||
s += "|";
|
||||
}
|
||||
|
||||
s += "\r\n\r\n";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private static String printThreadLog(List<MonitoredEnums> stillLockedPath, String dateFormat) {
|
||||
String s = "----------------------------\r\n" + dateFormat + "\r\n ";
|
||||
for(MonitoredEnums lock : stillLockedPath) {
|
||||
s += (lock.name() + " ");
|
||||
}
|
||||
s += "\r\n\r\n";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private static String printThreadStack(StackTraceElement[] list, String dateFormat) {
|
||||
String s = "----------------------------\r\n" + dateFormat + "\r\n";
|
||||
for(int i = 0; i < list.length; i++) {
|
||||
s += (" " + list[i].toString() + "\r\n");
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public void accessThreadTracker(boolean update, boolean lock, MonitoredEnums lockId, long lockOid) {
|
||||
ttLock.lock();
|
||||
try {
|
||||
if(update) {
|
||||
if(!lock) { // update tracker
|
||||
List<Long> toRemove = new ArrayList<>();
|
||||
|
||||
for(Long l : threadUpdate.keySet()) {
|
||||
int next = threadUpdate.get(l) + 1;
|
||||
if(next == 4) {
|
||||
List<MonitoredEnums> tt = threadTracker.get(l);
|
||||
|
||||
if(tt.isEmpty()) {
|
||||
toRemove.add(l);
|
||||
} else {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||
String df = dateFormat.format(new Date());
|
||||
|
||||
FilePrinter.print(FilePrinter.DEADLOCK_LOCKS, printThreadLog(tt, df));
|
||||
FilePrinter.print(FilePrinter.DEADLOCK_STACK, printThreadStack(threads.get(l).getStackTrace(), df));
|
||||
}
|
||||
}
|
||||
|
||||
threadUpdate.put(l, next);
|
||||
}
|
||||
|
||||
for(Long l : toRemove) {
|
||||
threadTracker.remove(l);
|
||||
threadUpdate.remove(l);
|
||||
threads.remove(l);
|
||||
|
||||
for(Map<Long, Integer> threadLock : locks.values()) {
|
||||
threadLock.remove(l);
|
||||
}
|
||||
}
|
||||
|
||||
toRemove.clear();
|
||||
|
||||
for(Entry<Long, Byte> it : lockUpdate.entrySet()) {
|
||||
byte val = (byte)(it.getValue() + 1);
|
||||
|
||||
if(val < 60) { // free the structure after 60 silent updates
|
||||
lockUpdate.put(it.getKey(), val);
|
||||
} else {
|
||||
toRemove.add(it.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
for(Long l : toRemove) {
|
||||
lockCount.remove(l);
|
||||
lockIds.remove(l);
|
||||
lockThreads.remove(l);
|
||||
lockUpdate.remove(l);
|
||||
}
|
||||
} else { // print status
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||
|
||||
FilePrinter.printError(FilePrinter.DEADLOCK_STATE, printThreadTrackerState(dateFormat.format(new Date())));
|
||||
//FilePrinter.printError(FilePrinter.DEADLOCK_STATE, "[" + dateFormat.format(new Date()) + "] Presenting current lock path for lockid " + lockId.name() + ".\r\n" + printLockStatus(lockId) + "\r\n-------------------------------\r\n");
|
||||
}
|
||||
} else {
|
||||
long tid = Thread.currentThread().getId();
|
||||
|
||||
if(lock) {
|
||||
AtomicInteger c = lockCount.get(lockOid);
|
||||
if(c == null) {
|
||||
c = new AtomicInteger(0);
|
||||
lockCount.put(lockOid, c);
|
||||
lockIds.put(lockOid, lockId);
|
||||
lockThreads.put(lockOid, tid);
|
||||
lockUpdate.put(lockOid, (byte) 0);
|
||||
}
|
||||
c.incrementAndGet();
|
||||
|
||||
List<MonitoredEnums> list = threadTracker.get(tid);
|
||||
if(list == null) {
|
||||
list = new ArrayList<>(20);
|
||||
threadTracker.put(tid, list);
|
||||
threadUpdate.put(tid, 0);
|
||||
threads.put(tid, Thread.currentThread());
|
||||
}
|
||||
list.add(lockId);
|
||||
|
||||
Map<Long, Integer> threadLock = locks.get(lockId);
|
||||
if(threadLock == null) {
|
||||
threadLock = new HashMap<>(5);
|
||||
locks.put(lockId, threadLock);
|
||||
}
|
||||
|
||||
Integer lc = threadLock.get(tid);
|
||||
if(lc != null) {
|
||||
threadLock.put(tid, lc + 1);
|
||||
} else {
|
||||
threadLock.put(tid, 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
AtomicInteger c = lockCount.get(lockOid);
|
||||
c.decrementAndGet();
|
||||
lockUpdate.put(lockOid, (byte) 0);
|
||||
|
||||
List<MonitoredEnums> list = threadTracker.get(tid);
|
||||
for(int i = list.size() - 1; i >= 0; i--) {
|
||||
if(lockId.getValue() == list.get(i).getValue()) {
|
||||
list.remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Map<Long, Integer> threadLock = locks.get(lockId);
|
||||
threadLock.put(tid, threadLock.get(tid) - 1);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
ttLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private String printLockStatus(MonitoredEnums lockId) {
|
||||
String s = "";
|
||||
|
||||
for(Long threadid : locks.get(lockId).keySet()) {
|
||||
for(MonitoredEnums lockid : threadTracker.get(threadid)) {
|
||||
s += (" " + lockid.name());
|
||||
}
|
||||
|
||||
s += " |\r\n";
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public void registerThreadTrackerTask() {
|
||||
threadTrackerSchedule = TimerManager.getInstance().register(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
accessThreadTracker(true, false, MonitoredEnums.UNDEFINED, -1);
|
||||
}
|
||||
}, 10000, 10000);
|
||||
}
|
||||
|
||||
public void cancelThreadTrackerTask() {
|
||||
threadTrackerSchedule.cancel(false);
|
||||
}
|
||||
|
||||
public static ThreadTracker getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new ThreadTracker();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,8 @@ import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
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;
|
||||
@@ -67,6 +68,7 @@ import tools.MaplePacketCreator;
|
||||
import client.MapleCharacter;
|
||||
import constants.ServerConstants;
|
||||
import server.maps.MapleMiniDungeonInfo;
|
||||
import tools.locks.MonitoredEnums;
|
||||
|
||||
public final class Channel {
|
||||
|
||||
@@ -90,11 +92,11 @@ public final class Channel {
|
||||
private Map<Integer, Integer> dojoParty = new HashMap<>();
|
||||
private Map<Integer, MapleMiniDungeon> dungeons = new HashMap<>();
|
||||
|
||||
private ReentrantReadWriteLock merchantLock = new ReentrantReadWriteLock(true);
|
||||
private ReentrantReadWriteLock merchantLock = new MonitoredReentrantReadWriteLock(MonitoredEnums.MERCHANT, true);
|
||||
private ReadLock merchRlock = merchantLock.readLock();
|
||||
private WriteLock merchWlock = merchantLock.writeLock();
|
||||
|
||||
private Lock lock = new ReentrantLock(true);
|
||||
private Lock lock = new MonitoredReentrantLock(MonitoredEnums.CHANNEL, true);
|
||||
|
||||
public Channel(final int world, final int channel) {
|
||||
this.world = world;
|
||||
|
||||
@@ -84,7 +84,7 @@ public final class ReportHandler extends AbstractMaplePacketHandler {
|
||||
public void addReport(int reporterid, int victimid, int reason, String description, String chatlog) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
Timestamp currentTimestamp = new java.sql.Timestamp(calendar.getTime().getTime());
|
||||
Connection con = null;
|
||||
Connection con;
|
||||
try {
|
||||
con = DatabaseConnection.getConnection();
|
||||
PreparedStatement ps = con.prepareStatement("INSERT INTO reports (`reporttime`, `reporterid`, `victimid`, `reason`, `chatlog`, `description`) VALUES (?, ?, ?, ?, ?, ?)");
|
||||
|
||||
@@ -51,6 +51,7 @@ import server.life.MobAttackInfoFactory;
|
||||
import server.life.MobSkill;
|
||||
import server.life.MobSkillFactory;
|
||||
import server.maps.MapleMap;
|
||||
import server.maps.MapleMapObject;
|
||||
import tools.FilePrinter;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Randomizer;
|
||||
@@ -78,9 +79,17 @@ public final class TakeDamageHandler extends AbstractMaplePacketHandler {
|
||||
oid = slea.readInt();
|
||||
|
||||
try {
|
||||
attacker = (MapleMonster) map.getMapObject(oid);
|
||||
List<loseItem> loseItems;
|
||||
MapleMapObject mmo = map.getMapObject(oid);
|
||||
if(mmo instanceof MapleMonster) {
|
||||
attacker = (MapleMonster) mmo;
|
||||
if(attacker.getId() != monsteridfrom) {
|
||||
attacker = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (attacker != null) {
|
||||
List<loseItem> loseItems;
|
||||
|
||||
if (attacker.isBuffed(MonsterStatus.NEUTRALISE)) {
|
||||
return;
|
||||
}
|
||||
@@ -119,10 +128,8 @@ public final class TakeDamageHandler extends AbstractMaplePacketHandler {
|
||||
} catch(ClassCastException e) {
|
||||
//this happens due to mob on last map damaging player just before changing maps
|
||||
|
||||
if(ServerConstants.USE_DEBUG) {
|
||||
e.printStackTrace();
|
||||
FilePrinter.printError(FilePrinter.EXCEPTION_CAUGHT, "Attacker is not a mob-type, rather is a " + map.getMapObject(oid).getClass().getName() + " entity.");
|
||||
}
|
||||
e.printStackTrace();
|
||||
FilePrinter.printError(FilePrinter.EXCEPTION_CAUGHT, "Attacker is not a mob-type, rather is a " + map.getMapObject(oid).getClass().getName() + " entity.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -36,12 +36,13 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
|
||||
import net.server.Server;
|
||||
import net.server.channel.Channel;
|
||||
import tools.DatabaseConnection;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.locks.MonitoredEnums;
|
||||
|
||||
public class MapleGuild {
|
||||
public final static int CREATE_GUILD_COST = 1500000;
|
||||
@@ -52,7 +53,7 @@ public class MapleGuild {
|
||||
}
|
||||
|
||||
private final List<MapleGuildCharacter> members;
|
||||
private final Lock membersLock = new ReentrantLock(true);
|
||||
private final Lock membersLock = new MonitoredReentrantLock(MonitoredEnums.GUILD, true);
|
||||
|
||||
private String rankTitles[] = new String[5]; // 1 = master, 2 = jr, 5 = lowest member
|
||||
private String name, notice;
|
||||
|
||||
@@ -30,8 +30,9 @@ import java.util.HashMap;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Map;
|
||||
import java.util.Comparator;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import tools.locks.MonitoredEnums;
|
||||
|
||||
public class MapleParty {
|
||||
private int id;
|
||||
@@ -43,7 +44,7 @@ public class MapleParty {
|
||||
private Map<Integer, Integer> histMembers = new HashMap<>();
|
||||
private int nextEntry = 0;
|
||||
|
||||
private Lock lock = new ReentrantLock(true);
|
||||
private Lock lock = new MonitoredReentrantLock(MonitoredEnums.PARTY, true);
|
||||
|
||||
public MapleParty(int id, MaplePartyCharacter chrfor) {
|
||||
this.leaderId = chrfor.getId();
|
||||
|
||||
@@ -43,7 +43,7 @@ import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
@@ -68,6 +68,7 @@ import server.maps.AbstractMapleMapObject;
|
||||
import tools.DatabaseConnection;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Pair;
|
||||
import tools.locks.MonitoredEnums;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -89,25 +90,25 @@ public class World {
|
||||
|
||||
private Map<Integer, MapleParty> parties = new HashMap<>();
|
||||
private AtomicInteger runningPartyId = new AtomicInteger();
|
||||
private Lock partyLock = new ReentrantLock(true);
|
||||
private Lock partyLock = new MonitoredReentrantLock(MonitoredEnums.WORLD_PARTY, true);
|
||||
|
||||
private Map<Integer, Integer> owlSearched = new LinkedHashMap<>();
|
||||
private Lock owlLock = new ReentrantLock();
|
||||
private Lock owlLock = new MonitoredReentrantLock(MonitoredEnums.WORLD_OWL);
|
||||
|
||||
private Lock activePetsLock = new ReentrantLock(true);
|
||||
private Lock activePetsLock = new MonitoredReentrantLock(MonitoredEnums.WORLD_PETS, true);
|
||||
private Map<Integer, Byte> activePets = new LinkedHashMap<>();
|
||||
private ScheduledFuture<?> petsSchedule;
|
||||
private long petUpdate;
|
||||
|
||||
private Lock activeMountsLock = new ReentrantLock(true);
|
||||
private Lock activeMountsLock = new MonitoredReentrantLock(MonitoredEnums.WORLD_MOUNTS, true);
|
||||
private Map<Integer, Byte> activeMounts = new LinkedHashMap<>();
|
||||
private ScheduledFuture<?> mountsSchedule;
|
||||
private long mountUpdate;
|
||||
|
||||
private Lock activePlayerShopsLock = new ReentrantLock(true);
|
||||
private Lock activePlayerShopsLock = new MonitoredReentrantLock(MonitoredEnums.WORLD_PSHOPS, true);
|
||||
private Map<Integer, MaplePlayerShop> activePlayerShops = new LinkedHashMap<>();
|
||||
|
||||
private Lock activeMerchantsLock = new ReentrantLock(true);
|
||||
private Lock activeMerchantsLock = new MonitoredReentrantLock(MonitoredEnums.WORLD_MERCHS, true);
|
||||
private Map<Integer, Pair<MapleHiredMerchant, Byte>> activeMerchants = new LinkedHashMap<>();
|
||||
private long merchantUpdate;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user