Load skillbook source information async on startup
This commit is contained in:
@@ -853,10 +853,12 @@ public class Server {
|
|||||||
throw new IllegalStateException(sqle);
|
throw new IllegalStateException(sqle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run slow operations asynchronously to make startup faster
|
||||||
final List<Future<?>> futures = new ArrayList<>();
|
final List<Future<?>> futures = new ArrayList<>();
|
||||||
futures.add(initExecutor.submit(() -> SkillFactory.loadAllSkills()));
|
futures.add(initExecutor.submit(() -> SkillFactory.loadAllSkills()));
|
||||||
futures.add(initExecutor.submit(() -> CashItemFactory.loadAllCashItems()));
|
futures.add(initExecutor.submit(() -> CashItemFactory.loadAllCashItems()));
|
||||||
futures.add(initExecutor.submit(() -> MapleQuest.loadAllQuests()));
|
futures.add(initExecutor.submit(() -> MapleQuest.loadAllQuests()));
|
||||||
|
futures.add(initExecutor.submit(() -> MapleSkillbookInformationProvider.loadAllSkillbookInformation()));
|
||||||
|
|
||||||
ThreadManager.getInstance().start();
|
ThreadManager.getInstance().start();
|
||||||
initializeTimelyTasks(); // aggregated method for timely tasks thanks to lxconan
|
initializeTimelyTasks(); // aggregated method for timely tasks thanks to lxconan
|
||||||
@@ -890,6 +892,7 @@ public class Server {
|
|||||||
log.info("Families loaded in {} seconds", familyLoadTime);
|
log.info("Families loaded in {} seconds", familyLoadTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait on all async tasks to complete
|
||||||
for (Future<?> future : futures) {
|
for (Future<?> future : futures) {
|
||||||
try {
|
try {
|
||||||
future.get();
|
future.get();
|
||||||
@@ -917,7 +920,6 @@ public class Server {
|
|||||||
Duration initDuration = Duration.between(beforeInit, Instant.now());
|
Duration initDuration = Duration.between(beforeInit, Instant.now());
|
||||||
log.info("Cosmic is now online after {} ms.", initDuration.toMillis());
|
log.info("Cosmic is now online after {} ms.", initDuration.toMillis());
|
||||||
|
|
||||||
MapleSkillbookInformationProvider.getInstance();
|
|
||||||
OpcodeConstants.generateOpcodeNames();
|
OpcodeConstants.generateOpcodeNames();
|
||||||
CommandsExecutor.getInstance();
|
CommandsExecutor.getInstance();
|
||||||
|
|
||||||
|
|||||||
@@ -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 "";
|
||||||
|
|||||||
@@ -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()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user