Merge pull request #20 from P0nk/faster-startup

Improve the startup sequence
This commit is contained in:
Ponk
2021-04-16 20:45:15 +02:00
committed by GitHub
11 changed files with 399 additions and 370 deletions
+5 -7
View File
@@ -182,8 +182,7 @@ public class MapleFamily {
} }
} }
public static void loadAllFamilies() { public static void loadAllFamilies(Connection con) {
try(Connection con = DatabaseConnection.getConnection()) {
List<Pair<Pair<Integer, Integer>, MapleFamilyEntry>> unmatchedJuniors = new ArrayList<>(200); // <<world, seniorid> familyEntry> List<Pair<Pair<Integer, Integer>, MapleFamilyEntry>> unmatchedJuniors = new ArrayList<>(200); // <<world, seniorid> familyEntry>
try (PreparedStatement psEntries = con.prepareStatement("SELECT * FROM family_character")) { try (PreparedStatement psEntries = con.prepareStatement("SELECT * FROM family_character")) {
ResultSet rsEntries = psEntries.executeQuery(); ResultSet rsEntries = psEntries.executeQuery();
@@ -236,7 +235,9 @@ public class MapleFamily {
if (senior != null) { if (senior != null) {
familyEntry.setSenior(family.getEntryByID(seniorid), false); familyEntry.setSenior(family.getEntryByID(seniorid), false);
} else { } else {
if(seniorid > 0) unmatchedJuniors.add(new Pair<>(new Pair<>(world, seniorid), familyEntry)); if (seniorid > 0) {
unmatchedJuniors.add(new Pair<>(new Pair<>(world, seniorid), familyEntry));
}
} }
familyEntry.setReputation(reputation); familyEntry.setReputation(reputation);
familyEntry.setTodaysRep(todaysRep); familyEntry.setTodaysRep(todaysRep);
@@ -267,10 +268,7 @@ public class MapleFamily {
FilePrinter.printError(FilePrinter.FAMILY_ERROR, "Missing senior for character " + junior.getName() + " in world " + world); FilePrinter.printError(FilePrinter.FAMILY_ERROR, "Missing senior for character " + junior.getName() + " in world " + world);
} }
} }
} catch(SQLException e) {
FilePrinter.printError(FilePrinter.FAMILY_ERROR, e, "Could not get DB connection.");
e.printStackTrace();
}
for (World world : Server.getInstance().getWorlds()) { for (World world : Server.getInstance().getWorlds()) {
for (MapleFamily family : world.getFamilies()) { for (MapleFamily family : world.getFamilies()) {
family.getLeader().doFullCount(); family.getLeader().doFullCount();
+7 -8
View File
@@ -31,33 +31,32 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
public class SkillFactory { public class SkillFactory {
private static Map<Integer, Skill> skills = new HashMap<>(); private static volatile Map<Integer, Skill> skills = new HashMap<>();
private static MapleDataProvider datasource = MapleDataProviderFactory.getDataProvider(MapleDataProviderFactory.fileInWZPath("Skill.wz")); private static final MapleDataProvider datasource = MapleDataProviderFactory.getDataProvider(MapleDataProviderFactory.fileInWZPath("Skill.wz"));
public static Skill getSkill(int id) { public static Skill getSkill(int id) {
if (!skills.isEmpty()) {
return skills.get(id); return skills.get(id);
} }
return null;
}
public static void loadAllSkills() { public static void loadAllSkills() {
final Map<Integer, Skill> loadedSkills = new HashMap<>();
final MapleDataDirectoryEntry root = datasource.getRoot(); final MapleDataDirectoryEntry root = datasource.getRoot();
int skillid;
for (MapleDataFileEntry topDir : root.getFiles()) { // Loop thru jobs for (MapleDataFileEntry topDir : root.getFiles()) { // Loop thru jobs
if (topDir.getName().length() <= 8) { if (topDir.getName().length() <= 8) {
for (MapleData data : datasource.getData(topDir.getName())) { // Loop thru each jobs for (MapleData data : datasource.getData(topDir.getName())) { // Loop thru each jobs
if (data.getName().equals("skill")) { if (data.getName().equals("skill")) {
for (MapleData data2 : data) { // Loop thru each jobs for (MapleData data2 : data) { // Loop thru each jobs
if (data2 != null) { if (data2 != null) {
skillid = Integer.parseInt(data2.getName()); int skillId = Integer.parseInt(data2.getName());
skills.put(skillid, loadFromData(skillid, data2)); loadedSkills.put(skillId, loadFromData(skillId, data2));
} }
} }
} }
} }
} }
} }
skills = loadedSkills;
} }
private static Skill loadFromData(int id, MapleData data) { private static Skill loadFromData(int id, MapleData data) {
@@ -19,6 +19,8 @@
*/ */
package client.inventory.manipulator; package client.inventory.manipulator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tools.DatabaseConnection; import tools.DatabaseConnection;
import java.sql.Connection; import java.sql.Connection;
@@ -32,7 +34,7 @@ import java.util.Set;
* @author RonanLana * @author RonanLana
*/ */
public class MapleCashidGenerator { public class MapleCashidGenerator {
private static final Logger log = LoggerFactory.getLogger(MapleCashidGenerator.class);
private final static Set<Integer> existentCashids = new HashSet<>(10000); private final static Set<Integer> existentCashids = new HashSet<>(10000);
private static Integer runningCashid = 0; private static Integer runningCashid = 0;
@@ -49,13 +51,9 @@ public class MapleCashidGenerator {
} }
} }
public static synchronized void loadExistentCashIdsFromDb() { public static synchronized void loadExistentCashIdsFromDb(Connection con) throws SQLException {
try (Connection con = DatabaseConnection.getConnection()) {
loadExistentCashIdsFromQuery(con, "SELECT id FROM rings"); loadExistentCashIdsFromQuery(con, "SELECT id FROM rings");
loadExistentCashIdsFromQuery(con, "SELECT petid FROM pets"); loadExistentCashIdsFromQuery(con, "SELECT petid FROM pets");
} catch (SQLException ex) {
ex.printStackTrace();
}
runningCashid = 0; runningCashid = 0;
do { do {
@@ -67,7 +65,11 @@ public class MapleCashidGenerator {
runningCashid++; runningCashid++;
if (runningCashid >= 777000000) { if (runningCashid >= 777000000) {
existentCashids.clear(); existentCashids.clear();
loadExistentCashIdsFromDb(); try (Connection con = DatabaseConnection.getConnection()) {
loadExistentCashIdsFromDb(con);
} catch (SQLException e) {
log.warn("Failed to reset overflowing cash ids", e);
}
} }
} }
@@ -340,8 +340,7 @@ public class NewYearCardRecord {
} }
} }
public static void startPendingNewYearCardRequests() { public static void startPendingNewYearCardRequests(Connection con) throws SQLException {
try (Connection con = DatabaseConnection.getConnection()) {
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM newyear WHERE timereceived = 0 AND senderdiscard = 0")) { try (PreparedStatement ps = con.prepareStatement("SELECT * FROM newyear WHERE timereceived = 0 AND senderdiscard = 0")) {
try (ResultSet rs = ps.executeQuery()) { try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) { while (rs.next()) {
@@ -353,8 +352,5 @@ public class NewYearCardRecord {
} }
} }
} }
} catch(SQLException sqle) {
sqle.printStackTrace();
}
} }
} }
+93 -71
View File
@@ -80,8 +80,13 @@ import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.time.Duration;
import java.time.Instant;
import java.util.*; import java.util.*;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.Lock;
@@ -134,7 +139,7 @@ public class Server {
private final AtomicLong currentTime = new AtomicLong(0); private final AtomicLong currentTime = new AtomicLong(0);
private long serverCurrentTime = 0; private long serverCurrentTime = 0;
private boolean availableDeveloperRoom = false; private volatile boolean availableDeveloperRoom = false;
private boolean online = false; private boolean online = false;
public static long uptime = System.currentTimeMillis(); public static long uptime = System.currentTimeMillis();
@@ -625,7 +630,7 @@ public class Server {
} }
} }
public void updateActiveCoupons() throws SQLException { public void updateActiveCoupons(Connection con) throws SQLException {
synchronized (activeCoupons) { synchronized (activeCoupons) {
activeCoupons.clear(); activeCoupons.clear();
Calendar c = Calendar.getInstance(); Calendar c = Calendar.getInstance();
@@ -633,8 +638,6 @@ public class Server {
int weekDay = c.get(Calendar.DAY_OF_WEEK); int weekDay = c.get(Calendar.DAY_OF_WEEK);
int hourDay = c.get(Calendar.HOUR_OF_DAY); int hourDay = c.get(Calendar.HOUR_OF_DAY);
try (Connection con = DatabaseConnection.getConnection()) {
int weekdayMask = (1 << weekDay); int weekdayMask = (1 << weekDay);
PreparedStatement ps = con.prepareStatement("SELECT couponid FROM nxcoupons WHERE (activeday & ?) = ? AND starthour <= ? AND endhour > ?"); PreparedStatement ps = con.prepareStatement("SELECT couponid FROM nxcoupons WHERE (activeday & ?) = ? AND starthour <= ? AND endhour > ?");
ps.setInt(1, weekdayMask); ps.setInt(1, weekdayMask);
@@ -647,9 +650,7 @@ public class Server {
activeCoupons.add(rs.getInt("couponid")); activeCoupons.add(rs.getInt("couponid"));
} }
} }
} catch (SQLException ex) {
ex.printStackTrace();
}
} }
} }
@@ -703,7 +704,7 @@ public class Server {
} }
private void installWorldPlayerRanking(int worldid) { private void installWorldPlayerRanking(int worldid) {
List<Pair<Integer, List<Pair<String, Integer>>>> ranking = updatePlayerRankingFromDB(worldid); List<Pair<Integer, List<Pair<String, Integer>>>> ranking = loadPlayerRankingFromDB(worldid);
if (!ranking.isEmpty()) { if (!ranking.isEmpty()) {
wldWLock.lock(); wldWLock.lock();
try { try {
@@ -735,7 +736,7 @@ public class Server {
wldWLock.unlock(); wldWLock.unlock();
} }
} else { } else {
List<Pair<Integer, List<Pair<String, Integer>>>> ranking = updatePlayerRankingFromDB(-1 * (this.getWorldsSize() - 2)); // update ranking list List<Pair<Integer, List<Pair<String, Integer>>>> ranking = loadPlayerRankingFromDB(-1 * (this.getWorldsSize() - 2)); // update ranking list
wldWLock.lock(); wldWLock.lock();
try { try {
@@ -747,8 +748,11 @@ public class Server {
} }
public void updateWorldPlayerRanking() { public void updateWorldPlayerRanking() {
List<Pair<Integer, List<Pair<String, Integer>>>> rankUpdates = updatePlayerRankingFromDB(-1 * (this.getWorldsSize() - 1)); List<Pair<Integer, List<Pair<String, Integer>>>> rankUpdates = loadPlayerRankingFromDB(-1 * (this.getWorldsSize() - 1));
if (!rankUpdates.isEmpty()) { if (rankUpdates.isEmpty()) {
return;
}
wldWLock.lock(); wldWLock.lock();
try { try {
if (!YamlConfig.config.server.USE_WHOLE_SERVER_RANKING) { if (!YamlConfig.config.server.USE_WHOLE_SERVER_RANKING) {
@@ -765,22 +769,26 @@ public class Server {
} finally { } finally {
wldWLock.unlock(); wldWLock.unlock();
} }
}
} }
private void initWorldPlayerRanking() { private void initWorldPlayerRanking() {
if (YamlConfig.config.server.USE_WHOLE_SERVER_RANKING) { if (YamlConfig.config.server.USE_WHOLE_SERVER_RANKING) {
wldWLock.lock();
try {
playerRanking.add(new ArrayList<>(0)); playerRanking.add(new ArrayList<>(0));
} finally {
wldWLock.unlock();
} }
}
updateWorldPlayerRanking(); updateWorldPlayerRanking();
} }
private static List<Pair<Integer, List<Pair<String, Integer>>>> updatePlayerRankingFromDB(int worldid) { private static List<Pair<Integer, List<Pair<String, Integer>>>> loadPlayerRankingFromDB(int worldid) {
List<Pair<Integer, List<Pair<String, Integer>>>> rankSystem = new ArrayList<>(); List<Pair<Integer, List<Pair<String, Integer>>>> rankSystem = new ArrayList<>();
List<Pair<String, Integer>> rankUpdate = new ArrayList<>(0);
try (Connection con = DatabaseConnection.getConnection()) { try (Connection con = DatabaseConnection.getConnection()) {
String worldQuery; String worldQuery;
if (!YamlConfig.config.server.USE_WHOLE_SERVER_RANKING) { if (!YamlConfig.config.server.USE_WHOLE_SERVER_RANKING) {
if (worldid >= 0) { if (worldid >= 0) {
@@ -792,6 +800,7 @@ public class Server {
worldQuery = (" AND `characters`.`world` >= 0 AND `characters`.`world` <= " + Math.abs(worldid)); worldQuery = (" AND `characters`.`world` >= 0 AND `characters`.`world` <= " + Math.abs(worldid));
} }
List<Pair<String, Integer>> rankUpdate = new ArrayList<>(0);
try (PreparedStatement ps = con.prepareStatement("SELECT `characters`.`name`, `characters`.`level`, `characters`.`world` FROM `characters` LEFT JOIN accounts ON accounts.id = characters.accountid WHERE `characters`.`gm` < 2 AND `accounts`.`banned` = '0'" + worldQuery + " ORDER BY " + (!YamlConfig.config.server.USE_WHOLE_SERVER_RANKING ? "world, " : "") + "level DESC, exp DESC, lastExpGainTime ASC LIMIT 50"); try (PreparedStatement ps = con.prepareStatement("SELECT `characters`.`name`, `characters`.`level`, `characters`.`world` FROM `characters` LEFT JOIN accounts ON accounts.id = characters.accountid WHERE `characters`.`gm` < 2 AND `accounts`.`banned` = '0'" + worldQuery + " ORDER BY " + (!YamlConfig.config.server.USE_WHOLE_SERVER_RANKING ? "world, " : "") + "level DESC, exp DESC, lastExpGainTime ASC LIMIT 50");
ResultSet rs = ps.executeQuery()) { ResultSet rs = ps.executeQuery()) {
@@ -824,6 +833,7 @@ public class Server {
} }
public void init() { public void init() {
Instant beforeInit = Instant.now();
log.info("Cosmic v{} starting up.", ServerConstants.VERSION); log.info("Cosmic v{} starting up.", ServerConstants.VERSION);
if (YamlConfig.config.server.SHUTDOWNHOOK) { if (YamlConfig.config.server.SHUTDOWNHOOK) {
@@ -834,50 +844,39 @@ public class Server {
throw new IllegalStateException("Failed to initiate a connection to the database"); throw new IllegalStateException("Failed to initiate a connection to the database");
} }
final ExecutorService initExecutor = Executors.newFixedThreadPool(10);
// Run slow operations asynchronously to make startup faster
final List<Future<?>> futures = new ArrayList<>();
futures.add(initExecutor.submit(() -> SkillFactory.loadAllSkills()));
futures.add(initExecutor.submit(() -> CashItemFactory.loadAllCashItems()));
futures.add(initExecutor.submit(() -> MapleQuest.loadAllQuests()));
futures.add(initExecutor.submit(() -> MapleSkillbookInformationProvider.loadAllSkillbookInformation()));
futures.add(initExecutor.submit(() -> MaplePlayerNPCFactory.loadFactoryMetadata()));
TimeZone.setDefault(TimeZone.getTimeZone(YamlConfig.config.server.TIMEZONE)); TimeZone.setDefault(TimeZone.getTimeZone(YamlConfig.config.server.TIMEZONE));
try (Connection con = DatabaseConnection.getConnection()) { try (Connection con = DatabaseConnection.getConnection()) {
try (PreparedStatement ps = con.prepareStatement("UPDATE accounts SET loggedin = 0")) { setAllLoggedOut(con);
ps.executeUpdate(); setAllMerchantsInactive(con);
}
try (PreparedStatement ps = con.prepareStatement("UPDATE characters SET HasMerchant = 0")) {
ps.executeUpdate();
}
cleanNxcodeCoupons(con); cleanNxcodeCoupons(con);
loadCouponRates(con); loadCouponRates(con);
updateActiveCoupons(); updateActiveCoupons(con);
} catch (SQLException sqle) { NewYearCardRecord.startPendingNewYearCardRequests(con);
sqle.printStackTrace(); MapleCashidGenerator.loadExistentCashIdsFromDb(con);
} applyAllNameChanges(con); // -- name changes can be missed by INSTANT_NAME_CHANGE --
applyAllWorldTransfers(con);
applyAllNameChanges(); // -- name changes can be missed by INSTANT_NAME_CHANGE -- if (YamlConfig.config.server.USE_FAMILY_SYSTEM) {
applyAllWorldTransfers(); MapleFamily.loadAllFamilies(con);
//MaplePet.clearMissingPetsFromDb(); // thanks Optimist for noticing this taking too long to run }
MapleCashidGenerator.loadExistentCashIdsFromDb(); } catch (SQLException sqle) {
log.error("Failed to run all startup-bound database tasks", sqle);
throw new IllegalStateException(sqle);
}
ThreadManager.getInstance().start(); ThreadManager.getInstance().start();
initializeTimelyTasks(); // aggregated method for timely tasks thanks to lxconan initializeTimelyTasks(); // aggregated method for timely tasks thanks to lxconan
long timeToTake = System.currentTimeMillis();
SkillFactory.loadAllSkills();
final double skillLoadTime = (System.currentTimeMillis() - timeToTake) / 1000.0;
log.info("Skills loaded in {} seconds", skillLoadTime);
timeToTake = System.currentTimeMillis();
CashItemFactory.getSpecialCashItems();
final double itemLoadTime = (System.currentTimeMillis() - timeToTake) / 1000.0;
log.info("Items loaded in {} seconds", itemLoadTime);
timeToTake = System.currentTimeMillis();
MapleQuest.loadAllQuest();
final double questLoadTime = (System.currentTimeMillis() - timeToTake) / 1000.0;
log.info("Quest loaded in {} seconds", questLoadTime);
NewYearCardRecord.startPendingNewYearCardRequests();
if (YamlConfig.config.server.USE_THREAD_TRACKER) { if (YamlConfig.config.server.USE_THREAD_TRACKER) {
ThreadTracker.getInstance().registerThreadTrackerTask(); ThreadTracker.getInstance().registerThreadTrackerTask();
} }
@@ -890,7 +889,6 @@ public class Server {
} }
initWorldPlayerRanking(); initWorldPlayerRanking();
MaplePlayerNPCFactory.loadFactoryMetadata();
loadPlayerNpcMapStepFromDb(); loadPlayerNpcMapStepFromDb();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace();//For those who get errors e.printStackTrace();//For those who get errors
@@ -898,11 +896,14 @@ public class Server {
System.exit(0); System.exit(0);
} }
if (YamlConfig.config.server.USE_FAMILY_SYSTEM) { // Wait on all async tasks to complete
timeToTake = System.currentTimeMillis(); for (Future<?> future : futures) {
MapleFamily.loadAllFamilies(); try {
final double familyLoadTime = (System.currentTimeMillis() - timeToTake) / 1000.0; future.get();
log.info("Families loaded in {} seconds", familyLoadTime); } catch (Exception e) {
log.error("Failed to run all startup-bound loading tasks", e);
throw new IllegalStateException(e);
}
} }
IoBuffer.setUseDirectBuffer(false); // join IO operations performed by lxconan IoBuffer.setUseDirectBuffer(false); // join IO operations performed by lxconan
@@ -919,10 +920,10 @@ public class Server {
log.info("Listening on port 8484"); log.info("Listening on port 8484");
log.info("Cosmic is now online.");
online = true; online = true;
Duration initDuration = Duration.between(beforeInit, Instant.now());
log.info("Cosmic is now online after {} ms.", initDuration.toMillis());
MapleSkillbookInformationProvider.getInstance();
OpcodeConstants.generateOpcodeNames(); OpcodeConstants.generateOpcodeNames();
CommandsExecutor.getInstance(); CommandsExecutor.getInstance();
@@ -931,6 +932,18 @@ public class Server {
} }
} }
private static void setAllLoggedOut(Connection con) throws SQLException {
try (PreparedStatement ps = con.prepareStatement("UPDATE accounts SET loggedin = 0")) {
ps.executeUpdate();
}
}
private static void setAllMerchantsInactive(Connection con) throws SQLException {
try (PreparedStatement ps = con.prepareStatement("UPDATE characters SET HasMerchant = 0")) {
ps.executeUpdate();
}
}
private void initializeTimelyTasks() { private void initializeTimelyTasks() {
TimerManager tMan = TimerManager.getInstance(); TimerManager tMan = TimerManager.getInstance();
tMan.start(); tMan.start();
@@ -1570,13 +1583,14 @@ public class Server {
} }
} }
private static void applyAllNameChanges() { private static void applyAllNameChanges(Connection con) throws SQLException {
try (Connection con = DatabaseConnection.getConnection(); try (PreparedStatement ps = con.prepareStatement("SELECT * FROM namechanges WHERE completionTime IS NULL");
PreparedStatement ps = con.prepareStatement("SELECT * FROM namechanges WHERE completionTime IS NULL");
ResultSet rs = ps.executeQuery()) { ResultSet rs = ps.executeQuery()) {
List<Pair<String, String>> changedNames = new LinkedList<>(); //logging only List<Pair<String, String>> changedNames = new LinkedList<>(); //logging only
while (rs.next()) {
con.setAutoCommit(false); con.setAutoCommit(false);
try {
while (rs.next()) {
int nameChangeId = rs.getInt("id"); int nameChangeId = rs.getInt("id");
int characterId = rs.getInt("characterId"); int characterId = rs.getInt("characterId");
String oldName = rs.getString("old"); String oldName = rs.getString("old");
@@ -1585,23 +1599,25 @@ public class Server {
if (!success) { if (!success) {
con.rollback(); //discard changes con.rollback(); //discard changes
} else { } else {
con.commit();
changedNames.add(new Pair<>(oldName, newName)); changedNames.add(new Pair<>(oldName, newName));
} }
}
} finally {
con.setAutoCommit(true); con.setAutoCommit(true);
} }
//log //log
for (Pair<String, String> namePair : changedNames) { for (Pair<String, String> namePair : changedNames) {
FilePrinter.print(FilePrinter.CHANGE_CHARACTER_NAME, "Name change applied : from \"" + namePair.getLeft() + "\" to \"" + namePair.getRight() + "\" at " + Calendar.getInstance().getTime().toString()); log.info("Name change applied - from: \"{}\" to \"{}\" at {}", namePair.getLeft(), namePair.getRight(), Instant.now());
} }
} catch (SQLException e) { } catch (SQLException e) {
e.printStackTrace(); log.warn("Failed to retrieve list of pending name changes", e);
FilePrinter.printError(FilePrinter.CHANGE_CHARACTER_NAME, e, "Failed to retrieve list of pending name changes."); throw e;
} }
} }
private static void applyAllWorldTransfers() { private static void applyAllWorldTransfers(Connection con) throws SQLException {
try (Connection con = DatabaseConnection.getConnection(); try (PreparedStatement ps = con.prepareStatement("SELECT * FROM worldtransfers WHERE completionTime IS NULL",
PreparedStatement ps = con.prepareStatement("SELECT * FROM worldtransfers WHERE completionTime IS NULL",
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ResultSet rs = ps.executeQuery()) { ResultSet rs = ps.executeQuery()) {
List<Integer> removedTransfers = new LinkedList<>(); List<Integer> removedTransfers = new LinkedList<>();
@@ -1625,8 +1641,10 @@ public class Server {
} }
rs.beforeFirst(); rs.beforeFirst();
List<Pair<Integer, Pair<Integer, Integer>>> worldTransfers = new LinkedList<>(); //logging only <charid, <oldWorld, newWorld>> List<Pair<Integer, Pair<Integer, Integer>>> worldTransfers = new LinkedList<>(); //logging only <charid, <oldWorld, newWorld>>
while (rs.next()) {
con.setAutoCommit(false); con.setAutoCommit(false);
try {
while (rs.next()) {
int nameChangeId = rs.getInt("id"); int nameChangeId = rs.getInt("id");
if (removedTransfers.contains(nameChangeId)) { if (removedTransfers.contains(nameChangeId)) {
continue; continue;
@@ -1638,20 +1656,24 @@ public class Server {
if (!success) { if (!success) {
con.rollback(); con.rollback();
} else { } else {
con.commit();
worldTransfers.add(new Pair<>(characterId, new Pair<>(oldWorld, newWorld))); worldTransfers.add(new Pair<>(characterId, new Pair<>(oldWorld, newWorld)));
} }
}
} finally {
con.setAutoCommit(true); con.setAutoCommit(true);
} }
//log //log
for (Pair<Integer, Pair<Integer, Integer>> worldTransferPair : worldTransfers) { for (Pair<Integer, Pair<Integer, Integer>> worldTransferPair : worldTransfers) {
int charId = worldTransferPair.getLeft(); int charId = worldTransferPair.getLeft();
int oldWorld = worldTransferPair.getRight().getLeft(); int oldWorld = worldTransferPair.getRight().getLeft();
int newWorld = worldTransferPair.getRight().getRight(); int newWorld = worldTransferPair.getRight().getRight();
FilePrinter.print(FilePrinter.WORLD_TRANSFER, "World transfer applied : Character ID " + charId + " from World " + oldWorld + " to World " + newWorld + " at " + Calendar.getInstance().getTime().toString()); log.info("World transfer applied - character id {} from world {} to world {} at {}", charId, oldWorld, newWorld, Instant.now());
} }
} catch (SQLException e) { } catch (SQLException e) {
e.printStackTrace(); log.warn("Failed to retrieve list of pending world transfers", e);
FilePrinter.printError(FilePrinter.WORLD_TRANSFER, e, "Failed to retrieve list of pending world transfers."); throw e;
} }
} }
+10 -2
View File
@@ -19,8 +19,12 @@
*/ */
package net.server.task; package net.server.task;
import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
import net.server.Server; import net.server.Server;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tools.DatabaseConnection;
import tools.FilePrinter; import tools.FilePrinter;
/** /**
@@ -28,13 +32,17 @@ import tools.FilePrinter;
* @info Thread responsible for maintaining coupons EXP & DROP effects active * @info Thread responsible for maintaining coupons EXP & DROP effects active
*/ */
public class CouponTask implements Runnable { public class CouponTask implements Runnable {
private static final Logger log = LoggerFactory.getLogger(CouponTask.class);
@Override @Override
public void run() { public void run() {
try { try {
Server.getInstance().updateActiveCoupons(); try (Connection con = DatabaseConnection.getConnection()) {
Server.getInstance().updateActiveCoupons(con);
}
Server.getInstance().commitActiveCoupons(); Server.getInstance().commitActiveCoupons();
} catch (SQLException sqle) { } catch (SQLException sqle) {
FilePrinter.printError(FilePrinter.EXCEPTION_CAUGHT, "Unexpected SQL error: " + sqle.getMessage()); log.error("Error updating coupon effects", sqle);
} }
} }
} }
@@ -570,7 +570,7 @@ public class NPCConversationManager extends AbstractPlayerInteraction {
public Object[] getAvailableSkillBooks() { public Object[] getAvailableSkillBooks() {
List<Integer> ret = MapleItemInformationProvider.getInstance().usableSkillBooks(this.getPlayer()); List<Integer> ret = MapleItemInformationProvider.getInstance().usableSkillBooks(this.getPlayer());
ret.addAll(MapleSkillbookInformationProvider.getInstance().getTeachableSkills(this.getPlayer())); ret.addAll(MapleSkillbookInformationProvider.getTeachableSkills(this.getPlayer()));
return ret.toArray(); return ret.toArray();
} }
@@ -580,7 +580,7 @@ public class NPCConversationManager extends AbstractPlayerInteraction {
} }
public String getSkillBookInfo(int itemid) { public String getSkillBookInfo(int itemid) {
SkillBookEntry sbe = MapleSkillbookInformationProvider.getInstance().getSkillbookAvailability(itemid); SkillBookEntry sbe = MapleSkillbookInformationProvider.getSkillbookAvailability(itemid);
switch (sbe) { switch (sbe) {
case UNAVAILABLE: case UNAVAILABLE:
return ""; return "";
+24 -19
View File
@@ -40,7 +40,6 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.*; import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.Lock;
/* /*
@@ -144,15 +143,16 @@ public class CashShop {
} }
public static class CashItemFactory { public static class CashItemFactory {
private static volatile Map<Integer, CashItem> items = new HashMap<>();
private static volatile List<Integer> randomitemsns = new ArrayList<>();
private static volatile Map<Integer, List<Integer>> packages = new HashMap<>();
private static volatile List<SpecialCashItem> specialcashitems = new ArrayList<>();
private static final Map<Integer, CashItem> items = new HashMap<>(); public static void loadAllCashItems() {
private static final Map<Integer, List<Integer>> packages = new HashMap<>();
private static final List<SpecialCashItem> specialcashitems = new ArrayList<>();
private static final List<Integer> randomitemsns = new ArrayList<>();
static {
MapleDataProvider etc = MapleDataProviderFactory.getDataProvider(new File("wz/Etc.wz")); MapleDataProvider etc = MapleDataProviderFactory.getDataProvider(new File("wz/Etc.wz"));
Map<Integer, CashItem> loadedItems = new HashMap<>();
List<Integer> onSaleItems = new ArrayList<>();
for (MapleData item : etc.getData("Commodity.img").getChildren()) { for (MapleData item : etc.getData("Commodity.img").getChildren()) {
int sn = MapleDataTool.getIntConvert("SN", item); int sn = MapleDataTool.getIntConvert("SN", item);
int itemId = MapleDataTool.getIntConvert("ItemId", item); int itemId = MapleDataTool.getIntConvert("ItemId", item);
@@ -160,9 +160,16 @@ public class CashShop {
long period = MapleDataTool.getIntConvert("Period", item, 1); long period = MapleDataTool.getIntConvert("Period", item, 1);
short count = (short) MapleDataTool.getIntConvert("Count", item, 1); short count = (short) MapleDataTool.getIntConvert("Count", item, 1);
boolean onSale = MapleDataTool.getIntConvert("OnSale", item, 0) == 1; boolean onSale = MapleDataTool.getIntConvert("OnSale", item, 0) == 1;
items.put(sn, new CashItem(sn, itemId, price, period, count, onSale)); loadedItems.put(sn, new CashItem(sn, itemId, price, period, count, onSale));
}
if (onSale) {
onSaleItems.add(sn);
}
}
CashItemFactory.items = loadedItems;
CashItemFactory.randomitemsns = onSaleItems;
Map<Integer, List<Integer>> loadedPackages = new HashMap<>();
for (MapleData cashPackage : etc.getData("CashPackage.img").getChildren()) { for (MapleData cashPackage : etc.getData("CashPackage.img").getChildren()) {
List<Integer> cPackage = new ArrayList<>(); List<Integer> cPackage = new ArrayList<>();
@@ -170,24 +177,21 @@ public class CashShop {
cPackage.add(Integer.parseInt(item.getData().toString())); cPackage.add(Integer.parseInt(item.getData().toString()));
} }
packages.put(Integer.parseInt(cashPackage.getName()), cPackage); loadedPackages.put(Integer.parseInt(cashPackage.getName()), cPackage);
}
for (Entry<Integer, CashItem> e : items.entrySet()) {
if (e.getValue().isOnSale()) {
randomitemsns.add(e.getKey());
}
} }
CashItemFactory.packages = loadedPackages;
List<SpecialCashItem> loadedSpecialItems = new ArrayList<>();
try (Connection con = DatabaseConnection.getConnection(); try (Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT * FROM specialcashitems"); PreparedStatement ps = con.prepareStatement("SELECT * FROM specialcashitems");
ResultSet rs = ps.executeQuery()) { ResultSet rs = ps.executeQuery()) {
while (rs.next()) { while (rs.next()) {
specialcashitems.add(new SpecialCashItem(rs.getInt("sn"), rs.getInt("modifier"), rs.getByte("info"))); loadedSpecialItems.add(new SpecialCashItem(rs.getInt("sn"), rs.getInt("modifier"), rs.getByte("info")));
} }
} catch (SQLException ex) { } catch (SQLException ex) {
ex.printStackTrace(); ex.printStackTrace();
} }
CashItemFactory.specialcashitems = loadedSpecialItems;
} }
public static CashItem getRandomCashItem() { public static CashItem getRandomCashItem() {
@@ -222,16 +226,17 @@ public class CashShop {
} }
public static void reloadSpecialCashItems() {//Yay? public static void reloadSpecialCashItems() {//Yay?
specialcashitems.clear(); List<SpecialCashItem> loadedSpecialItems = new ArrayList<>();
try (Connection con = DatabaseConnection.getConnection(); try (Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT * FROM specialcashitems"); PreparedStatement ps = con.prepareStatement("SELECT * FROM specialcashitems");
ResultSet rs = ps.executeQuery()) { ResultSet rs = ps.executeQuery()) {
while (rs.next()) { while (rs.next()) {
specialcashitems.add(new SpecialCashItem(rs.getInt("sn"), rs.getInt("modifier"), rs.getByte("info"))); loadedSpecialItems.add(new SpecialCashItem(rs.getInt("sn"), rs.getInt("modifier"), rs.getByte("info")));
} }
} catch (SQLException ex) { } catch (SQLException ex) {
ex.printStackTrace(); ex.printStackTrace();
} }
CashItemFactory.specialcashitems = loadedSpecialItems;
} }
} }
@@ -40,15 +40,12 @@ import java.util.regex.Pattern;
* *
* @author RonanLana * @author RonanLana
*/ */
/**
* Only used in 1 script that gives players information about where skillbooks can be found
*/
public class MapleSkillbookInformationProvider { public class MapleSkillbookInformationProvider {
private static volatile Map<Integer, SkillBookEntry> foundSkillbooks = new HashMap<>();
private final static MapleSkillbookInformationProvider instance = new MapleSkillbookInformationProvider();
public static MapleSkillbookInformationProvider getInstance() {
return instance;
}
protected static Map<Integer, SkillBookEntry> foundSkillbooks = new HashMap<>();
public enum SkillBookEntry { public enum SkillBookEntry {
UNAVAILABLE, UNAVAILABLE,
@@ -59,13 +56,15 @@ public class MapleSkillbookInformationProvider {
SCRIPT SCRIPT
} }
private static String rootDirectory = "."; private static final int SKILLBOOK_MIN_ITEMID = 2280000;
private static final int SKILLBOOK_MAX_ITEMID = 2300000; // exclusively
private static int skillbookMinItemid = 2280000; public static void loadAllSkillbookInformation() {
private static int skillbookMaxItemid = 2300000; // exclusively Map<Integer, SkillBookEntry> loadedSkillbooks = new HashMap<>();
loadedSkillbooks.putAll(fetchSkillbooksFromQuests());
static { loadedSkillbooks.putAll(fetchSkillbooksFromReactors());
loadSkillbooks(); loadedSkillbooks.putAll(fetchSkillbooksFromScripts());
MapleSkillbookInformationProvider.foundSkillbooks = loadedSkillbooks;
} }
private static boolean is4thJobSkill(int itemid) { private static boolean is4thJobSkill(int itemid) {
@@ -73,7 +72,7 @@ public class MapleSkillbookInformationProvider {
} }
private static boolean isSkillBook(int itemid) { private static boolean isSkillBook(int itemid) {
return itemid >= skillbookMinItemid && itemid < skillbookMaxItemid; return itemid >= SKILLBOOK_MIN_ITEMID && itemid < SKILLBOOK_MAX_ITEMID;
} }
private static boolean isQuestBook(int itemid) { private static boolean isQuestBook(int itemid) {
@@ -86,9 +85,9 @@ public class MapleSkillbookInformationProvider {
MapleData startReqItemData = questStartData.getChildByPath("item"); MapleData startReqItemData = questStartData.getChildByPath("item");
if (startReqItemData != null) { if (startReqItemData != null) {
for (MapleData itemData : startReqItemData.getChildren()) { for (MapleData itemData : startReqItemData.getChildren()) {
int itemid = MapleDataTool.getInt("id", itemData, 0); int itemId = MapleDataTool.getInt("id", itemData, 0);
if (isQuestBook(itemid)) { if (isQuestBook(itemId)) {
return itemid; return itemId;
} }
} }
} }
@@ -115,41 +114,41 @@ public class MapleSkillbookInformationProvider {
return -1; return -1;
} }
private static void fetchSkillbooksFromQuests() { private static Map<Integer, SkillBookEntry> fetchSkillbooksFromQuests() {
MapleDataProvider questDataProvider = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/" + "Quest.wz")); MapleDataProvider questDataProvider = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/" + "Quest.wz"));
MapleData actData = questDataProvider.getData("Act.img"); MapleData actData = questDataProvider.getData("Act.img");
MapleData checkData = questDataProvider.getData("Check.img"); MapleData checkData = questDataProvider.getData("Check.img");
final Map<Integer, SkillBookEntry> loadedSkillbooks = new HashMap<>();
for (MapleData questData : actData.getChildren()) { for (MapleData questData : actData.getChildren()) {
for (MapleData questStatusData : questData.getChildren()) { for (MapleData questStatusData : questData.getChildren()) {
for (MapleData questNodeData : questStatusData.getChildren()) { for (MapleData questNodeData : questStatusData.getChildren()) {
String actNodeName = questNodeData.getName(); String actNodeName = questNodeData.getName();
if (actNodeName.contentEquals("item")) { if (actNodeName.contentEquals("item")) {
for (MapleData questItemData : questNodeData.getChildren()) { for (MapleData questItemData : questNodeData.getChildren()) {
int itemid = MapleDataTool.getInt("id", questItemData, 0); int itemId = MapleDataTool.getInt("id", questItemData, 0);
int itemcount = MapleDataTool.getInt("count", questItemData, 0); int itemCount = MapleDataTool.getInt("count", questItemData, 0);
if (isSkillBook(itemid) && itemcount > 0) { if (isSkillBook(itemId) && itemCount > 0) {
int questbook = fetchQuestbook(checkData, questData.getName()); int questbook = fetchQuestbook(checkData, questData.getName());
if (questbook < 0) { if (questbook < 0) {
foundSkillbooks.put(itemid, SkillBookEntry.QUEST); loadedSkillbooks.put(itemId, SkillBookEntry.QUEST);
} else { } else {
foundSkillbooks.put(itemid, SkillBookEntry.QUEST_BOOK); loadedSkillbooks.put(itemId, SkillBookEntry.QUEST_BOOK);
} }
} }
} }
} else if (actNodeName.contentEquals("skill")) { } else if (actNodeName.contentEquals("skill")) {
for (MapleData questSkillData : questNodeData.getChildren()) { for (MapleData questSkillData : questNodeData.getChildren()) {
int skillid = MapleDataTool.getInt("id", questSkillData, 0); int skillId = MapleDataTool.getInt("id", questSkillData, 0);
if (is4thJobSkill(skillid)) { if (is4thJobSkill(skillId)) {
// negative itemids are skill rewards // negative itemids are skill rewards
int questbook = fetchQuestbook(checkData, questData.getName()); int questbook = fetchQuestbook(checkData, questData.getName());
if (questbook < 0) { if (questbook < 0) {
foundSkillbooks.put(-skillid, SkillBookEntry.QUEST_REWARD); loadedSkillbooks.put(-skillId, SkillBookEntry.QUEST_REWARD);
} else { } else {
foundSkillbooks.put(-skillid, SkillBookEntry.QUEST_BOOK); loadedSkillbooks.put(-skillId, SkillBookEntry.QUEST_BOOK);
}
} }
} }
} }
@@ -158,22 +157,29 @@ public class MapleSkillbookInformationProvider {
} }
} }
private static void fetchSkillbooksFromReactors() { return loadedSkillbooks;
}
private static Map<Integer, SkillBookEntry> fetchSkillbooksFromReactors() {
Map<Integer, SkillBookEntry> loadedSkillbooks = new HashMap<>();
try (Connection con = DatabaseConnection.getConnection(); try (Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT itemid FROM reactordrops WHERE itemid >= ? AND itemid < ?;")) { PreparedStatement ps = con.prepareStatement("SELECT itemid FROM reactordrops WHERE itemid >= ? AND itemid < ?;")) {
ps.setInt(1, skillbookMinItemid); ps.setInt(1, SKILLBOOK_MIN_ITEMID);
ps.setInt(2, skillbookMaxItemid); ps.setInt(2, SKILLBOOK_MAX_ITEMID);
try (ResultSet rs = ps.executeQuery()) { try (ResultSet rs = ps.executeQuery()) {
if (rs.isBeforeFirst()) { if (rs.isBeforeFirst()) {
while (rs.next()) { while (rs.next()) {
foundSkillbooks.put(rs.getInt("itemid"), SkillBookEntry.REACTOR); loadedSkillbooks.put(rs.getInt("itemid"), SkillBookEntry.REACTOR);
} }
} }
} }
} catch (SQLException sqle) { } catch (SQLException sqle) {
sqle.printStackTrace(); sqle.printStackTrace();
} }
return loadedSkillbooks;
} }
private static void listFiles(String directoryName, ArrayList<File> files) { private static void listFiles(String directoryName, ArrayList<File> files) {
@@ -197,28 +203,20 @@ public class MapleSkillbookInformationProvider {
return files; return files;
} }
private static void filterScriptDirectorySearchMatchingData(String path) { private static Set<Integer> findMatchingSkillbookIdsOnFile(String fileContent) {
for (File file : listFilesFromDirectoryRecursively(rootDirectory + "/" + path)) { Set<Integer> skillbookIds = new HashSet<>(4);
if (file.getName().endsWith(".js")) {
fileSearchMatchingData(file);
}
}
}
private static Set<Integer> foundMatchingDataOnFile(String fileContent) {
Set<Integer> matches = new HashSet<>(4);
Matcher searchM = Pattern.compile("22(8|9)[0-9]{4}").matcher(fileContent); Matcher searchM = Pattern.compile("22(8|9)[0-9]{4}").matcher(fileContent);
int idx = 0; int idx = 0;
while (searchM.find(idx)) { while (searchM.find(idx)) {
idx = searchM.end(); idx = searchM.end();
matches.add(Integer.valueOf(fileContent.substring(searchM.start(), idx))); skillbookIds.add(Integer.valueOf(fileContent.substring(searchM.start(), idx)));
} }
return matches; return skillbookIds;
} }
static String readFileToString(File file, String encoding) throws IOException { private static String readFileToString(File file, String encoding) throws IOException {
Scanner scanner = new Scanner(file, encoding); Scanner scanner = new Scanner(file, encoding);
String text = ""; String text = "";
try { try {
@@ -232,36 +230,42 @@ public class MapleSkillbookInformationProvider {
return text; return text;
} }
private static void fileSearchMatchingData(File file) { private static Map<Integer, SkillBookEntry> fileSearchMatchingData(File file) {
Map<Integer, SkillBookEntry> scriptFileSkillbooks = new HashMap<>();
try { try {
String fileContent = readFileToString(file, "UTF-8"); String fileContent = readFileToString(file, "UTF-8");
Set<Integer> books = foundMatchingDataOnFile(fileContent); Set<Integer> skillbookIds = findMatchingSkillbookIdsOnFile(fileContent);
for (Integer i : books) { for (Integer skillbookId : skillbookIds) {
foundSkillbooks.put(i, SkillBookEntry.SCRIPT); scriptFileSkillbooks.put(skillbookId, SkillBookEntry.SCRIPT);
} }
} catch (IOException ioe) { } catch (IOException ioe) {
System.out.println("Failed to read " + file.getName() + "."); System.out.println("Failed to read " + file.getName() + ".");
ioe.printStackTrace(); ioe.printStackTrace();
} }
return scriptFileSkillbooks;
} }
private static void fetchSkillbooksFromScripts() { private static Map<Integer, SkillBookEntry> fetchSkillbooksFromScripts() {
filterScriptDirectorySearchMatchingData("scripts"); Map<Integer, SkillBookEntry> scriptSkillbooks = new HashMap<>();
for (File file : listFilesFromDirectoryRecursively("./scripts")) {
if (file.getName().endsWith(".js")) {
scriptSkillbooks.putAll(fileSearchMatchingData(file));
}
} }
private static void loadSkillbooks() { return scriptSkillbooks;
fetchSkillbooksFromQuests();
fetchSkillbooksFromReactors();
fetchSkillbooksFromScripts();
} }
public SkillBookEntry getSkillbookAvailability(int itemid) { public static SkillBookEntry getSkillbookAvailability(int itemId) {
SkillBookEntry sbe = foundSkillbooks.get(itemid); SkillBookEntry sbe = foundSkillbooks.get(itemId);
return sbe != null ? sbe : SkillBookEntry.UNAVAILABLE; return sbe != null ? sbe : SkillBookEntry.UNAVAILABLE;
} }
public List<Integer> getTeachableSkills(MapleCharacter chr) { public static List<Integer> getTeachableSkills(MapleCharacter chr) {
List<Integer> list = new ArrayList<>(); List<Integer> list = new ArrayList<>();
for (Integer book : foundSkillbooks.keySet()) { for (Integer book : foundSkillbooks.keySet()) {
@@ -19,17 +19,18 @@
*/ */
package server.life; package server.life;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.LinkedList;
import net.server.Server; import net.server.Server;
import provider.MapleData; import provider.MapleData;
import provider.MapleDataProvider; import provider.MapleDataProvider;
import provider.MapleDataProviderFactory; import provider.MapleDataProviderFactory;
import provider.MapleDataTool; import provider.MapleDataTool;
import java.io.File;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/** /**
* *
* @author RonanLana * @author RonanLana
@@ -41,11 +42,11 @@ public class MaplePlayerNPCFactory {
private static final Map<Integer, List<MaplePlayerNPC>> dnpcMaps = new HashMap<>(); private static final Map<Integer, List<MaplePlayerNPC>> dnpcMaps = new HashMap<>();
private static Integer runningDeveloperOid = 2147483000; // 647 slots, long enough private static Integer runningDeveloperOid = 2147483000; // 647 slots, long enough
public static boolean isExistentScriptid(int scriptid) { public synchronized static boolean isExistentScriptid(int scriptid) {
return npcData.getData(scriptid + ".img") != null; return npcData.getData(scriptid + ".img") != null;
} }
public static void loadDeveloperRoomMetadata(MapleDataProvider npc) { private static void loadDeveloperRoomMetadata(MapleDataProvider npc) {
MapleData thisData = npc.getData("9977777.img"); MapleData thisData = npc.getData("9977777.img");
if(thisData != null) { if(thisData != null) {
MapleDataProvider map = MapleDataProviderFactory.getDataProvider(new File("wz/Map.wz")); MapleDataProvider map = MapleDataProviderFactory.getDataProvider(new File("wz/Map.wz"));
@@ -65,7 +66,7 @@ public class MaplePlayerNPCFactory {
} }
} }
public static void loadFactoryMetadata() { public synchronized static void loadFactoryMetadata() {
MapleDataProvider npc = npcData; MapleDataProvider npc = npcData;
loadDeveloperRoomMetadata(npc); loadDeveloperRoomMetadata(npc);
@@ -134,7 +135,7 @@ public class MaplePlayerNPCFactory {
} }
} }
public static List<MaplePlayerNPC> getDeveloperNpcsFromMapid(int mapid) { public synchronized static List<MaplePlayerNPC> getDeveloperNpcsFromMapid(int mapid) {
return dnpcMaps.get(mapid); return dnpcMaps.get(mapid);
} }
} }
+16 -22
View File
@@ -21,20 +21,10 @@
*/ */
package server.quest; package server.quest;
import java.io.File;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import client.MapleCharacter; import client.MapleCharacter;
import client.MapleQuestStatus; import client.MapleQuestStatus;
import client.MapleQuestStatus.Status; import client.MapleQuestStatus.Status;
import config.YamlConfig; import config.YamlConfig;
import java.util.Collection;
import java.util.EnumMap;
import java.util.Map.Entry;
import java.util.Set;
import provider.MapleData; import provider.MapleData;
import provider.MapleDataProvider; import provider.MapleDataProvider;
import provider.MapleDataProviderFactory; import provider.MapleDataProviderFactory;
@@ -44,6 +34,10 @@ import server.quest.requirements.*;
import tools.MaplePacketCreator; import tools.MaplePacketCreator;
import tools.StringUtil; import tools.StringUtil;
import java.io.File;
import java.util.*;
import java.util.Map.Entry;
/** /**
* *
* @author Matze * @author Matze
@@ -51,8 +45,8 @@ import tools.StringUtil;
*/ */
public class MapleQuest { public class MapleQuest {
private static Map<Integer, MapleQuest> quests = new HashMap<>(); private static volatile Map<Integer, MapleQuest> quests = new HashMap<>();
private static Map<Integer, Integer> infoNumberQuests = new HashMap<>(); private static volatile Map<Integer, Integer> infoNumberQuests = new HashMap<>();
private static Map<Short, Integer> medals = new HashMap<>(); private static Map<Short, Integer> medals = new HashMap<>();
private static final Set<Short> exploitableQuests = new HashSet<>(); private static final Set<Short> exploitableQuests = new HashSet<>();
@@ -459,10 +453,8 @@ public class MapleQuest {
} }
public static void clearCache(int quest) { public static void clearCache(int quest) {
if(quests.containsKey(quest)){
quests.remove(quest); quests.remove(quest);
} }
}
public static void clearCache() { public static void clearCache() {
quests.clear(); quests.clear();
@@ -657,28 +649,30 @@ public class MapleQuest {
return ret; return ret;
} }
public static void loadAllQuest() { public static void loadAllQuests() {
try { final Map<Integer, MapleQuest> loadedQuests = new HashMap<>();
final Map<Integer, Integer> loadedInfoNumberQuests = new HashMap<>();
for (MapleData quest : questInfo.getChildren()) { for (MapleData quest : questInfo.getChildren()) {
int questID = Integer.parseInt(quest.getName()); int questID = Integer.parseInt(quest.getName());
MapleQuest q = new MapleQuest(questID); MapleQuest q = new MapleQuest(questID);
quests.put(questID, q); loadedQuests.put(questID, q);
int infoNumber; int infoNumber;
infoNumber = q.getInfoNumber(Status.STARTED); infoNumber = q.getInfoNumber(Status.STARTED);
if (infoNumber > 0) { if (infoNumber > 0) {
infoNumberQuests.put(infoNumber, questID); loadedInfoNumberQuests.put(infoNumber, questID);
} }
infoNumber = q.getInfoNumber(Status.COMPLETED); infoNumber = q.getInfoNumber(Status.COMPLETED);
if (infoNumber > 0) { if (infoNumber > 0) {
infoNumberQuests.put(infoNumber, questID); loadedInfoNumberQuests.put(infoNumber, questID);
} }
} }
} catch (Exception ex) {
ex.printStackTrace(); MapleQuest.quests = loadedQuests;
} MapleQuest.infoNumberQuests = loadedInfoNumberQuests;
} }
} }