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:
Vendored
BIN
Binary file not shown.
@@ -103,5 +103,6 @@ Project:
|
||||
* Fixed/added some missing packets for MoveEnvironment, summons and others.
|
||||
* Reviewed many Java object aspects that needed concurrency protection.
|
||||
* Heavily reviewed future task management inside the project. Way less trivial schedules are spawned now, relieving task overload on the TimerManager.
|
||||
* ThreadTracker: embedded auditing tool for run-time deadlock scanning throughout the server source (relies heavily on memory usage, designed only for debugging purposes).
|
||||
|
||||
---------------------------
|
||||
@@ -669,4 +669,9 @@ Corrigido GM shop sendo liberado pra jogadores em Amherst.
|
||||
13 - 14 Novembro 2017,
|
||||
Modificado ID de jogador agora começando em 20,000,000, evitando assim clash de id de jogador (que tb representa seu OID) com OIDs de objetos do mapa.
|
||||
Nova ferramenta: MapleSkillMakerFetcher. A ferramenta lê info pertinente às descrições de itens feitos pelo Maker e as compila numa tabela, pra ser usada na DB.
|
||||
Corrigida questline de mounts e skills de Aran.
|
||||
Corrigida questline de mounts e skills de Aran.
|
||||
|
||||
15 Novembro 2017,
|
||||
Implementado sistema de auditoria de deadlocks: ThreadTracker.
|
||||
Corrigido bug onde jogadores recebem dano de mobs de mapas anteriores (que acarretavam em problemas com OID e natureza dos objetos).
|
||||
Corrigido alguns problemas com exceção sendo lançada ao tentar desligar o server.
|
||||
@@ -2,6 +2,9 @@
|
||||
<project-private xmlns="http://www.netbeans.org/ns/project-private/1">
|
||||
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="2"/>
|
||||
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2">
|
||||
<group/>
|
||||
<group>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/command/Commands.java</file>
|
||||
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/constants/ServerConstants.java</file>
|
||||
</group>
|
||||
</open-files>
|
||||
</project-private>
|
||||
|
||||
@@ -22,7 +22,7 @@ function start(mode, type, selection) {
|
||||
}
|
||||
}
|
||||
if (status == 0)
|
||||
qm.sendYesNo("In order to rescue the princess, you must first navigate the Mushroom Forest. King Pepe set up a powerful barrier forbidding anyone from entering the castle. Please investigate this matter for us.");
|
||||
qm.sendAcceptDecline("In order to rescue the princess, you must first navigate the Mushroom Forest. King Pepe set up a powerful barrier forbidding anyone from entering the castle. Please investigate this matter for us.");
|
||||
if (status == 1)
|
||||
qm.sendNext("You'll run into the barrier at the Mushroom Forest by heading east of where you are standing right now. Please be careful. I hear that the area is infested with crazy, fear-inducing monsters.");
|
||||
if(status == 2){
|
||||
|
||||
+25
-6
@@ -18793,7 +18793,6 @@ USE `maplesolaxia`;
|
||||
(3400004,4000542,1,1,0,400000),
|
||||
(3400005,4032508,1,1,2273,999999),
|
||||
(3400006,4000543,1,1,0,400000),
|
||||
(3400007,4032508,1,1,2273,999999),
|
||||
(3400008,4000544,1,1,0,400000),
|
||||
(4300001,1302009,1,1,0,700),
|
||||
(4300001,1312007,1,1,0,700),
|
||||
@@ -18939,7 +18938,7 @@ USE `maplesolaxia`;
|
||||
(4300006,4000525,1,1,0,600000),
|
||||
(4300006,4004000,1,1,0,10000),
|
||||
(4300006,4020008,1,1,0,9000),
|
||||
(4300006,4032506,1,1,2277,999999),
|
||||
(4300006,4032506,1,1,2277,80000),
|
||||
(4300007,1302009,1,1,0,700),
|
||||
(4300007,1312007,1,1,0,700),
|
||||
(4300007,1322016,1,1,0,700),
|
||||
@@ -18976,7 +18975,7 @@ USE `maplesolaxia`;
|
||||
(4300007,4000526,1,1,0,600000),
|
||||
(4300007,4004000,1,1,0,10000),
|
||||
(4300007,4020008,1,1,0,9000),
|
||||
(4300007,4032506,1,1,2277,999999),
|
||||
(4300007,4032506,1,1,2277,80000),
|
||||
(4300008,1302009,1,1,0,700),
|
||||
(4300008,1312007,1,1,0,700),
|
||||
(4300008,1322016,1,1,0,700),
|
||||
@@ -19013,7 +19012,7 @@ USE `maplesolaxia`;
|
||||
(4300008,4000527,1,1,0,400000),
|
||||
(4300008,4004000,1,1,0,10000),
|
||||
(4300008,4020008,1,1,0,9000),
|
||||
(4300008,4032506,1,1,2277,999999),
|
||||
(4300008,4032506,1,1,2277,80000),
|
||||
(4300009,1302009,1,1,0,700),
|
||||
(4300009,1312007,1,1,0,700),
|
||||
(4300009,1322016,1,1,0,700),
|
||||
@@ -19207,7 +19206,6 @@ USE `maplesolaxia`;
|
||||
(3400004,0,60,80,0,400000),
|
||||
(3400005,0,80,85,0,400000),
|
||||
(3400006,0,80,90,0,400000),
|
||||
(3400007,0,90,100,0,400000),
|
||||
(3400008,0,100,110,0,400000),
|
||||
(4300001,0,100,120,0,400000),
|
||||
(4300003,0,100,120,0,400000),
|
||||
@@ -19792,7 +19790,28 @@ USE `maplesolaxia`;
|
||||
(2230111, 4032147, 1, 1, 20723, 40000),
|
||||
(9300378, 4001272, 1, 1, 0, 400000),
|
||||
(9300378, 4032324, 1, 1, 21736, 40000),
|
||||
(9300344, 4032322, 1, 1, 21731, 999999);
|
||||
(9300344, 4032322, 1, 1, 21731, 999999),
|
||||
(3400008, 1302008, 1, 1, 0, 8500),
|
||||
(3400008, 1412004, 1, 1, 0, 8500),
|
||||
(3400008, 1422007, 1, 1, 0, 8500),
|
||||
(3400008, 1442009, 1, 1, 0, 8500),
|
||||
(3400008, 1332010, 1, 1, 0, 8500),
|
||||
(3400008, 1372001, 1, 1, 0, 8500),
|
||||
(3400008, 1382002, 1, 1, 0, 8500),
|
||||
(3400008, 1002013, 1, 1, 0, 8500),
|
||||
(3400008, 1002152, 1, 1, 0, 8500),
|
||||
(3400008, 1061047, 1, 1, 0, 8500),
|
||||
(3400008, 1072090, 1, 1, 0, 8500),
|
||||
(3400008, 1002137, 1, 1, 0, 8500),
|
||||
(3400008, 1040023, 1, 1, 0, 8500),
|
||||
(3400008, 1040072, 1, 1, 0, 8500),
|
||||
(3400008, 1060062, 1, 1, 0, 8500),
|
||||
(3400008, 1082049, 1, 1, 0, 8500),
|
||||
(3400008, 1082072, 1, 1, 0, 8500),
|
||||
(3400008, 1072081, 1, 1, 0, 8500),
|
||||
(3400008, 1332031, 1, 1, 0, 8500),
|
||||
(3400008, 1482003, 1, 1, 0, 8500),
|
||||
(3400008, 4032508, 1, 1, 2273, 80000);
|
||||
|
||||
# (dropperid, itemid, minqty, maxqty, questid, chance)
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.Comparator;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
@@ -154,6 +154,7 @@ import constants.skills.ThunderBreaker;
|
||||
import net.server.channel.handlers.PartyOperationHandler;
|
||||
import scripting.item.ItemScriptManager;
|
||||
import server.maps.MapleMapItem;
|
||||
import tools.locks.MonitoredEnums;
|
||||
|
||||
public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
private static NumberFormat nf = new DecimalFormat("#,###,###,###");
|
||||
@@ -270,10 +271,10 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
|
||||
private ScheduledFuture<?> extraRecoveryTask = null;
|
||||
private ScheduledFuture<?> chairRecoveryTask = null;
|
||||
private ScheduledFuture<?> pendantOfSpirit = null; //1122017
|
||||
private Lock chrLock = new ReentrantLock(true);
|
||||
private Lock effLock = new ReentrantLock(true);
|
||||
private Lock petLock = new ReentrantLock(true); // for quest tasks as well
|
||||
private Lock prtLock = new ReentrantLock();
|
||||
private Lock chrLock = new MonitoredReentrantLock(MonitoredEnums.CHR, true);
|
||||
private Lock effLock = new MonitoredReentrantLock(MonitoredEnums.EFF, true);
|
||||
private Lock petLock = new MonitoredReentrantLock(MonitoredEnums.PET, true); // for quest tasks as well
|
||||
private Lock prtLock = new MonitoredReentrantLock(MonitoredEnums.PRT);
|
||||
private Map<Integer, Set<Integer>> excluded = new LinkedHashMap<>();
|
||||
private Set<Integer> excludedItems = new LinkedHashSet<>();
|
||||
private List<MapleRing> crushRings = new ArrayList<>();
|
||||
|
||||
@@ -42,7 +42,7 @@ import java.util.List;
|
||||
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 javax.script.ScriptEngine;
|
||||
|
||||
@@ -77,6 +77,7 @@ import tools.FilePrinter;
|
||||
import tools.HexTool;
|
||||
import tools.MapleAESOFB;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.locks.MonitoredEnums;
|
||||
|
||||
public class MapleClient {
|
||||
|
||||
@@ -108,7 +109,7 @@ public class MapleClient {
|
||||
private int picattempt = 0;
|
||||
private byte gender = -1;
|
||||
private boolean disconnecting = false;
|
||||
private final Lock lock = new ReentrantLock(true);
|
||||
private final Lock lock = new MonitoredReentrantLock(MonitoredEnums.CLIENT, true);
|
||||
private int votePoints;
|
||||
private int voteTime = -1;
|
||||
private long lastNpcClick;
|
||||
@@ -832,7 +833,7 @@ public class MapleClient {
|
||||
|
||||
removePlayer();
|
||||
player.saveCooldowns();
|
||||
player.saveToDB();
|
||||
player.saveToDB(true);
|
||||
|
||||
player = null;
|
||||
return;
|
||||
|
||||
@@ -31,16 +31,17 @@ import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
import tools.DatabaseConnection;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.locks.MonitoredEnums;
|
||||
|
||||
public final class MonsterBook {
|
||||
private int specialCard = 0;
|
||||
private int normalCard = 0;
|
||||
private int bookLevel = 1;
|
||||
private Map<Integer, Integer> cards = new LinkedHashMap<>();
|
||||
private Lock lock = new ReentrantLock();
|
||||
private Lock lock = new MonitoredReentrantLock(MonitoredEnums.BOOK);
|
||||
|
||||
private Set<Entry<Integer, Integer>> getCardSet() {
|
||||
lock.lock();
|
||||
|
||||
@@ -346,7 +346,7 @@ public class Commands {
|
||||
|
||||
case "time":
|
||||
DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone("-GMT3"));
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||
player.yellowMessage("Solaxia Server Time: " + dateFormat.format(new Date()));
|
||||
break;
|
||||
|
||||
@@ -741,7 +741,7 @@ public class Commands {
|
||||
player.yellowMessage("Players on this map:");
|
||||
for (MapleMapObject mmo : player.getMap().getPlayers()) {
|
||||
MapleCharacter chr = (MapleCharacter) mmo;
|
||||
player.dropMessage(5, ">> " + chr.getName());
|
||||
player.dropMessage(5, ">> " + chr.getName() + " - " + chr.getId() + " - Oid: " + chr.getObjectId());
|
||||
}
|
||||
player.yellowMessage("NPCs on this map:");
|
||||
for (MapleMapObject npcs : player.getMap().getMapObjects()) {
|
||||
@@ -755,7 +755,7 @@ public class Commands {
|
||||
if (mobs instanceof MapleMonster) {
|
||||
MapleMonster mob = (MapleMonster) mobs;
|
||||
if(mob.isAlive()){
|
||||
player.dropMessage(5, ">> " + mob.getName() + " - " + mob.getId());
|
||||
player.dropMessage(5, ">> " + mob.getName() + " - " + mob.getId() + " - Oid: " + mob.getObjectId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,9 +27,11 @@ import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
import tools.DatabaseConnection;
|
||||
import tools.Pair;
|
||||
import tools.locks.MonitoredEnums;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -45,7 +47,7 @@ public enum ItemFactory {
|
||||
MERCHANT(6, false);
|
||||
private final int value;
|
||||
private final boolean account;
|
||||
private static final ReentrantLock lock = new ReentrantLock(true);
|
||||
private static final Lock lock = new MonitoredReentrantLock(MonitoredEnums.ITEM, true);
|
||||
|
||||
private ItemFactory(int value, boolean account) {
|
||||
this.value = value;
|
||||
|
||||
@@ -30,7 +30,7 @@ import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
|
||||
import tools.Pair;
|
||||
import client.MapleCharacter;
|
||||
@@ -39,6 +39,7 @@ import constants.ItemConstants;
|
||||
import server.MapleItemInformationProvider;
|
||||
import server.MapleInventoryManipulator;
|
||||
import tools.FilePrinter;
|
||||
import tools.locks.MonitoredEnums;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -50,7 +51,7 @@ public class MapleInventory implements Iterable<Item> {
|
||||
private byte slotLimit;
|
||||
private MapleInventoryType type;
|
||||
private boolean checked = false;
|
||||
private Lock lock = new ReentrantLock(true);
|
||||
private Lock lock = new MonitoredReentrantLock(MonitoredEnums.INVENTORY, true);
|
||||
|
||||
public MapleInventory(MapleCharacter mc, MapleInventoryType type, byte slotLimit) {
|
||||
this.owner = mc;
|
||||
|
||||
@@ -8,10 +8,12 @@ public class ServerConstants {
|
||||
public static String DB_URL = "";
|
||||
public static String DB_USER = "";
|
||||
public static String DB_PASS = "";
|
||||
public static final boolean DB_EXPERIMENTAL_POOL = true; //[EXPERIMENTAL] Installs a connection pool to hub DB connections. Set false to default.
|
||||
public static final boolean DB_EXPERIMENTAL_POOL = true; //[EXPERIMENTAL] Installs a connection pool to hub DB connections. Set false to default.
|
||||
public static final boolean USE_THREAD_TRACKER = true; //[WARNING] This deadlock auditing thing will bloat the memory as fast as the time frame one takes to lose track of a raindrop on a tempesting day. Only for debug purposes.
|
||||
|
||||
//World And Version
|
||||
public static short VERSION = 83;
|
||||
public static String TIMEZONE = "-GMT3";
|
||||
public static String[] WORLD_NAMES = {"Scania", "Bera", "Broa", "Windia", "Khaini", "Bellocan", "Mardia", "Kradia", "Yellonde", "Demethos", "Galicia", "El Nido", "Zenith", "Arcenia", "Kastia", "Judis", "Plana", "Kalluna", "Stius", "Croa", "Medere"};
|
||||
|
||||
//Login Configuration
|
||||
@@ -85,6 +87,7 @@ public class ServerConstants {
|
||||
//Dangling Items Configuration
|
||||
public static final int ITEM_EXPIRE_TIME = 3 * 60 * 1000; //Time before items start disappearing. Recommended to be set up to 3 minutes.
|
||||
public static final int ITEM_MONITOR_TIME = 5 * 60 * 1000; //Interval between item monitoring tasks on maps, which checks for dangling (null) item objects on the map item history.
|
||||
public static final int LOCK_MONITOR_TIME = 30 * 1000; //Waiting time for a lock to be released. If it reach timed out, a critical server deadlock has made present.
|
||||
public static final int ITEM_EXPIRE_CHECK = 10 * 1000; //Interval between item expiring tasks on maps, which checks and makes disappear expired items.
|
||||
public static final int ITEM_LIMIT_ON_MAP = 200; //Max number of items allowed on a map.
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -35,7 +35,8 @@ import java.util.Set;
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
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;
|
||||
@@ -69,6 +70,7 @@ import server.MapleItemInformationProvider;
|
||||
import server.life.MapleLifeFactory;
|
||||
import server.life.MapleNPC;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.locks.MonitoredEnums;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -90,12 +92,12 @@ public class EventInstanceManager {
|
||||
private List<Integer> mapIds = new LinkedList<>();
|
||||
private List<Boolean> isInstanced = new LinkedList<>();
|
||||
|
||||
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
|
||||
private final ReentrantReadWriteLock lock = new MonitoredReentrantReadWriteLock(MonitoredEnums.EIM, true);
|
||||
private final ReadLock rL = lock.readLock();
|
||||
private final WriteLock wL = lock.writeLock();
|
||||
|
||||
private final Lock pL = new ReentrantLock(true);
|
||||
private final Lock sL = new ReentrantLock();
|
||||
private final Lock pL = new MonitoredReentrantLock(MonitoredEnums.EIM_PARTY, true);
|
||||
private final Lock sL = new MonitoredReentrantLock(MonitoredEnums.EIM_SCRIPT, true);
|
||||
|
||||
private ScheduledFuture<?> event_schedule = null;
|
||||
private boolean disposed = false;
|
||||
|
||||
@@ -53,7 +53,8 @@ import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import tools.locks.MonitoredEnums;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -74,8 +75,8 @@ public class EventManager {
|
||||
private Integer readyId = 0;
|
||||
private Properties props = new Properties();
|
||||
private String name;
|
||||
private Lock lobbyLock = new ReentrantLock();
|
||||
private Lock queueLock = new ReentrantLock();
|
||||
private Lock lobbyLock = new MonitoredReentrantLock(MonitoredEnums.EM_LOBBY);
|
||||
private Lock queueLock = new MonitoredReentrantLock(MonitoredEnums.EM_QUEUE);
|
||||
|
||||
private static final int maxLobbys = 8; // an event manager holds up to this amount of concurrent lobbys
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ 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.MonitoredReentrantLock;
|
||||
|
||||
import provider.MapleData;
|
||||
import provider.MapleDataProvider;
|
||||
@@ -46,6 +46,7 @@ import client.inventory.MapleInventoryType;
|
||||
import client.inventory.MaplePet;
|
||||
import constants.ItemConstants;
|
||||
import java.util.Collections;
|
||||
import tools.locks.MonitoredEnums;
|
||||
|
||||
/*
|
||||
* @author Flav
|
||||
@@ -241,7 +242,7 @@ public class CashShop {
|
||||
private List<Item> inventory = new ArrayList<>();
|
||||
private List<Integer> wishList = new ArrayList<>();
|
||||
private int notes = 0;
|
||||
private Lock lock = new ReentrantLock();
|
||||
private Lock lock = new MonitoredReentrantLock(MonitoredEnums.CASHSHOP);
|
||||
|
||||
public CashShop(int accountId, int characterId, int jobType) throws SQLException {
|
||||
this.accountId = accountId;
|
||||
|
||||
@@ -32,13 +32,14 @@ import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
import net.SendOpcode;
|
||||
import server.maps.AbstractMapleMapObject;
|
||||
import server.maps.MapleMapObjectType;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Pair;
|
||||
import tools.data.output.MaplePacketLittleEndianWriter;
|
||||
import tools.locks.MonitoredEnums;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -55,7 +56,7 @@ public class MaplePlayerShop extends AbstractMapleMapObject {
|
||||
private List<String> bannedList = new ArrayList<>();
|
||||
private List<Pair<MapleCharacter, String>> chatLog = new LinkedList<>();
|
||||
private Map<Integer, Byte> chatSlot = new LinkedHashMap<>();
|
||||
private Lock visitorLock = new ReentrantLock(true);
|
||||
private Lock visitorLock = new MonitoredReentrantLock(MonitoredEnums.VISITOR_PSHOP, true);
|
||||
|
||||
public MaplePlayerShop(MapleCharacter owner, String description) {
|
||||
this.setPosition(owner.getPosition());
|
||||
|
||||
@@ -34,10 +34,11 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
import tools.DatabaseConnection;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Pair;
|
||||
import tools.locks.MonitoredEnums;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -50,7 +51,7 @@ public class MapleStorage {
|
||||
private byte slots;
|
||||
private Map<MapleInventoryType, List<Item>> typeItems = new HashMap<>();
|
||||
private List<Item> items;
|
||||
private Lock lock = new ReentrantLock(true);
|
||||
private Lock lock = new MonitoredReentrantLock(MonitoredEnums.STORAGE, true);
|
||||
|
||||
private MapleStorage(int id, byte slots, int meso) {
|
||||
this.id = id;
|
||||
|
||||
@@ -51,7 +51,8 @@ import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
import net.server.world.MapleParty;
|
||||
import net.server.world.MaplePartyCharacter;
|
||||
import server.TimerManager;
|
||||
@@ -62,6 +63,7 @@ import server.maps.MapleMapObjectType;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Pair;
|
||||
import tools.Randomizer;
|
||||
import tools.locks.MonitoredEnums;
|
||||
|
||||
public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
private ChangeableStats ostats = null; //unused, v83 WZs offers no support for changeable stats.
|
||||
@@ -84,9 +86,9 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
private int team;
|
||||
private final HashMap<Integer, AtomicInteger> takenDamage = new HashMap<>();
|
||||
|
||||
private ReentrantLock externalLock = new ReentrantLock();
|
||||
private ReentrantLock monsterLock = new ReentrantLock(true);
|
||||
private ReentrantLock statiLock = new ReentrantLock();
|
||||
private Lock externalLock = new MonitoredReentrantLock(MonitoredEnums.MOB_EXT);
|
||||
private Lock monsterLock = new MonitoredReentrantLock(MonitoredEnums.MOB, true);
|
||||
private Lock statiLock = new MonitoredReentrantLock(MonitoredEnums.MOB_STATI);
|
||||
|
||||
public MapleMonster(int id, MapleMonsterStats stats) {
|
||||
super(id);
|
||||
|
||||
@@ -27,6 +27,7 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
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;
|
||||
@@ -34,6 +35,7 @@ import provider.MapleData;
|
||||
import provider.MapleDataProvider;
|
||||
import provider.MapleDataProviderFactory;
|
||||
import provider.MapleDataTool;
|
||||
import tools.locks.MonitoredEnums;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -44,7 +46,7 @@ public class MobSkillFactory {
|
||||
private static Map<String, MobSkill> mobSkills = new HashMap<String, MobSkill>();
|
||||
private final static MapleDataProvider dataSource = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/Skill.wz"));
|
||||
private static MapleData skillRoot = dataSource.getData("MobSkill.img");
|
||||
private final static ReentrantReadWriteLock dataLock = new ReentrantReadWriteLock();
|
||||
private final static ReentrantReadWriteLock dataLock = new MonitoredReentrantReadWriteLock(MonitoredEnums.MOBSKILL_FACTORY);
|
||||
private final static ReadLock rL = dataLock.readLock();
|
||||
private final static WriteLock wL = dataLock.writeLock();
|
||||
|
||||
|
||||
@@ -27,7 +27,8 @@ import scripting.portal.PortalScriptManager;
|
||||
import server.MaplePortal;
|
||||
import tools.MaplePacketCreator;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import tools.locks.MonitoredEnums;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
|
||||
public class MapleGenericPortal implements MaplePortal {
|
||||
|
||||
@@ -117,7 +118,7 @@ public class MapleGenericPortal implements MaplePortal {
|
||||
|
||||
if(scriptName != null) {
|
||||
if(scriptLock == null) {
|
||||
scriptLock = new ReentrantLock(false);
|
||||
scriptLock = new MonitoredReentrantLock(MonitoredEnums.PORTAL, false);
|
||||
}
|
||||
} else {
|
||||
scriptLock = null;
|
||||
|
||||
@@ -37,7 +37,7 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
import net.server.Server;
|
||||
import server.MapleInventoryManipulator;
|
||||
import server.MapleItemInformationProvider;
|
||||
@@ -45,6 +45,7 @@ import server.MaplePlayerShopItem;
|
||||
import tools.DatabaseConnection;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Pair;
|
||||
import tools.locks.MonitoredEnums;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -63,7 +64,7 @@ public class MapleHiredMerchant extends AbstractMapleMapObject {
|
||||
private List<SoldItem> sold = new LinkedList<>();
|
||||
private AtomicBoolean open = new AtomicBoolean();
|
||||
private MapleMap map;
|
||||
private Lock visitorLock = new ReentrantLock(true);
|
||||
private Lock visitorLock = new MonitoredReentrantLock(MonitoredEnums.VISITOR_MERCH, true);
|
||||
|
||||
public MapleHiredMerchant(final MapleCharacter owner, int itemId, String desc) {
|
||||
this.setPosition(owner.getPosition());
|
||||
|
||||
@@ -52,6 +52,7 @@ import java.util.Map.Entry;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import tools.locks.MonitoredReentrantReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
||||
@@ -78,13 +79,14 @@ import server.life.MonsterGlobalDropEntry;
|
||||
import server.life.SpawnPoint;
|
||||
import server.partyquest.MonsterCarnival;
|
||||
import server.partyquest.MonsterCarnivalParty;
|
||||
import server.partyquest.Pyramid;
|
||||
//import server.partyquest.Pyramid;
|
||||
import scripting.event.EventInstanceManager;
|
||||
import server.life.MonsterListener;
|
||||
import tools.FilePrinter;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Pair;
|
||||
import tools.Randomizer;
|
||||
import tools.locks.MonitoredEnums;
|
||||
|
||||
public class MapleMap {
|
||||
private static final List<MapleMapObjectType> rangedMapobjectTypes = Arrays.asList(MapleMapObjectType.SHOP, MapleMapObjectType.ITEM, MapleMapObjectType.NPC, MapleMapObjectType.MONSTER, MapleMapObjectType.DOOR, MapleMapObjectType.SUMMON, MapleMapObjectType.REACTOR);
|
||||
@@ -161,11 +163,11 @@ public class MapleMap {
|
||||
if (this.monsterRate == 0) {
|
||||
this.monsterRate = 1;
|
||||
}
|
||||
final ReentrantReadWriteLock chrLock = new ReentrantReadWriteLock(true);
|
||||
final ReentrantReadWriteLock chrLock = new MonitoredReentrantReadWriteLock(MonitoredEnums.MAP_CHRS, true);
|
||||
chrRLock = chrLock.readLock();
|
||||
chrWLock = chrLock.writeLock();
|
||||
|
||||
final ReentrantReadWriteLock objectLock = new ReentrantReadWriteLock(true);
|
||||
final ReentrantReadWriteLock objectLock = new MonitoredReentrantReadWriteLock(MonitoredEnums.MAP_OBJS, true);
|
||||
objectRLock = objectLock.readLock();
|
||||
objectWLock = objectLock.writeLock();
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
import tools.locks.MonitoredReentrantReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
|
||||
@@ -46,6 +47,7 @@ import server.life.MapleMonster;
|
||||
import scripting.event.EventInstanceManager;
|
||||
import tools.DatabaseConnection;
|
||||
import tools.StringUtil;
|
||||
import tools.locks.MonitoredEnums;
|
||||
|
||||
public class MapleMapFactory {
|
||||
|
||||
@@ -64,7 +66,7 @@ public class MapleMapFactory {
|
||||
this.channel = channel;
|
||||
this.event = eim;
|
||||
|
||||
ReentrantReadWriteLock rrwl = new ReentrantReadWriteLock();
|
||||
ReentrantReadWriteLock rrwl = new MonitoredReentrantReadWriteLock(MonitoredEnums.MAP_FACTORY);
|
||||
this.mapsRLock = rrwl.readLock();
|
||||
this.mapsWLock = rrwl.writeLock();
|
||||
}
|
||||
|
||||
@@ -24,8 +24,10 @@ import client.MapleCharacter;
|
||||
import client.MapleClient;
|
||||
import client.inventory.Item;
|
||||
import java.awt.Point;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.locks.MonitoredEnums;
|
||||
|
||||
public class MapleMapItem extends AbstractMapleMapObject {
|
||||
|
||||
@@ -35,7 +37,7 @@ public class MapleMapItem extends AbstractMapleMapObject {
|
||||
protected byte type;
|
||||
protected boolean pickedUp = false, playerDrop;
|
||||
protected long dropTime;
|
||||
private ReentrantLock itemLock = new ReentrantLock();
|
||||
private Lock itemLock = new MonitoredReentrantLock(MonitoredEnums.MAP_ITEM);
|
||||
|
||||
public MapleMapItem(Item item, Point position, MapleMapObject dropper, MapleCharacter owner, byte type, boolean playerDrop) {
|
||||
setPosition(position);
|
||||
|
||||
@@ -25,8 +25,9 @@ import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.locks.MonitoredEnums;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -35,7 +36,7 @@ import tools.MaplePacketCreator;
|
||||
public class MapleMiniDungeon {
|
||||
List<MapleCharacter> players = new ArrayList<>();
|
||||
ScheduledFuture<?> timeoutTask = null;
|
||||
Lock lock = new ReentrantLock(true);
|
||||
Lock lock = new MonitoredReentrantLock(MonitoredEnums.MINIDUNGEON, true);
|
||||
|
||||
int baseMap;
|
||||
long expireTime;
|
||||
|
||||
@@ -29,12 +29,13 @@ import java.util.List;
|
||||
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
|
||||
import scripting.reactor.ReactorScriptManager;
|
||||
import server.TimerManager;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Pair;
|
||||
import tools.locks.MonitoredEnums;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -53,7 +54,7 @@ public class MapleReactor extends AbstractMapleMapObject {
|
||||
private boolean shouldCollect;
|
||||
private boolean attackHit;
|
||||
private ScheduledFuture<?> timeoutTask = null;
|
||||
private Lock reactorLock = new ReentrantLock(true);
|
||||
private Lock reactorLock = new MonitoredReentrantLock(MonitoredEnums.REACTOR, true);
|
||||
|
||||
public MapleReactor(MapleReactorStats stats, int rid) {
|
||||
this.evstate = (byte)0;
|
||||
|
||||
@@ -44,7 +44,11 @@ public class FilePrinter {
|
||||
QUEST_UNCODED = "uncodedQuests.txt",
|
||||
AUTOSAVING_CHARACTER = "saveCharAuto.txt",
|
||||
SAVING_CHARACTER = "saveChar.txt",
|
||||
USED_COMMANDS = "usedCommands.txt";//more to come (maps)
|
||||
USED_COMMANDS = "usedCommands.txt",
|
||||
DEADLOCK_ERROR = "deadlocks.txt",
|
||||
DEADLOCK_STACK = "deadlocks/path.txt",
|
||||
DEADLOCK_LOCKS = "deadlocks/locks.txt",
|
||||
DEADLOCK_STATE = "deadlocks/state.txt";
|
||||
|
||||
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); //for file system purposes, it's nice to use yyyy-MM-dd
|
||||
private static final String FILE_PATH = "logs/" + sdf.format(Calendar.getInstance().getTime()) + "/"; // + sdf.format(Calendar.getInstance().getTime()) + "/"
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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 tools.locks;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author RonanLana
|
||||
*/
|
||||
|
||||
public enum MonitoredEnums {
|
||||
UNDEFINED(-1),
|
||||
CHR(0),
|
||||
EFF(1),
|
||||
PET(2),
|
||||
PRT(3),
|
||||
CLIENT(4),
|
||||
BOOK(5),
|
||||
ITEM(6),
|
||||
INVENTORY(7),
|
||||
SHANDLER_IDLE(8),
|
||||
SHANDLER_TEMP(9),
|
||||
BUFF_STORAGE(10),
|
||||
PLAYER_STORAGE(11),
|
||||
SERVER(12),
|
||||
MERCHANT(13),
|
||||
CHANNEL(14),
|
||||
GUILD(15),
|
||||
PARTY(16),
|
||||
WORLD_PARTY(17),
|
||||
WORLD_OWL(18),
|
||||
WORLD_PETS(19),
|
||||
WORLD_MOUNTS(20),
|
||||
WORLD_PSHOPS(21),
|
||||
WORLD_MERCHS(21),
|
||||
EIM(22),
|
||||
EIM_PARTY(23),
|
||||
EIM_SCRIPT(24),
|
||||
EM_LOBBY(25),
|
||||
EM_QUEUE(26),
|
||||
CASHSHOP(27),
|
||||
VISITOR_PSHOP(28),
|
||||
STORAGE(29),
|
||||
MOB_EXT(30),
|
||||
MOB(31),
|
||||
MOB_STATI(32),
|
||||
MOBSKILL_FACTORY(33),
|
||||
PORTAL(34),
|
||||
VISITOR_MERCH(35),
|
||||
MAP_CHRS(36),
|
||||
MAP_OBJS(37),
|
||||
MAP_FACTORY(38),
|
||||
MAP_ITEM(39),
|
||||
MINIDUNGEON(40),
|
||||
REACTOR(41);
|
||||
|
||||
private final int i;
|
||||
|
||||
private MonitoredEnums(int val) {
|
||||
this.i = val;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* 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 tools.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 MonitoredEnums 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() {
|
||||
super.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();
|
||||
}
|
||||
}
|
||||
|
||||
@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,150 @@
|
||||
/*
|
||||
* 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 tools.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 MonitoredEnums id;
|
||||
private final int hashcode;
|
||||
private final Lock state = new ReentrantLock(true);
|
||||
private final AtomicInteger reentrantCount = new AtomicInteger(0);
|
||||
|
||||
public MonitoredReentrantLock(MonitoredEnums id) {
|
||||
super();
|
||||
this.id = id;
|
||||
hashcode = this.hashCode();
|
||||
}
|
||||
|
||||
public MonitoredReentrantLock(MonitoredEnums id, boolean fair) {
|
||||
super(fair);
|
||||
this.id = id;
|
||||
hashcode = this.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lock() {
|
||||
super.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();
|
||||
}
|
||||
}
|
||||
|
||||
@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,49 @@
|
||||
/*
|
||||
* 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 tools.locks;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author RonanLana
|
||||
*/
|
||||
public class MonitoredReentrantReadWriteLock extends ReentrantReadWriteLock {
|
||||
public final MonitoredEnums id;
|
||||
|
||||
public MonitoredReentrantReadWriteLock(MonitoredEnums id) {
|
||||
super();
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public MonitoredReentrantReadWriteLock(MonitoredEnums id, boolean fair) {
|
||||
super(fair);
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadLock readLock() {
|
||||
return super.readLock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WriteLock writeLock() {
|
||||
return super.writeLock();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* 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 tools.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 MonitoredEnums 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() {
|
||||
super.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();
|
||||
}
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -1,14 +1,24 @@
|
||||
Red Potion
|
||||
Lemon
|
||||
W. Ramen
|
||||
Elixir
|
||||
Mana Elixir
|
||||
Mushroom Miso Ramen
|
||||
Power Elixir
|
||||
Lunar Gloves
|
||||
LeFay Jester
|
||||
Eclipse Earrings
|
||||
Herculean Crown
|
||||
Lockewood Hat
|
||||
Pickpocket Pilfer
|
||||
Eclipse Cloak
|
||||
Gladius
|
||||
Niam
|
||||
Titan
|
||||
Crescent Polearm
|
||||
Iron Dagger
|
||||
White Crusader Chainmail (Male)
|
||||
Wizard Wand
|
||||
Wizard Staff
|
||||
Golden Pride
|
||||
Blue Guiltian
|
||||
Red Amorian Skirt (Female)
|
||||
Red Salt Shoes
|
||||
Green Pole-Feather Hat
|
||||
Black Bennis Chainmail (Male)
|
||||
Red Legolier (Male)
|
||||
Blue Legolier Pants (Male)
|
||||
Green Marker
|
||||
Gold Brace
|
||||
Green Hunter Boots
|
||||
Dragon Toenail
|
||||
Rouge Way
|
||||
Guardian Katara
|
||||
Justice Katara
|
||||
Norman Grip
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
1302008
|
||||
1412004
|
||||
1422007
|
||||
1442009
|
||||
1332010
|
||||
1372001
|
||||
1382002
|
||||
1002013
|
||||
1002152
|
||||
1061047
|
||||
1072090
|
||||
1002137
|
||||
1040023
|
||||
1040072
|
||||
1060062
|
||||
1082049
|
||||
1082072
|
||||
1072081
|
||||
1332031
|
||||
1482003
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
compile.on.save=true
|
||||
user.properties.file=C:\\Users\\USER\\AppData\\Roaming\\NetBeans\\8.0.2\\build.properties
|
||||
user.properties.file=C:\\Users\\RonanLana\\AppData\\Roaming\\NetBeans\\8.0.2\\build.properties
|
||||
|
||||
@@ -41,9 +41,11 @@ import java.util.ArrayList;
|
||||
* Set whether you are first installing the handbook on the SQL Server (TRUE) or just fetching whatever is on your "fetch.txt"
|
||||
* file (FALSE) on the INSTALL_SQLTABLE property and build the project. With all done, run the Java executable.
|
||||
*
|
||||
* Expected installing time: 30 minutes
|
||||
*
|
||||
*/
|
||||
public class MapleIdRetriever {
|
||||
private final static boolean INSTALL_SQLTABLE = true;
|
||||
private final static boolean INSTALL_SQLTABLE = false;
|
||||
|
||||
static String host = "jdbc:mysql://localhost:3306/maplesolaxia";
|
||||
static String driver = "com.mysql.jdbc.Driver";
|
||||
@@ -83,7 +85,12 @@ public class MapleIdRetriever {
|
||||
|
||||
if(tokens.length > 1) {
|
||||
PreparedStatement ps = con.prepareStatement("INSERT INTO `handbook` (`id`, `name`) VALUES (?, ?)");
|
||||
ps.setInt(1, Integer.parseInt(tokens[0]));
|
||||
try {
|
||||
ps.setInt(1, Integer.parseInt(tokens[0]));
|
||||
} catch (NumberFormatException npe) { // odd...
|
||||
String num = tokens[0].substring(1);
|
||||
ps.setInt(1, Integer.parseInt(num));
|
||||
}
|
||||
ps.setString(2, tokens[1]);
|
||||
ps.execute();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user