From da66e7614d9e0bb383f1bdde0d6b2e01ba29c839 Mon Sep 17 00:00:00 2001 From: P0nk Date: Sat, 10 Jul 2021 19:20:25 +0200 Subject: [PATCH] Move MapleCashCosmeticsChecker to main module --- src/main/java/provider/wz/WZFiles.java | 8 +- .../mapletools/CashCosmeticsChecker.java | 437 +++++++++--------- .../java/tools/mapletools/ToolConstants.java | 4 + .../MapleCashCosmeticsChecker/lib/result.txt | 213 --------- .../src/maplecashcosmeticschecker/Pair.java | 121 ----- tools/input/.gitignore | 2 + .../care => input/cosmetics}/amoria/face.txt | 0 .../care => input/cosmetics}/amoria/hair.txt | 0 .../care => input/cosmetics}/ariant/face.txt | 0 .../care => input/cosmetics}/ariant/hair.txt | 0 .../lib/care => input/cosmetics}/cbd/face.txt | 0 .../lib/care => input/cosmetics}/cbd/hair.txt | 0 .../lib => input/cosmetics}/colors.txt | 0 .../care => input/cosmetics}/henesys/face.txt | 0 .../care => input/cosmetics}/henesys/hair.txt | 0 .../cosmetics}/kerning_city/face.txt | 0 .../cosmetics}/kerning_city/hair.txt | 0 .../cosmetics}/ludibrium/face.txt | 0 .../cosmetics}/ludibrium/hair.txt | 0 .../care => input/cosmetics}/mu_lung/face.txt | 0 .../care => input/cosmetics}/mu_lung/hair.txt | 0 .../lib/care => input/cosmetics}/nlc/face.txt | 0 .../lib/care => input/cosmetics}/nlc/hair.txt | 0 .../care => input/cosmetics}/orbis/face.txt | 0 .../care => input/cosmetics}/orbis/hair.txt | 0 .../care => input/cosmetics}/showa/face.txt | 0 .../care => input/cosmetics}/showa/hair.txt | 0 27 files changed, 220 insertions(+), 565 deletions(-) rename tools/MapleCashCosmeticsChecker/src/maplecashcosmeticschecker/MapleCashCosmeticsChecker.java => src/main/java/tools/mapletools/CashCosmeticsChecker.java (74%) delete mode 100644 tools/MapleCashCosmeticsChecker/lib/result.txt delete mode 100644 tools/MapleCashCosmeticsChecker/src/maplecashcosmeticschecker/Pair.java rename tools/{MapleCashCosmeticsChecker/lib/care => input/cosmetics}/amoria/face.txt (100%) rename tools/{MapleCashCosmeticsChecker/lib/care => input/cosmetics}/amoria/hair.txt (100%) rename tools/{MapleCashCosmeticsChecker/lib/care => input/cosmetics}/ariant/face.txt (100%) rename tools/{MapleCashCosmeticsChecker/lib/care => input/cosmetics}/ariant/hair.txt (100%) rename tools/{MapleCashCosmeticsChecker/lib/care => input/cosmetics}/cbd/face.txt (100%) rename tools/{MapleCashCosmeticsChecker/lib/care => input/cosmetics}/cbd/hair.txt (100%) rename tools/{MapleCashCosmeticsChecker/lib => input/cosmetics}/colors.txt (100%) rename tools/{MapleCashCosmeticsChecker/lib/care => input/cosmetics}/henesys/face.txt (100%) rename tools/{MapleCashCosmeticsChecker/lib/care => input/cosmetics}/henesys/hair.txt (100%) rename tools/{MapleCashCosmeticsChecker/lib/care => input/cosmetics}/kerning_city/face.txt (100%) rename tools/{MapleCashCosmeticsChecker/lib/care => input/cosmetics}/kerning_city/hair.txt (100%) rename tools/{MapleCashCosmeticsChecker/lib/care => input/cosmetics}/ludibrium/face.txt (100%) rename tools/{MapleCashCosmeticsChecker/lib/care => input/cosmetics}/ludibrium/hair.txt (100%) rename tools/{MapleCashCosmeticsChecker/lib/care => input/cosmetics}/mu_lung/face.txt (100%) rename tools/{MapleCashCosmeticsChecker/lib/care => input/cosmetics}/mu_lung/hair.txt (100%) rename tools/{MapleCashCosmeticsChecker/lib/care => input/cosmetics}/nlc/face.txt (100%) rename tools/{MapleCashCosmeticsChecker/lib/care => input/cosmetics}/nlc/hair.txt (100%) rename tools/{MapleCashCosmeticsChecker/lib/care => input/cosmetics}/orbis/face.txt (100%) rename tools/{MapleCashCosmeticsChecker/lib/care => input/cosmetics}/orbis/hair.txt (100%) rename tools/{MapleCashCosmeticsChecker/lib/care => input/cosmetics}/showa/face.txt (100%) rename tools/{MapleCashCosmeticsChecker/lib/care => input/cosmetics}/showa/hair.txt (100%) diff --git a/src/main/java/provider/wz/WZFiles.java b/src/main/java/provider/wz/WZFiles.java index 94b07e668c..e5073d0058 100644 --- a/src/main/java/provider/wz/WZFiles.java +++ b/src/main/java/provider/wz/WZFiles.java @@ -21,15 +21,15 @@ public enum WZFiles { private final String fileName; - WZFiles(String fileName) { - this.fileName = fileName; + WZFiles(String name) { + this.fileName = name + ".wz"; } public File getFile() { - return new File(getFilePath()); + return new File(DIRECTORY, fileName); } public String getFilePath() { - return String.format("%s/%s.wz", DIRECTORY, fileName); + return getFile().getPath(); } } diff --git a/tools/MapleCashCosmeticsChecker/src/maplecashcosmeticschecker/MapleCashCosmeticsChecker.java b/src/main/java/tools/mapletools/CashCosmeticsChecker.java similarity index 74% rename from tools/MapleCashCosmeticsChecker/src/maplecashcosmeticschecker/MapleCashCosmeticsChecker.java rename to src/main/java/tools/mapletools/CashCosmeticsChecker.java index bec5033721..8a19bc919d 100644 --- a/tools/MapleCashCosmeticsChecker/src/maplecashcosmeticschecker/MapleCashCosmeticsChecker.java +++ b/src/main/java/tools/mapletools/CashCosmeticsChecker.java @@ -1,77 +1,51 @@ -/* - This file is part of the HeavenMS MapleStory Server - Copyleft (L) 2016 - 2019 RonanLana +package tools.mapletools; - 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 maplecashcosmeticschecker; +import provider.wz.WZFiles; +import tools.Pair; import java.io.*; +import java.nio.charset.StandardCharsets; import java.util.*; -import java.util.Map.Entry; /** - * * @author RonanLana - - This application parses the cosmetic recipes defined within "lib/care" folder, loads - every present cosmetic itemid from the XML data, then checks the scripts for missed - cosmetics within the stylist/surgeon. Results from the search are reported in a report - file. - - Note: to best make use of this feature, set ignoreCurrentScriptCosmetics = true. This - way, every available cosmetic present on the recipes will be listed on the report. - - Estimated parse time: 1 minute - + *

+ * This application parses the cosmetic recipes defined within "lib/care" folder, loads + * every present cosmetic itemid from the XML data, then checks the scripts for missed + * cosmetics within the stylist/surgeon. Results from the search are reported in a report + * file. + *

+ * Note: to best make use of this feature, set IGNORE_CURRENT_SCRIPT_COSMETICS = true. This + * way, every available cosmetic present on the recipes will be listed on the report. + *

+ * Estimated parse time: 1 minute */ -public class MapleCashCosmeticsChecker { - static String libPath = "lib"; - static String handbookPath = "../../handbook"; - static String wzPath = "../../wz"; - static String scriptPath = "../../scripts"; - - static PrintWriter printWriter = null; - static InputStreamReader fileReader = null; - static BufferedReader bufferedReader = null; - - static boolean ignoreCurrentScriptCosmetics = false; - - static int initialStringLength = 50; - - static byte status = 0; - - static Map> scriptCosmetics = new HashMap<>(); - static Map scriptEntries = new HashMap<>(500); - - static Set allCosmetics = new HashSet<>(); - - static Set unusedCosmetics = new HashSet<>(); - static Map> usedCosmetics = new HashMap<>(); - - static Map couponNames = new HashMap<>(); - static Map cosmeticNpcs = new HashMap<>(); // expected only 1 NPC per cosmetic coupon (town care/salon) - static Map, Integer> cosmeticNpcids = new HashMap<>(); - - static Set missingCosmeticNames = new HashSet<>(); - static Map cosmeticNameIds = new HashMap<>(); - static Map cosmeticIdNames = new HashMap<>(); - - static Map, Set> missingCosmeticsNpcTypes = new HashMap<>(); - +public class CashCosmeticsChecker { + private static final String HANDBOOK_PATH = "handbook"; + private static final String SCRIPTS_PATH = "scripts"; + private static final String INPUT_DIRECTORY_PATH = ToolConstants.getInputFile("care").getPath(); + private static final File OUTPUT_FILE = ToolConstants.getOutputFile("cash_cosmetics_result.txt"); + private static final boolean IGNORE_CURRENT_SCRIPT_COSMETICS = false; // Toggle to preference + private static final int INITIAL_STRING_LENGTH = 50; + + private static final Map> scriptCosmetics = new HashMap<>(); + private static final Map scriptEntries = new HashMap<>(500); + private static final Set allCosmetics = new HashSet<>(); + private static final Set unusedCosmetics = new HashSet<>(); + private static final Map> usedCosmetics = new HashMap<>(); + private static final Map couponNames = new HashMap<>(); + private static final Map cosmeticNpcs = new HashMap<>(); // expected only 1 NPC per cosmetic coupon (town care/salon) + private static final Map, Integer> cosmeticNpcids = new HashMap<>(); + private static final Set missingCosmeticNames = new HashSet<>(); + private static final Map cosmeticNameIds = new HashMap<>(); + private static final Map cosmeticIdNames = new HashMap<>(); + private static final Map, Set> missingCosmeticsNpcTypes = new HashMap<>(); + + private static PrintWriter printWriter = null; + private static InputStreamReader fileReader = null; + private static BufferedReader bufferedReader = null; + private static byte status = 0; + private static String getName(String token) { int i, j; char[] dest; @@ -81,13 +55,13 @@ public class MapleCashCosmeticsChecker { i = token.indexOf("\"", i) + 1; //lower bound of the string j = token.indexOf("\"", i); //upper bound - dest = new char[initialStringLength]; + dest = new char[INITIAL_STRING_LENGTH]; token.getChars(i, j, dest, 0); d = new String(dest); - return(d.trim()); + return (d.trim()); } - + private static String getValue(String token) { int i, j; char[] dest; @@ -97,84 +71,81 @@ public class MapleCashCosmeticsChecker { i = token.indexOf("\"", i) + 1; //lower bound of the string j = token.indexOf("\"", i); //upper bound - dest = new char[initialStringLength]; + dest = new char[INITIAL_STRING_LENGTH]; token.getChars(i, j, dest, 0); d = new String(dest); - return(d.trim()); + return (d.trim()); } - + private static void forwardCursor(int st) { String line = null; try { - while(status >= st && (line = bufferedReader.readLine()) != null) { + while (status >= st && (line = bufferedReader.readLine()) != null) { simpleToken(line); } - } - catch(Exception e) { + } catch (Exception e) { e.printStackTrace(); } } private static void simpleToken(String token) { - if(token.contains("/imgdir")) { + if (token.contains("/imgdir")) { status -= 1; - } - else if(token.contains("imgdir")) { + } else if (token.contains("imgdir")) { status += 1; } } - + private static void translateToken(String token) { - if(token.contains("/imgdir")) { + if (token.contains("/imgdir")) { status -= 1; - } - else if(token.contains("imgdir")) { + } else if (token.contains("imgdir")) { status += 1; - + if (status == 3) { String d = getName(token); - + if (!(d.contentEquals("Face") || d.contentEquals("Hair"))) { forwardCursor(status); } } else if (status == 4) { String d = getName(token); - int itemid = Integer.valueOf(d); - + int itemid = Integer.parseInt(d); + int cosmeticid; if (itemid >= 30000) { cosmeticid = (itemid / 10) * 10; } else { cosmeticid = itemid - ((itemid / 100) % 10) * 100; } - + allCosmetics.add(cosmeticid); forwardCursor(status); } } } - + private static void readEqpStringData(String eqpStringDirectory) throws IOException { String line; - - fileReader = new InputStreamReader(new FileInputStream(eqpStringDirectory), "UTF-8"); + + fileReader = new InputStreamReader(new FileInputStream(eqpStringDirectory), StandardCharsets.UTF_8); bufferedReader = new BufferedReader(fileReader); - while((line = bufferedReader.readLine()) != null) { + while ((line = bufferedReader.readLine()) != null) { translateToken(line); } bufferedReader.close(); fileReader.close(); } - + private static void loadCosmeticWzData() throws IOException { System.out.println("Reading String.wz ..."); - readEqpStringData(wzPath + "/String.wz/Eqp.img.xml"); + readEqpStringData(WZFiles.STRING.getFilePath() + "/Eqp.img.xml"); } - + private static void setCosmeticUsage(List usedByNpcids, int cosmeticid) { if (!usedByNpcids.isEmpty()) { usedCosmetics.put(cosmeticid, usedByNpcids); @@ -182,7 +153,7 @@ public class MapleCashCosmeticsChecker { unusedCosmetics.add(cosmeticid); } } - + private static void listFiles(String directoryName, ArrayList files) { File directory = new File(directoryName); @@ -196,60 +167,60 @@ public class MapleCashCosmeticsChecker { } } } - + private static int getNpcIdFromFilename(String name) { try { - return Integer.valueOf(name.substring(0, name.indexOf('.'))); - } catch(Exception e) { + return Integer.parseInt(name.substring(0, name.indexOf('.'))); + } catch (Exception e) { return -1; } } - + private static List findCosmeticDataNpcids(int itemid) { List npcids = new LinkedList<>(); - for (Entry> sc : scriptCosmetics.entrySet()) { + for (Map.Entry> sc : scriptCosmetics.entrySet()) { if (sc.getValue().contains(itemid)) { npcids.add(itemid); } } - + return npcids; } - + private static void loadScripts() throws IOException { ArrayList files = new ArrayList<>(); - listFiles(scriptPath + "/npc", files); + listFiles(SCRIPTS_PATH + "/npc", files); - for(File f : files) { + for (File f : files) { Integer npcid = getNpcIdFromFilename(f.getName()); - + //System.out.println("Parsing " + f.getAbsolutePath()); - fileReader = new InputStreamReader(new FileInputStream(f), "UTF-8"); + fileReader = new InputStreamReader(new FileInputStream(f), StandardCharsets.UTF_8); bufferedReader = new BufferedReader(fileReader); String line; StringBuilder stringBuffer = new StringBuilder(); - + boolean cosmeticNpc = false; Set cosmeticids = new HashSet<>(); - while((line = bufferedReader.readLine())!=null){ + while ((line = bufferedReader.readLine()) != null) { String[] s = line.split("hair_. = Array\\(", 2); - + if (s.length > 1) { cosmeticNpc = true; s = s[1].split("\\)", 2); s = s[0].split(", "); - + for (String st : s) { if (!st.isEmpty()) { - int itemid = Integer.valueOf(st); + int itemid = Integer.parseInt(st); cosmeticids.add(itemid); } } } else { s = line.split("face_. = Array\\(", 2); - + if (s.length > 1) { cosmeticNpc = true; s = s[1].split("\\)", 2); @@ -257,18 +228,18 @@ public class MapleCashCosmeticsChecker { for (String st : s) { if (!st.isEmpty()) { - int itemid = Integer.valueOf(st); + int itemid = Integer.parseInt(st); cosmeticids.add(itemid); } } } } - + stringBuffer.append(line).append("\n"); } - + scriptEntries.put(npcid, stringBuffer.toString()); - + if (cosmeticNpc) { scriptCosmetics.put(npcid, cosmeticids); } @@ -277,72 +248,74 @@ public class MapleCashCosmeticsChecker { fileReader.close(); } } - + private static void processCosmeticScriptData() throws IOException { System.out.println("Reading script files ..."); loadScripts(); - - if (ignoreCurrentScriptCosmetics) { + + if (IGNORE_CURRENT_SCRIPT_COSMETICS) { for (Set npcCosmetics : scriptCosmetics.values()) { npcCosmetics.clear(); } } - + for (Integer itemid : allCosmetics) { List npcids = findCosmeticDataNpcids(itemid); setCosmeticUsage(npcids, itemid); } } - + private static List loadCosmeticCouponids() throws IOException { List couponItemids = new LinkedList<>(); - - fileReader = new InputStreamReader(new FileInputStream(handbookPath + "/Cash.txt"), "UTF-8"); + + fileReader = new InputStreamReader(new FileInputStream(getHandbookFileName("/Cash.txt")), StandardCharsets.UTF_8); bufferedReader = new BufferedReader(fileReader); String line; - while((line = bufferedReader.readLine())!=null){ - if (line.isEmpty()) continue; + while ((line = bufferedReader.readLine()) != null) { + if (line.isEmpty()) { + continue; + } String[] s = line.split(" - ", 3); - - int itemid = Integer.valueOf(s[0]); + + int itemid = Integer.parseInt(s[0]); if (itemid >= 5150000 && itemid < 5160000) { couponItemids.add(itemid); couponNames.put(itemid, s[1]); } } - + bufferedReader.close(); fileReader.close(); - + return couponItemids; } - + private static List findItemidOnScript(int itemid) { List files = new LinkedList<>(); String t = String.valueOf(itemid); - - for (Entry text : scriptEntries.entrySet()) { + + for (Map.Entry text : scriptEntries.entrySet()) { if (text.getValue().contains(t)) { files.add(text.getKey()); } } - + return files; } - + private static void loadCosmeticCouponNpcs() throws IOException { System.out.println("Locating cosmetic NPCs ..."); - + for (Integer itemid : loadCosmeticCouponids()) { List npcids = findItemidOnScript(itemid); - + if (!npcids.isEmpty()) { cosmeticNpcs.put(itemid, npcids.get(0)); } } } - + private enum CosmeticType { HAIRSTYLE, HAIRCOLOR, @@ -351,11 +324,11 @@ public class MapleCashCosmeticsChecker { EYE_COLOR, SKIN_CARE } - + private static Pair parseCosmeticCoupon(String[] tokens) { for (int i = 0; i < tokens.length; i++) { String s = tokens[i]; - + if (s.startsWith("Hair")) { if (s.contentEquals("Hairstyle")) { return new Pair<>(i, CosmeticType.HAIRSTYLE); @@ -378,10 +351,10 @@ public class MapleCashCosmeticsChecker { return new Pair<>(i, CosmeticType.SKIN_CARE); } } - + return null; } - + private static List getCosmeticCouponData(String town, String type, String subtype) { List ret = new ArrayList<>(3); ret.add(town); @@ -389,77 +362,83 @@ public class MapleCashCosmeticsChecker { ret.add(subtype); return ret; } - + private static List parseCosmeticCoupon(String couponName) { String town, type, subtype = "EXP"; - + String[] s = couponName.split(" Coupon ", 2); - + if (s.length > 1) { subtype = s[1].substring(1, s[1].length() - 1); } - + String[] tokens = s[0].split(" "); Pair cosmeticData = parseCosmeticCoupon(tokens); - if (cosmeticData == null) return null; - + if (cosmeticData == null) { + return null; + } + town = ""; for (int i = 0; i < cosmeticData.left; i++) { town += (tokens[i] + "_"); } town = town.substring(0, town.length() - 1).toLowerCase(); - + switch (cosmeticData.right) { case HAIRSTYLE: type = "hair"; break; - + case FACE_SURGERY: type = "face"; break; - + default: return null; } - + return getCosmeticCouponData(town, type, subtype); } - + private static void generateCosmeticPlaceNpcs() { - for (Entry e : couponNames.entrySet()) { + for (Map.Entry e : couponNames.entrySet()) { Integer npcid = cosmeticNpcs.get(e.getKey()); - if (npcid == null) continue; - + if (npcid == null) { + continue; + } + String couponName = e.getValue(); List couponData = parseCosmeticCoupon(couponName); - - if (couponData == null) continue; + + if (couponData == null) { + continue; + } cosmeticNpcids.put(couponData, npcid); } } - + private static Integer getCosmeticNpcid(String townName, String typeCosmetic, String typeCoupon) { return cosmeticNpcids.get(getCosmeticCouponData(townName, typeCosmetic, typeCoupon)); } - + private static String getCosmeticName(String name, boolean gender) { - String ret = name + " (" + (gender ? "F" : "M") + ")"; - return ret; + final String genderString = gender ? "F" : "M"; + return String.format("%s (%s)", name, genderString); } - + private static void loadCosmeticNames(String cosmeticPath) throws IOException { - fileReader = new InputStreamReader(new FileInputStream(cosmeticPath), "UTF-8"); + fileReader = new InputStreamReader(new FileInputStream(cosmeticPath), StandardCharsets.UTF_8); bufferedReader = new BufferedReader(fileReader); String line; - while((line = bufferedReader.readLine()) != null) { + while ((line = bufferedReader.readLine()) != null) { String[] s = line.split(" - ", 3); - int itemid = Integer.valueOf(s[0]); - + int itemid = Integer.parseInt(s[0]); + String name; if (itemid < 30000) { itemid = itemid - ((itemid / 100) % 10) * 100; - + int idx = s[1].lastIndexOf(" "); if (idx > -1) { name = s[1].substring(0, idx); @@ -468,7 +447,7 @@ public class MapleCashCosmeticsChecker { } } else { itemid = (Integer.valueOf(s[0]) / 10) * 10; - + int idx = s[1].indexOf(" "); if (idx > -1) { name = s[1].substring(idx + 1); @@ -476,17 +455,17 @@ public class MapleCashCosmeticsChecker { name = s[1]; } } - + name = name.trim(); - + String cname = getCosmeticName(name, (((itemid / 1000) % 10) % 3) != 0); - + /* if (cosmeticNameIds.containsKey(cname) && Math.abs(cosmeticNameIds.get(cname) - itemid) > 50) { System.out.println("Clashing '" + name + "' " + itemid + "/" + cosmeticNameIds.get(cname)); } */ - + cosmeticNameIds.put(cname, itemid); cosmeticIdNames.put(itemid, name); } @@ -494,17 +473,21 @@ public class MapleCashCosmeticsChecker { bufferedReader.close(); fileReader.close(); } - + private static void loadCosmeticNames() throws IOException { System.out.println("Reading cosmetics from handbook ..."); - - loadCosmeticNames(handbookPath + "/Equip/Face.txt"); - loadCosmeticNames(handbookPath + "/Equip/Hair.txt"); + + loadCosmeticNames(getHandbookFileName("/Equip/Face.txt")); + loadCosmeticNames(getHandbookFileName("/Equip/Hair.txt")); } - + + private static String getHandbookFileName(String fileName) { + return HANDBOOK_PATH + fileName; + } + private static List fetchExpectedCosmetics(String[] cosmeticList, boolean gender) { List list = new LinkedList<>(); - + for (String cosmetic : cosmeticList) { String cname = getCosmeticName(cosmetic, gender); Integer itemid = cosmeticNameIds.get(cname); @@ -514,30 +497,30 @@ public class MapleCashCosmeticsChecker { missingCosmeticNames.add(cosmetic); } } - + return list; } - + private static void verifyCosmeticExpectedFile(File f) throws IOException { String townName = f.getParent().substring(f.getParent().lastIndexOf("\\") + 1); String typeCosmetic = f.getName().substring(0, f.getName().indexOf(".")); - - fileReader = new InputStreamReader(new FileInputStream(f), "UTF-8"); + + fileReader = new InputStreamReader(new FileInputStream(f), StandardCharsets.UTF_8); bufferedReader = new BufferedReader(fileReader); String line; - while((line = bufferedReader.readLine())!=null){ + while ((line = bufferedReader.readLine()) != null) { String[] s = line.split(": ", 2); String[] t = s[0].split("ale "); - + String typeCoupon = t[1]; boolean gender = !t[0].contentEquals("M"); - + Integer npcid = getCosmeticNpcid(townName, typeCosmetic, typeCoupon); if (npcid != null) { String[] cosmetics = s[1].split(", "); List cosmeticItemids = fetchExpectedCosmetics(cosmetics, gender); - + Set npcCosmetics = scriptCosmetics.get(npcid); Set missingCosmetics = new HashSet<>(); for (Integer itemid : cosmeticItemids) { @@ -545,10 +528,10 @@ public class MapleCashCosmeticsChecker { missingCosmetics.add(itemid); } } - + if (!missingCosmetics.isEmpty()) { Pair key = new Pair<>(npcid, typeCoupon); - + Set list = missingCosmeticsNpcTypes.get(key); if (list == null) { missingCosmeticsNpcTypes.put(key, missingCosmetics); @@ -558,34 +541,34 @@ public class MapleCashCosmeticsChecker { } } } - + bufferedReader.close(); fileReader.close(); } - + private static void verifyCosmeticExpectedData() throws IOException { System.out.println("Analyzing cosmetic NPC scripts ..."); - + ArrayList cosmeticRecipes = new ArrayList<>(); - listFiles(libPath + "/care", cosmeticRecipes); - + listFiles(INPUT_DIRECTORY_PATH, cosmeticRecipes); + for (File f : cosmeticRecipes) { verifyCosmeticExpectedFile(f); } } - + private static List, List>> getSortedMapEntries(Map, Set> map) { List, List>> list = new ArrayList<>(map.size()); - for(Entry, Set> e : map.entrySet()) { + for (Map.Entry, Set> e : map.entrySet()) { List il = new ArrayList<>(2); il.addAll(e.getValue()); - - Collections.sort(il, (o1, o2) -> o1 - o2); - + + il.sort((o1, o2) -> o1 - o2); + list.add(new Pair<>(e.getKey(), il)); } - - Collections.sort(list, (o1, o2) -> { + + list.sort((o1, o2) -> { int cmp = o1.getLeft().getLeft() - o2.getLeft().getLeft(); if (cmp == 0) { return o1.getLeft().getRight().compareTo(o2.getLeft().getRight()); @@ -593,20 +576,20 @@ public class MapleCashCosmeticsChecker { return cmp; } }); - + return list; } - + private static void printReportFileHeader() { printWriter.println(" # Report File autogenerated from the MapleCashCosmeticsChecker feature by Ronan Lana."); printWriter.println(" # Generated data takes into account several data info from the server source files and the server-side WZ.xmls."); printWriter.println(); } - + private static Pair, List> getCosmeticReport(List itemids) { List maleItemids = new LinkedList<>(); List femaleItemids = new LinkedList<>(); - + for (Integer i : itemids) { if ((((i / 1000) % 10) % 3) == 0) { maleItemids.add(i); @@ -614,10 +597,10 @@ public class MapleCashCosmeticsChecker { femaleItemids.add(i); } } - + return new Pair<>(maleItemids, femaleItemids); } - + private static void reportNpcCosmetics(List itemids) { if (!itemids.isEmpty()) { String res = " "; @@ -625,75 +608,75 @@ public class MapleCashCosmeticsChecker { res += (i + ", "); unusedCosmetics.remove(i); } - + printWriter.println(res.substring(0, res.length() - 2)); } } - + private static void reportCosmeticResults() throws IOException { System.out.println("Reporting results ..."); - - printWriter = new PrintWriter("lib/result.txt", "UTF-8"); - + + printWriter = new PrintWriter(OUTPUT_FILE, StandardCharsets.UTF_8); + printReportFileHeader(); - + if (!missingCosmeticsNpcTypes.isEmpty()) { printWriter.println("Found " + missingCosmeticsNpcTypes.size() + " entries with missing cosmetic entries."); - + for (Pair, List> mcn : getSortedMapEntries(missingCosmeticsNpcTypes)) { printWriter.println(" NPC " + mcn.getLeft()); - + Pair, List> genderItemids = getCosmeticReport(mcn.getRight()); reportNpcCosmetics(genderItemids.getLeft()); reportNpcCosmetics(genderItemids.getRight()); printWriter.println(); } } - + if (!unusedCosmetics.isEmpty()) { printWriter.println("Unused cosmetics: " + unusedCosmetics.size()); - + List list = new ArrayList<>(unusedCosmetics); Collections.sort(list); - + for (Integer i : list) { printWriter.println(i + " " + cosmeticIdNames.get(i)); } - + printWriter.println(); } - + if (!missingCosmeticNames.isEmpty()) { printWriter.println("Missing cosmetic itemids: " + missingCosmeticNames.size()); - + List listString = new ArrayList<>(missingCosmeticNames); Collections.sort(listString); - + for (String c : listString) { printWriter.println(c); } - + printWriter.println(); } printWriter.close(); } - + public static void main(String[] args) { try { loadCosmeticWzData(); processCosmeticScriptData(); - + loadCosmeticCouponNpcs(); generateCosmeticPlaceNpcs(); - + loadCosmeticNames(); verifyCosmeticExpectedData(); - + reportCosmeticResults(); System.out.println("Done!"); } catch (IOException ioe) { ioe.printStackTrace(); } } -} \ No newline at end of file +} diff --git a/src/main/java/tools/mapletools/ToolConstants.java b/src/main/java/tools/mapletools/ToolConstants.java index aa097172cf..f5f4fb9b34 100644 --- a/src/main/java/tools/mapletools/ToolConstants.java +++ b/src/main/java/tools/mapletools/ToolConstants.java @@ -6,6 +6,10 @@ public class ToolConstants { public static final File INPUT_DIRECTORY = new File("tools/input"); public static final File OUTPUT_DIRECTORY = new File("tools/output"); + public static File getInputFile(String fileName) { + return new File(INPUT_DIRECTORY, fileName); + } + public static File getOutputFile(String fileName) { return new File(OUTPUT_DIRECTORY, fileName); } diff --git a/tools/MapleCashCosmeticsChecker/lib/result.txt b/tools/MapleCashCosmeticsChecker/lib/result.txt deleted file mode 100644 index 60ce233efb..0000000000 --- a/tools/MapleCashCosmeticsChecker/lib/result.txt +++ /dev/null @@ -1,213 +0,0 @@ - # Report File autogenerated from the MapleCashCosmeticsChecker feature by Ronan Lana. - # Generated data takes into account several data info from the server source files and the server-side WZ.xmls. - -Found 42 entries with missing cosmetic entries. - NPC 1012103:VIP - 30060, 30140, 30200, 30210, 30310, 33040, 33100 - 31150, 31300, 31350, 31700, 31740, 34050, 34110 - - NPC 1012104:EXP - 30030, 30140, 30200, 30210, 30310, 30610, 33040, 33100 - 31070, 31150, 31300, 31350, 31430, 31700, 34050, 34110 - - NPC 1012104:REG - 30060, 30140, 30200, 30210, 30310, 30610, 33040, 33100 - 31070, 31080, 31150, 31300, 31350, 31700, 34050, 34110 - - NPC 1052004:VIP - 20000, 20001, 20003, 20004, 20005, 20006, 20007, 20008, 20012, 20014, 20015, 20022, 20028, 20031 - 21000, 21001, 21002, 21003, 21004, 21005, 21006, 21007, 21008, 21012, 21013, 21014, 21023, 21026 - - NPC 1052005:REG - 20000, 20005, 20008, 20012, 20016, 20022, 20032 - 21000, 21002, 21008, 21014, 21020, 21024, 21029 - - NPC 1052100:VIP - 30040, 30130, 30780, 30850, 30860, 30920, 33040 - 31090, 31140, 31330, 31440, 31760, 31880, 34050 - - NPC 1052101:EXP - 30130, 30430, 30520, 30770, 30780, 30850, 30920, 33040 - 31060, 31140, 31330, 31520, 31760, 31880, 34010, 34050 - - NPC 1052101:REG - 30040, 30130, 30520, 30770, 30780, 30850, 30920, 33040 - 31060, 31140, 31330, 31440, 31520, 31750, 31760, 31880, 34050 - - NPC 2010001:VIP - 30230, 30260, 30280, 30340, 30490 - 31110, 31220, 31230, 31630, 31790 - - NPC 2010002:VIP - 20000, 20001, 20003, 20004, 20005, 20006, 20007, 20008, 20012, 20014, 20022, 20028, 20031 - 21000, 21001, 21002, 21003, 21004, 21005, 21006, 21007, 21008, 21012, 21014, 21023, 21026 - - NPC 2012007:EXP - 30230, 30280, 30340, 30490, 30530, 30740 - 31110, 31220, 31230, 31710, 31790, 31890, 31930 - - NPC 2012007:REG - 30230, 30260, 30280, 30340, 30490, 30530, 30630, 30740 - 31110, 31220, 31230, 31630, 31650, 31710, 31790, 31890, 31930 - - NPC 2012009:REG - 20003, 20011, 20021, 20022, 20023, 20027, 20031 - 21004, 21007, 21010, 21012, 21020, 21021, 21030 - - NPC 2040019:REG - 20001, 20003, 20007, 20013, 20021, 20023, 20025 - 21002, 21004, 21006, 21008, 21022, 21027, 21029 - - NPC 2041007:VIP - 30160, 30190, 30250, 30640, 30660, 30840, 30870, 30990 - 31270, 31290, 31550, 31680, 31810, 31830, 31840, 31870 - - NPC 2041009:EXP - 30030, 30190, 30220, 30250, 30540, 30610, 30620, 30640, 30650, 30660, 30840, 30990 - 31170, 31270, 31430, 31510, 31540, 31550, 31600, 31680, 31810, 31830, 31840, 31870 - - NPC 2041009:REG - 30190, 30220, 30250, 30540, 30610, 30620, 30640, 30650, 30660, 30840, 30870, 30940, 30990 - 31170, 31270, 31290, 31510, 31540, 31550, 31600, 31640, 31680, 31810, 31830, 31840, 31870 - - NPC 2041010:VIP - 20000, 20001, 20003, 20004, 20005, 20006, 20007, 20008, 20011, 20012, 20014, 20031 - 21000, 21001, 21002, 21003, 21004, 21005, 21006, 21007, 21008, 21010, 21012, 21014 - - NPC 2090100:VIP - 30150, 30240, 30370, 30420, 30640, 30710, 30750, 30810 - 31140, 31160, 31180, 31300, 31460, 31470, 31660, 31910 - - NPC 2090101:EXP - 30030, 30150, 30240, 30370, 30420, 30550, 30600, 30640, 30700, 30710, 30720, 30750, 30810, 30830 - 31140, 31160, 31180, 31210, 31300, 31430, 31460, 31470, 31660, 31690, 31800, 31890, 31910, 31940 - - NPC 2090104:REG - 20002, 20005, 20007, 20011, 20014, 20017, 20029 - 21001, 21010, 21013, 21018, 21020, 21021, 21030 - - NPC 2090104:VIP - 20000, 20001, 20004, 20005, 20006, 20007, 20009, 20012, 20022, 20028, 20031 - 21000, 21003, 21005, 21006, 21008, 21009, 21011, 21012, 21023, 21024, 21026 - - NPC 2100005:REG - 30150, 30170, 30180, 30320, 30330, 30410, 30460, 30680, 30800, 30820, 30900 - 31090, 31190, 31330, 31340, 31400, 31420, 31520, 31620, 31650, 31660, 34000 - - NPC 2100006:VIP - 30150, 30170, 30180, 30320, 30330, 30410, 30460, 30820, 30900 - 31040, 31090, 31190, 31330, 31340, 31400, 31420, 31620, 31660 - - NPC 2100008:VIP - 20000, 20004, 20005, 20012, 20013, 20031 - 21000, 21003, 21006, 21009, 21012, 21024 - - NPC 2100009:REG - 20001, 20003, 20009, 20010, 20025, 20031 - 21002, 21009, 21011, 21013, 21016, 21029, 21030 - - NPC 9120100:VIP - 30260, 30280, 30340, 30710, 30780, 30800, 30810, 30820, 30920 - 31000, 31030, 31100, 31350, 31460, 31550, 31770, 31790, 31850 - - NPC 9120101:REG - 30260, 30280, 30340, 30360, 30710, 30780, 30790, 30800, 30810, 30820, 30920 - 31350, 31410, 31460, 31540, 31550, 31710, 31720, 31770, 31790, 31800, 31850, 34000 - - NPC 9120102:VIP - 20000, 20004, 20005, 20012, 20020, 20031 - 21000, 21003, 21006, 21012, 21021, 21024 - - NPC 9120103:REG - 20000, 20016, 20019, 20020, 20021, 20024, 20026 - 21000, 21002, 21009, 21016, 21022, 21025, 21027 - - NPC 9201015:VIP - 30050, 30300, 30410, 30450, 30510, 30570, 30580, 30590, 30660, 30910 - 31150, 31220, 31260, 31310, 31420, 31480, 31490, 31580, 31590, 31610, 31630 - - NPC 9201016:EXP - 30000, 30020, 30110, 30130, 30160, 30190, 30240, 30270, 30430 - 31000, 31030, 31050, 31070, 31090, 31150, 31310, 31910, 34010 - - NPC 9201018:VIP - 20000, 20001, 20003, 20004, 20005, 20006, 20007, 20008, 20018, 20019 - 21001, 21002, 21003, 21004, 21005, 21006, 21007, 21012, 21018, 21019 - - NPC 9201019:REG - 20002, 20005, 20007, 20011, 20014, 20027, 20029 - 21001, 21005, 21007, 21017, 21018, 21020, 21022 - - NPC 9201063:EXP - 30250, 30400, 30430, 30440, 30490, 30730, 30830, 30870, 30880, 33100 - 31320, 31450, 31560, 31570, 31690, 31720, 31730, 31830, 34010 - - NPC 9201064:VIP - 30250, 30490, 30730, 30870, 30880, 33100 - 31320, 31450, 31560, 31730, 31830 - - NPC 9201069:VIP - 20000, 20001, 20003, 20004, 20005, 20006, 20008, 20012, 20031 - 21001, 21002, 21003, 21004, 21005, 21006, 21008, 21012, 21016 - - NPC 9201070:REG - 20001, 20008, 20011, 20013, 20024, 20029, 20032 - 21000, 21007, 21011, 21012, 21017, 21020, 21022 - - NPC 9270023:REG - 20002, 20005, 20006, 20013, 20017, 20021, 20024 - 21002, 21003, 21014, 21016, 21017, 21021, 21027 - - NPC 9270024:VIP - 20005, 20012, 20013, 20020, 20021, 20026 - 21006, 21009, 21011, 21012, 21021, 21025 - - NPC 9270036:VIP - 30000, 30020, 30110, 30120, 30270, 30290, 30310, 30670, 30840 - 31010, 31050, 31110, 31120, 31240, 31250, 31280, 31670, 31810 - - NPC 9270037:REG - 30110, 30180, 30260, 30290, 30300, 30350, 30470, 30720, 30840 - 31110, 31200, 31250, 31280, 31600, 31640, 31670, 31810, 34020 - -Unused cosmetics: 22 -30010 Zeta -30070 Back -30080 Buzzcut -30090 Mohawk -30100 Fantasy -30480 Babby Cut -30560 Grand Lionman -30690 Metro Man -30760 Bowling Ball -30890 Eastern Mystery -30930 Boy Band Cut -30950 Volume Cut -31020 Francesca -31130 Jolie -31530 Zessica -31780 ???? ?? -31820 Grace -31860 Laguna Beach -31920 CL Hair -31950 Vintage Flip -33000 Prince Cut -34030 Designer Hair - -Missing cosmetic itemids: 15 -Bohemian Hair -Bow Hair -Clean-Cut Short Hair -Dual Blade Hair -Evan Hair (F) -Evan Hair (M) -Explosion -Lilin Hair -Low Cut Bob -Messy Pigtails -Oh So Windy -Spiky Shag -Top Tied Hair -Updo -Windy Hair - diff --git a/tools/MapleCashCosmeticsChecker/src/maplecashcosmeticschecker/Pair.java b/tools/MapleCashCosmeticsChecker/src/maplecashcosmeticschecker/Pair.java deleted file mode 100644 index 3e2f924b51..0000000000 --- a/tools/MapleCashCosmeticsChecker/src/maplecashcosmeticschecker/Pair.java +++ /dev/null @@ -1,121 +0,0 @@ -/* -This file is part of the OdinMS Maple Story Server -Copyright (C) 2008 ~ 2010 Patrick Huy -Matthias Butz -Jan Christian Meyer - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License 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 maplecashcosmeticschecker; - -/** - * Represents a pair of values. - * - * @author Frz - * @since Revision 333 - * @version 1.0 - * - * @param The type of the left value. - * @param The type of the right value. - */ -public class Pair { - - public E left; - public F right; - - /** - * Class constructor - pairs two objects together. - * - * @param left The left object. - * @param right The right object. - */ - public Pair(E left, F right) { - this.left = left; - this.right = right; - } - - /** - * Gets the left value. - * - * @return The left value. - */ - public E getLeft() { - return left; - } - - /** - * Gets the right value. - * - * @return The right value. - */ - public F getRight() { - return right; - } - - /** - * Turns the pair into a string. - * - * @return Each value of the pair as a string joined with a colon. - */ - @Override - public String toString() { - return left.toString() + ":" + right.toString(); - } - - /** - * Gets the hash code of this pair. - */ - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((left == null) ? 0 : left.hashCode()); - result = prime * result + ((right == null) ? 0 : right.hashCode()); - return result; - } - - /** - * Checks to see if two pairs are equal. - */ - @SuppressWarnings("unchecked") - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - final Pair other = (Pair) obj; - if (left == null) { - if (other.left != null) { - return false; - } - } else if (!left.equals(other.left)) { - return false; - } - if (right == null) { - if (other.right != null) { - return false; - } - } else if (!right.equals(other.right)) { - return false; - } - return true; - } -} \ No newline at end of file diff --git a/tools/input/.gitignore b/tools/input/.gitignore index c96a04f008..9e88c6e0f0 100644 --- a/tools/input/.gitignore +++ b/tools/input/.gitignore @@ -1,2 +1,4 @@ * +!*/ +!/cosmetics/** !.gitignore \ No newline at end of file diff --git a/tools/MapleCashCosmeticsChecker/lib/care/amoria/face.txt b/tools/input/cosmetics/amoria/face.txt similarity index 100% rename from tools/MapleCashCosmeticsChecker/lib/care/amoria/face.txt rename to tools/input/cosmetics/amoria/face.txt diff --git a/tools/MapleCashCosmeticsChecker/lib/care/amoria/hair.txt b/tools/input/cosmetics/amoria/hair.txt similarity index 100% rename from tools/MapleCashCosmeticsChecker/lib/care/amoria/hair.txt rename to tools/input/cosmetics/amoria/hair.txt diff --git a/tools/MapleCashCosmeticsChecker/lib/care/ariant/face.txt b/tools/input/cosmetics/ariant/face.txt similarity index 100% rename from tools/MapleCashCosmeticsChecker/lib/care/ariant/face.txt rename to tools/input/cosmetics/ariant/face.txt diff --git a/tools/MapleCashCosmeticsChecker/lib/care/ariant/hair.txt b/tools/input/cosmetics/ariant/hair.txt similarity index 100% rename from tools/MapleCashCosmeticsChecker/lib/care/ariant/hair.txt rename to tools/input/cosmetics/ariant/hair.txt diff --git a/tools/MapleCashCosmeticsChecker/lib/care/cbd/face.txt b/tools/input/cosmetics/cbd/face.txt similarity index 100% rename from tools/MapleCashCosmeticsChecker/lib/care/cbd/face.txt rename to tools/input/cosmetics/cbd/face.txt diff --git a/tools/MapleCashCosmeticsChecker/lib/care/cbd/hair.txt b/tools/input/cosmetics/cbd/hair.txt similarity index 100% rename from tools/MapleCashCosmeticsChecker/lib/care/cbd/hair.txt rename to tools/input/cosmetics/cbd/hair.txt diff --git a/tools/MapleCashCosmeticsChecker/lib/colors.txt b/tools/input/cosmetics/colors.txt similarity index 100% rename from tools/MapleCashCosmeticsChecker/lib/colors.txt rename to tools/input/cosmetics/colors.txt diff --git a/tools/MapleCashCosmeticsChecker/lib/care/henesys/face.txt b/tools/input/cosmetics/henesys/face.txt similarity index 100% rename from tools/MapleCashCosmeticsChecker/lib/care/henesys/face.txt rename to tools/input/cosmetics/henesys/face.txt diff --git a/tools/MapleCashCosmeticsChecker/lib/care/henesys/hair.txt b/tools/input/cosmetics/henesys/hair.txt similarity index 100% rename from tools/MapleCashCosmeticsChecker/lib/care/henesys/hair.txt rename to tools/input/cosmetics/henesys/hair.txt diff --git a/tools/MapleCashCosmeticsChecker/lib/care/kerning_city/face.txt b/tools/input/cosmetics/kerning_city/face.txt similarity index 100% rename from tools/MapleCashCosmeticsChecker/lib/care/kerning_city/face.txt rename to tools/input/cosmetics/kerning_city/face.txt diff --git a/tools/MapleCashCosmeticsChecker/lib/care/kerning_city/hair.txt b/tools/input/cosmetics/kerning_city/hair.txt similarity index 100% rename from tools/MapleCashCosmeticsChecker/lib/care/kerning_city/hair.txt rename to tools/input/cosmetics/kerning_city/hair.txt diff --git a/tools/MapleCashCosmeticsChecker/lib/care/ludibrium/face.txt b/tools/input/cosmetics/ludibrium/face.txt similarity index 100% rename from tools/MapleCashCosmeticsChecker/lib/care/ludibrium/face.txt rename to tools/input/cosmetics/ludibrium/face.txt diff --git a/tools/MapleCashCosmeticsChecker/lib/care/ludibrium/hair.txt b/tools/input/cosmetics/ludibrium/hair.txt similarity index 100% rename from tools/MapleCashCosmeticsChecker/lib/care/ludibrium/hair.txt rename to tools/input/cosmetics/ludibrium/hair.txt diff --git a/tools/MapleCashCosmeticsChecker/lib/care/mu_lung/face.txt b/tools/input/cosmetics/mu_lung/face.txt similarity index 100% rename from tools/MapleCashCosmeticsChecker/lib/care/mu_lung/face.txt rename to tools/input/cosmetics/mu_lung/face.txt diff --git a/tools/MapleCashCosmeticsChecker/lib/care/mu_lung/hair.txt b/tools/input/cosmetics/mu_lung/hair.txt similarity index 100% rename from tools/MapleCashCosmeticsChecker/lib/care/mu_lung/hair.txt rename to tools/input/cosmetics/mu_lung/hair.txt diff --git a/tools/MapleCashCosmeticsChecker/lib/care/nlc/face.txt b/tools/input/cosmetics/nlc/face.txt similarity index 100% rename from tools/MapleCashCosmeticsChecker/lib/care/nlc/face.txt rename to tools/input/cosmetics/nlc/face.txt diff --git a/tools/MapleCashCosmeticsChecker/lib/care/nlc/hair.txt b/tools/input/cosmetics/nlc/hair.txt similarity index 100% rename from tools/MapleCashCosmeticsChecker/lib/care/nlc/hair.txt rename to tools/input/cosmetics/nlc/hair.txt diff --git a/tools/MapleCashCosmeticsChecker/lib/care/orbis/face.txt b/tools/input/cosmetics/orbis/face.txt similarity index 100% rename from tools/MapleCashCosmeticsChecker/lib/care/orbis/face.txt rename to tools/input/cosmetics/orbis/face.txt diff --git a/tools/MapleCashCosmeticsChecker/lib/care/orbis/hair.txt b/tools/input/cosmetics/orbis/hair.txt similarity index 100% rename from tools/MapleCashCosmeticsChecker/lib/care/orbis/hair.txt rename to tools/input/cosmetics/orbis/hair.txt diff --git a/tools/MapleCashCosmeticsChecker/lib/care/showa/face.txt b/tools/input/cosmetics/showa/face.txt similarity index 100% rename from tools/MapleCashCosmeticsChecker/lib/care/showa/face.txt rename to tools/input/cosmetics/showa/face.txt diff --git a/tools/MapleCashCosmeticsChecker/lib/care/showa/hair.txt b/tools/input/cosmetics/showa/hair.txt similarity index 100% rename from tools/MapleCashCosmeticsChecker/lib/care/showa/hair.txt rename to tools/input/cosmetics/showa/hair.txt