/* This file is part of the HeavenMS MapleStory Server Copyleft (L) 2016 - 2018 RonanLana This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation version 3 as published by the Free Software Foundation. You may not use, modify or distribute this program under any other version of the GNU Affero General Public License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ package maplegachaponitemidretriever; import java.util.ArrayList; import java.util.List; import java.util.LinkedList; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Collections; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * * @author RonanLana * * This application reads metadata for the gachapons found on the "gachapon_items.txt" * recipe file, then checks up the Handbook DB (installed through MapleIdRetriever) * and translates the item names from the recipe file into their respective itemids. * The translated itemids are then stored in specific gachapon files inside the * "lib/gachapons" folder. * * Estimated parse time: 1 minute */ public class MapleGachaponItemidRetriever { static String host = "jdbc:mysql://localhost:3306/cosmic"; static String driver = "com.mysql.jdbc.Driver"; static String username = "cosmic_server"; static String password = "snailshell"; static Connection con = null; static InputStreamReader fileReader = null; static BufferedReader bufferedReader = null; static PrintWriter printWriter = null; // ------- SET-UP section arguments -------- static String directoryName = "./handbook/"; // ------- SEARCH section arguments -------- static String inputName = "lib/gachapon_items.txt"; static String outputPath = "lib/gachapons/"; static Pattern p = Pattern.compile("(\\d*)%"); static int[] scrollsChances = new int[]{10, 15, 30, 60, 65, 70, 100}; static Map> scrollItemids = new HashMap<>(); private static void insertGachaponScrollItemid(Integer id, String name, String description, boolean both) { GachaponScroll gachaScroll = getGachaponScroll(name, description, both); List list = scrollItemids.get(gachaScroll); if (list == null) { list = new LinkedList<>(); scrollItemids.put(gachaScroll, list); } list.add(id); } private static void loadHandbookUseNames() throws SQLException { PreparedStatement ps = con.prepareStatement("SELECT * FROM `handbook` WHERE `id` >= 2040000 AND `id` < 2050000 ORDER BY `id` ASC;"); ResultSet rs = ps.executeQuery(); while(rs.next()) { Integer id = rs.getInt("id"); String name = rs.getString("name"); if (isUpgradeScroll(name)) { String description = rs.getString("description"); insertGachaponScrollItemid(id, name, description, false); insertGachaponScrollItemid(id, name, description, true); } } rs.close(); ps.close(); /* for (Entry> e : scrollItemids.entrySet()) { System.out.println(e); } System.out.println("------------"); */ } private static class GachaponScroll { private String header; private String target; private String buff; private int prop; private GachaponScroll(GachaponScroll from, int prop) { this.header = from.header; this.target = from.target; this.buff = from.buff; this.prop = prop; } private GachaponScroll(String name, String description, boolean both) { String[] params = name.split(" for "); if (params.length < 3) { return; } String header = both ? "scroll" : " " + params[0]; String target = params[1]; int prop = 0; String buff = params[2]; Matcher m = p.matcher(buff); if (m.find()) { prop = Integer.valueOf(m.group(1)); buff = buff.substring(0, m.start() - 1).trim(); } else { m = p.matcher(description); if (m.find()) { prop = Integer.valueOf(m.group(1)); } } int idx = buff.indexOf(" ("); // remove percentage & dots from name checking if (idx > -1) { buff = buff.substring(0, idx); } buff = buff.replace(".", ""); this.header = header; this.target = target; this.buff = buff; this.prop = prop; } @Override public int hashCode() { int result = (int) (prop ^ (prop >>> 32)); result = 31 * result + (header != null ? header.hashCode() : 0); result = 31 * result + (target != null ? target.hashCode() : 0); result = 31 * result + (buff != null ? buff.hashCode() : 0); return result; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; GachaponScroll sc = (GachaponScroll) o; if (header != null ? !header.equals(sc.header) : sc.header != null) return false; if (target != null ? !target.equals(sc.target) : sc.target != null) return false; if (buff != null ? !buff.equals(sc.buff) : sc.buff != null) return false; if (prop != sc.prop) return false; return true; } @Override public String toString() { return header + " for " + target + " for " + buff + " - " + prop + "%"; } } private static String getGachaponScrollResults(String line, boolean both) { String str = ""; List gachaScrollList; GachaponScroll gachaScroll = getGachaponScroll(line, "", both); if (gachaScroll.prop != 0) { gachaScrollList = Collections.singletonList(gachaScroll); } else { gachaScrollList = new ArrayList<>(scrollsChances.length); for (int prop : scrollsChances) { gachaScrollList.add(new GachaponScroll(gachaScroll, prop)); } } for (GachaponScroll gs : gachaScrollList) { List gachaItemids = scrollItemids.get(gs); if (gachaItemids != null) { String listStr = ""; for (Integer id : gachaItemids) { listStr += id.toString(); listStr += " "; } if (gachaItemids.size() > 1) { str += "[" + listStr + "]"; } else { str += listStr; } } } return str; } private static GachaponScroll getGachaponScroll(String name, String description, boolean both) { name = name.toLowerCase(); name = name.replace("for acc ", "for accuracy "); name = name.replace("blunt weapon", "bw"); name = name.replace("eye eqp.", "eye accessory"); name = name.replace("face eqp.", "face accessory"); name = name.replace("for attack", "for att"); name = name.replace("1-handed", "one-handed"); name = name.replace("2-handed", "two-handed"); return new GachaponScroll(name, description, both); } private static boolean isUpgradeScroll(String name) { return name.matches("^(([D|d]ark )?[S|s]croll for).*"); } private static void fetchLineOnMapleHandbook(String line, String rarity) throws SQLException { String str = ""; if (!isUpgradeScroll(line)) { PreparedStatement ps = con.prepareStatement("SELECT `id` FROM `handbook` WHERE `name` LIKE ? COLLATE latin1_general_ci ORDER BY `id` ASC;"); ps.setString(1, line); ResultSet rs = ps.executeQuery(); while(rs.next()) { Integer id = rs.getInt("id"); str += id.toString(); str += " "; } rs.close(); ps.close(); } else { str += getGachaponScrollResults(line, false); if (str.isEmpty()) { str += getGachaponScrollResults(line, true); if (str.isEmpty()) { System.out.println("NONE for '" + line + "' : " + getGachaponScroll(line, "", false)); } } } if (str.isEmpty()) { str += line; } if (rarity != null) { str += ("- " + rarity); } printWriter.println(str); } private static void fetchDataOnMapleHandbook() throws SQLException { String line; try { fileReader = new InputStreamReader(new FileInputStream(inputName), "UTF-8"); bufferedReader = new BufferedReader(fileReader); int skip = 0; boolean lineHeader = false; while((line = bufferedReader.readLine()) != null) { if (skip > 0) { skip--; if (lineHeader) { if (!line.isEmpty()) { lineHeader = false; printWriter.println(); printWriter.println(line + ":"); } } } else if (line.isEmpty()) { printWriter.println(""); } else if (line.startsWith("Gachapon ")) { String s[] = line.split("� "); String gachaponName = s[s.length - 1]; gachaponName = gachaponName.replace(" ", "_"); gachaponName = gachaponName.toLowerCase(); if (printWriter != null) printWriter.close(); printWriter = new PrintWriter(outputPath + gachaponName + ".txt", "UTF-8"); skip = 2; lineHeader = true; } else if (line.startsWith(".")) { skip = 1; lineHeader = true; } else { line = line.replace("�", "'"); for (String item : line.split("\\s\\|\\s")) { item = item.trim(); if (!item.contentEquals("n/a")) { String[] itemInfo = item.split(" - "); fetchLineOnMapleHandbook(itemInfo[0], itemInfo.length > 1 ? itemInfo[1] : null); } } } } if (printWriter != null) printWriter.close(); bufferedReader.close(); fileReader.close(); } catch(FileNotFoundException ex) { System.out.println(ex.getMessage()); } catch(IOException ex) { System.out.println(ex.getMessage()); } } public static void main(String[] args) { try { Class.forName(driver).newInstance(); con = DriverManager.getConnection(host, username, password); loadHandbookUseNames(); fetchDataOnMapleHandbook(); con.close(); } catch(SQLException e) { System.out.println("Error: invalid SQL syntax"); System.out.println(e.getMessage()); } catch(ClassNotFoundException e) { System.out.println("Error: could not find class"); System.out.println(e.getMessage()); } catch(InstantiationException | IllegalAccessException e) { System.out.println("Error: instantiation failure"); System.out.println(e.getMessage()); } } }