Merge pull request #20 from P0nk/faster-startup
Improve the startup sequence
This commit is contained in:
@@ -182,8 +182,7 @@ public class MapleFamily {
|
||||
}
|
||||
}
|
||||
|
||||
public static void loadAllFamilies() {
|
||||
try(Connection con = DatabaseConnection.getConnection()) {
|
||||
public static void loadAllFamilies(Connection con) {
|
||||
List<Pair<Pair<Integer, Integer>, MapleFamilyEntry>> unmatchedJuniors = new ArrayList<>(200); // <<world, seniorid> familyEntry>
|
||||
try (PreparedStatement psEntries = con.prepareStatement("SELECT * FROM family_character")) {
|
||||
ResultSet rsEntries = psEntries.executeQuery();
|
||||
@@ -236,7 +235,9 @@ public class MapleFamily {
|
||||
if (senior != null) {
|
||||
familyEntry.setSenior(family.getEntryByID(seniorid), false);
|
||||
} 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.setTodaysRep(todaysRep);
|
||||
@@ -267,10 +268,7 @@ public class MapleFamily {
|
||||
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 (MapleFamily family : world.getFamilies()) {
|
||||
family.getLeader().doFullCount();
|
||||
|
||||
@@ -31,33 +31,32 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class SkillFactory {
|
||||
private static Map<Integer, Skill> skills = new HashMap<>();
|
||||
private static MapleDataProvider datasource = MapleDataProviderFactory.getDataProvider(MapleDataProviderFactory.fileInWZPath("Skill.wz"));
|
||||
private static volatile Map<Integer, Skill> skills = new HashMap<>();
|
||||
private static final MapleDataProvider datasource = MapleDataProviderFactory.getDataProvider(MapleDataProviderFactory.fileInWZPath("Skill.wz"));
|
||||
|
||||
public static Skill getSkill(int id) {
|
||||
if (!skills.isEmpty()) {
|
||||
return skills.get(id);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void loadAllSkills() {
|
||||
final Map<Integer, Skill> loadedSkills = new HashMap<>();
|
||||
final MapleDataDirectoryEntry root = datasource.getRoot();
|
||||
int skillid;
|
||||
for (MapleDataFileEntry topDir : root.getFiles()) { // Loop thru jobs
|
||||
if (topDir.getName().length() <= 8) {
|
||||
for (MapleData data : datasource.getData(topDir.getName())) { // Loop thru each jobs
|
||||
if (data.getName().equals("skill")) {
|
||||
for (MapleData data2 : data) { // Loop thru each jobs
|
||||
if (data2 != null) {
|
||||
skillid = Integer.parseInt(data2.getName());
|
||||
skills.put(skillid, loadFromData(skillid, data2));
|
||||
int skillId = Integer.parseInt(data2.getName());
|
||||
loadedSkills.put(skillId, loadFromData(skillId, data2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
skills = loadedSkills;
|
||||
}
|
||||
|
||||
private static Skill loadFromData(int id, MapleData data) {
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
*/
|
||||
package client.inventory.manipulator;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import tools.DatabaseConnection;
|
||||
|
||||
import java.sql.Connection;
|
||||
@@ -32,7 +34,7 @@ import java.util.Set;
|
||||
* @author RonanLana
|
||||
*/
|
||||
public class MapleCashidGenerator {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(MapleCashidGenerator.class);
|
||||
private final static Set<Integer> existentCashids = new HashSet<>(10000);
|
||||
private static Integer runningCashid = 0;
|
||||
|
||||
@@ -49,13 +51,9 @@ public class MapleCashidGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized void loadExistentCashIdsFromDb() {
|
||||
try (Connection con = DatabaseConnection.getConnection()) {
|
||||
public static synchronized void loadExistentCashIdsFromDb(Connection con) throws SQLException {
|
||||
loadExistentCashIdsFromQuery(con, "SELECT id FROM rings");
|
||||
loadExistentCashIdsFromQuery(con, "SELECT petid FROM pets");
|
||||
} catch (SQLException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
runningCashid = 0;
|
||||
do {
|
||||
@@ -67,7 +65,11 @@ public class MapleCashidGenerator {
|
||||
runningCashid++;
|
||||
if (runningCashid >= 777000000) {
|
||||
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() {
|
||||
try (Connection con = DatabaseConnection.getConnection()) {
|
||||
public static void startPendingNewYearCardRequests(Connection con) throws SQLException {
|
||||
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM newyear WHERE timereceived = 0 AND senderdiscard = 0")) {
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
@@ -353,8 +352,5 @@ public class NewYearCardRecord {
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(SQLException sqle) {
|
||||
sqle.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,8 +80,13 @@ import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
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.locks.Lock;
|
||||
|
||||
@@ -134,7 +139,7 @@ public class Server {
|
||||
private final AtomicLong currentTime = new AtomicLong(0);
|
||||
private long serverCurrentTime = 0;
|
||||
|
||||
private boolean availableDeveloperRoom = false;
|
||||
private volatile boolean availableDeveloperRoom = false;
|
||||
private boolean online = false;
|
||||
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) {
|
||||
activeCoupons.clear();
|
||||
Calendar c = Calendar.getInstance();
|
||||
@@ -633,8 +638,6 @@ public class Server {
|
||||
int weekDay = c.get(Calendar.DAY_OF_WEEK);
|
||||
int hourDay = c.get(Calendar.HOUR_OF_DAY);
|
||||
|
||||
try (Connection con = DatabaseConnection.getConnection()) {
|
||||
|
||||
int weekdayMask = (1 << weekDay);
|
||||
PreparedStatement ps = con.prepareStatement("SELECT couponid FROM nxcoupons WHERE (activeday & ?) = ? AND starthour <= ? AND endhour > ?");
|
||||
ps.setInt(1, weekdayMask);
|
||||
@@ -647,9 +650,7 @@ public class Server {
|
||||
activeCoupons.add(rs.getInt("couponid"));
|
||||
}
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -703,7 +704,7 @@ public class Server {
|
||||
}
|
||||
|
||||
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()) {
|
||||
wldWLock.lock();
|
||||
try {
|
||||
@@ -735,7 +736,7 @@ public class Server {
|
||||
wldWLock.unlock();
|
||||
}
|
||||
} 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();
|
||||
try {
|
||||
@@ -747,8 +748,11 @@ public class Server {
|
||||
}
|
||||
|
||||
public void updateWorldPlayerRanking() {
|
||||
List<Pair<Integer, List<Pair<String, Integer>>>> rankUpdates = updatePlayerRankingFromDB(-1 * (this.getWorldsSize() - 1));
|
||||
if (!rankUpdates.isEmpty()) {
|
||||
List<Pair<Integer, List<Pair<String, Integer>>>> rankUpdates = loadPlayerRankingFromDB(-1 * (this.getWorldsSize() - 1));
|
||||
if (rankUpdates.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
wldWLock.lock();
|
||||
try {
|
||||
if (!YamlConfig.config.server.USE_WHOLE_SERVER_RANKING) {
|
||||
@@ -765,22 +769,26 @@ public class Server {
|
||||
} finally {
|
||||
wldWLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void initWorldPlayerRanking() {
|
||||
if (YamlConfig.config.server.USE_WHOLE_SERVER_RANKING) {
|
||||
wldWLock.lock();
|
||||
try {
|
||||
playerRanking.add(new ArrayList<>(0));
|
||||
} finally {
|
||||
wldWLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
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<String, Integer>> rankUpdate = new ArrayList<>(0);
|
||||
|
||||
try (Connection con = DatabaseConnection.getConnection()) {
|
||||
|
||||
String worldQuery;
|
||||
if (!YamlConfig.config.server.USE_WHOLE_SERVER_RANKING) {
|
||||
if (worldid >= 0) {
|
||||
@@ -792,6 +800,7 @@ public class Server {
|
||||
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");
|
||||
ResultSet rs = ps.executeQuery()) {
|
||||
|
||||
@@ -824,6 +833,7 @@ public class Server {
|
||||
}
|
||||
|
||||
public void init() {
|
||||
Instant beforeInit = Instant.now();
|
||||
log.info("Cosmic v{} starting up.", ServerConstants.VERSION);
|
||||
|
||||
if (YamlConfig.config.server.SHUTDOWNHOOK) {
|
||||
@@ -834,50 +844,39 @@ public class Server {
|
||||
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));
|
||||
|
||||
try (Connection con = DatabaseConnection.getConnection()) {
|
||||
try (PreparedStatement ps = con.prepareStatement("UPDATE accounts SET loggedin = 0")) {
|
||||
ps.executeUpdate();
|
||||
}
|
||||
|
||||
try (PreparedStatement ps = con.prepareStatement("UPDATE characters SET HasMerchant = 0")) {
|
||||
ps.executeUpdate();
|
||||
}
|
||||
|
||||
setAllLoggedOut(con);
|
||||
setAllMerchantsInactive(con);
|
||||
cleanNxcodeCoupons(con);
|
||||
loadCouponRates(con);
|
||||
updateActiveCoupons();
|
||||
} catch (SQLException sqle) {
|
||||
sqle.printStackTrace();
|
||||
}
|
||||
updateActiveCoupons(con);
|
||||
NewYearCardRecord.startPendingNewYearCardRequests(con);
|
||||
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 --
|
||||
applyAllWorldTransfers();
|
||||
//MaplePet.clearMissingPetsFromDb(); // thanks Optimist for noticing this taking too long to run
|
||||
MapleCashidGenerator.loadExistentCashIdsFromDb();
|
||||
if (YamlConfig.config.server.USE_FAMILY_SYSTEM) {
|
||||
MapleFamily.loadAllFamilies(con);
|
||||
}
|
||||
} catch (SQLException sqle) {
|
||||
log.error("Failed to run all startup-bound database tasks", sqle);
|
||||
throw new IllegalStateException(sqle);
|
||||
}
|
||||
|
||||
ThreadManager.getInstance().start();
|
||||
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) {
|
||||
ThreadTracker.getInstance().registerThreadTrackerTask();
|
||||
}
|
||||
@@ -890,7 +889,6 @@ public class Server {
|
||||
}
|
||||
initWorldPlayerRanking();
|
||||
|
||||
MaplePlayerNPCFactory.loadFactoryMetadata();
|
||||
loadPlayerNpcMapStepFromDb();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();//For those who get errors
|
||||
@@ -898,11 +896,14 @@ public class Server {
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
if (YamlConfig.config.server.USE_FAMILY_SYSTEM) {
|
||||
timeToTake = System.currentTimeMillis();
|
||||
MapleFamily.loadAllFamilies();
|
||||
final double familyLoadTime = (System.currentTimeMillis() - timeToTake) / 1000.0;
|
||||
log.info("Families loaded in {} seconds", familyLoadTime);
|
||||
// Wait on all async tasks to complete
|
||||
for (Future<?> future : futures) {
|
||||
try {
|
||||
future.get();
|
||||
} 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
|
||||
@@ -919,10 +920,10 @@ public class Server {
|
||||
|
||||
log.info("Listening on port 8484");
|
||||
|
||||
log.info("Cosmic is now online.");
|
||||
online = true;
|
||||
Duration initDuration = Duration.between(beforeInit, Instant.now());
|
||||
log.info("Cosmic is now online after {} ms.", initDuration.toMillis());
|
||||
|
||||
MapleSkillbookInformationProvider.getInstance();
|
||||
OpcodeConstants.generateOpcodeNames();
|
||||
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() {
|
||||
TimerManager tMan = TimerManager.getInstance();
|
||||
tMan.start();
|
||||
@@ -1570,13 +1583,14 @@ public class Server {
|
||||
}
|
||||
}
|
||||
|
||||
private static void applyAllNameChanges() {
|
||||
try (Connection con = DatabaseConnection.getConnection();
|
||||
PreparedStatement ps = con.prepareStatement("SELECT * FROM namechanges WHERE completionTime IS NULL");
|
||||
private static void applyAllNameChanges(Connection con) throws SQLException {
|
||||
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM namechanges WHERE completionTime IS NULL");
|
||||
ResultSet rs = ps.executeQuery()) {
|
||||
List<Pair<String, String>> changedNames = new LinkedList<>(); //logging only
|
||||
while (rs.next()) {
|
||||
|
||||
con.setAutoCommit(false);
|
||||
try {
|
||||
while (rs.next()) {
|
||||
int nameChangeId = rs.getInt("id");
|
||||
int characterId = rs.getInt("characterId");
|
||||
String oldName = rs.getString("old");
|
||||
@@ -1585,23 +1599,25 @@ public class Server {
|
||||
if (!success) {
|
||||
con.rollback(); //discard changes
|
||||
} else {
|
||||
con.commit();
|
||||
changedNames.add(new Pair<>(oldName, newName));
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
con.setAutoCommit(true);
|
||||
}
|
||||
//log
|
||||
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) {
|
||||
e.printStackTrace();
|
||||
FilePrinter.printError(FilePrinter.CHANGE_CHARACTER_NAME, e, "Failed to retrieve list of pending name changes.");
|
||||
log.warn("Failed to retrieve list of pending name changes", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private static void applyAllWorldTransfers() {
|
||||
try (Connection con = DatabaseConnection.getConnection();
|
||||
PreparedStatement ps = con.prepareStatement("SELECT * FROM worldtransfers WHERE completionTime IS NULL",
|
||||
private static void applyAllWorldTransfers(Connection con) throws SQLException {
|
||||
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM worldtransfers WHERE completionTime IS NULL",
|
||||
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
|
||||
ResultSet rs = ps.executeQuery()) {
|
||||
List<Integer> removedTransfers = new LinkedList<>();
|
||||
@@ -1625,8 +1641,10 @@ public class Server {
|
||||
}
|
||||
rs.beforeFirst();
|
||||
List<Pair<Integer, Pair<Integer, Integer>>> worldTransfers = new LinkedList<>(); //logging only <charid, <oldWorld, newWorld>>
|
||||
while (rs.next()) {
|
||||
|
||||
con.setAutoCommit(false);
|
||||
try {
|
||||
while (rs.next()) {
|
||||
int nameChangeId = rs.getInt("id");
|
||||
if (removedTransfers.contains(nameChangeId)) {
|
||||
continue;
|
||||
@@ -1638,20 +1656,24 @@ public class Server {
|
||||
if (!success) {
|
||||
con.rollback();
|
||||
} else {
|
||||
con.commit();
|
||||
worldTransfers.add(new Pair<>(characterId, new Pair<>(oldWorld, newWorld)));
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
con.setAutoCommit(true);
|
||||
}
|
||||
|
||||
//log
|
||||
for (Pair<Integer, Pair<Integer, Integer>> worldTransferPair : worldTransfers) {
|
||||
int charId = worldTransferPair.getLeft();
|
||||
int oldWorld = worldTransferPair.getRight().getLeft();
|
||||
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) {
|
||||
e.printStackTrace();
|
||||
FilePrinter.printError(FilePrinter.WORLD_TRANSFER, e, "Failed to retrieve list of pending world transfers.");
|
||||
log.warn("Failed to retrieve list of pending world transfers", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,12 @@
|
||||
*/
|
||||
package net.server.task;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import net.server.Server;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import tools.DatabaseConnection;
|
||||
import tools.FilePrinter;
|
||||
|
||||
/**
|
||||
@@ -28,13 +32,17 @@ import tools.FilePrinter;
|
||||
* @info Thread responsible for maintaining coupons EXP & DROP effects active
|
||||
*/
|
||||
public class CouponTask implements Runnable {
|
||||
private static final Logger log = LoggerFactory.getLogger(CouponTask.class);
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Server.getInstance().updateActiveCoupons();
|
||||
try (Connection con = DatabaseConnection.getConnection()) {
|
||||
Server.getInstance().updateActiveCoupons(con);
|
||||
}
|
||||
Server.getInstance().commitActiveCoupons();
|
||||
} 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() {
|
||||
List<Integer> ret = MapleItemInformationProvider.getInstance().usableSkillBooks(this.getPlayer());
|
||||
ret.addAll(MapleSkillbookInformationProvider.getInstance().getTeachableSkills(this.getPlayer()));
|
||||
ret.addAll(MapleSkillbookInformationProvider.getTeachableSkills(this.getPlayer()));
|
||||
|
||||
return ret.toArray();
|
||||
}
|
||||
@@ -580,7 +580,7 @@ public class NPCConversationManager extends AbstractPlayerInteraction {
|
||||
}
|
||||
|
||||
public String getSkillBookInfo(int itemid) {
|
||||
SkillBookEntry sbe = MapleSkillbookInformationProvider.getInstance().getSkillbookAvailability(itemid);
|
||||
SkillBookEntry sbe = MapleSkillbookInformationProvider.getSkillbookAvailability(itemid);
|
||||
switch (sbe) {
|
||||
case UNAVAILABLE:
|
||||
return "";
|
||||
|
||||
@@ -40,7 +40,6 @@ import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
/*
|
||||
@@ -144,15 +143,16 @@ public class CashShop {
|
||||
}
|
||||
|
||||
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<>();
|
||||
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 {
|
||||
public static void loadAllCashItems() {
|
||||
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()) {
|
||||
int sn = MapleDataTool.getIntConvert("SN", item);
|
||||
int itemId = MapleDataTool.getIntConvert("ItemId", item);
|
||||
@@ -160,9 +160,16 @@ public class CashShop {
|
||||
long period = MapleDataTool.getIntConvert("Period", item, 1);
|
||||
short count = (short) MapleDataTool.getIntConvert("Count", item, 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()) {
|
||||
List<Integer> cPackage = new ArrayList<>();
|
||||
|
||||
@@ -170,24 +177,21 @@ public class CashShop {
|
||||
cPackage.add(Integer.parseInt(item.getData().toString()));
|
||||
}
|
||||
|
||||
packages.put(Integer.parseInt(cashPackage.getName()), cPackage);
|
||||
}
|
||||
|
||||
for (Entry<Integer, CashItem> e : items.entrySet()) {
|
||||
if (e.getValue().isOnSale()) {
|
||||
randomitemsns.add(e.getKey());
|
||||
}
|
||||
loadedPackages.put(Integer.parseInt(cashPackage.getName()), cPackage);
|
||||
}
|
||||
CashItemFactory.packages = loadedPackages;
|
||||
|
||||
List<SpecialCashItem> loadedSpecialItems = new ArrayList<>();
|
||||
try (Connection con = DatabaseConnection.getConnection();
|
||||
PreparedStatement ps = con.prepareStatement("SELECT * FROM specialcashitems");
|
||||
ResultSet rs = ps.executeQuery()) {
|
||||
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) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
CashItemFactory.specialcashitems = loadedSpecialItems;
|
||||
}
|
||||
|
||||
public static CashItem getRandomCashItem() {
|
||||
@@ -222,16 +226,17 @@ public class CashShop {
|
||||
}
|
||||
|
||||
public static void reloadSpecialCashItems() {//Yay?
|
||||
specialcashitems.clear();
|
||||
List<SpecialCashItem> loadedSpecialItems = new ArrayList<>();
|
||||
try (Connection con = DatabaseConnection.getConnection();
|
||||
PreparedStatement ps = con.prepareStatement("SELECT * FROM specialcashitems");
|
||||
ResultSet rs = ps.executeQuery()) {
|
||||
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) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
CashItemFactory.specialcashitems = loadedSpecialItems;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,15 +40,12 @@ import java.util.regex.Pattern;
|
||||
*
|
||||
* @author RonanLana
|
||||
*/
|
||||
|
||||
/**
|
||||
* Only used in 1 script that gives players information about where skillbooks can be found
|
||||
*/
|
||||
public class MapleSkillbookInformationProvider {
|
||||
|
||||
private final static MapleSkillbookInformationProvider instance = new MapleSkillbookInformationProvider();
|
||||
|
||||
public static MapleSkillbookInformationProvider getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
protected static Map<Integer, SkillBookEntry> foundSkillbooks = new HashMap<>();
|
||||
private static volatile Map<Integer, SkillBookEntry> foundSkillbooks = new HashMap<>();
|
||||
|
||||
public enum SkillBookEntry {
|
||||
UNAVAILABLE,
|
||||
@@ -59,13 +56,15 @@ public class MapleSkillbookInformationProvider {
|
||||
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;
|
||||
private static int skillbookMaxItemid = 2300000; // exclusively
|
||||
|
||||
static {
|
||||
loadSkillbooks();
|
||||
public static void loadAllSkillbookInformation() {
|
||||
Map<Integer, SkillBookEntry> loadedSkillbooks = new HashMap<>();
|
||||
loadedSkillbooks.putAll(fetchSkillbooksFromQuests());
|
||||
loadedSkillbooks.putAll(fetchSkillbooksFromReactors());
|
||||
loadedSkillbooks.putAll(fetchSkillbooksFromScripts());
|
||||
MapleSkillbookInformationProvider.foundSkillbooks = loadedSkillbooks;
|
||||
}
|
||||
|
||||
private static boolean is4thJobSkill(int itemid) {
|
||||
@@ -73,7 +72,7 @@ public class MapleSkillbookInformationProvider {
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -86,9 +85,9 @@ public class MapleSkillbookInformationProvider {
|
||||
MapleData startReqItemData = questStartData.getChildByPath("item");
|
||||
if (startReqItemData != null) {
|
||||
for (MapleData itemData : startReqItemData.getChildren()) {
|
||||
int itemid = MapleDataTool.getInt("id", itemData, 0);
|
||||
if (isQuestBook(itemid)) {
|
||||
return itemid;
|
||||
int itemId = MapleDataTool.getInt("id", itemData, 0);
|
||||
if (isQuestBook(itemId)) {
|
||||
return itemId;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,41 +114,41 @@ public class MapleSkillbookInformationProvider {
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static void fetchSkillbooksFromQuests() {
|
||||
private static Map<Integer, SkillBookEntry> fetchSkillbooksFromQuests() {
|
||||
MapleDataProvider questDataProvider = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/" + "Quest.wz"));
|
||||
MapleData actData = questDataProvider.getData("Act.img");
|
||||
MapleData checkData = questDataProvider.getData("Check.img");
|
||||
|
||||
final Map<Integer, SkillBookEntry> loadedSkillbooks = new HashMap<>();
|
||||
for (MapleData questData : actData.getChildren()) {
|
||||
for (MapleData questStatusData : questData.getChildren()) {
|
||||
for (MapleData questNodeData : questStatusData.getChildren()) {
|
||||
String actNodeName = questNodeData.getName();
|
||||
if (actNodeName.contentEquals("item")) {
|
||||
for (MapleData questItemData : questNodeData.getChildren()) {
|
||||
int itemid = MapleDataTool.getInt("id", questItemData, 0);
|
||||
int itemcount = MapleDataTool.getInt("count", questItemData, 0);
|
||||
int itemId = MapleDataTool.getInt("id", 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());
|
||||
if (questbook < 0) {
|
||||
foundSkillbooks.put(itemid, SkillBookEntry.QUEST);
|
||||
loadedSkillbooks.put(itemId, SkillBookEntry.QUEST);
|
||||
} else {
|
||||
foundSkillbooks.put(itemid, SkillBookEntry.QUEST_BOOK);
|
||||
loadedSkillbooks.put(itemId, SkillBookEntry.QUEST_BOOK);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (actNodeName.contentEquals("skill")) {
|
||||
for (MapleData questSkillData : questNodeData.getChildren()) {
|
||||
int skillid = MapleDataTool.getInt("id", questSkillData, 0);
|
||||
if (is4thJobSkill(skillid)) {
|
||||
int skillId = MapleDataTool.getInt("id", questSkillData, 0);
|
||||
if (is4thJobSkill(skillId)) {
|
||||
// negative itemids are skill rewards
|
||||
|
||||
int questbook = fetchQuestbook(checkData, questData.getName());
|
||||
if (questbook < 0) {
|
||||
foundSkillbooks.put(-skillid, SkillBookEntry.QUEST_REWARD);
|
||||
loadedSkillbooks.put(-skillId, SkillBookEntry.QUEST_REWARD);
|
||||
} 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();
|
||||
PreparedStatement ps = con.prepareStatement("SELECT itemid FROM reactordrops WHERE itemid >= ? AND itemid < ?;")) {
|
||||
ps.setInt(1, skillbookMinItemid);
|
||||
ps.setInt(2, skillbookMaxItemid);
|
||||
ps.setInt(1, SKILLBOOK_MIN_ITEMID);
|
||||
ps.setInt(2, SKILLBOOK_MAX_ITEMID);
|
||||
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
if (rs.isBeforeFirst()) {
|
||||
while (rs.next()) {
|
||||
foundSkillbooks.put(rs.getInt("itemid"), SkillBookEntry.REACTOR);
|
||||
loadedSkillbooks.put(rs.getInt("itemid"), SkillBookEntry.REACTOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SQLException sqle) {
|
||||
sqle.printStackTrace();
|
||||
}
|
||||
|
||||
return loadedSkillbooks;
|
||||
}
|
||||
|
||||
private static void listFiles(String directoryName, ArrayList<File> files) {
|
||||
@@ -197,28 +203,20 @@ public class MapleSkillbookInformationProvider {
|
||||
return files;
|
||||
}
|
||||
|
||||
private static void filterScriptDirectorySearchMatchingData(String path) {
|
||||
for (File file : listFilesFromDirectoryRecursively(rootDirectory + "/" + path)) {
|
||||
if (file.getName().endsWith(".js")) {
|
||||
fileSearchMatchingData(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Set<Integer> foundMatchingDataOnFile(String fileContent) {
|
||||
Set<Integer> matches = new HashSet<>(4);
|
||||
private static Set<Integer> findMatchingSkillbookIdsOnFile(String fileContent) {
|
||||
Set<Integer> skillbookIds = new HashSet<>(4);
|
||||
|
||||
Matcher searchM = Pattern.compile("22(8|9)[0-9]{4}").matcher(fileContent);
|
||||
int idx = 0;
|
||||
while (searchM.find(idx)) {
|
||||
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);
|
||||
String text = "";
|
||||
try {
|
||||
@@ -232,36 +230,42 @@ public class MapleSkillbookInformationProvider {
|
||||
return text;
|
||||
}
|
||||
|
||||
private static void fileSearchMatchingData(File file) {
|
||||
private static Map<Integer, SkillBookEntry> fileSearchMatchingData(File file) {
|
||||
Map<Integer, SkillBookEntry> scriptFileSkillbooks = new HashMap<>();
|
||||
|
||||
try {
|
||||
String fileContent = readFileToString(file, "UTF-8");
|
||||
|
||||
Set<Integer> books = foundMatchingDataOnFile(fileContent);
|
||||
for (Integer i : books) {
|
||||
foundSkillbooks.put(i, SkillBookEntry.SCRIPT);
|
||||
Set<Integer> skillbookIds = findMatchingSkillbookIdsOnFile(fileContent);
|
||||
for (Integer skillbookId : skillbookIds) {
|
||||
scriptFileSkillbooks.put(skillbookId, SkillBookEntry.SCRIPT);
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
System.out.println("Failed to read " + file.getName() + ".");
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
|
||||
return scriptFileSkillbooks;
|
||||
}
|
||||
|
||||
private static void fetchSkillbooksFromScripts() {
|
||||
filterScriptDirectorySearchMatchingData("scripts");
|
||||
private static Map<Integer, SkillBookEntry> fetchSkillbooksFromScripts() {
|
||||
Map<Integer, SkillBookEntry> scriptSkillbooks = new HashMap<>();
|
||||
|
||||
for (File file : listFilesFromDirectoryRecursively("./scripts")) {
|
||||
if (file.getName().endsWith(".js")) {
|
||||
scriptSkillbooks.putAll(fileSearchMatchingData(file));
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadSkillbooks() {
|
||||
fetchSkillbooksFromQuests();
|
||||
fetchSkillbooksFromReactors();
|
||||
fetchSkillbooksFromScripts();
|
||||
return scriptSkillbooks;
|
||||
}
|
||||
|
||||
public SkillBookEntry getSkillbookAvailability(int itemid) {
|
||||
SkillBookEntry sbe = foundSkillbooks.get(itemid);
|
||||
public static SkillBookEntry getSkillbookAvailability(int itemId) {
|
||||
SkillBookEntry sbe = foundSkillbooks.get(itemId);
|
||||
return sbe != null ? sbe : SkillBookEntry.UNAVAILABLE;
|
||||
}
|
||||
|
||||
public List<Integer> getTeachableSkills(MapleCharacter chr) {
|
||||
public static List<Integer> getTeachableSkills(MapleCharacter chr) {
|
||||
List<Integer> list = new ArrayList<>();
|
||||
|
||||
for (Integer book : foundSkillbooks.keySet()) {
|
||||
|
||||
@@ -19,17 +19,18 @@
|
||||
*/
|
||||
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 provider.MapleData;
|
||||
import provider.MapleDataProvider;
|
||||
import provider.MapleDataProviderFactory;
|
||||
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
|
||||
@@ -41,11 +42,11 @@ public class MaplePlayerNPCFactory {
|
||||
private static final Map<Integer, List<MaplePlayerNPC>> dnpcMaps = new HashMap<>();
|
||||
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;
|
||||
}
|
||||
|
||||
public static void loadDeveloperRoomMetadata(MapleDataProvider npc) {
|
||||
private static void loadDeveloperRoomMetadata(MapleDataProvider npc) {
|
||||
MapleData thisData = npc.getData("9977777.img");
|
||||
if(thisData != null) {
|
||||
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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,20 +21,10 @@
|
||||
*/
|
||||
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.MapleQuestStatus;
|
||||
import client.MapleQuestStatus.Status;
|
||||
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.MapleDataProvider;
|
||||
import provider.MapleDataProviderFactory;
|
||||
@@ -44,6 +34,10 @@ import server.quest.requirements.*;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.StringUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Matze
|
||||
@@ -51,8 +45,8 @@ import tools.StringUtil;
|
||||
*/
|
||||
public class MapleQuest {
|
||||
|
||||
private static Map<Integer, MapleQuest> quests = new HashMap<>();
|
||||
private static Map<Integer, Integer> infoNumberQuests = new HashMap<>();
|
||||
private static volatile Map<Integer, MapleQuest> quests = new HashMap<>();
|
||||
private static volatile Map<Integer, Integer> infoNumberQuests = new HashMap<>();
|
||||
private static Map<Short, Integer> medals = new HashMap<>();
|
||||
|
||||
private static final Set<Short> exploitableQuests = new HashSet<>();
|
||||
@@ -459,10 +453,8 @@ public class MapleQuest {
|
||||
}
|
||||
|
||||
public static void clearCache(int quest) {
|
||||
if(quests.containsKey(quest)){
|
||||
quests.remove(quest);
|
||||
}
|
||||
}
|
||||
|
||||
public static void clearCache() {
|
||||
quests.clear();
|
||||
@@ -657,28 +649,30 @@ public class MapleQuest {
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static void loadAllQuest() {
|
||||
try {
|
||||
public static void loadAllQuests() {
|
||||
final Map<Integer, MapleQuest> loadedQuests = new HashMap<>();
|
||||
final Map<Integer, Integer> loadedInfoNumberQuests = new HashMap<>();
|
||||
|
||||
for (MapleData quest : questInfo.getChildren()) {
|
||||
int questID = Integer.parseInt(quest.getName());
|
||||
|
||||
MapleQuest q = new MapleQuest(questID);
|
||||
quests.put(questID, q);
|
||||
loadedQuests.put(questID, q);
|
||||
|
||||
int infoNumber;
|
||||
|
||||
infoNumber = q.getInfoNumber(Status.STARTED);
|
||||
if (infoNumber > 0) {
|
||||
infoNumberQuests.put(infoNumber, questID);
|
||||
loadedInfoNumberQuests.put(infoNumber, questID);
|
||||
}
|
||||
|
||||
infoNumber = q.getInfoNumber(Status.COMPLETED);
|
||||
if (infoNumber > 0) {
|
||||
infoNumberQuests.put(infoNumber, questID);
|
||||
loadedInfoNumberQuests.put(infoNumber, questID);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
MapleQuest.quests = loadedQuests;
|
||||
MapleQuest.infoNumberQuests = loadedInfoNumberQuests;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user